提交 8667bd06 authored 作者: Thomas Mueller's avatar Thomas Mueller

--no commit message

--no commit message
上级 68882ef5
...@@ -161,7 +161,7 @@ public class TransactionCommand extends Prepared { ...@@ -161,7 +161,7 @@ public class TransactionCommand extends Prepared {
// close the database, but don't update the persistent setting // close the database, but don't update the persistent setting
session.getDatabase().setCloseDelay(0); session.getDatabase().setCloseDelay(0);
Database db = session.getDatabase(); Database db = session.getDatabase();
Session[] sessions = db.getSessions(); Session[] sessions = db.getSessions(false);
for (int i = 0; i < sessions.length; i++) { for (int i = 0; i < sessions.length; i++) {
Session s = sessions[i]; Session s = sessions[i];
synchronized (s) { synchronized (s) {
......
...@@ -359,7 +359,9 @@ public class SysProperties { ...@@ -359,7 +359,9 @@ public class SysProperties {
* System property <code>h2.reuseSpaceQuickly</code> (default: true).<br /> * System property <code>h2.reuseSpaceQuickly</code> (default: true).<br />
* Reuse space in database files quickly. * Reuse space in database files quickly.
*/ */
public static final boolean REUSE_SPACE_QUICKLY = getBooleanSetting("h2.reuseSpaceQuickly", true); int test;
// public static final boolean REUSE_SPACE_QUICKLY = getBooleanSetting("h2.reuseSpaceQuickly", true);
public static final boolean REUSE_SPACE_QUICKLY = getBooleanSetting("h2.reuseSpaceQuickly", false);
/** /**
* System property <code>h2.runFinalize</code> (default: true).<br /> * System property <code>h2.runFinalize</code> (default: true).<br />
...@@ -478,7 +480,9 @@ public class SysProperties { ...@@ -478,7 +480,9 @@ public class SysProperties {
* INTERNAL * INTERNAL
*/ */
public static int getLogFileDeleteDelay() { public static int getLogFileDeleteDelay() {
int test;
return getIntSetting(H2_LOG_DELETE_DELAY, 0); return getIntSetting(H2_LOG_DELETE_DELAY, 0);
//return getIntSetting(H2_LOG_DELETE_DELAY, 1000);
} }
/** /**
......
...@@ -8,6 +8,7 @@ package org.h2.engine; ...@@ -8,6 +8,7 @@ package org.h2.engine;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
...@@ -89,7 +90,7 @@ public class Database implements DataHandler { ...@@ -89,7 +90,7 @@ public class Database implements DataHandler {
private final HashMap userDataTypes = new HashMap(); private final HashMap userDataTypes = new HashMap();
private final HashMap aggregates = new HashMap(); private final HashMap aggregates = new HashMap();
private final HashMap comments = new HashMap(); private final HashMap comments = new HashMap();
private final Set sessions = Collections.synchronizedSet(new HashSet()); private final Set userSessions = Collections.synchronizedSet(new HashSet());
private Session exclusiveSession; private Session exclusiveSession;
private final BitField objectIds = new BitField(); private final BitField objectIds = new BitField();
private final Object lobSyncObject = new Object(); private final Object lobSyncObject = new Object();
...@@ -808,12 +809,12 @@ public class Database implements DataHandler { ...@@ -808,12 +809,12 @@ public class Database implements DataHandler {
return getUser(name, Message.getSQLException(ErrorCode.USER_NOT_FOUND_1, name)); return getUser(name, Message.getSQLException(ErrorCode.USER_NOT_FOUND_1, name));
} }
public synchronized Session createSession(User user) throws SQLException { public synchronized Session createUserSession(User user) throws SQLException {
if (exclusiveSession != null) { if (exclusiveSession != null) {
throw Message.getSQLException(ErrorCode.DATABASE_IS_IN_EXCLUSIVE_MODE); throw Message.getSQLException(ErrorCode.DATABASE_IS_IN_EXCLUSIVE_MODE);
} }
Session session = new Session(this, user, ++nextSessionId); Session session = new Session(this, user, ++nextSessionId);
sessions.add(session); userSessions.add(session);
traceSystem.getTrace(Trace.SESSION).info("connecting #" + session.getId() + " to " + databaseName); traceSystem.getTrace(Trace.SESSION).info("connecting #" + session.getId() + " to " + databaseName);
if (delayedCloser != null) { if (delayedCloser != null) {
delayedCloser.reset(); delayedCloser.reset();
...@@ -827,12 +828,12 @@ public class Database implements DataHandler { ...@@ -827,12 +828,12 @@ public class Database implements DataHandler {
if (exclusiveSession == session) { if (exclusiveSession == session) {
exclusiveSession = null; exclusiveSession = null;
} }
sessions.remove(session); userSessions.remove(session);
if (session != systemSession) { if (session != systemSession) {
traceSystem.getTrace(Trace.SESSION).info("disconnecting #" + session.getId()); traceSystem.getTrace(Trace.SESSION).info("disconnecting #" + session.getId());
} }
} }
if (sessions.size() == 0 && session != systemSession) { if (userSessions.size() == 0 && session != systemSession) {
if (closeDelay == 0) { if (closeDelay == 0) {
close(false); close(false);
} else if (closeDelay < 0) { } else if (closeDelay < 0) {
...@@ -851,13 +852,13 @@ public class Database implements DataHandler { ...@@ -851,13 +852,13 @@ public class Database implements DataHandler {
synchronized void close(boolean fromShutdownHook) { synchronized void close(boolean fromShutdownHook) {
closing = true; closing = true;
if (sessions.size() > 0) { if (userSessions.size() > 0) {
if (!fromShutdownHook) { if (!fromShutdownHook) {
return; return;
} }
traceSystem.getTrace(Trace.DATABASE).info("closing " + databaseName + " from shutdown hook"); traceSystem.getTrace(Trace.DATABASE).info("closing " + databaseName + " from shutdown hook");
Session[] all = new Session[sessions.size()]; Session[] all = new Session[userSessions.size()];
sessions.toArray(all); userSessions.toArray(all);
for (int i = 0; i < all.length; i++) { for (int i = 0; i < all.length; i++) {
Session s = all[i]; Session s = all[i];
try { try {
...@@ -878,7 +879,7 @@ public class Database implements DataHandler { ...@@ -878,7 +879,7 @@ public class Database implements DataHandler {
// set it to null, to make sure it's called only once // set it to null, to make sure it's called only once
eventListener = null; eventListener = null;
e.closingDatabase(); e.closingDatabase();
if (sessions.size() > 0) { if (userSessions.size() > 0) {
// if a connection was opened, we can't close the database // if a connection was opened, we can't close the database
return; return;
} }
...@@ -1086,10 +1087,14 @@ public class Database implements DataHandler { ...@@ -1086,10 +1087,14 @@ public class Database implements DataHandler {
return log; return log;
} }
public Session[] getSessions() { public Session[] getSessions(boolean includingSystemSession) {
Session[] list = new Session[sessions.size()]; ArrayList list = new ArrayList(userSessions);
sessions.toArray(list); if (includingSystemSession && systemSession != null) {
return list; list.add(systemSession);
}
Session[] array = new Session[list.size()];
list.toArray(array);
return array;
} }
public synchronized void update(Session session, DbObject obj) throws SQLException { public synchronized void update(Session session, DbObject obj) throws SQLException {
...@@ -1403,6 +1408,8 @@ public class Database implements DataHandler { ...@@ -1403,6 +1408,8 @@ public class Database implements DataHandler {
public void deleteLogFileLater(String fileName) throws SQLException { public void deleteLogFileLater(String fileName) throws SQLException {
if (writer != null) { if (writer != null) {
int test;
//FileUtils.rename(fileName, fileName + ".trace.db");
writer.deleteLogFileLater(fileName); writer.deleteLogFileLater(fileName);
} else { } else {
FileUtils.delete(fileName); FileUtils.delete(fileName);
...@@ -1700,7 +1707,7 @@ public class Database implements DataHandler { ...@@ -1700,7 +1707,7 @@ public class Database implements DataHandler {
} }
public int getSessionCount() { public int getSessionCount() {
return sessions.size(); return userSessions.size();
} }
public void setReferentialIntegrity(boolean b) { public void setReferentialIntegrity(boolean b) {
......
...@@ -90,7 +90,7 @@ public class Engine { ...@@ -90,7 +90,7 @@ public class Engine {
} }
} }
checkClustering(ci, database); checkClustering(ci, database);
Session session = database.createSession(user); Session session = database.createUserSession(user);
return session; return session;
} }
} }
......
...@@ -39,6 +39,7 @@ import org.h2.table.TableFilter; ...@@ -39,6 +39,7 @@ import org.h2.table.TableFilter;
import org.h2.tools.CompressTool; import org.h2.tools.CompressTool;
import org.h2.tools.Csv; import org.h2.tools.Csv;
import org.h2.util.AutoCloseInputStream; import org.h2.util.AutoCloseInputStream;
import org.h2.util.DateTimeUtils;
import org.h2.util.FileUtils; import org.h2.util.FileUtils;
import org.h2.util.MathUtils; import org.h2.util.MathUtils;
import org.h2.util.MemoryUtils; import org.h2.util.MemoryUtils;
...@@ -565,22 +566,22 @@ public class Function extends Expression implements FunctionCall { ...@@ -565,22 +566,22 @@ public class Function extends Expression implements FunctionCall {
break; break;
} }
case DAYOFMONTH: case DAYOFMONTH:
result = ValueInt.get(getDatePart(v0.getTimestampNoCopy(), Calendar.DAY_OF_MONTH)); result = ValueInt.get(DateTimeUtils.getDatePart(v0.getTimestampNoCopy(), Calendar.DAY_OF_MONTH));
break; break;
case DAYOFWEEK: case DAYOFWEEK:
result = ValueInt.get(getDatePart(v0.getTimestampNoCopy(), Calendar.DAY_OF_WEEK)); result = ValueInt.get(DateTimeUtils.getDatePart(v0.getTimestampNoCopy(), Calendar.DAY_OF_WEEK));
break; break;
case DAYOFYEAR: case DAYOFYEAR:
result = ValueInt.get(getDatePart(v0.getTimestampNoCopy(), Calendar.DAY_OF_YEAR)); result = ValueInt.get(DateTimeUtils.getDatePart(v0.getTimestampNoCopy(), Calendar.DAY_OF_YEAR));
break; break;
case HOUR: case HOUR:
result = ValueInt.get(getDatePart(v0.getTimestampNoCopy(), Calendar.HOUR_OF_DAY)); result = ValueInt.get(DateTimeUtils.getDatePart(v0.getTimestampNoCopy(), Calendar.HOUR_OF_DAY));
break; break;
case MINUTE: case MINUTE:
result = ValueInt.get(getDatePart(v0.getTimestampNoCopy(), Calendar.MINUTE)); result = ValueInt.get(DateTimeUtils.getDatePart(v0.getTimestampNoCopy(), Calendar.MINUTE));
break; break;
case MONTH: case MONTH:
result = ValueInt.get(getDatePart(v0.getTimestampNoCopy(), Calendar.MONTH)); result = ValueInt.get(DateTimeUtils.getDatePart(v0.getTimestampNoCopy(), Calendar.MONTH));
break; break;
case MONTHNAME: { case MONTHNAME: {
synchronized (FORMAT_MONTHNAME) { synchronized (FORMAT_MONTHNAME) {
...@@ -589,16 +590,16 @@ public class Function extends Expression implements FunctionCall { ...@@ -589,16 +590,16 @@ public class Function extends Expression implements FunctionCall {
break; break;
} }
case QUARTER: case QUARTER:
result = ValueInt.get((getDatePart(v0.getTimestamp(), Calendar.MONTH) - 1) / 3 + 1); result = ValueInt.get((DateTimeUtils.getDatePart(v0.getTimestamp(), Calendar.MONTH) - 1) / 3 + 1);
break; break;
case SECOND: case SECOND:
result = ValueInt.get(getDatePart(v0.getTimestamp(), Calendar.SECOND)); result = ValueInt.get(DateTimeUtils.getDatePart(v0.getTimestamp(), Calendar.SECOND));
break; break;
case WEEK: case WEEK:
result = ValueInt.get(getDatePart(v0.getTimestamp(), Calendar.WEEK_OF_YEAR)); result = ValueInt.get(DateTimeUtils.getDatePart(v0.getTimestamp(), Calendar.WEEK_OF_YEAR));
break; break;
case YEAR: case YEAR:
result = ValueInt.get(getDatePart(v0.getTimestamp(), Calendar.YEAR)); result = ValueInt.get(DateTimeUtils.getDatePart(v0.getTimestamp(), Calendar.YEAR));
break; break;
case CURDATE: case CURDATE:
case CURRENT_DATE: case CURRENT_DATE:
...@@ -768,7 +769,7 @@ public class Function extends Expression implements FunctionCall { ...@@ -768,7 +769,7 @@ public class Function extends Expression implements FunctionCall {
private boolean cancelStatement(Session session, int targetSessionId) throws SQLException { private boolean cancelStatement(Session session, int targetSessionId) throws SQLException {
session.getUser().checkAdmin(); session.getUser().checkAdmin();
Session[] sessions = session.getDatabase().getSessions(); Session[] sessions = session.getDatabase().getSessions(false);
for (int i = 0; i < sessions.length; i++) { for (int i = 0; i < sessions.length; i++) {
Session s = sessions[i]; Session s = sessions[i];
if (s.getId() == targetSessionId) { if (s.getId() == targetSessionId) {
...@@ -948,7 +949,7 @@ public class Function extends Expression implements FunctionCall { ...@@ -948,7 +949,7 @@ public class Function extends Expression implements FunctionCall {
break; break;
case EXTRACT: { case EXTRACT: {
int field = getDatePart(v0.getString()); int field = getDatePart(v0.getString());
result = ValueInt.get(getDatePart(v1.getTimestamp(), field)); result = ValueInt.get(DateTimeUtils.getDatePart(v1.getTimestamp(), field));
break; break;
} }
case FORMATDATETIME: { case FORMATDATETIME: {
...@@ -1125,60 +1126,6 @@ public class Function extends Expression implements FunctionCall { ...@@ -1125,60 +1126,6 @@ public class Function extends Expression implements FunctionCall {
return bytes; return bytes;
} }
private static int getDatePart(Timestamp d, int field) {
Calendar c = Calendar.getInstance();
c.setTime(d);
int value = c.get(field);
if (field == Calendar.MONTH) {
value++;
}
return value;
}
// private static long datediffRound(String part, Date d1, Date d2)
// throws SQLException {
// // diff (yy, 31.12.2004, 1.1.2005) = 0
// Integer p = (Integer) datePart.get(StringUtils.toUpperEnglish(part));
// if (p == null) {
// throw Message.getSQLException(ErrorCode.INVALID_VALUE_2,
// new String[] { "part", part }, null);
// }
// int field = p.intValue();
// long t1 = d1.getTime(), t2 = d2.getTime();
// switch (field) {
// case Calendar.MILLISECOND:
// return t2 - t1;
// case Calendar.SECOND:
// return (t2 - t1) / 1000;
// case Calendar.MINUTE:
// return (t2 - t1) / 1000 / 60;
// case Calendar.HOUR_OF_DAY:
// return (t2 - t1) / 1000 / 60 / 60;
// case Calendar.DATE:
// return (t2 - t1) / 1000 / 60 / 60 / 24;
// }
// Calendar g1 = Calendar.getInstance();
// g1.setTimeInMillis(t1);
// int year1 = g1.get(Calendar.YEAR);
// Calendar g2 = Calendar.getInstance();
// g2.setTimeInMillis(t2);
// int year2 = g2.get(Calendar.YEAR);
// int result = year2 - year1;
// if (field == Calendar.MONTH) {
// int month1 = g1.get(Calendar.MONTH);
// int month2 = g2.get(Calendar.MONTH);
// result = 12 * result + (month2 - month1);
// g2.set(Calendar.MONTH, month1);
// }
// g2.set(Calendar.YEAR, year1);
// if (result > 0 && g1.after(g2)) {
// result--;
// } else if (result < 0 && g1.before(g2)) {
// result++;
// }
// return result;
// }
private static int getDatePart(String part) throws SQLException { private static int getDatePart(String part) throws SQLException {
Integer p = (Integer) DATE_PART.get(StringUtils.toUpperEnglish(part)); Integer p = (Integer) DATE_PART.get(StringUtils.toUpperEnglish(part));
if (p == null) { if (p == null) {
......
...@@ -87,7 +87,7 @@ public class LogSystem { ...@@ -87,7 +87,7 @@ public class LogSystem {
// (even if they are resolved), can't update or delete the log files // (even if they are resolved), can't update or delete the log files
return; return;
} }
Session[] sessions = database.getSessions(); Session[] sessions = database.getSessions(true);
int firstUncommittedLog = currentLog.getId(); int firstUncommittedLog = currentLog.getId();
int firstUncommittedPos = currentLog.getPos(); int firstUncommittedPos = currentLog.getPos();
for (int i = 0; i < sessions.length; i++) { for (int i = 0; i < sessions.length; i++) {
...@@ -111,6 +111,7 @@ public class LogSystem { ...@@ -111,6 +111,7 @@ public class LogSystem {
} else { } else {
l.setFirstUncommittedPos(firstUncommittedPos); l.setFirstUncommittedPos(firstUncommittedPos);
} }
} }
} }
for (int i = 0; i < activeLogs.size(); i++) { for (int i = 0; i < activeLogs.size(); i++) {
...@@ -193,9 +194,9 @@ public class LogSystem { ...@@ -193,9 +194,9 @@ public class LogSystem {
for (int i = 0; i < activeLogs.size(); i++) { for (int i = 0; i < activeLogs.size(); i++) {
LogFile log = (LogFile) activeLogs.get(i); LogFile log = (LogFile) activeLogs.get(i);
log.redoAllGoEnd(); log.redoAllGoEnd();
}
database.getDataFile().flushRedoLog(); database.getDataFile().flushRedoLog();
database.getIndexFile().flushRedoLog(); database.getIndexFile().flushRedoLog();
}
int end = currentLog.getPos(); int end = currentLog.getPos();
Object[] states = sessions.values().toArray(); Object[] states = sessions.values().toArray();
inDoubtTransactions = new ObjectArray(); inDoubtTransactions = new ObjectArray();
...@@ -388,7 +389,9 @@ public class LogSystem { ...@@ -388,7 +389,9 @@ public class LogSystem {
storageId = -storageId; storageId = -storageId;
} }
currentLog.addTruncate(session, storageId, recordId, blockCount); currentLog.addTruncate(session, storageId, recordId, blockCount);
if (currentLog.getFileSize() > maxLogSize) { int test;
// if (currentLog.getFileSize() > maxLogSize) {
if (currentLog.getFileSize()*100 > maxLogSize) {
checkpoint(); checkpoint();
} }
} }
...@@ -412,7 +415,9 @@ public class LogSystem { ...@@ -412,7 +415,9 @@ public class LogSystem {
session.addLogPos(log, pos); session.addLogPos(log, pos);
record.setLastLog(log, pos); record.setLastLog(log, pos);
currentLog.add(session, storageId, record); currentLog.add(session, storageId, record);
if (currentLog.getFileSize() > maxLogSize) { int test;
// if (currentLog.getFileSize() > maxLogSize) {
if (currentLog.getFileSize()*100 > maxLogSize) {
checkpoint(); checkpoint();
} }
} }
......
...@@ -610,7 +610,7 @@ public class DiskFile implements CacheWriter { ...@@ -610,7 +610,7 @@ public class DiskFile implements CacheWriter {
void reuseSpace() throws SQLException { void reuseSpace() throws SQLException {
if (SysProperties.REUSE_SPACE_QUICKLY) { if (SysProperties.REUSE_SPACE_QUICKLY) {
if (potentiallyFreePages.size() >= SysProperties.REUSE_SPACE_AFTER) { if (potentiallyFreePages.size() >= SysProperties.REUSE_SPACE_AFTER) {
Session[] sessions = database.getSessions(); Session[] sessions = database.getSessions(true);
int oldest = 0; int oldest = 0;
for (int i = 0; i < sessions.length; i++) { for (int i = 0; i < sessions.length; i++) {
int deleteId = sessions[i].getLastUncommittedDelete(); int deleteId = sessions[i].getLastUncommittedDelete();
...@@ -904,9 +904,6 @@ public class DiskFile implements CacheWriter { ...@@ -904,9 +904,6 @@ public class DiskFile implements CacheWriter {
pages.toArray(pagesCopy); pages.toArray(pagesCopy);
for (int i = 0; i < pagesCopy.length; i++) { for (int i = 0; i < pagesCopy.length; i++) {
int page = pagesCopy[i]; int page = pagesCopy[i];
if (logChanges) {
log.addTruncate(session, this, storageId, page * BLOCKS_PER_PAGE, BLOCKS_PER_PAGE);
}
for (int j = 0; j < BLOCKS_PER_PAGE; j++) { for (int j = 0; j < BLOCKS_PER_PAGE; j++) {
Record r = (Record) cache.find(page * BLOCKS_PER_PAGE + j); Record r = (Record) cache.find(page * BLOCKS_PER_PAGE + j);
if (r != null) { if (r != null) {
...@@ -915,6 +912,14 @@ public class DiskFile implements CacheWriter { ...@@ -915,6 +912,14 @@ public class DiskFile implements CacheWriter {
} }
deleted.setRange(page * BLOCKS_PER_PAGE, BLOCKS_PER_PAGE, true); deleted.setRange(page * BLOCKS_PER_PAGE, BLOCKS_PER_PAGE, true);
setUnused(session, page * BLOCKS_PER_PAGE, BLOCKS_PER_PAGE); setUnused(session, page * BLOCKS_PER_PAGE, BLOCKS_PER_PAGE);
// the truncate entry must be written after changing the
// in-memory structures (page owner, in-use bit set), because
// the log file could change just after the truncate record
// and before the flags are reset - this would result in
// incorrect in use bits written
if (logChanges) {
log.addTruncate(session, this, storageId, page * BLOCKS_PER_PAGE, BLOCKS_PER_PAGE);
}
} }
} }
} }
......
...@@ -163,9 +163,14 @@ public class WriterThread extends Thread { ...@@ -163,9 +163,14 @@ public class WriterThread extends Thread {
if (oldLogFile != null) { if (oldLogFile != null) {
FileUtils.delete(oldLogFile); FileUtils.delete(oldLogFile);
} }
int delay = SysProperties.getLogFileDeleteDelay();
if (delay == 0 && fileName != null) {
FileUtils.delete(fileName);
} else {
oldLogFile = fileName; oldLogFile = fileName;
if (fileName != null) { if (fileName != null) {
oldLogFileDelete = System.currentTimeMillis() + SysProperties.getLogFileDeleteDelay(); oldLogFileDelete = System.currentTimeMillis() + delay;
}
} }
} }
......
...@@ -366,7 +366,12 @@ public class FileSystemDisk extends FileSystem { ...@@ -366,7 +366,12 @@ public class FileSystemDisk extends FileSystem {
trace("openRandomAccessFile", fileName, f); trace("openRandomAccessFile", fileName, f);
} catch (IOException e) { } catch (IOException e) {
freeMemoryAndFinalize(); freeMemoryAndFinalize();
try {
f = new FileObjectDisk(fileName, mode); f = new FileObjectDisk(fileName, mode);
} catch (IOException e2) {
e2.initCause(e);
throw e2;
}
} }
return f; return f;
} }
......
...@@ -1211,7 +1211,7 @@ public class MetaTable extends Table { ...@@ -1211,7 +1211,7 @@ public class MetaTable extends Table {
break; break;
} }
case SESSIONS: { case SESSIONS: {
Session[] sessions = database.getSessions(); Session[] sessions = database.getSessions(false);
boolean admin = session.getUser().getAdmin(); boolean admin = session.getUser().getAdmin();
for (int i = 0; i < sessions.length; i++) { for (int i = 0; i < sessions.length; i++) {
Session s = sessions[i]; Session s = sessions[i];
...@@ -1229,7 +1229,7 @@ public class MetaTable extends Table { ...@@ -1229,7 +1229,7 @@ public class MetaTable extends Table {
break; break;
} }
case LOCKS: { case LOCKS: {
Session[] sessions = database.getSessions(); Session[] sessions = database.getSessions(false);
boolean admin = session.getUser().getAdmin(); boolean admin = session.getUser().getAdmin();
for (int i = 0; i < sessions.length; i++) { for (int i = 0; i < sessions.length; i++) {
Session s = sessions[i]; Session s = sessions[i];
......
...@@ -21,7 +21,7 @@ public class ConvertTraceFile { ...@@ -21,7 +21,7 @@ public class ConvertTraceFile {
private void showUsage() { private void showUsage() {
System.out.println("java "+getClass().getName() System.out.println("java "+getClass().getName()
+ " [-traceFile <trace file name>] [-javaClass <java class name>] [-script <sql script file>]"); + " [-traceFile <trace file name>]\n [-javaClass <java class name>] [-script <sql script file>]");
System.out.println("See also http://h2database.com/javadoc/org/h2/tools/ConvertTraceFile.html"); System.out.println("See also http://h2database.com/javadoc/org/h2/tools/ConvertTraceFile.html");
} }
......
...@@ -261,7 +261,7 @@ public class Csv implements SimpleRowSource { ...@@ -261,7 +261,7 @@ public class Csv implements SimpleRowSource {
} else { } else {
writer.write(s); writer.write(s);
} }
} else if (nullString.length() > 0) { } else if (nullString != null && nullString.length() > 0) {
writer.write(nullString); writer.write(nullString);
} }
} }
......
...@@ -126,8 +126,8 @@ public class DateTimeUtils { ...@@ -126,8 +126,8 @@ public class DateTimeUtils {
int year = 1970, month = 1, day = 1; int year = 1970, month = 1, day = 1;
if (type != Value.TIME) { if (type != Value.TIME) {
// support +year
if (s.startsWith("+")) { if (s.startsWith("+")) {
// +year
s = s.substring(1); s = s.substring(1);
} }
// start at position 1 to support -year // start at position 1 to support -year
...@@ -235,4 +235,18 @@ public class DateTimeUtils { ...@@ -235,4 +235,18 @@ public class DateTimeUtils {
return c.getTime().getTime(); return c.getTime().getTime();
} }
public static int getDatePart(java.util.Date d, int field) {
Calendar c = Calendar.getInstance();
c.setTime(d);
int value = c.get(field);
if (field == Calendar.MONTH) {
value++;
} else if (field == Calendar.YEAR) {
if (c.get(Calendar.ERA) == GregorianCalendar.BC) {
value = 1 - value;
}
}
return value;
}
} }
...@@ -8,6 +8,7 @@ package org.h2.value; ...@@ -8,6 +8,7 @@ package org.h2.value;
import java.sql.Date; import java.sql.Date;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Calendar;
import org.h2.constant.ErrorCode; import org.h2.constant.ErrorCode;
import org.h2.util.DateTimeUtils; import org.h2.util.DateTimeUtils;
...@@ -53,7 +54,17 @@ public class ValueDate extends Value { ...@@ -53,7 +54,17 @@ public class ValueDate extends Value {
} }
public String getString() { public String getString() {
return value.toString(); String s = value.toString();
long time = value.getTime();
// special case: java.sql.Date doesn't format
// years below year 1 (BC) correctly
if (time < ValueTimestamp.YEAR_ONE) {
int year = DateTimeUtils.getDatePart(value, Calendar.YEAR);
if (year < 1) {
s = year + s.substring(s.indexOf('-'));
}
}
return s;
} }
public long getPrecision() { public long getPrecision() {
......
...@@ -9,6 +9,7 @@ import java.math.BigDecimal; ...@@ -9,6 +9,7 @@ import java.math.BigDecimal;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Timestamp; import java.sql.Timestamp;
import java.util.Calendar;
import org.h2.constant.ErrorCode; import org.h2.constant.ErrorCode;
import org.h2.message.Message; import org.h2.message.Message;
...@@ -24,6 +25,13 @@ public class ValueTimestamp extends Value { ...@@ -24,6 +25,13 @@ public class ValueTimestamp extends Value {
public static final int DEFAULT_SCALE = 10; public static final int DEFAULT_SCALE = 10;
private final Timestamp value; private final Timestamp value;
/**
* This is used to find out if a date is possibly BC. Because of timezone
* issues (the date is time zone specific), the second day is used. That
* means the value is not exact, but it does not need to be.
*/
static final long YEAR_ONE = java.sql.Date.valueOf("0001-01-02").getTime();
private ValueTimestamp(Timestamp value) { private ValueTimestamp(Timestamp value) {
this.value = value; this.value = value;
} }
...@@ -55,7 +63,17 @@ public class ValueTimestamp extends Value { ...@@ -55,7 +63,17 @@ public class ValueTimestamp extends Value {
} }
public String getString() { public String getString() {
return value.toString(); String s = value.toString();
long time = value.getTime();
// special case: java.sql.Timestamp doesn't format
// years below year 1 (BC) correctly
if (time < YEAR_ONE) {
int year = DateTimeUtils.getDatePart(value, Calendar.YEAR);
if (year < 1) {
s = year + s.substring(s.indexOf('-'));
}
}
return s;
} }
public long getPrecision() { public long getPrecision() {
......
...@@ -160,21 +160,16 @@ java org.h2.test.TestAll timer ...@@ -160,21 +160,16 @@ java org.h2.test.TestAll timer
/* /*
write to system table before adding to internal data structures should write (log) to system table before adding to internal data structures
//new TestCrashAPI().init(test).testCase(2046453618); //new TestCrashAPI().init(test).testCase(2046453618);
MiniConnectionPoolManager
-------------- --------------
scheduler: what if invoke takes more than... scheduler: what if invoke takes more than...
scheduler: log at startup next 5 scheduler: log at startup next 5
scheduler: add an a cron functionality scheduler: add an a cron functionality
performance of drop table / index is slow document: read uncommitted and multi-threaded mode at the same time is dangerous
(when deleting a lot of rows randomly?)
use a default delay of 1 second before closing a database.
more tests with disk based select distinct; order by: more tests with disk based select distinct; order by:
select distinct x from system_range(1, 200000); select distinct x from system_range(1, 200000);
...@@ -192,10 +187,6 @@ INSERT INTO TEST VALUES(1,'Apples',1.20), ...@@ -192,10 +187,6 @@ INSERT INTO TEST VALUES(1,'Apples',1.20),
(9,NULL,-10.0); (9,NULL,-10.0);
SELECT DISTINCT NAME FROM TEST; SELECT DISTINCT NAME FROM TEST;
CREATE TABLE p(d DATE);
INSERT INTO p VALUES('0000-01-01');
INSERT INTO p VALUES('0001-01-01');
C:\temp\db\diff.patch C:\temp\db\diff.patch
out of memory problem: out of memory problem:
...@@ -215,8 +206,6 @@ test with: ...@@ -215,8 +206,6 @@ test with:
- large varchar columns (40 KB) - large varchar columns (40 KB)
- not closing the database - not closing the database
read uncommitted and multi-threaded mode at the same time is dangerous
test multi-threaded kernel fulltext test multi-threaded kernel fulltext
Can sometimes not delete log file? need test case Can sometimes not delete log file? need test case
...@@ -224,6 +213,12 @@ Can sometimes not delete log file? need test case ...@@ -224,6 +213,12 @@ Can sometimes not delete log file? need test case
Add where required // TODO: change in version 1.1 Add where required // TODO: change in version 1.1
History: History:
When a log file switch occured in the middle of a sequence flush (sequences are only
flushed every 32 values by default), the sequence was lost. Fixed.
When a log file switch occured just after a truncate table or drop table statement,
the database could not be started normally (RECOVER=1 was required). Fixed.
There was a bug in the recovery code that would stop recovery sometimes when
there are multiple log files to recover.
A new Shell tools is now included (org.h2.tools.Shell) query a A new Shell tools is now included (org.h2.tools.Shell) query a
database from the command line. database from the command line.
Performance was very slow when using LOG=2 and deleting or Performance was very slow when using LOG=2 and deleting or
...@@ -238,12 +233,18 @@ Fulltext search (native implementation): The words table is no longer ...@@ -238,12 +233,18 @@ Fulltext search (native implementation): The words table is no longer
It was possible to create a role with the name as an existing user It was possible to create a role with the name as an existing user
(but not vice versa). This is not allowed any more. (but not vice versa). This is not allowed any more.
The recovery tool didn't work correctly for tables without rows. The recovery tool didn't work correctly for tables without rows.
For years below 1, the YEAR method didn't return the correct value,
and the conversion from date and timestamp to varchar was incorrect.
CSVWRITE caused a NullPointerException when not specifying a nullString.
Roadmap: Roadmap:
SET LOG_SYSTEM SET LOG_SYSTEM
{NATIVE|LOG4J|COMMONS|DRIVER_MANAGER} {NATIVE|LOG4J|COMMONS|DRIVER_MANAGER}
Fluent API for tools: Server.createTcpServer(). Fluent API for tools: Server.createTcpServer().
setPort(9081).setPassword(password).start(); setPort(9081).setPassword(password).start();
MySQL compatiblity: SHOW TABLES, DESCRIBE TEST (then remove from Shell)
Use a default delay of 1 second before closing a database.
*/ */
......
...@@ -133,9 +133,16 @@ public abstract class TestBase { ...@@ -133,9 +133,16 @@ public abstract class TestBase {
if (admin) { if (admin) {
url += ";LOG=" + config.logMode; url += ";LOG=" + config.logMode;
} }
if (config.smallLog && admin) {
int test;
// if (config.smallLog && admin) {
// url += ";MAX_LOG_SIZE=1";
// }
if (admin) {
url += ";MAX_LOG_SIZE=1"; url += ";MAX_LOG_SIZE=1";
} }
if (config.diskUndo && admin) { if (config.diskUndo && admin) {
url += ";MAX_MEMORY_UNDO=3"; url += ";MAX_MEMORY_UNDO=3";
} }
......
...@@ -133,4 +133,20 @@ public class Db { ...@@ -133,4 +133,20 @@ public class Db {
return new Error("Error: " + e.toString(), e); return new Error("Error: " + e.toString(), e);
} }
public void setAutoCommit(boolean autoCommit) {
try {
conn.setAutoCommit(autoCommit);
} catch (Exception e) {
throw convert(e);
}
}
public void commit() {
try {
conn.commit();
} catch (Exception e) {
throw convert(e);
}
}
} }
...@@ -119,6 +119,9 @@ public class TestCsv extends TestBase { ...@@ -119,6 +119,9 @@ public class TestCsv extends TestBase {
} }
private String randomData(Random random) { private String randomData(Random random) {
if (random.nextInt(10) == 1) {
return null;
}
int len = random.nextInt(5); int len = random.nextInt(5);
StringBuffer buff = new StringBuffer(); StringBuffer buff = new StringBuffer();
String chars = "\\\'\",\r\n\t ;.-123456|#"; String chars = "\\\'\",\r\n\t ;.-123456|#";
......
--- special grammar and test cases --------------------------------------------------------------------------------------------- --- special grammar and test cases ---------------------------------------------------------------------------------------------
CREATE TABLE p(d date);
> ok
INSERT INTO p VALUES('-1-01-01'), ('0-01-01'), ('0001-01-01');
> update count: 3
select d, year(d), extract(year from d), cast(d as timestamp) from p;
> D YEAR(D) EXTRACT(YEAR FROM D) CAST(D AS TIMESTAMP)
> ---------- ------- -------------------- ---------------------
> -1-01-01 -1 -1 -1-01-01 00:00:00.0
> 0-01-01 0 0 0-01-01 00:00:00.0
> 0001-01-01 1 1 0001-01-01 00:00:00.0
> rows: 3
drop table p;
> ok
(SELECT X FROM DUAL ORDER BY X+2) UNION SELECT X FROM DUAL; (SELECT X FROM DUAL ORDER BY X+2) UNION SELECT X FROM DUAL;
> X > X
> - > -
......
...@@ -228,7 +228,7 @@ drop schema b; ...@@ -228,7 +228,7 @@ drop schema b;
select date '+0011-01-01'; select date '+0011-01-01';
> 0011-01-01; > 0011-01-01;
select date'-0010-01-01'; select date'-0010-01-01';
> 0011-01-01; > -10-01-01;
select datediff('HOUR', timestamp '2007-01-06 10:00:00Z', '2007-01-06 10:00:00Z'); select datediff('HOUR', timestamp '2007-01-06 10:00:00Z', '2007-01-06 10:00:00Z');
> 0; > 0;
select datediff('HOUR', timestamp '1234-05-06 10:00:00+01:00', '1234-05-06 10:00:00+02:00'); select datediff('HOUR', timestamp '1234-05-06 10:00:00+01:00', '1234-05-06 10:00:00+02:00');
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论