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

--no commit message

--no commit message
上级 2e63b5ff
......@@ -155,6 +155,8 @@
90132=Aggregate {0} not found
90133=Cannot change the setting {0} when the database is already open
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}
HY004=Unknown data type\: {0}
HYC00=Feature not supported
......
......@@ -2397,7 +2397,10 @@ public class Parser {
if (types[i] == CHAR_SPECIAL_2) {
i++;
}
// fall through
currentToken = sqlCommand.substring(start, i);
currentTokenType = getSpecialType(currentToken);
parseIndex = i;
return;
case CHAR_SPECIAL_1:
currentToken = sqlCommand.substring(start, i);
currentTokenType = getSpecialType(currentToken);
......@@ -2600,7 +2603,6 @@ public class Parser {
command[i] = ' ';
command[i + 1] = ' ';
i++;
break;
} else if (command[i + 1] == '/') {
// single line comment
changed = true;
......@@ -2613,9 +2615,10 @@ public class Parser {
command[i++] = ' ';
checkRunOver(i, len, startLoop);
}
break;
} else {
type = CHAR_SPECIAL_1;
}
// fall through
break;
case '-':
if (command[i + 1] == '-') {
// single line comment
......@@ -2629,9 +2632,10 @@ public class Parser {
command[i++] = ' ';
checkRunOver(i, len, startLoop);
}
break;
} else {
type = CHAR_SPECIAL_1;
}
// fall through
break;
case '(':
case ')':
case '{':
......
......@@ -549,6 +549,9 @@ public class Select extends Query {
Expression on = f.getJoinCondition();
if (on != null) {
if (!on.isEverything(ExpressionVisitor.EVALUATABLE)) {
if (f.isJoinOuter()) {
throw Message.getSQLException(ErrorCode.UNSUPPORTED_OUTER_JOIN_CONDITION_1, on.getSQL());
}
f.removeJoinCondition();
// need to check that all added are bound to a table
on = on.optimize(session);
......
......@@ -316,6 +316,7 @@ public class ErrorCode {
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 DATABASE_IS_IN_EXCLUSIVE_MODE = 90135;
public static final int UNSUPPORTED_OUTER_JOIN_CONDITION_1 = 90136;
/**
* INTERNAL
......
......@@ -127,6 +127,7 @@ public class ScanIndex extends BaseIndex {
row.setPos(key);
rows.set(key, row);
}
row.setDeleted(false);
}
if (database.isMultiVersion()) {
if (delta == null) {
......
......@@ -155,7 +155,8 @@
90132=Aggregat-Funktion {0} nicht gefunden
90133=Kann das Setting {0} nicht \u00E4ndern wenn die Datenbank bereits ge\u00F6ffnet ist
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}
HY004=Unbekannter Datentyp\: {0}
HYC00=Dieses Feature wird unterst\u00FCtzt
......
......@@ -156,6 +156,7 @@
90133=Cannot change the setting {0} when the database is already open
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}
HY004=Unknown data type\: {0}
HYC00=Feature not supported
......
......@@ -156,6 +156,7 @@
90133=\#Cannot change the setting {0} when the database is already open
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=\u4E00\u822C\u30A8\u30E9\u30FC\: {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
......
......@@ -156,6 +156,7 @@
90133=\#Cannot change the setting {0} when the database is already open
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=Blad ogolny\: {0}
HY004=Nieznany typ danyche\: {0}
HYC00=Cecha nie jest wspierana
......
......@@ -156,6 +156,7 @@
90133=\#Cannot change the setting {0} when the database is already open
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=Erro geral\: {0}
HY004=Tipo de dados desconhecido\: {0}
HYC00=Recurso n\u00E3o suportado
......
......@@ -91,6 +91,12 @@ public class FtpControl extends Thread {
return;
}
server.log(">" + command);
FtpEventListener listener = server.getEventListener();
FtpEvent event = null;
if (listener != null) {
event = new FtpEvent(this, command, param);
listener.beforeCommand(event);
}
replied = false;
if (connected) {
processConnected(command, param);
......@@ -126,8 +132,12 @@ public class FtpControl extends Thread {
}
}
if (!replied) {
listener.onUnsupportedCommand(event);
reply(506, "Invalid command");
}
if (listener != null) {
listener.afterCommand(event);
}
}
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 {
private boolean allowTask;
static final String TASK_SUFFIX = ".task";
private FtpEventListener eventListener;
public void listen() {
try {
while (serverSocket != null) {
......@@ -311,8 +313,31 @@ public class FtpServer implements Service {
p.destroy();
}
/**
* Get the file system used by this FTP server.
*
* @return the file system
*/
public FileSystem getFileSystem() {
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;
}
}
......@@ -200,32 +200,32 @@ function keyDown(event) {
return false;
}
if (key == 13 && event.ctrlKey) {
// ctrl + return
// ctrl + return
document.h2query.submit();
return false;
} else if(key == 32 && event.ctrlKey) {
// ctrl + space
autoCompleteManual = true;
lastQuery = null;
lastList = '';
// ctrl + space
autoCompleteManual = true;
lastQuery = null;
lastList = '';
showAutoCompleteNow();
return false;
} else if(key == 190 && autoComplete==0) {
// dot
// dot
help();
return true;
}
var table = getAutoCompleteTable();
if(table.rows.length > 0) {
if(key == 27) {
// escape
// escape
while(table.rows.length > 0) {
table.deleteRow(0);
}
showOutput('');
return false;
} else if((key == 13 && !event.shiftKey) || (key==9 && !event.shiftKey)) {
// enter or tab
// enter or tab
if(table.rows.length > selectedRow) {
var row = table.rows[selectedRow];
if(row.cells.length>1) {
......@@ -237,14 +237,14 @@ function keyDown(event) {
return false;
}
} else if(key == 38 && !event.shiftKey) {
// up
// up
if(table.rows.length > selectedRow) {
selectedRow = selectedRow <= 0 ? table.rows.length-1 : selectedRow-1;
highlightRow(selectedRow);
}
return false;
} else if(key == 40 && !event.shiftKey) {
// down
// down
if(table.rows.length > selectedRow) {
selectedRow = selectedRow >= table.rows.length-1 ? 0 : selectedRow+1;
highlightRow(selectedRow);
......@@ -262,11 +262,11 @@ function keyDown(event) {
function keyUp(event) {
if(autoComplete != 0) {
var key=event == null ? 0 : (event.keyCode? event.keyCode : event.charCode);
if(key != 37 && key != 38 && key != 39 && key != 40) {
// left, right, up, down: don't show autocomplete
showAutoComplete();
}
var key=event == null ? 0 : (event.keyCode? event.keyCode : event.charCode);
if(key != 37 && key != 38 && key != 39 && key != 40) {
// left, right, up, down: don't show autocomplete
showAutoComplete();
}
}
return true;
}
......
......@@ -61,32 +61,32 @@ function editRow(row, session, write, undo) {
}
function editCancel(row) {
var editing = document.getElementById('editing');
editing.row.value = row;
editing.op.value='3';
editing.submit();
var editing = document.getElementById('editing');
editing.row.value = row;
editing.op.value='3';
editing.submit();
}
function editOk(row) {
var editing = document.getElementById('editing');
editing.row.value = row;
editing.op.value='1';
editing.submit();
var editing = document.getElementById('editing');
editing.row.value = row;
editing.op.value='1';
editing.submit();
}
function editKeyDown(row, object, event) {
var key=event.keyCode? event.keyCode : event.charCode;
if(key == 46 && event.ctrlKey) {
// ctrl + delete
object.value = 'null';
return false;
} else if(key == 13) {
editOk(row);
return false;
} else if(key == 27) {
editCancel(row);
return false;
}
// ctrl + delete
object.value = 'null';
return false;
} else if(key == 13) {
editOk(row);
return false;
} else if(key == 27) {
editCancel(row);
return false;
}
}
function getInnerText(el) {
......
......@@ -336,8 +336,6 @@ public class DiskFile implements CacheWriter {
Record rec = (Record) list.get(i);
writeBack(rec);
}
// TODO flush performance: maybe it would be faster to write records in
// the same loop
for (int i = 0; i < fileBlockCount; i++) {
i = deleted.nextSetBit(i);
if (i < 0) {
......@@ -351,32 +349,33 @@ public class DiskFile implements CacheWriter {
}
}
public void flushNew() throws SQLException {
int todoTest;
synchronized (database) {
database.checkPowerOff();
ObjectArray list = cache.getAllChanged();
CacheObject.sort(list);
int deletePos = deleted.nextSetBit(0);
int writeIndex = 0;
Record writeRecord = null;
while (true) {
if (writeRecord == null && writeIndex < list.size()) {
writeRecord = (Record) list.get(writeIndex++);
}
if (writeRecord != null && (deletePos < 0 || writeRecord.getPos() < deletePos)) {
writeBack(writeRecord);
writeRecord = null;
} else if (deletePos < fileBlockCount && deletePos >= 0) {
writeDirectDeleted(deletePos, 1);
deleted.clear(deletePos);
deletePos = deleted.nextSetBit(deletePos);
} else {
break;
}
}
}
}
// this implementation accesses the file in a linear way
// public void flushNew() throws SQLException {
// int todoTest;
// synchronized (database) {
// database.checkPowerOff();
// ObjectArray list = cache.getAllChanged();
// CacheObject.sort(list);
// int deletePos = deleted.nextSetBit(0);
// int writeIndex = 0;
// Record writeRecord = null;
// while (true) {
// if (writeRecord == null && writeIndex < list.size()) {
// writeRecord = (Record) list.get(writeIndex++);
// }
// if (writeRecord != null && (deletePos < 0 || writeRecord.getPos() < deletePos)) {
// writeBack(writeRecord);
// writeRecord = null;
// } else if (deletePos < fileBlockCount && deletePos >= 0) {
// writeDirectDeleted(deletePos, 1);
// deleted.clear(deletePos);
// deletePos = deleted.nextSetBit(deletePos);
// } else {
// break;
// }
// }
// }
// }
public void close() throws SQLException {
synchronized (database) {
......
......@@ -24,14 +24,13 @@ public class FileLister {
/**
* Get the list of database files.
*
*
* @param dir the directory (null for the current directory)
* @param db the database name (null for all databases)
* @param all if true, files such as the lock, trace, hash index, and lob
* files are included. If false, only data, index and log files
* are returned
* @return the list of files
* @throws SQLException
*/
public static ArrayList getDatabaseFiles(String dir, String db, boolean all) throws SQLException {
if (dir == null || dir.equals("")) {
......
......@@ -15,13 +15,13 @@ import org.h2.util.IntArray;
import org.h2.util.MathUtils;
/**
* This class represents an persistent container that stores data of a table or an index.
* An object contains a list of records, see {@link Record}.
* For each storage there is a {@link RecordReader} object that knows how to
* This class represents an persistent container that stores data of a table or an index.
* An object contains a list of records, see {@link Record}.
* For each storage there is a {@link RecordReader} object that knows how to
* convert records into a byte array and vice versa.
* The data is stored in a {@link DiskFile}. A storage occupies a number of pages
* in a file.
*
*
* File format:
* <pre>
* int block size
......@@ -262,7 +262,7 @@ public class Storage {
void removePage(int i) {
pages.removeValue(i);
}
private void checkOnePage() throws SQLException {
pageCheckIndex = (pageCheckIndex + 1) % pages.size();
int page = pages.get(pageCheckIndex);
......
......@@ -53,7 +53,7 @@ public class Csv implements SimpleRowSource {
/**
* Get a new object of this class.
*
*
* @return the new instance
*/
public static Csv getInstance() {
......@@ -86,7 +86,7 @@ public class Csv implements SimpleRowSource {
/**
* Writes the result set to a file in the CSV format.
*
*
* @param writer
* the writer
* @param rs
......@@ -102,7 +102,7 @@ public class Csv implements SimpleRowSource {
/**
* Writes the result set to a file in the CSV format.
*
*
* @param fileName
* the name of the csv file
* @param rs
......@@ -124,7 +124,7 @@ public class Csv implements SimpleRowSource {
/**
* Writes the result set of a query to a file in the CSV format.
*
*
* @param conn
* the connection
* @param fileName
......@@ -148,7 +148,7 @@ public class Csv implements SimpleRowSource {
* Reads from the CSV file and returns a result set. The rows in the result
* set are created on demand, that means the file is kept open until all
* rows are read or the result set is closed.
*
*
* @param fileName the file name
* @param colNames or null if the column names should be read from the CSV file
* @param charset the charset or null to use UTF-8
......@@ -168,7 +168,7 @@ public class Csv implements SimpleRowSource {
* Reads CSV data from a reader and returns a result set. The rows in the
* result set are created on demand, that means the reader is kept open
* until all rows are read or the result set is closed.
*
*
* @param reader the reader
* @param colNames or null if the column names should be read from the CSV file
* @return the result set
......@@ -347,15 +347,6 @@ public class Csv implements SimpleRowSource {
continue;
} else if (ch == fieldSeparatorRead) {
break;
} else if (ch == commentLineStart) {
while (true) {
ch = readChar();
if (ch < 0 || ch == '\r' || ch == '\n') {
break;
}
}
endOfLine = true;
break;
} else if (ch == fieldDelimiter) {
StringBuffer buff = new StringBuffer();
boolean containsEscape = false;
......@@ -406,6 +397,15 @@ public class Csv implements SimpleRowSource {
}
}
break;
} else if (ch == commentLineStart) {
while (true) {
ch = readChar();
if (ch < 0 || ch == '\r' || ch == '\n') {
break;
}
}
endOfLine = true;
break;
} else {
StringBuffer buff = new StringBuffer();
buff.append((char) ch);
......@@ -433,13 +433,22 @@ public class Csv implements SimpleRowSource {
private String unEscape(String s) {
StringBuffer buff = new StringBuffer(s.length());
int start = 0;
char[] chars = null;
while (true) {
int idx = s.indexOf(escapeCharacter, start);
if (idx < 0) {
break;
}
buff.append(s.toCharArray(), start, idx);
start = idx + 1;
if (chars == null) {
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));
return buff.toString();
......@@ -496,7 +505,7 @@ public class Csv implements SimpleRowSource {
IOUtils.closeSilently(writer);
writer = null;
}
/**
* INTERNAL
*/
......@@ -506,7 +515,7 @@ public class Csv implements SimpleRowSource {
/**
* Override the field separator for writing. The default is ",".
*
*
* @param fieldSeparatorWrite the field separator
*/
public void setFieldSeparatorWrite(String fieldSeparatorWrite) {
......@@ -515,7 +524,7 @@ public class Csv implements SimpleRowSource {
/**
* Get the current field separator for writing.
*
*
* @return the field separator
*/
public String getFieldSeparatorWrite() {
......@@ -524,7 +533,7 @@ public class Csv implements SimpleRowSource {
/**
* Override the field separator for reading. The default is ','.
*
*
* @param fieldSeparatorRead the field separator
*/
public void setFieldSeparatorRead(char fieldSeparatorRead) {
......@@ -533,7 +542,7 @@ public class Csv implements SimpleRowSource {
/**
* Get the current field separator for reading.
*
*
* @return the field separator
*/
public char getFieldSeparatorRead() {
......@@ -542,7 +551,7 @@ public class Csv implements SimpleRowSource {
/**
* Get the current row separator for writing.
*
*
* @return the row separator
*/
public String getRowSeparatorWrite() {
......@@ -552,7 +561,7 @@ public class Csv implements SimpleRowSource {
/**
* Override the end-of-row marker for writing. The default is null.
* After writing the end-of-row marker, a line feed is written (\n or \r\n depending on the system settings).
*
*
* @param rowSeparatorWrite the row separator
*/
public void setRowSeparatorWrite(String rowSeparatorWrite) {
......@@ -562,7 +571,7 @@ public class Csv implements SimpleRowSource {
/**
* Set the field delimiter. The default is " (a double quote).
* 0 means no field delimiter is used.
*
*
* @param fieldDelimiter the field delimiter
*/
public void setFieldDelimiter(char fieldDelimiter) {
......@@ -572,7 +581,7 @@ public class Csv implements SimpleRowSource {
/**
* Get the current field delimiter.
* 0 means no field delimiter is used.
*
*
* @return the field delimiter
*/
public char getFieldDelimiter() {
......@@ -582,7 +591,7 @@ public class Csv implements SimpleRowSource {
/**
* Set the escape character (used to escape the field delimiter). The default is " (a double quote).
* 0 means no escape character is used.
*
*
* @param escapeCharacter the escape character
*/
public void setEscapeCharacter(char escapeCharacter) {
......@@ -592,7 +601,7 @@ public class Csv implements SimpleRowSource {
/**
* Get the current escape character.
* 0 means no escape character is used.
*
*
* @return the escape character
*/
public char getEscapeCharacter() {
......
......@@ -534,4 +534,13 @@ public class Server implements Runnable, ShutdownHandler {
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;
import org.h2.tools.DeleteDbFiles;
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 static void main(String[] args) throws Exception {
DeleteDbFiles.execute("data", "test", true);
......@@ -21,13 +26,13 @@ public class Compact {
stat.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR)");
stat.execute("INSERT INTO TEST VALUES(1, 'Hello'), (2, 'World');");
conn.close();
System.out.println("Compacting...");
compact("data", "test", "sa", "");
System.out.println("Done.");
}
public static void compact(String dir, String dbName, String user, String password) throws Exception {
String url = "jdbc:h2:" + dir + "/" + dbName;
String file = "data/test.sql";
......
......@@ -11,6 +11,11 @@ import java.sql.Types;
import org.h2.tools.Csv;
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 static void main(String[] args) throws Exception {
CsvSample.write();
......
......@@ -11,6 +11,10 @@ import java.sql.DriverManager;
import java.sql.ResultSet;
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 static void main(String[] args) throws Exception {
......
......@@ -14,8 +14,12 @@ import java.sql.Types;
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 static void main(String[] args) throws Exception {
Class.forName("org.h2.Driver");
Connection conn = DriverManager.getConnection("jdbc:h2:mem:", "sa", "");
......@@ -36,18 +40,18 @@ public class Function {
public static boolean isPrime(int value) {
return new BigInteger(String.valueOf(value)).isProbablePrime(100);
}
public static ResultSet query(Connection conn, String sql) throws SQLException {
return conn.createStatement().executeQuery(sql);
}
public static ResultSet simpleResultSet() throws SQLException {
SimpleResultSet rs = new SimpleResultSet();
rs.addColumn("ID", Types.INTEGER, 10, 0);
rs.addColumn("NAME", Types.VARCHAR, 255, 0);
rs.addRow(new Object[] { new Integer(0), "Hello" });
return rs;
}
}
public static ResultSet getMatrix(Connection conn, Integer id) throws SQLException {
SimpleResultSet rs = new SimpleResultSet();
......
......@@ -14,8 +14,14 @@ import java.sql.Types;
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 static void main(String[] args) throws Exception {
Class.forName("org.h2.Driver");
Connection conn = DriverManager.getConnection("jdbc:h2:mem:", "sa", "");
......@@ -30,7 +36,7 @@ public class FunctionMultiReturn {
double y = rs.getDouble(2);
System.out.println("result: (x=" + x + ", y="+y+")");
}
stat.execute("CREATE TABLE TEST(ID IDENTITY, R DOUBLE, A DOUBLE)");
stat.execute("INSERT INTO TEST(R, A) VALUES(5.0, 0.5), (10.0, 0.6)");
stat.execute("CREATE ALIAS P2C_SET FOR \"org.h2.samples.FunctionMultiReturn.polar2CartesianSet\" ");
......@@ -41,8 +47,8 @@ public class FunctionMultiReturn {
double x = rs.getDouble("X");
double y = rs.getDouble("Y");
System.out.println("(r="+r+" a="+a+") : (x=" + x + ", y="+y+")");
}
}
stat.execute("CREATE ALIAS P2C_A FOR \"org.h2.samples.FunctionMultiReturn.polar2CartesianArray\" ");
rs = conn.createStatement().executeQuery("SELECT R, A, P2C_A(R, A) FROM TEST");
while (rs.next()) {
......@@ -54,7 +60,7 @@ public class FunctionMultiReturn {
double y = ((Double) xy[1]).doubleValue();
System.out.println("(r=" + r + " a=" + a + ") : (x=" + x + ", y=" + y + ")");
}
rs = conn.createStatement().executeQuery("SELECT R, A, ARRAY_GET(E, 1), ARRAY_GET(E, 2) FROM (SELECT R, A, P2C_A(R, A) E FROM TEST)");
while (rs.next()) {
double r = rs.getDouble(1);
......@@ -62,13 +68,13 @@ public class FunctionMultiReturn {
double x = rs.getDouble(3);
double y = rs.getDouble(4);
System.out.println("(r="+r+" a="+a+") : (x=" + x + ", y="+y+")");
}
}
conn.close();
}
/**
* The function may be called twice, once to retrieve the result columns (with null parameters),
* The function may be called twice, once to retrieve the result columns (with null parameters),
* and the second time to return the data.
*/
public static ResultSet polar2Cartesian(Double r, Double alpha) throws SQLException {
......@@ -81,17 +87,17 @@ public class FunctionMultiReturn {
rs.addRow(new Object[] { new Double(x), new Double(y) });
}
return rs;
}
}
/**
* The function may be called twice, once to retrieve the result columns (with null parameters),
* The function may be called twice, once to retrieve the result columns (with null parameters),
* and the second time to return the data.
*/
public static Object[] polar2CartesianArray(Double r, Double alpha) throws SQLException {
double x = r.doubleValue() * Math.cos(alpha.doubleValue());
double y = r.doubleValue() * Math.sin(alpha.doubleValue());
return new Object[]{new Double(x), new Double(y)};
}
}
public static ResultSet polar2CartesianSet(Connection conn, String query) throws SQLException {
SimpleResultSet result = new SimpleResultSet();
......@@ -110,6 +116,6 @@ public class FunctionMultiReturn {
}
}
return result;
}
}
}
......@@ -13,13 +13,16 @@ import java.sql.Statement;
import org.h2.tools.RunScript;
/**
* In this example a database is initialized from compressed script in a jar file.
*/
public class InitDatabaseFromJar {
public static void main(String[] args) throws Exception {
new InitDatabaseFromJar().createScript();
new InitDatabaseFromJar().createScript();
new InitDatabaseFromJar().initDb();
}
private void createScript() throws Exception {
Class.forName("org.h2.Driver");
Connection conn = DriverManager.getConnection("jdbc:h2:mem:test");
......
......@@ -10,26 +10,31 @@ import java.sql.SQLException;
import java.sql.Statement;
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 static void main(String[] args) throws Exception {
// start the server, allows to access the database remotly
Server server = Server.createTcpServer(new String[]{"-tcpPort", "9081"});
server.start();
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)");
// now use the database in your application in embedded mode
Class.forName("org.h2.Driver");
Connection conn = DriverManager.getConnection("jdbc:h2:~/test", "sa", "sa");
// some simple 'business usage'
Statement stat = conn.createStatement();
stat.execute("DROP TABLE TIMER IF EXISTS");
stat.execute("CREATE TABLE TIMER(ID INT PRIMARY KEY, TIME VARCHAR)");
System.out.println("Execute this a few times: SELECT TIME FROM TIMER");
System.out.println("To stop this application (and the server), run: DROP TABLE TIMER");
try {
public static void main(String[] args) throws Exception {
// start the server, allows to access the database remotly
Server server = Server.createTcpServer(new String[] { "-tcpPort", "9081" });
server.start();
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)");
// now use the database in your application in embedded mode
Class.forName("org.h2.Driver");
Connection conn = DriverManager.getConnection("jdbc:h2:~/test", "sa", "sa");
// some simple 'business usage'
Statement stat = conn.createStatement();
stat.execute("DROP TABLE TIMER IF EXISTS");
stat.execute("CREATE TABLE TIMER(ID INT PRIMARY KEY, TIME VARCHAR)");
System.out.println("Execute this a few times: SELECT TIME FROM TIMER");
System.out.println("To stop this application (and the server), run: DROP TABLE TIMER");
try {
while (true) {
// runs forever, except if you drop the table remotely
stat.execute("MERGE INTO TIMER VALUES(1, NOW())");
......@@ -38,9 +43,9 @@ public class MixedMode {
} catch (SQLException e) {
System.out.println("Error: " + e.toString());
}
conn.close();
// stop the server
server.stop();
}
conn.close();
// stop the server
server.stop();
}
}
......@@ -16,6 +16,10 @@ import java.sql.ResultSet;
import org.h2.tools.RunScript;
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 static void main(String[] args) throws Exception {
Class.forName("org.h2.Driver");
......
......@@ -13,25 +13,31 @@ import java.sql.ResultSet;
import java.sql.SQLException;
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 {
Connection conn;
Statement stat;
private Connection conn;
private Statement stat;
public static void main(String[] args) throws Exception {
new SQLInjection().run("org.h2.Driver",
new SQLInjection().run("org.h2.Driver",
"jdbc:h2:test", "sa", "sa");
// new SQLInjection().run("org.postgresql.Driver",
// new SQLInjection().run("org.postgresql.Driver",
// "jdbc:postgresql:jpox2", "sa", "sa");
// new SQLInjection().run("com.mysql.jdbc.Driver",
// new SQLInjection().run("com.mysql.jdbc.Driver",
// "jdbc:mysql://localhost/test", "sa", "sa");
// new SQLInjection().run("org.hsqldb.jdbcDriver",
// new SQLInjection().run("org.hsqldb.jdbcDriver",
// "jdbc:hsqldb:test", "sa", "");
// new SQLInjection().run(
// "org.apache.derby.jdbc.EmbeddedDriver",
// "org.apache.derby.jdbc.EmbeddedDriver",
// "jdbc:derby:test3;create=true", "sa", "sa");
}
void run(String driver, String url, String user, String password) throws Exception {
Class.forName(driver);
conn = DriverManager.getConnection(url, user, password);
......@@ -41,37 +47,37 @@ public class SQLInjection {
} catch (SQLException e) {
// ignore
}
stat.execute("CREATE TABLE USERS(ID INT PRIMARY KEY, " +
stat.execute("CREATE TABLE USERS(ID INT PRIMARY KEY, " +
"NAME VARCHAR(255), PASSWORD VARCHAR(255))");
stat.execute("INSERT INTO USERS VALUES(1, 'admin', 'super')");
stat.execute("INSERT INTO USERS VALUES(2, 'guest', '123456')");
stat.execute("INSERT INTO USERS VALUES(3, 'test', 'abc')");
// loginByNameInsecure();
loginByNameInsecure();
if (url.startsWith("jdbc:h2:")) {
// loginStoredProcedureInsecure();
loginStoredProcedureInsecure();
limitRowAccess();
}
// loginByNameSecure();
loginByNameSecure();
if (url.startsWith("jdbc:h2:")) {
stat.execute("SET ALLOW_LITERALS NONE");
stat.execute("SET ALLOW_LITERALS NUMBERS");
stat.execute("SET ALLOW_LITERALS ALL");
}
// loginByIdInsecure();
// loginByIdSecure();
loginByIdInsecure();
loginByIdSecure();
try {
stat.execute("DROP TABLE ITEMS");
} catch (SQLException e) {
// ignore
}
stat.execute("CREATE TABLE ITEMS(ID INT PRIMARY KEY, " +
stat.execute("CREATE TABLE ITEMS(ID INT PRIMARY KEY, " +
"NAME VARCHAR(255), ACTIVE INT)");
stat.execute("INSERT INTO ITEMS VALUES(0, 'XBox', 0)");
stat.execute("INSERT INTO ITEMS VALUES(1, 'XBox 360', 1)");
......@@ -88,23 +94,23 @@ public class SQLInjection {
stat.execute("CREATE CONSTANT TYPE_ACTIVE VALUE 1");
listActiveItemsUsingConstants();
}
// listItemsSortedInsecure();
// listItemsSortedSecure();
listItemsSortedInsecure();
listItemsSortedSecure();
if (url.startsWith("jdbc:h2:")) {
listItemsSortedSecureParam();
// storePasswordHashWithSalt();
storePasswordHashWithSalt();
}
conn.close();
}
void loginByNameInsecure() throws Exception {
System.out.println("Insecure Systems Inc. - login");
String name = input("Name?");
String password = input("Password?");
ResultSet rs = stat.executeQuery("SELECT * FROM USERS WHERE " +
ResultSet rs = stat.executeQuery("SELECT * FROM USERS WHERE " +
"NAME='" + name + "' AND PASSWORD='" + password + "'");
if (rs.next()) {
System.out.println("Welcome!");
......@@ -112,7 +118,7 @@ public class SQLInjection {
System.out.println("Access denied!");
}
}
public static ResultSet getUser(Connection conn, String userName, String password) throws Exception {
PreparedStatement prep = conn.prepareStatement(
"SELECT * FROM USERS WHERE NAME=? AND PASSWORD=?");
......@@ -132,9 +138,9 @@ public class SQLInjection {
void loginStoredProcedureInsecure() throws Exception {
System.out.println("Insecure Systems Inc. - login using a stored procedure");
stat.execute("CREATE ALIAS IF NOT EXISTS " +
stat.execute("CREATE ALIAS IF NOT EXISTS " +
"GET_USER FOR \"org.h2.samples.SQLInjection.getUser\"");
stat.execute("CREATE ALIAS IF NOT EXISTS " +
stat.execute("CREATE ALIAS IF NOT EXISTS " +
"CHANGE_PASSWORD FOR \"org.h2.samples.SQLInjection.changePassword\"");
String name = input("Name?");
String password = input("Password?");
......@@ -146,13 +152,13 @@ public class SQLInjection {
System.out.println("Access denied!");
}
}
void loginByNameSecure() throws Exception {
System.out.println("Secure Systems Inc. - login using placeholders");
String name = input("Name?");
String password = input("Password?");
PreparedStatement prep = conn.prepareStatement(
"SELECT * FROM USERS WHERE " +
"SELECT * FROM USERS WHERE " +
"NAME=? AND PASSWORD=?");
prep.setString(1, name);
prep.setString(2, password);
......@@ -169,8 +175,8 @@ public class SQLInjection {
stat.execute("DROP TABLE IF EXISTS SESSION_USER");
stat.execute("CREATE TABLE SESSION_USER(ID INT, USER INT)");
stat.execute("DROP VIEW IF EXISTS MY_USER");
stat.execute("CREATE VIEW MY_USER AS " +
"SELECT U.* FROM SESSION_USER S, USERS U " +
stat.execute("CREATE VIEW MY_USER AS " +
"SELECT U.* FROM SESSION_USER S, USERS U " +
"WHERE S.ID=SESSION_ID() AND S.USER=U.ID");
stat.execute("INSERT INTO SESSION_USER VALUES(SESSION_ID(), 1)");
ResultSet rs = stat.executeQuery("SELECT ID, NAME FROM MY_USER");
......@@ -185,7 +191,7 @@ public class SQLInjection {
String password = input("Password?");
try {
PreparedStatement prep = conn.prepareStatement(
"SELECT * FROM USERS WHERE " +
"SELECT * FROM USERS WHERE " +
"ID=" + id + " AND PASSWORD=?");
prep.setString(1, password);
ResultSet rs = prep.executeQuery();
......@@ -205,7 +211,7 @@ public class SQLInjection {
String password = input("Password?");
try {
PreparedStatement prep = conn.prepareStatement(
"SELECT * FROM USERS WHERE " +
"SELECT * FROM USERS WHERE " +
"ID=? AND PASSWORD=?");
prep.setInt(1, Integer.parseInt(id));
prep.setString(2, password);
......@@ -219,7 +225,7 @@ public class SQLInjection {
System.out.println(e);
}
}
void listActiveItems() throws Exception {
System.out.println("Half Secure Systems Inc. - list active items");
ResultSet rs = stat.executeQuery(
......@@ -251,7 +257,7 @@ public class SQLInjection {
System.out.println(e);
}
}
void listItemsSortedSecure() throws Exception {
System.out.println("Secure Systems Inc. - list items");
String order = input("order (id, name)?");
......@@ -288,9 +294,9 @@ public class SQLInjection {
void storePasswordHashWithSalt() throws Exception {
System.out.println("Very Secure Systems Inc. - login");
stat.execute("DROP TABLE IF EXISTS USERS2");
stat.execute("CREATE TABLE USERS2(ID INT PRIMARY KEY, " +
stat.execute("CREATE TABLE USERS2(ID INT PRIMARY KEY, " +
"NAME VARCHAR, SALT BINARY, HASH BINARY)");
stat.execute("INSERT INTO USERS2 VALUES" +
stat.execute("INSERT INTO USERS2 VALUES" +
"(1, 'admin', SECURE_RAND(16), NULL)");
stat.execute("DROP CONSTANT IF EXISTS HASH_ITERATIONS");
stat.execute("DROP CONSTANT IF EXISTS HASH_ALGORITHM");
......@@ -303,7 +309,7 @@ public class SQLInjection {
String password = input("password?");
stat.execute("SET ALLOW_LITERALS NONE");
PreparedStatement prep = conn.prepareStatement(
"SELECT * FROM USERS2 WHERE NAME=? AND " +
"SELECT * FROM USERS2 WHERE NAME=? AND " +
"HASH=HASH(HASH_ALGORITHM, STRINGTOUTF8(? || SALT), HASH_ITERATIONS)");
prep.setString(1, user);
prep.setString(2, password);
......@@ -321,5 +327,5 @@ public class SQLInjection {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
return reader.readLine();
}
}
......@@ -13,10 +13,15 @@ import java.sql.Statement;
import org.h2.api.DatabaseEventListener;
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 {
private long last, start;
public ShowProgress() {
start = last = System.currentTimeMillis();
}
......@@ -24,7 +29,7 @@ public class ShowProgress implements DatabaseEventListener {
public static void main(String[] args) throws Exception {
new ShowProgress().test();
}
void test() throws Exception {
Class.forName("org.h2.Driver");
Connection conn = DriverManager.getConnection("jdbc:h2:test;LOG=2", "sa", "");
......@@ -54,14 +59,14 @@ public class ShowProgress implements DatabaseEventListener {
} else {
conn.close();
}
System.out.println("Open connection...");
time = System.currentTimeMillis();
conn = DriverManager.getConnection("jdbc:h2:test;LOG=2;DATABASE_EVENT_LISTENER='" + getClass().getName() + "'", "sa", "");
time = System.currentTimeMillis() - time;
System.out.println("Done after " + time + " ms");
conn.close();
}
public void diskSpaceIsLow(long stillAvailable) throws SQLException {
......@@ -106,7 +111,7 @@ public class ShowProgress implements DatabaseEventListener {
public void init(String url) {
System.out.println("Initializing the event listener for database " + url);
}
public void opened() {
}
......
......@@ -4,6 +4,10 @@
*/
package org.h2.samples;
/**
* This very simple sample application stops a H2 TCP server
* if it is running.
*/
public class ShutdownServer {
public static void main(String[] args) throws Exception {
org.h2.tools.Server.shutdownTcpServer("tcp://localhost:9094", "", false);
......
......@@ -14,6 +14,9 @@ import java.sql.Statement;
import org.h2.api.Trigger;
/**
* This sample application shows how to use database triggers.
*/
public class TriggerSample {
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;
import org.h2.test.jdbc.TestUpdatableResultSet;
import org.h2.test.jdbc.TestZloty;
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.TestPgServer;
import org.h2.test.server.TestWeb;
......@@ -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:
link to history page, bug page
......@@ -188,12 +201,8 @@ CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR);
<reconnect>
out of memory?
shrink newsletter list (migrate to google groups)
don't create @~ of not translated
clustered tables: test, document
extend tests that simulate power off
HSQLDB compatibility:
......@@ -214,20 +223,16 @@ move Performance Tuning > Advanced Topics
testHalt
java org.h2.test.TestAll halt
Automate real power off tests
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?
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 SQL Injection solution proposal to PostgreSQL, MySQL, Derby, HSQLDB,...
Convert SQL-injection-2.txt to html document, include SQLInjection.java sample
MySQL, PostgreSQL
READ_TEXT(fileName String) returning a CLOB.
......@@ -235,8 +240,6 @@ I am not sure if this will read the CLOB in memory however.
Improve LOB in directories performance
Automate real power off tests
http://fastutil.dsi.unimi.it/
http://javolution.org/
http://joda-time.sourceforge.net/
......@@ -251,8 +254,6 @@ glossary
spell check / word list per language
translated .pdf
write tests using the PostgreSQL JDBC driver
*/
// run TestHalt
......@@ -280,6 +281,9 @@ write tests using the PostgreSQL JDBC driver
Features of H2
- Case insensitive string data type
- GROUP_CONCAT aggregate, User defined aggregates
- Fulltext search
- MVCC
- User defined types
*/
if (args.length > 0) {
......@@ -499,6 +503,8 @@ Features of H2
cache2Q = false;
testAll();
memory = true;
testAll();
}
void testAll() throws Exception {
......@@ -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);
beforeTest();
// int testMvcc;
// mvcc = true;
// db
new TestScriptSimple().runTest(this);
new TestScript().runTest(this);
......@@ -607,7 +610,8 @@ Features of H2
new TestZloty().runTest(this);
// mvcc
new TestMVCC().runTest(this);
new TestMvcc1().runTest(this);
new TestMvcc2().runTest(this);
// synthetic
new TestCrashAPI().runTest(this);
......
......@@ -52,9 +52,6 @@ public abstract class TestBase {
}
public void runTest(TestAll conf) {
if (conf.networked) {
return;
}
try {
init(conf);
start = System.currentTimeMillis();
......
......@@ -8,9 +8,12 @@ import java.io.File;
import java.io.FileReader;
import java.io.RandomAccessFile;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Random;
import org.h2.test.TestBase;
import org.h2.tools.Csv;
......@@ -20,6 +23,7 @@ import org.h2.util.StringUtils;
public class TestCsv extends TestBase {
public void test() throws Exception {
testRandomData();
testEmptyFieldDelimiter();
testFieldDelimiter();
testAsTable();
......@@ -27,7 +31,49 @@ public class TestCsv extends TestBase {
testRead();
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 {
File f = new File(baseDir + "/test.csv");
f.delete();
......
......@@ -15,8 +15,11 @@ import org.h2.constant.ErrorCode;
import org.h2.test.TestBase;
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;
Statement s1, s2;
......@@ -41,10 +44,10 @@ public class TestMVCC extends TestBase {
}
rs = stat.executeQuery("select * from information_schema.settings where name='MVCC'");
rs.next();
check("FALSE", rs.getString("VALUE"));
check("FALSE", rs.getString("VALUE"));
c1.close();
}
private void testCases() throws Exception {
if (!config.mvcc) {
return;
......@@ -71,7 +74,7 @@ public class TestMVCC extends TestBase {
s2 = c2.createStatement();
c1.setAutoCommit(false);
c2.setAutoCommit(false);
// it should not be possible to drop a table when an uncommitted transaction changed something
s1.execute("create table test(id int primary key)");
s1.execute("insert into test values(1)");
......@@ -85,11 +88,11 @@ public class TestMVCC extends TestBase {
c1.rollback();
s2.execute("drop table test");
c2.rollback();
// referential integrity problem
s1.execute("create table a (id integer identity not null, code varchar(10) not null, primary key(id))");
s1.execute("create table b (name varchar(100) not null, a integer, primary key(name), foreign key(a) references a(id))");
s1.execute("insert into a(code) values('one')");
s1.execute("create table b (name varchar(100) not null, a integer, primary key(name), foreign key(a) references a(id))");
s1.execute("insert into a(code) values('one')");
try {
s2.execute("insert into b values('un B', 1)");
error("Unexpected success");
......@@ -100,7 +103,7 @@ public class TestMVCC extends TestBase {
c1.rollback();
s1.execute("drop table a, b");
c2.commit();
// select for update should do an exclusive lock, even with mvcc
s1.execute("create table test(id int primary key, name varchar(255))");
s1.execute("insert into test values(1, 'y')");
......@@ -117,7 +120,7 @@ public class TestMVCC extends TestBase {
s1.execute("drop table test");
c1.commit();
c2.commit();
s1.execute("create table test(id int primary key, name varchar(255))");
s2.execute("insert into test values(4, 'Hello')");
c2.rollback();
......@@ -126,7 +129,7 @@ public class TestMVCC extends TestBase {
c1.commit();
c2.commit();
s1.execute("DROP TABLE TEST");
s1.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR(255))");
s1.execute("INSERT INTO TEST VALUES(1, 'Test')");
c1.commit();
......@@ -138,7 +141,7 @@ public class TestMVCC extends TestBase {
c2.commit();
s1.execute("DROP TABLE TEST");
s1.execute("create table test as select * from table(id int=(1, 2))");
s1.execute("update test set id=1 where id=1");
s1.execute("select max(id) from test");
......@@ -172,7 +175,7 @@ public class TestMVCC extends TestBase {
c1.commit();
test(s1, "SELECT COUNT(*) FROM TEST", "0");
s1.execute("DROP TABLE TEST");
s1.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR)");
s1.execute("INSERT INTO TEST VALUES(1, 'Hello'), (2, 'World')");
test(s2, "SELECT COUNT(*) FROM TEST", "0");
......@@ -205,7 +208,7 @@ public class TestMVCC extends TestBase {
s1.execute("INSERT INTO TEST(NAME) VALUES('Ruebezahl')");
s1.execute("DROP TABLE TEST");
c1.commit();
s1.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR)");
s1.execute("INSERT INTO TEST VALUES(1, 'Hello')");
c1.commit();
......@@ -213,7 +216,7 @@ public class TestMVCC extends TestBase {
c1.rollback();
s1.execute("DROP TABLE TEST");
c1.commit();
Random random = new Random(1);
s1.execute("CREATE TABLE TEST(ID INT IDENTITY, NAME VARCHAR)");
Statement s;
......@@ -291,7 +294,7 @@ public class TestMVCC extends TestBase {
s1.execute("DROP TABLE TEST");
c1.commit();
c2.commit();
s1.execute("CREATE TABLE TEST(ID INT, NAME VARCHAR)");
s1.execute("INSERT INTO TEST VALUES(1, 'Hello')");
test(s2, "SELECT COUNT(*) FROM TEST WHERE NAME!='X'", "0");
......@@ -302,7 +305,7 @@ public class TestMVCC extends TestBase {
s1.execute("DROP TABLE TEST");
c1.commit();
c2.commit();
s1.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR)");
s1.execute("INSERT INTO TEST VALUES(1, 'Hello')");
test(s2, "SELECT COUNT(*) FROM TEST WHERE ID<100", "0");
......@@ -313,7 +316,7 @@ public class TestMVCC extends TestBase {
s1.execute("DROP TABLE TEST");
c1.commit();
c2.commit();
s1.execute("CREATE TABLE TEST(ID INT, NAME VARCHAR, PRIMARY KEY(ID, NAME))");
s1.execute("INSERT INTO TEST VALUES(1, 'Hello')");
c1.commit();
......@@ -324,8 +327,8 @@ public class TestMVCC extends TestBase {
s1.execute("DROP TABLE TEST");
c1.commit();
c2.commit();
s1.execute("create table test(id int primary key, name varchar(255))");
s1.execute("insert into test values(1, 'Hello'), (2, 'World')");
c1.commit();
......@@ -343,7 +346,7 @@ public class TestMVCC extends TestBase {
check(rs.getInt(1), 2);
check(rs.getString(2), "World");
checkFalse(rs.next());
rs = s2.executeQuery("select * from test order by id");
check(rs.next());
check(rs.getInt(1), 1);
......@@ -355,12 +358,10 @@ public class TestMVCC extends TestBase {
s1.execute("drop table test");
c1.commit();
c2.commit();
c1.close();
c2.close();
}
private void test(Statement stat, String sql, String expected) throws Exception {
......@@ -377,7 +378,5 @@ public class TestMVCC extends TestBase {
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 ---------------------------------------------------------------------------------------------
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);
> 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?
/*
* Copyright 2004-2007 H2 Group. Licensed under the H2 License, Version 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
* 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.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.tools.Server;
public class TestFtp extends TestBase {
public class TestFtp extends TestBase implements FtpEventListener {
private FtpEvent lastEvent;
public void test() throws Exception {
test(baseDir);
......@@ -15,17 +20,33 @@ public class TestFtp extends TestBase {
private void test(String dir) throws Exception {
Server server = Server.createFtpServer(new String[]{"-ftpDir", dir}).start();
FtpServer ftp = (FtpServer) server.getService();
ftp.setEventListener(this);
FtpClient client = FtpClient.open("localhost:8021");
client.login("sa", "sa");
client.makeDirectory("test");
client.changeWorkingDirectory("test");
check(lastEvent.getCommand(), "CWD");
client.makeDirectory("hello");
client.changeWorkingDirectory("hello");
client.changeDirectoryUp();
check(lastEvent.getCommand(), "CDUP");
client.nameList("hello");
client.removeDirectory("hello");
client.close();
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 {
}
private void testManagementDb() throws Exception {
if (config.networked) {
return;
}
int count = getSize(2, 10);
for (int i = 0; i < count; i++) {
Server server = Server.createTcpServer(new String[] {}).start();
......@@ -331,11 +334,13 @@ public class TestTools extends TestBase {
Server.shutdownTcpServer("tcp://localhost", "", true);
error("shouldn't work and should throw an exception");
} catch (SQLException e) {
// expected
checkNotGeneralException(e);
}
conn = DriverManager.getConnection("jdbc:h2:tcp://localhost/test", "sa", "");
conn.close();
// conn.close();
Server.shutdownTcpServer("tcp://localhost", "abc", true);
// check that the database is closed
deleteDb("test");
try {
conn = DriverManager.getConnection("jdbc:h2:tcp://localhost/test", "sa", "");
error("server must have been closed");
......
......@@ -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
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
countdown paused javac
countdown paused javac analyzing accesses solving forcefully urgent originally defect coordinates
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论