提交 771c08fe authored 作者: Thomas Mueller's avatar Thomas Mueller

--no commit message

--no commit message
上级 8c20d4bd
...@@ -40,7 +40,15 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch. ...@@ -40,7 +40,15 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch.
<h3>Version 1.0 (Current)</h3> <h3>Version 1.0 (Current)</h3>
<h3>Version 1.0.x (2007-09-x)</h3><ul> <h3>Version 1.0.x (2007-09-x)</h3><ul>
<li>Using spaces in column and table aliases was not supported when used inside a view or temporary view. <li>After deleting data, empty space in the database files was not efficiently reused
(but it was reused when opening the database). This has been fixed.
</li><li>About 230 bytes per database was leaked. This is a problem for applications
opening and closing many thousand databases. The main problem: a shutdown hook
was added but never removed. Fixed. In JDK 1.4, there is an additionally problem,
see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4197876.
A workaround has been implemented.
</li><li>Optimization for COLUMN IN(.., NULL) if the column does not allow NULL values.
</li><li>Using spaces in column and table aliases was not supported when used inside a view or temporary view.
</li><li>The version (build) number is now included in the manifest file. </li><li>The version (build) number is now included in the manifest file.
</li><li>In some systems, SecureRandom.generateSeed is very slow (taking one minute or more). </li><li>In some systems, SecureRandom.generateSeed is very slow (taking one minute or more).
For those cases, an alternative method is used that takes less than one second. For those cases, an alternative method is used that takes less than one second.
...@@ -730,6 +738,12 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch. ...@@ -730,6 +738,12 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch.
</li><li>Support indexes for views (probably requires materialized views) </li><li>Support indexes for views (probably requires materialized views)
</li><li>Linked tables that point to the same database should share the connection </li><li>Linked tables that point to the same database should share the connection
</li><li>Use log for rollback </li><li>Use log for rollback
</li><li>Document SET SEARCH_PATH, BEGIN, EXECUTE, $ parameters
</li><li>Complete Javadocs for ErrorCode messages and add to docs
</li><li>Browser: use Desktop.isDesktopSupported and browse when using JDK 1.6
</li><li>Document org.h2.samples.MixedMode
</li><li>Server: use one listener (detect if the request comes from an PG or TCP client)
</li><li>Store dates as 'local'. Existing files use GMT. Use escape syntax for backward compatiblity)
</li></ul> </li></ul>
<h3>Not Planned</h3> <h3>Not Planned</h3>
......
...@@ -137,6 +137,7 @@ public class Database implements DataHandler { ...@@ -137,6 +137,7 @@ public class Database implements DataHandler {
private String accessModeLog, accessModeData; private String accessModeLog, accessModeData;
private boolean referentialIntegrity = true; private boolean referentialIntegrity = true;
private boolean multiVersion; private boolean multiVersion;
private DatabaseCloser closeOnExit;
public Database(String name, ConnectionInfo ci, String cipher) throws SQLException { public Database(String name, ConnectionInfo ci, String cipher) throws SQLException {
this.compareMode = new CompareMode(null, null); this.compareMode = new CompareMode(null, null);
...@@ -180,7 +181,7 @@ public class Database implements DataHandler { ...@@ -180,7 +181,7 @@ public class Database implements DataHandler {
open(traceLevelFile, traceLevelSystemOut); open(traceLevelFile, traceLevelSystemOut);
} }
if (closeAtVmShutdown) { if (closeAtVmShutdown) {
DatabaseCloser closeOnExit = new DatabaseCloser(this, 0, true); closeOnExit = new DatabaseCloser(this, 0, true);
try { try {
Runtime.getRuntime().addShutdownHook(closeOnExit); Runtime.getRuntime().addShutdownHook(closeOnExit);
} catch (IllegalStateException e) { } catch (IllegalStateException e) {
...@@ -841,6 +842,15 @@ public class Database implements DataHandler { ...@@ -841,6 +842,15 @@ public class Database implements DataHandler {
} }
traceSystem.getTrace(Trace.DATABASE).info("closed"); traceSystem.getTrace(Trace.DATABASE).info("closed");
traceSystem.close(); traceSystem.close();
if (closeOnExit != null) {
closeOnExit.reset();
try {
Runtime.getRuntime().removeShutdownHook(closeOnExit);
} catch (IllegalStateException e) {
// ignore
}
closeOnExit = null;
}
Engine.getInstance().close(databaseName); Engine.getInstance().close(databaseName);
if (deleteFilesOnDisconnect && persistent) { if (deleteFilesOnDisconnect && persistent) {
deleteFilesOnDisconnect = false; deleteFilesOnDisconnect = false;
......
...@@ -11,6 +11,7 @@ public class DatabaseCloser extends Thread { ...@@ -11,6 +11,7 @@ public class DatabaseCloser extends Thread {
private final boolean shutdownHook; private final boolean shutdownHook;
private volatile WeakReference databaseRef; private volatile WeakReference databaseRef;
private int delayInMillis; private int delayInMillis;
private boolean stopImmediately;
DatabaseCloser(Database db, int delayInMillis, boolean shutdownHook) { DatabaseCloser(Database db, int delayInMillis, boolean shutdownHook) {
this.databaseRef = new WeakReference(db); this.databaseRef = new WeakReference(db);
...@@ -22,9 +23,19 @@ public class DatabaseCloser extends Thread { ...@@ -22,9 +23,19 @@ public class DatabaseCloser extends Thread {
synchronized (this) { synchronized (this) {
databaseRef = null; databaseRef = null;
} }
if (getThreadGroup().activeCount() > 100) {
// in JDK 1.4 and below, all Thread objects are added to the ThreadGroup,
// and cause a memory leak if never started.
// Need to start it, otherwise it leaks memory in JDK 1.4 and below
stopImmediately = true;
start();
}
} }
public void run() { public void run() {
if (stopImmediately) {
return;
}
while (delayInMillis > 0) { while (delayInMillis > 0) {
try { try {
int step = 100; int step = 100;
......
...@@ -56,9 +56,6 @@ merge into pg_catalog.pg_type values( ...@@ -56,9 +56,6 @@ merge into pg_catalog.pg_type values(
0 0
); );
create view pg_catalog.pg_class -- (oid, relname, relnamespace, relkind, relam, reltuples, relpages, relhasrules, relhasoids) create view pg_catalog.pg_class -- (oid, relname, relnamespace, relkind, relam, reltuples, relpages, relhasrules, relhasoids)
as as
select select
......
...@@ -185,7 +185,7 @@ public class DiskFile implements CacheWriter { ...@@ -185,7 +185,7 @@ public class DiskFile implements CacheWriter {
} }
} }
private boolean isPageFree(int page) { boolean isPageFree(int page) {
for (int i = page * BLOCKS_PER_PAGE; i < (page + 1) * BLOCKS_PER_PAGE; i++) { for (int i = page * BLOCKS_PER_PAGE; i < (page + 1) * BLOCKS_PER_PAGE; i++) {
if (used.get(i)) { if (used.get(i)) {
return false; return false;
...@@ -500,8 +500,7 @@ public class DiskFile implements CacheWriter { ...@@ -500,8 +500,7 @@ public class DiskFile implements CacheWriter {
for (int i = pos; i < pos + blockCount; i++) { for (int i = pos; i < pos + blockCount; i++) {
used.clear(i); used.clear(i);
if ((i % BLOCKS_PER_PAGE == 0) && (pos + blockCount >= i + BLOCKS_PER_PAGE)) { if ((i % BLOCKS_PER_PAGE == 0) && (pos + blockCount >= i + BLOCKS_PER_PAGE)) {
// if this is the first page of a block and if the whole page is // if this is the first page of a block and if the whole page is free
// free
setPageOwner(getPage(i), -1); setPageOwner(getPage(i), -1);
} }
} }
......
...@@ -37,6 +37,7 @@ public class Storage { ...@@ -37,6 +37,7 @@ public class Storage {
private int id; private int id;
private Database database; private Database database;
private DataPage dummy; private DataPage dummy;
private int pageCheckIndex;
public Storage(Database database, DiskFile file, RecordReader reader, int id) { public Storage(Database database, DiskFile file, RecordReader reader, int id) {
this.database = database; this.database = database;
...@@ -133,6 +134,7 @@ public class Storage { ...@@ -133,6 +134,7 @@ public class Storage {
} }
public void removeRecord(Session session, int pos) throws SQLException { public void removeRecord(Session session, int pos) throws SQLException {
checkOnePage();
Record record = getRecord(session, pos); Record record = getRecord(session, pos);
if (SysProperties.CHECK && record.getDeleted()) { if (SysProperties.CHECK && record.getDeleted()) {
throw Message.getInternalError("duplicate delete " + pos); throw Message.getInternalError("duplicate delete " + pos);
...@@ -144,10 +146,6 @@ public class Storage { ...@@ -144,10 +146,6 @@ public class Storage {
file.removeRecord(session, pos, record, blockCount); file.removeRecord(session, pos, record, blockCount);
} }
public void removeRecord(Session session, int pos, int blockCount) throws SQLException {
}
private boolean isFreeAndMine(int pos, int blocks) { private boolean isFreeAndMine(int pos, int blocks) {
BitField used = file.getUsed(); BitField used = file.getUsed();
for (int i = blocks + pos - 1; i >= pos; i--) { for (int i = blocks + pos - 1; i >= pos; i--) {
...@@ -255,4 +253,23 @@ public class Storage { ...@@ -255,4 +253,23 @@ public class Storage {
pages.removeValue(i); pages.removeValue(i);
} }
private int test;
//private static long totalCheck;
private void checkOnePage() throws SQLException {
// if(true) return;
//long time = System.currentTimeMillis();
pageCheckIndex = (pageCheckIndex + 1) % pages.size();
int page = pages.get(pageCheckIndex);
if (file.isPageFree(page)) {
//System.out.println("found one! " + page);
file.setPageOwner(page, -1);
}
//time = System.currentTimeMillis() - time;
//totalCheck+= time;
//if(totalCheck > 1000) {
// System.out.println("##took one second");
// totalCheck--;
//}
}
} }
...@@ -251,7 +251,9 @@ public class TableFilter implements ColumnResolver { ...@@ -251,7 +251,9 @@ public class TableFilter implements ColumnResolver {
if (alwaysFalse) { if (alwaysFalse) {
state = AFTER_LAST; state = AFTER_LAST;
} else { } else {
scanCount++; if ((++scanCount & 4095) == 0) {
logScanCount();
}
if (cursor.next()) { if (cursor.next()) {
currentSearchRow = cursor.getSearchRow(); currentSearchRow = cursor.getSearchRow();
current = null; current = null;
...@@ -301,6 +303,10 @@ public class TableFilter implements ColumnResolver { ...@@ -301,6 +303,10 @@ public class TableFilter implements ColumnResolver {
return false; return false;
} }
private void logScanCount() {
// System.out.println(this.alias+ " " + table.getName() + ": " + scanCount);
}
private boolean isOk(Expression condition) throws SQLException { private boolean isOk(Expression condition) throws SQLException {
if (condition == null) { if (condition == null) {
return true; return true;
......
...@@ -43,9 +43,7 @@ public class Csv implements SimpleRowSource { ...@@ -43,9 +43,7 @@ public class Csv implements SimpleRowSource {
private char fieldDelimiter = '\"'; private char fieldDelimiter = '\"';
private char escapeCharacter = '\"'; private char escapeCharacter = '\"';
private String fileName; private String fileName;
private InputStream in;
private Reader reader; private Reader reader;
private OutputStream out;
private PrintWriter writer; private PrintWriter writer;
private int back; private int back;
private boolean endOfLine, endOfFile; private boolean endOfLine, endOfFile;
...@@ -226,9 +224,9 @@ public class Csv implements SimpleRowSource { ...@@ -226,9 +224,9 @@ public class Csv implements SimpleRowSource {
private void initWrite() throws IOException { private void initWrite() throws IOException {
if (writer == null) { if (writer == null) {
try { try {
out = new FileOutputStream(fileName); OutputStream out = new FileOutputStream(fileName);
BufferedOutputStream o = new BufferedOutputStream(out, bufferSize); out = new BufferedOutputStream(out, bufferSize);
writer = new PrintWriter(new OutputStreamWriter(o, charset)); writer = new PrintWriter(new OutputStreamWriter(out, charset));
// TODO performance: what is faster? one, two, or both? // TODO performance: what is faster? one, two, or both?
// writer = new PrintWriter(new BufferedWriter(new // writer = new PrintWriter(new BufferedWriter(new
// OutputStreamWriter(out, encoding), bufferSize)); // OutputStreamWriter(out, encoding), bufferSize));
...@@ -287,12 +285,11 @@ public class Csv implements SimpleRowSource { ...@@ -287,12 +285,11 @@ public class Csv implements SimpleRowSource {
private void initRead() throws IOException { private void initRead() throws IOException {
if (reader == null) { if (reader == null) {
try { try {
in = FileUtils.openFileInputStream(fileName); InputStream in = FileUtils.openFileInputStream(fileName);
BufferedInputStream i = new BufferedInputStream(in, bufferSize); in = new BufferedInputStream(in, bufferSize);
reader = new InputStreamReader(i, charset); reader = new InputStreamReader(in, charset);
// TODO what is faster, 1, 2, 1+2 // TODO what is faster, 1, 2, 1+2
// reader = new BufferedReader(new InputStreamReader(in, // reader = new BufferedReader(new InputStreamReader(in, encoding), bufferSize);
// encoding), bufferSize);
} catch (IOException e) { } catch (IOException e) {
close(); close();
throw e; throw e;
...@@ -500,12 +497,8 @@ public class Csv implements SimpleRowSource { ...@@ -500,12 +497,8 @@ public class Csv implements SimpleRowSource {
public void close() { public void close() {
IOUtils.closeSilently(reader); IOUtils.closeSilently(reader);
reader = null; reader = null;
IOUtils.closeSilently(in);
in = null;
IOUtils.closeSilently(writer); IOUtils.closeSilently(writer);
writer = null; writer = null;
IOUtils.closeSilently(out);
out = null;
} }
/** /**
......
...@@ -22,6 +22,7 @@ import org.h2.engine.Constants; ...@@ -22,6 +22,7 @@ import org.h2.engine.Constants;
import org.h2.message.Message; import org.h2.message.Message;
import org.h2.util.ClassUtils; import org.h2.util.ClassUtils;
import org.h2.util.FileUtils; import org.h2.util.FileUtils;
import org.h2.util.IOUtils;
import org.h2.util.ObjectUtils; import org.h2.util.ObjectUtils;
import org.h2.util.JdbcUtils; import org.h2.util.JdbcUtils;
import org.h2.util.ScriptReader; import org.h2.util.ScriptReader;
...@@ -159,11 +160,11 @@ public class RunScript { ...@@ -159,11 +160,11 @@ public class RunScript {
InputStream in = FileUtils.openFileInputStream(fileName); InputStream in = FileUtils.openFileInputStream(fileName);
String path = FileUtils.getParent(fileName); String path = FileUtils.getParent(fileName);
try { try {
BufferedInputStream bin = new BufferedInputStream(in, Constants.IO_BUFFER_SIZE); in = new BufferedInputStream(in, Constants.IO_BUFFER_SIZE);
InputStreamReader reader = new InputStreamReader(bin, charsetName); InputStreamReader reader = new InputStreamReader(in, charsetName);
execute(conn, threadMap, continueOnError, path, reader, charsetName); execute(conn, threadMap, continueOnError, path, reader, charsetName);
} finally { } finally {
in.close(); IOUtils.closeSilently(in);
} }
} }
......
...@@ -148,49 +148,9 @@ java -Xmx512m -Xrunhprof:cpu=samples,depth=8 org.h2.tools.RunScript ...@@ -148,49 +148,9 @@ java -Xmx512m -Xrunhprof:cpu=samples,depth=8 org.h2.tools.RunScript
/* /*
SYSDATE sollte CURRENT_TIMESTAMP database files grow when updating data
support Trunc(Sysdate),...
public static String chr(int code) {
return String.valueOf((char) code);
}
public static Object nvl(Object value, Object ifNull) {
return (value != null) ? value : ifNull;
}
public static Object nvl2(Object value, Object notNull, Object ifNull) {
return (value != null) ? notNull : ifNull;
}
public static Timestamp sysdate() {
return new Timestamp(System.currentTimeMillis());
}
public static String to_char(Object what, String format) {
throw new Error("not yet"); // @todo check format
}
public static Date to_date(Object what, String format) {
throw new Error("not yet"); // @todo check format
}
public static Number to_number(String str) {
return new Double(str);
}
public static java.sql.Date trunc(Timestamp tsp) {
return new java.sql.Date(tsp.getTime());
}
public static Object trunc(Object what, String format) {
System.out.println("*** trunc ***");
if (what == null)
return null;
else if (what instanceof Date) {
System.out.println("*** date-format = " + format);
return Timestamp.valueOf("1963-03-27 12:34:56.0");
} else if (what instanceof Number) {
System.out.println("*** number-format = " + format);
return new Double(123.456D);
} else
throw new ClassCastException("number or date expected");
}
slow: slow:
select ta.attname, ia.attnum, ic.relname select ta.attname, ia.attnum, ic.relname
from pg_catalog.pg_attribute ta, pg_catalog.pg_attribute ia, pg_catalog.pg_class ic, pg_catalog.pg_index i, pg_catalog.pg_namespace n from pg_catalog.pg_attribute ta, pg_catalog.pg_attribute ia, pg_catalog.pg_class ic, pg_catalog.pg_index i, pg_catalog.pg_namespace n
where ic.relname = 'dummy_pkey' where ic.relname = 'dummy_pkey'
...@@ -204,51 +164,10 @@ AND (NOT ta.attisdropped) ...@@ -204,51 +164,10 @@ AND (NOT ta.attisdropped)
AND (NOT ia.attisdropped) AND (NOT ia.attisdropped)
order by ia.attnum; order by ia.attnum;
database files grow when updating data
change default for in-memory undo change default for in-memory undo
japanese topics in the javascript search japanese topics in the javascript search
feature request: optimization for
where link_id in (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
with NULL and LINK_ID doesn't allow nulls
slow power off test: slow memFS?
DROP TABLE ONE;
DROP TABLE TWO;
CREATE TABLE ONE(A INT PRIMARY KEY, B INT);
INSERT INTO ONE VALUES(0, NULL);
INSERT INTO ONE VALUES(1, 0);
INSERT INTO ONE VALUES(2, 1);
INSERT INTO ONE VALUES(3, 4);
CREATE TABLE TWO(A INT PRIMARY KEY, B INT);
INSERT INTO TWO VALUES(0, NULL);
INSERT INTO TWO VALUES(1, 0);
INSERT INTO TWO VALUES(2, 2);
INSERT INTO TWO VALUES(3, 3);
INSERT INTO TWO VALUES(4, NULL);
SELECT * FROM ONE A LEFT JOIN ONE B ON NOT A.A=A.A;
SELECT T0.A FROM TWO T0 WHERE NOT ((T0.B=T0.A ) AND (T0.B=0 )) AND (T0.B IS NULL );
SELECT T0.A, T1.A, T2.A, T3.A FROM ONE T0 LEFT JOIN ONE T1 ON NOT T0.B=T0.B LEFT JOIN ONE T2 ON T1.A=T2.A LEFT JOIN ONE T3 ON (T3.B=0 ) OR (T2.A<-1 );
SELECT T0.A, T1.A, T2.A, T3.A FROM TWO T0 LEFT JOIN ONE T1 ON T0.B<T0.A LEFT JOIN ONE T2 ON T1.A=T2.A LEFT JOIN TWO T3 ON (T2.A=T3.A ) OR (T3.B=0 );
SELECT T0.A, T1.A, T2.A, T3.A FROM TWO T0 LEFT JOIN ONE T1 ON T0.B>2 LEFT JOIN ONE T2 ON T1.A=T2.A LEFT JOIN TWO T3 ON T2.A IS NULL;
SELECT T0.A, T1.A FROM TWO T0 INNER JOIN TWO T1 ON NOT (((T0.A=T0.B ) AND (T0.B=0 )) OR (T0.A=T1.A )) OR (T0.A=T0.B );
SELECT T0.A, T1.A FROM ONE T0 INNER JOIN ONE T1 ON NOT ((T0.A=T0.B ) AND (T0.B=1 )) OR (T0.B=2 );
document:
maximum file size increment is 16 MB
dont increase database size by more than 128 MB
DROP TABLE IF EXISTS TEST; DROP TABLE IF EXISTS TEST;
CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR); CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR);
@LOOP 1000000 INSERT INTO TEST VALUES(?, SPACE(100000)); @LOOP 1000000 INSERT INTO TEST VALUES(?, SPACE(100000));
...@@ -266,15 +185,11 @@ add MVCC ...@@ -266,15 +185,11 @@ add MVCC
don't create @~ of not translated don't create @~ of not translated
improve documentation of 'mixed mode' usage.
test performance and document fulltext search test performance and document fulltext search
clustered tables: test, document clustered tables: test, document
search for japanese: works, but is it ok? search for japanese: works, but is it ok?
pdf: first page looks empty (because the top part is empty) - title on the top?
pdf / openoffice: pictures don't work?
extend tests that simulate power off extend tests that simulate power off
...@@ -330,27 +245,16 @@ Test Eclipse DTP 1.5 (HSQLDB / H2 connection bug fixed) ...@@ -330,27 +245,16 @@ Test Eclipse DTP 1.5 (HSQLDB / H2 connection bug fixed)
Automate real power off tests Automate real power off tests
Negative dictionary:
Please note that
Merge more from diff.zip (Pavel Ganelin)
Integrate patches from Pavel Ganelin: www.dullesopen.com/software/h2-database-03-04-07-mod.src.zip
store dates as 'local'. Problem: existing files use GMT (use escape syntax)
drop table test; drop table test;
CREATE TABLE TEST( ID BIGINT PRIMARY KEY, CREATED TIMESTAMP); CREATE TABLE TEST( ID BIGINT PRIMARY KEY, CREATED TIMESTAMP);
INSERT INTO TEST VALUES(1, '2007-01-01 00:00:00'); INSERT INTO TEST VALUES(1, '2007-01-01 00:00:00');
SELECT * FROM TEST; SELECT * FROM TEST;
Server: use one listener (detect if the request comes from an PG or TCP client).
http://fastutil.dsi.unimi.it/ http://fastutil.dsi.unimi.it/
http://javolution.org/ http://javolution.org/
http://joda-time.sourceforge.net/ http://joda-time.sourceforge.net/
http://ibatis.apache.org/ http://ibatis.apache.org/
Document org.h2.samples.MixedMode
http://www.igniterealtime.org/projects/openfire/index.jsp http://www.igniterealtime.org/projects/openfire/index.jsp
translation: translation:
...@@ -366,15 +270,47 @@ translated .pdf ...@@ -366,15 +270,47 @@ translated .pdf
docs: xml:lang="en" > correct language (and detect wrong language based on _ja) docs: xml:lang="en" > correct language (and detect wrong language based on _ja)
docs: xhtml: use UTF-8 encoding (<?xml version="1.0"?>) docs: xhtml: use UTF-8 encoding (<?xml version="1.0"?>)
io: wrapped streams are closed: simplify code
document SET SEARCH_PATH, BEGIN, EXECUTE, $ parameters
Complete Javadocs for Messages and add to docs
write tests using the PostgreSQL JDBC driver write tests using the PostgreSQL JDBC driver
JDK 1.6: Desktop.isDesktopSupported, browse(URI uri) SYSDATE sollte CURRENT_TIMESTAMP
support Trunc(Sysdate),...
public static String chr(int code) {
return String.valueOf((char) code);
}
public static Object nvl(Object value, Object ifNull) {
return (value != null) ? value : ifNull;
}
public static Object nvl2(Object value, Object notNull, Object ifNull) {
return (value != null) ? notNull : ifNull;
}
public static Timestamp sysdate() {
return new Timestamp(System.currentTimeMillis());
}
public static String to_char(Object what, String format) {
throw new Error("not yet"); // @todo check format
}
public static Date to_date(Object what, String format) {
throw new Error("not yet"); // @todo check format
}
public static Number to_number(String str) {
return new Double(str);
}
public static java.sql.Date trunc(Timestamp tsp) {
return new java.sql.Date(tsp.getTime());
}
public static Object trunc(Object what, String format) {
System.out.println("*** trunc ***");
if (what == null)
return null;
else if (what instanceof Date) {
System.out.println("*** date-format = " + format);
return Timestamp.valueOf("1963-03-27 12:34:56.0");
} else if (what instanceof Number) {
System.out.println("*** number-format = " + format);
return new Double(123.456D);
} else
throw new ClassCastException("number or date expected");
}
*/ */
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论