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

--no commit message

--no commit message
上级 68882ef5
......@@ -161,7 +161,7 @@ public class TransactionCommand extends Prepared {
// close the database, but don't update the persistent setting
session.getDatabase().setCloseDelay(0);
Database db = session.getDatabase();
Session[] sessions = db.getSessions();
Session[] sessions = db.getSessions(false);
for (int i = 0; i < sessions.length; i++) {
Session s = sessions[i];
synchronized (s) {
......
......@@ -359,7 +359,9 @@ public class SysProperties {
* System property <code>h2.reuseSpaceQuickly</code> (default: true).<br />
* 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 />
......@@ -478,7 +480,9 @@ public class SysProperties {
* INTERNAL
*/
public static int getLogFileDeleteDelay() {
int test;
return getIntSetting(H2_LOG_DELETE_DELAY, 0);
//return getIntSetting(H2_LOG_DELETE_DELAY, 1000);
}
/**
......
......@@ -8,6 +8,7 @@ package org.h2.engine;
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
......@@ -89,7 +90,7 @@ public class Database implements DataHandler {
private final HashMap userDataTypes = new HashMap();
private final HashMap aggregates = 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 final BitField objectIds = new BitField();
private final Object lobSyncObject = new Object();
......@@ -808,12 +809,12 @@ public class Database implements DataHandler {
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) {
throw Message.getSQLException(ErrorCode.DATABASE_IS_IN_EXCLUSIVE_MODE);
}
Session session = new Session(this, user, ++nextSessionId);
sessions.add(session);
userSessions.add(session);
traceSystem.getTrace(Trace.SESSION).info("connecting #" + session.getId() + " to " + databaseName);
if (delayedCloser != null) {
delayedCloser.reset();
......@@ -827,12 +828,12 @@ public class Database implements DataHandler {
if (exclusiveSession == session) {
exclusiveSession = null;
}
sessions.remove(session);
userSessions.remove(session);
if (session != systemSession) {
traceSystem.getTrace(Trace.SESSION).info("disconnecting #" + session.getId());
}
}
if (sessions.size() == 0 && session != systemSession) {
if (userSessions.size() == 0 && session != systemSession) {
if (closeDelay == 0) {
close(false);
} else if (closeDelay < 0) {
......@@ -851,13 +852,13 @@ public class Database implements DataHandler {
synchronized void close(boolean fromShutdownHook) {
closing = true;
if (sessions.size() > 0) {
if (userSessions.size() > 0) {
if (!fromShutdownHook) {
return;
}
traceSystem.getTrace(Trace.DATABASE).info("closing " + databaseName + " from shutdown hook");
Session[] all = new Session[sessions.size()];
sessions.toArray(all);
Session[] all = new Session[userSessions.size()];
userSessions.toArray(all);
for (int i = 0; i < all.length; i++) {
Session s = all[i];
try {
......@@ -878,7 +879,7 @@ public class Database implements DataHandler {
// set it to null, to make sure it's called only once
eventListener = null;
e.closingDatabase();
if (sessions.size() > 0) {
if (userSessions.size() > 0) {
// if a connection was opened, we can't close the database
return;
}
......@@ -1086,10 +1087,14 @@ public class Database implements DataHandler {
return log;
}
public Session[] getSessions() {
Session[] list = new Session[sessions.size()];
sessions.toArray(list);
return list;
public Session[] getSessions(boolean includingSystemSession) {
ArrayList list = new ArrayList(userSessions);
if (includingSystemSession && systemSession != null) {
list.add(systemSession);
}
Session[] array = new Session[list.size()];
list.toArray(array);
return array;
}
public synchronized void update(Session session, DbObject obj) throws SQLException {
......@@ -1403,6 +1408,8 @@ public class Database implements DataHandler {
public void deleteLogFileLater(String fileName) throws SQLException {
if (writer != null) {
int test;
//FileUtils.rename(fileName, fileName + ".trace.db");
writer.deleteLogFileLater(fileName);
} else {
FileUtils.delete(fileName);
......@@ -1700,7 +1707,7 @@ public class Database implements DataHandler {
}
public int getSessionCount() {
return sessions.size();
return userSessions.size();
}
public void setReferentialIntegrity(boolean b) {
......
......@@ -90,7 +90,7 @@ public class Engine {
}
}
checkClustering(ci, database);
Session session = database.createSession(user);
Session session = database.createUserSession(user);
return session;
}
}
......
......@@ -39,6 +39,7 @@ import org.h2.table.TableFilter;
import org.h2.tools.CompressTool;
import org.h2.tools.Csv;
import org.h2.util.AutoCloseInputStream;
import org.h2.util.DateTimeUtils;
import org.h2.util.FileUtils;
import org.h2.util.MathUtils;
import org.h2.util.MemoryUtils;
......@@ -565,22 +566,22 @@ public class Function extends Expression implements FunctionCall {
break;
}
case DAYOFMONTH:
result = ValueInt.get(getDatePart(v0.getTimestampNoCopy(), Calendar.DAY_OF_MONTH));
result = ValueInt.get(DateTimeUtils.getDatePart(v0.getTimestampNoCopy(), Calendar.DAY_OF_MONTH));
break;
case DAYOFWEEK:
result = ValueInt.get(getDatePart(v0.getTimestampNoCopy(), Calendar.DAY_OF_WEEK));
result = ValueInt.get(DateTimeUtils.getDatePart(v0.getTimestampNoCopy(), Calendar.DAY_OF_WEEK));
break;
case DAYOFYEAR:
result = ValueInt.get(getDatePart(v0.getTimestampNoCopy(), Calendar.DAY_OF_YEAR));
result = ValueInt.get(DateTimeUtils.getDatePart(v0.getTimestampNoCopy(), Calendar.DAY_OF_YEAR));
break;
case HOUR:
result = ValueInt.get(getDatePart(v0.getTimestampNoCopy(), Calendar.HOUR_OF_DAY));
result = ValueInt.get(DateTimeUtils.getDatePart(v0.getTimestampNoCopy(), Calendar.HOUR_OF_DAY));
break;
case MINUTE:
result = ValueInt.get(getDatePart(v0.getTimestampNoCopy(), Calendar.MINUTE));
result = ValueInt.get(DateTimeUtils.getDatePart(v0.getTimestampNoCopy(), Calendar.MINUTE));
break;
case MONTH:
result = ValueInt.get(getDatePart(v0.getTimestampNoCopy(), Calendar.MONTH));
result = ValueInt.get(DateTimeUtils.getDatePart(v0.getTimestampNoCopy(), Calendar.MONTH));
break;
case MONTHNAME: {
synchronized (FORMAT_MONTHNAME) {
......@@ -589,16 +590,16 @@ public class Function extends Expression implements FunctionCall {
break;
}
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;
case SECOND:
result = ValueInt.get(getDatePart(v0.getTimestamp(), Calendar.SECOND));
result = ValueInt.get(DateTimeUtils.getDatePart(v0.getTimestamp(), Calendar.SECOND));
break;
case WEEK:
result = ValueInt.get(getDatePart(v0.getTimestamp(), Calendar.WEEK_OF_YEAR));
result = ValueInt.get(DateTimeUtils.getDatePart(v0.getTimestamp(), Calendar.WEEK_OF_YEAR));
break;
case YEAR:
result = ValueInt.get(getDatePart(v0.getTimestamp(), Calendar.YEAR));
result = ValueInt.get(DateTimeUtils.getDatePart(v0.getTimestamp(), Calendar.YEAR));
break;
case CURDATE:
case CURRENT_DATE:
......@@ -768,7 +769,7 @@ public class Function extends Expression implements FunctionCall {
private boolean cancelStatement(Session session, int targetSessionId) throws SQLException {
session.getUser().checkAdmin();
Session[] sessions = session.getDatabase().getSessions();
Session[] sessions = session.getDatabase().getSessions(false);
for (int i = 0; i < sessions.length; i++) {
Session s = sessions[i];
if (s.getId() == targetSessionId) {
......@@ -948,7 +949,7 @@ public class Function extends Expression implements FunctionCall {
break;
case EXTRACT: {
int field = getDatePart(v0.getString());
result = ValueInt.get(getDatePart(v1.getTimestamp(), field));
result = ValueInt.get(DateTimeUtils.getDatePart(v1.getTimestamp(), field));
break;
}
case FORMATDATETIME: {
......@@ -1125,60 +1126,6 @@ public class Function extends Expression implements FunctionCall {
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 {
Integer p = (Integer) DATE_PART.get(StringUtils.toUpperEnglish(part));
if (p == null) {
......
......@@ -87,7 +87,7 @@ public class LogSystem {
// (even if they are resolved), can't update or delete the log files
return;
}
Session[] sessions = database.getSessions();
Session[] sessions = database.getSessions(true);
int firstUncommittedLog = currentLog.getId();
int firstUncommittedPos = currentLog.getPos();
for (int i = 0; i < sessions.length; i++) {
......@@ -111,6 +111,7 @@ public class LogSystem {
} else {
l.setFirstUncommittedPos(firstUncommittedPos);
}
}
}
for (int i = 0; i < activeLogs.size(); i++) {
......@@ -193,9 +194,9 @@ public class LogSystem {
for (int i = 0; i < activeLogs.size(); i++) {
LogFile log = (LogFile) activeLogs.get(i);
log.redoAllGoEnd();
database.getDataFile().flushRedoLog();
database.getIndexFile().flushRedoLog();
}
database.getDataFile().flushRedoLog();
database.getIndexFile().flushRedoLog();
int end = currentLog.getPos();
Object[] states = sessions.values().toArray();
inDoubtTransactions = new ObjectArray();
......@@ -388,7 +389,9 @@ public class LogSystem {
storageId = -storageId;
}
currentLog.addTruncate(session, storageId, recordId, blockCount);
if (currentLog.getFileSize() > maxLogSize) {
int test;
// if (currentLog.getFileSize() > maxLogSize) {
if (currentLog.getFileSize()*100 > maxLogSize) {
checkpoint();
}
}
......@@ -412,7 +415,9 @@ public class LogSystem {
session.addLogPos(log, pos);
record.setLastLog(log, pos);
currentLog.add(session, storageId, record);
if (currentLog.getFileSize() > maxLogSize) {
int test;
// if (currentLog.getFileSize() > maxLogSize) {
if (currentLog.getFileSize()*100 > maxLogSize) {
checkpoint();
}
}
......
......@@ -610,7 +610,7 @@ public class DiskFile implements CacheWriter {
void reuseSpace() throws SQLException {
if (SysProperties.REUSE_SPACE_QUICKLY) {
if (potentiallyFreePages.size() >= SysProperties.REUSE_SPACE_AFTER) {
Session[] sessions = database.getSessions();
Session[] sessions = database.getSessions(true);
int oldest = 0;
for (int i = 0; i < sessions.length; i++) {
int deleteId = sessions[i].getLastUncommittedDelete();
......@@ -904,9 +904,6 @@ public class DiskFile implements CacheWriter {
pages.toArray(pagesCopy);
for (int i = 0; i < pagesCopy.length; 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++) {
Record r = (Record) cache.find(page * BLOCKS_PER_PAGE + j);
if (r != null) {
......@@ -915,6 +912,14 @@ public class DiskFile implements CacheWriter {
}
deleted.setRange(page * BLOCKS_PER_PAGE, BLOCKS_PER_PAGE, true);
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 {
if (oldLogFile != null) {
FileUtils.delete(oldLogFile);
}
oldLogFile = fileName;
if (fileName != null) {
oldLogFileDelete = System.currentTimeMillis() + SysProperties.getLogFileDeleteDelay();
int delay = SysProperties.getLogFileDeleteDelay();
if (delay == 0 && fileName != null) {
FileUtils.delete(fileName);
} else {
oldLogFile = fileName;
if (fileName != null) {
oldLogFileDelete = System.currentTimeMillis() + delay;
}
}
}
......
......@@ -366,7 +366,12 @@ public class FileSystemDisk extends FileSystem {
trace("openRandomAccessFile", fileName, f);
} catch (IOException e) {
freeMemoryAndFinalize();
f = new FileObjectDisk(fileName, mode);
try {
f = new FileObjectDisk(fileName, mode);
} catch (IOException e2) {
e2.initCause(e);
throw e2;
}
}
return f;
}
......
......@@ -1211,7 +1211,7 @@ public class MetaTable extends Table {
break;
}
case SESSIONS: {
Session[] sessions = database.getSessions();
Session[] sessions = database.getSessions(false);
boolean admin = session.getUser().getAdmin();
for (int i = 0; i < sessions.length; i++) {
Session s = sessions[i];
......@@ -1229,7 +1229,7 @@ public class MetaTable extends Table {
break;
}
case LOCKS: {
Session[] sessions = database.getSessions();
Session[] sessions = database.getSessions(false);
boolean admin = session.getUser().getAdmin();
for (int i = 0; i < sessions.length; i++) {
Session s = sessions[i];
......
......@@ -21,7 +21,7 @@ public class ConvertTraceFile {
private void showUsage() {
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");
}
......
......@@ -261,7 +261,7 @@ public class Csv implements SimpleRowSource {
} else {
writer.write(s);
}
} else if (nullString.length() > 0) {
} else if (nullString != null && nullString.length() > 0) {
writer.write(nullString);
}
}
......
......@@ -126,8 +126,8 @@ public class DateTimeUtils {
int year = 1970, month = 1, day = 1;
if (type != Value.TIME) {
// support +year
if (s.startsWith("+")) {
// +year
s = s.substring(1);
}
// start at position 1 to support -year
......@@ -235,4 +235,18 @@ public class DateTimeUtils {
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;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Calendar;
import org.h2.constant.ErrorCode;
import org.h2.util.DateTimeUtils;
......@@ -53,7 +54,17 @@ public class ValueDate extends Value {
}
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() {
......
......@@ -9,6 +9,7 @@ import java.math.BigDecimal;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Calendar;
import org.h2.constant.ErrorCode;
import org.h2.message.Message;
......@@ -23,6 +24,13 @@ public class ValueTimestamp extends Value {
public static final int DISPLAY_SIZE = 23; // 2001-01-01 23:59:59.000
public static final int DEFAULT_SCALE = 10;
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) {
this.value = value;
......@@ -55,7 +63,17 @@ public class ValueTimestamp extends Value {
}
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() {
......
......@@ -157,24 +157,19 @@ java org.h2.test.TestAll timer
long time = System.currentTimeMillis();
TestAll test = new TestAll();
test.printSystem();
/*
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);
MiniConnectionPoolManager
--------------
scheduler: what if invoke takes more than...
scheduler: log at startup next 5
scheduler: add an a cron functionality
performance of drop table / index is slow
(when deleting a lot of rows randomly?)
use a default delay of 1 second before closing a database.
document: read uncommitted and multi-threaded mode at the same time is dangerous
more tests with disk based select distinct; order by:
select distinct x from system_range(1, 200000);
......@@ -192,10 +187,6 @@ INSERT INTO TEST VALUES(1,'Apples',1.20),
(9,NULL,-10.0);
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
out of memory problem:
......@@ -215,8 +206,6 @@ test with:
- large varchar columns (40 KB)
- not closing the database
read uncommitted and multi-threaded mode at the same time is dangerous
test multi-threaded kernel fulltext
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
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
database from the command line.
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
It was possible to create a role with the name as an existing user
(but not vice versa). This is not allowed any more.
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:
SET LOG_SYSTEM
{NATIVE|LOG4J|COMMONS|DRIVER_MANAGER}
Fluent API for tools: Server.createTcpServer().
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 {
if (admin) {
url += ";LOG=" + config.logMode;
}
if (config.smallLog && admin) {
url += ";MAX_LOG_SIZE=1";
}
int test;
// if (config.smallLog && admin) {
// url += ";MAX_LOG_SIZE=1";
// }
if (admin) {
url += ";MAX_LOG_SIZE=1";
}
if (config.diskUndo && admin) {
url += ";MAX_MEMORY_UNDO=3";
}
......
......@@ -133,4 +133,20 @@ public class Db {
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 {
}
private String randomData(Random random) {
if (random.nextInt(10) == 1) {
return null;
}
int len = random.nextInt(5);
StringBuffer buff = new StringBuffer();
String chars = "\\\'\",\r\n\t ;.-123456|#";
......
--- 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;
> X
> -
......
......@@ -228,7 +228,7 @@ drop schema b;
select date '+0011-01-01';
> 0011-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');
> 0;
select datediff('HOUR', timestamp '1234-05-06 10:00:00+01:00', '1234-05-06 10:00:00+02:00');
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论