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

--no commit message

--no commit message
上级 920ce7b4
......@@ -94,12 +94,12 @@ This database supports the transaction isolation level 'serializable', in which
reads and phantom reads are prohibited.
<ul>
<li><b>Dirty Reads</b><br>
<li><b>Dirty Reads</b><br />
Means a connection can read uncommitted changes made by another connection.
<li><b>Non-Repeatable Reads</b><br>
<li><b>Non-Repeatable Reads</b><br />
A connection reads a row, another connection changes a row and commits,
and the first connection re-reads the same row and gets the new result.
<li><b>Phantom Reads</b><br>
<li><b>Phantom Reads</b><br />
A connection reads a set of rows using a condition, another connection
inserts a row that falls in this condition and commits, then the first connection
re-reads using the same condition and gets the new row.
......@@ -129,6 +129,7 @@ for each connection.
<br /><a name="clustering"></a>
<h2>Clustering / High Availability</h2>
<p>
This database supports a simple clustering / high availability mechanism. The architecture is:
two database servers run on two different computers, and on both computers is a copy of the
same database. If both servers run, each database operation is executed on both computers.
......@@ -139,8 +140,9 @@ Clustering can only be used in the server mode (the embedded mode does not suppo
It is possible to restore the cluster without stopping the server, however it is critical that no other
application is changing the data in the first database while the second database is restored, so
restoring the cluster is currently a manual process.
<p>
</p><p>
To initialize the cluster, use the following steps:
</p>
<ul>
<li>Create a database
<li>Use the CreateCluster tool to copy the database to another location and initialize the clustering.
......@@ -289,7 +291,7 @@ where you can create new or modify existing data sources.
When you create a new H2 ODBC data source, a dialog window will appear
and ask for the database settings:
<p>
<img src="odbcDataSource.png" alt="ODBC Configuration">
<img src="odbcDataSource.png" alt="ODBC Configuration"/>
<h3>Log Option</h3>
The driver is able to log operations to a file.
......@@ -639,7 +641,7 @@ Here is a small program to estimate the proability of having two identical UUIDs
after generating a number of values:
<pre>
double x = Math.pow(2, 122);
for(int i=35; i<62; i++) {
for(int i=35; i&lt;62; i++) {
double n = Math.pow(2, i);
double p = 1 - Math.exp(-(n*n)/(2*x));
String ps = String.valueOf(1+p).substring(1);
......
......@@ -137,9 +137,8 @@ Features
<table><tr>
<th>Feature</th>
<th>H2</th>
<th>HSQLDB</th>
<th>Derby</th>
<th>Daffodil</th>
<th>HSQLDB</th>
<th>MySQL</th>
<th>PostgreSQL</th>
</tr><tr>
......@@ -147,39 +146,34 @@ Features
<td class="compareY">Yes</td>
<td class="compareY">Yes</td>
<td class="compareY">Yes</td>
<td class="compareN">No</td>
<td class="compareN">No</td>
</tr><tr>
<td>Pure Java</td>
<td class="compareY">Yes</td>
<td class="compareY">Yes</td>
<td class="compareY">Yes</td>
<td class="compareN">No</td>
<td class="compareN">No</td>
</tr><tr>
<td>Performance (Embedded)</td>
<td class="compareY">Fast</td>
<td class="compareY">Fast</td>
<td class="compareN">Slow</td>
<td class="compareN">Slow</td>
<td class="compareY">Fast</td>
<td class="compareN">N/A</td>
<td class="compareN">N/A</td>
</tr><tr>
<td>Performance (Server)</td>
<td class="compareY">Fast</td>
<td class="compareY">Fast</td>
<td class="compareN">Slow</td>
<td class="compareN">Slow</td>
<td class="compareN">Slow</td>
<td class="compareN">Slow</td>
</tr><tr>
<td>Transaction Isolation</td>
<td class="compareY">Yes</td>
<td class="compareN">No</td>
<td class="compareY">Yes</td>
<td class="compareY">Yes</td>
<td class="compareN">No</td>
<td class="compareY">Yes</td>
<td class="compareY">Yes</td>
</tr><tr>
<td>Cost Based Optimizer</td>
<td class="compareY">Yes</td>
<td class="compareN">No</td>
<td class="compareY">Yes</td>
<td class="compareY">Yes</td>
<td class="compareN">No</td>
<td class="compareY">Yes</td>
<td class="compareY">Yes</td>
</tr><tr>
......@@ -187,13 +181,11 @@ Features
<td class="compareY">Yes</td>
<td class="compareN">No</td>
<td class="compareN">No</td>
<td class="compareN">No</td>
<td class="compareY">Yes</td>
<td class="compareY">Yes</td>
</tr><tr>
<td>Encrypted Database</td>
<td class="compareY">Yes</td>
<td class="compareN">No</td>
<td class="compareY">Yes</td>
<td class="compareN">No</td>
<td class="compareN">No</td>
......@@ -201,22 +193,26 @@ Features
</tr><tr>
<td>Files per Database</td>
<td class="compareY">Few</td>
<td class="compareY">Few</td>
<td class="compareN">Many</td>
<td class="compareY">Few</td>
<td class="compareN">Many</td>
<td class="compareN">Many</td>
</tr><tr>
<td>Footprint (jar/dll size)</td>
<td class="compareY">~ 1 MB</td>
<td class="compareY">~ 600 KB</td>
<td class="compareY">~ 2 MB</td>
<td class="compareY">~ 3 MB</td>
<td class="compareN">~ 4 MB</td>
<td class="compareN">~ 6 MB</td>
<td>~ 1 MB</td>
<td>~ 2 MB</td>
<td>~ 600 KB</td>
<td>~ 4 MB</td>
<td>~ 6 MB</td>
</tr>
</table>
<h3>DaffodilDb and One$Db</h3>
It looks like the development of this database has stopped. The last release was February 2006.
<h3>McKoi</h3>
It looks like the development of this database has stopped. The last release was August 2004
<br /><a name="products_work_with"></a>
<h2>Products that Work with H2</h2>
<table>
......@@ -1125,8 +1121,8 @@ public static ResultSet getMatrix(Integer id) throws SQLException {
if(id == null) {
return rs;
}
for(int x = 0; x < id.intValue(); x++) {
for(int y = 0; y < id.intValue(); y++) {
for(int x = 0; x &lt; id.intValue(); x++) {
for(int y = 0; y &lt; id.intValue(); y++) {
rs.addRow(new Object[] { new Integer(x), new Integer(y) });
}
}
......
......@@ -13,8 +13,8 @@ Initial Developer: H2 Group
<link rel="alternate" type="application/rss+xml" title="H2 Newsfeed" href="http://www.h2database.com/html/newsfeed-rss.xml" />
</head>
<frameset cols="180,*" rows="*" frameborder="2" framespacing="4" border="4" onLoad="loadFrameset()">
<frame frameborder="0" marginheight=0 marginwidth=0 src="search.html" name="menu">
<frame frameborder="0" marginheight=0 marginwidth=0 src="main.html" name="main">
<frame frameborder="0" marginheight="0" marginwidth="0" src="search.html" name="menu">
<frame frameborder="0" marginheight="0" marginwidth="0" src="main.html" name="main">
</frameset>
<noframes>
<body>
......
......@@ -34,6 +34,19 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch.
<h3>Version 1.0 (Current)</h3>
<h3>Version 1.0 / TODO</h3><ul>
<li>Can now parse timestamps with timezone information (Z or +/-hh:mm) and dates before year 1.
However dates before year 1 are not formatted correctly (this is a Java problem).
<li>When stopping the TCP server from an application and immediately afterwards staring it again
using a different TCP password, an exception was thrown sometimes.
<li>Now PreparedStatement.setBigDecimal(..) can only be called with an object
of type java.math.BigDecimal. Derived classes are not allowed any more. Many thanks to
Maciej Wegorkiewicz for finding this problem.
<li>It was possible to manipulate values in the byte array after calling PreparedStatement.setBytes, and this
could lead to problems if the same byte array was used again. Now the byte array is copied if required.
<li>Date, time and timestamp objects were cloned in cases where it was not required. Fixed.
</ul>
<h3>Version 1.0 / 2007-01-02</h3><ul>
<li>It was possible to drop the sequence of a temporary tables with DROP ALL OBJECTS, resulting in a null pointer exception afterwards.
<li>Prepard statements with non-constant functions such as CURRENT_TIMESTAMP() did not get re-evaluated if the result of the function changed. Fixed.
......@@ -802,7 +815,7 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch.
only the necessary parameters / operators are evaluated.
<li>
Bugfix for CASEWHEN: data type of return value was not evaluated, and this was a problem
when using prepared statements like this: WHERE CASEWHEN(ID<10, A, B)=?
when using prepared statements like this: WHERE CASEWHEN(ID &lt; 10, A, B)=?
<li>
New function DATABASE_PATH to retrieve the path and file name of a database.
<li>
......
......@@ -18,7 +18,7 @@ Initial Developer: H2 Group
</div>
<form name="searchForm" action="submit" onsubmit="return goFirst();">
<table width=100% class="search">
<table width="100%" class="search">
<tr class="search">
<td class="search" colspan="2">
<b>Search:</b>
......
......@@ -10,8 +10,8 @@ Initial Developer: H2 Group
<link rel="stylesheet" type="text/css" href="stylesheet.css">
</head>
<frameset cols="175,*" rows="*" frameborder="2" framespacing="4" border="4" >
<frame frameborder="0" marginheight=0 marginwidth=0 src="classes.html" name="classes">
<frame frameborder="0" marginheight=0 marginwidth=0 src="overview.html" name="javadoc">
<frame frameborder="0" marginheight="0" marginwidth="0" src="classes.html" name="classes">
<frame frameborder="0" marginheight="0" marginwidth="0" src="overview.html" name="javadoc">
</frameset>
<noframes>
<body>
......
......@@ -1772,7 +1772,7 @@ public class Parser {
if("X".equals(name) && currentTokenType == VALUE && currentValue.getType() == Value.STRING) {
read();
byte[] buffer = ByteUtils.convertStringToBytes(currentValue.getString());
r = ValueExpression.get(ValueBytes.get(buffer));
r = ValueExpression.get(ValueBytes.getNoCopy(buffer));
} else if(readIf(".")) {
return readTermObjectDot(name);
} else if (readIf("(")) {
......@@ -1803,7 +1803,7 @@ public class Parser {
} else if("TIMESTAMP".equals(name) && currentTokenType == VALUE && currentValue.getType() == Value.STRING) {
String timestamp = currentValue.getString();
read();
return ValueExpression.get(ValueTimestamp.get(ValueTimestamp.parseTimestamp(timestamp)));
return ValueExpression.get(ValueTimestamp.getNoCopy(ValueTimestamp.parseTimestamp(timestamp)));
} else if("CASE".equals(name)) {
if(isToken("WHEN")) {
return readWhen(null);
......
......@@ -14,7 +14,6 @@ import org.h2.expression.Expression;
import org.h2.message.Message;
import org.h2.message.Trace;
import org.h2.table.Table;
import org.h2.util.TypeConverter;
import org.h2.value.DataType;
import org.h2.value.Value;
import org.h2.value.ValueNull;
......@@ -152,7 +151,7 @@ public class FunctionAlias extends DbObject {
if(columnList) {
// if the column list is requested, the parameters may be null
// need to set to default value otherwise the function can't be called at all
o = TypeConverter.getDefaultForPrimitiveType(paramClass);
o = DataType.getDefaultForPrimitiveType(paramClass);
} else {
// NULL value for a java primitive: return NULL
return ValueNull.INSTANCE;
......@@ -160,7 +159,7 @@ public class FunctionAlias extends DbObject {
}
} else {
if(!paramClass.isAssignableFrom(o.getClass()) && !paramClass.isPrimitive()) {
o = TypeConverter.convertTo(session, session.createConnection(false), v, paramClass);
o = DataType.convertTo(session, session.createConnection(false), v, paramClass);
}
}
params[p] = o;
......
......@@ -488,22 +488,22 @@ public class Function extends Expression implements FunctionCall {
return ValueDouble.get(((d < 0) ? Math.ceil(g) : Math.floor(g)) / f);
}
case SECURE_RAND:
return ValueBytes.get(RandomUtils.getSecureBytes(v0.getInt()));
return ValueBytes.getNoCopy(RandomUtils.getSecureBytes(v0.getInt()));
case HASH:
return ValueBytes.get(getHash(v0.getString(), v1.getBytes(), v2.getInt()));
return ValueBytes.getNoCopy(getHash(v0.getString(), v1.getBytesNoCopy(), v2.getInt()));
case ENCRYPT:
return ValueBytes.get(encrypt(v0.getString(), v1.getBytes(), v2.getBytes()));
return ValueBytes.getNoCopy(encrypt(v0.getString(), v1.getBytesNoCopy(), v2.getBytesNoCopy()));
case DECRYPT:
return ValueBytes.get(decrypt(v0.getString(), v1.getBytes(), v2.getBytes()));
return ValueBytes.getNoCopy(decrypt(v0.getString(), v1.getBytesNoCopy(), v2.getBytesNoCopy()));
case COMPRESS: {
String algorithm = null;
if(v1 != null) {
algorithm = v1.getString();
}
return ValueBytes.get(CompressTool.getInstance().compress(v0.getBytes(), algorithm));
return ValueBytes.getNoCopy(CompressTool.getInstance().compress(v0.getBytesNoCopy(), algorithm));
}
case EXPAND:
return ValueBytes.get(CompressTool.getInstance().expand(v0.getBytes()));
return ValueBytes.getNoCopy(CompressTool.getInstance().expand(v0.getBytesNoCopy()));
case ZERO:
return ValueInt.get(0);
case RANDOM_UUID:
......@@ -614,9 +614,9 @@ public class Function extends Expression implements FunctionCall {
case STRINGDECODE:
return ValueString.get(StringUtils.javaDecode(v0.getString()));
case STRINGTOUTF8:
return ValueBytes.get(StringUtils.utf8Encode(v0.getString()));
return ValueBytes.getNoCopy(StringUtils.utf8Encode(v0.getString()));
case UTF8TOSTRING:
return ValueString.get(StringUtils.utf8Decode(v0.getBytes()));
return ValueString.get(StringUtils.utf8Decode(v0.getBytesNoCopy()));
case XMLATTR:
return ValueString.get(StringUtils.xmlAttr(v0.getString(), v1.getString()));
case XMLNODE: {
......@@ -634,25 +634,25 @@ public class Function extends Expression implements FunctionCall {
return ValueString.get(StringUtils.xmlText(v0.getString()));
// date
case DATEADD:
return ValueTimestamp.get(dateadd(v0.getString(), v1.getInt(), v2.getTimestamp()));
return ValueTimestamp.getNoCopy(dateadd(v0.getString(), v1.getInt(), v2.getTimestampNoCopy()));
case DATEDIFF:
return ValueLong.get(datediff(v0.getString(), v1.getTimestamp(), v2.getTimestamp()));
return ValueLong.get(datediff(v0.getString(), v1.getTimestampNoCopy(), v2.getTimestampNoCopy()));
case DAYNAME:
return ValueString.get(FORMAT_DAYNAME.format(v0.getDate()));
return ValueString.get(FORMAT_DAYNAME.format(v0.getDateNoCopy()));
case DAYOFMONTH:
return ValueInt.get(getDatePart(v0.getTimestamp(), Calendar.DAY_OF_MONTH));
return ValueInt.get(getDatePart(v0.getTimestampNoCopy(), Calendar.DAY_OF_MONTH));
case DAYOFWEEK:
return ValueInt.get(getDatePart(v0.getTimestamp(), Calendar.DAY_OF_WEEK));
return ValueInt.get(getDatePart(v0.getTimestampNoCopy(), Calendar.DAY_OF_WEEK));
case DAYOFYEAR:
return ValueInt.get(getDatePart(v0.getTimestamp(), Calendar.DAY_OF_YEAR));
return ValueInt.get(getDatePart(v0.getTimestampNoCopy(), Calendar.DAY_OF_YEAR));
case HOUR:
return ValueInt.get(getDatePart(v0.getTimestamp(), Calendar.HOUR_OF_DAY));
return ValueInt.get(getDatePart(v0.getTimestampNoCopy(), Calendar.HOUR_OF_DAY));
case MINUTE:
return ValueInt.get(getDatePart(v0.getTimestamp(), Calendar.MINUTE));
return ValueInt.get(getDatePart(v0.getTimestampNoCopy(), Calendar.MINUTE));
case MONTH:
return ValueInt.get(getDatePart(v0.getTimestamp(), Calendar.MONTH));
return ValueInt.get(getDatePart(v0.getTimestampNoCopy(), Calendar.MONTH));
case MONTHNAME:
return ValueString.get(FORMAT_MONTHNAME.format(v0.getDate()));
return ValueString.get(FORMAT_MONTHNAME.format(v0.getDateNoCopy()));
case QUARTER:
return ValueInt.get((getDatePart(v0.getTimestamp(), Calendar.MONTH) - 1) / 3 + 1);
case SECOND:
......@@ -663,13 +663,15 @@ public class Function extends Expression implements FunctionCall {
return ValueInt.get(getDatePart(v0.getTimestamp(), Calendar.YEAR));
case CURDATE:
case CURRENT_DATE:
// need to normalize
return ValueDate.get(new Date(System.currentTimeMillis()));
case CURTIME:
case CURRENT_TIME:
// need to normalize
return ValueTime.get(new Time(System.currentTimeMillis()));
case NOW:
case CURRENT_TIMESTAMP: {
ValueTimestamp vt = ValueTimestamp.get(new Timestamp(System.currentTimeMillis()));
ValueTimestamp vt = ValueTimestamp.getNoCopy(new Timestamp(System.currentTimeMillis()));
if(v0 != null) {
vt = (ValueTimestamp)vt.convertScale(Mode.getCurrentMode().convertOnlyToSmallerScale, v0.getInt());
}
......@@ -696,7 +698,7 @@ public class Function extends Expression implements FunctionCall {
Value v3 = args.length <= 3 ? null : args[3].getValue(session);
String tz = v3 == null ? null : v3 == ValueNull.INSTANCE ? null : v3.getString();
java.util.Date d = StringUtils.parseDateTime(v0.getString(), v1.getString(), locale, tz);
return ValueTimestamp.get(new Timestamp(d.getTime()));
return ValueTimestamp.getNoCopy(new Timestamp(d.getTime()));
}
// system
case DATABASE:
......
......@@ -8,14 +8,14 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import java.sql.*;
import java.sql.Clob;
import java.sql.SQLException;
import org.h2.engine.Constants;
import org.h2.engine.SessionInterface;
import org.h2.message.Message;
import org.h2.message.TraceObject;
import org.h2.util.IOUtils;
import org.h2.util.TypeConverter;
import org.h2.value.Value;
/**
......@@ -93,7 +93,7 @@ public class JdbcClob extends TraceObject implements Clob
debugCodeCall("getAsciiStream");
checkClosed();
String s = value.getString();
return s == null ? null : TypeConverter.getInputStream(s);
return IOUtils.getInputStream(s);
} catch(Throwable e) {
throw logAndConvert(e);
}
......
......@@ -26,8 +26,9 @@ import org.h2.expression.ParameterInterface;
import org.h2.message.Message;
import org.h2.message.TraceObject;
import org.h2.result.ResultInterface;
import org.h2.util.DateTimeUtils;
import org.h2.util.IOUtils;
import org.h2.util.ObjectArray;
import org.h2.util.TypeConverter;
import org.h2.value.DataType;
import org.h2.value.Value;
import org.h2.value.ValueBoolean;
......@@ -585,7 +586,7 @@ public class JdbcPreparedStatement extends JdbcStatement implements PreparedStat
if (x == null) {
setParameter(parameterIndex, ValueNull.INSTANCE);
} else {
setParameter(parameterIndex, TypeConverter.convertDateToUniversal(x, calendar));
setParameter(parameterIndex, DateTimeUtils.convertDateToUniversal(x, calendar));
}
} catch(Throwable e) {
throw logAndConvert(e);
......@@ -608,7 +609,7 @@ public class JdbcPreparedStatement extends JdbcStatement implements PreparedStat
if (x == null) {
setParameter(parameterIndex, ValueNull.INSTANCE);
} else {
setParameter(parameterIndex, TypeConverter.convertTimeToUniversal(x, calendar));
setParameter(parameterIndex, DateTimeUtils.convertTimeToUniversal(x, calendar));
}
} catch(Throwable e) {
throw logAndConvert(e);
......@@ -631,7 +632,7 @@ public class JdbcPreparedStatement extends JdbcStatement implements PreparedStat
if (x == null) {
setParameter(parameterIndex, ValueNull.INSTANCE);
} else {
setParameter(parameterIndex, TypeConverter.convertTimestampToUniversal(x, calendar));
setParameter(parameterIndex, DateTimeUtils.convertTimestampToUniversal(x, calendar));
}
} catch(Throwable e) {
throw logAndConvert(e);
......@@ -877,7 +878,7 @@ public class JdbcPreparedStatement extends JdbcStatement implements PreparedStat
debugCode("setAsciiStream("+parameterIndex+", x, "+length+");");
}
checkClosed();
Value v = conn.createClob(TypeConverter.getAsciiReader(x), length);
Value v = conn.createClob(IOUtils.getAsciiReader(x), length);
setParameter(parameterIndex, v);
} catch(Throwable e) {
throw logAndConvert(e);
......
......@@ -16,10 +16,12 @@ import org.h2.engine.Constants;
import org.h2.engine.SessionInterface;
import org.h2.message.*;
import org.h2.result.ResultInterface;
import org.h2.result.UpdatableRow;
import org.h2.util.ByteUtils;
import org.h2.util.DateTimeUtils;
import org.h2.util.IOUtils;
import org.h2.util.MathUtils;
import org.h2.util.StringUtils;
import org.h2.util.TypeConverter;
import org.h2.util.UpdatableRow;
import org.h2.value.DataType;
import org.h2.value.Value;
import org.h2.value.ValueBoolean;
......@@ -401,7 +403,7 @@ public class JdbcResultSet extends TraceObject implements ResultSet {
Value v = get(columnIndex);
if(Constants.SERIALIZE_JAVA_OBJECTS) {
if (v.getType() == Value.JAVA_OBJECT) {
return TypeConverter.deserialize(v.getBytes());
return ByteUtils.deserialize(v.getBytesNoCopy());
}
}
return v.getObject();
......@@ -423,7 +425,7 @@ public class JdbcResultSet extends TraceObject implements ResultSet {
Value v = get(columnName);
if(Constants.SERIALIZE_JAVA_OBJECTS) {
if (v.getType() == Value.JAVA_OBJECT) {
return TypeConverter.deserialize(v.getBytes());
return ByteUtils.deserialize(v.getBytesNoCopy());
}
}
return v.getObject();
......@@ -776,7 +778,7 @@ public class JdbcResultSet extends TraceObject implements ResultSet {
debugCode("getDate(" + columnIndex + ", calendar)");
}
Date x = get(columnIndex).getDate();
return TypeConverter.convertDateToCalendar(x, calendar);
return DateTimeUtils.convertDateToCalendar(x, calendar);
} catch(Throwable e) {
throw logAndConvert(e);
}
......@@ -796,7 +798,7 @@ public class JdbcResultSet extends TraceObject implements ResultSet {
debugCode("getDate(" + StringUtils.quoteJavaString(columnName) + ", calendar)");
}
Date x = get(columnName).getDate();
return TypeConverter.convertDateToCalendar(x, calendar);
return DateTimeUtils.convertDateToCalendar(x, calendar);
} catch(Throwable e) {
throw logAndConvert(e);
}
......@@ -816,7 +818,7 @@ public class JdbcResultSet extends TraceObject implements ResultSet {
debugCode("getTime(" + columnIndex + ", calendar)");
}
Time x = get(columnIndex).getTime();
return TypeConverter.convertTimeToCalendar(x, calendar);
return DateTimeUtils.convertTimeToCalendar(x, calendar);
} catch(Throwable e) {
throw logAndConvert(e);
}
......@@ -836,7 +838,7 @@ public class JdbcResultSet extends TraceObject implements ResultSet {
debugCode("getTime(" + StringUtils.quoteJavaString(columnName) + ", calendar)");
}
Time x = get(columnName).getTime();
return TypeConverter.convertTimeToCalendar(x, calendar);
return DateTimeUtils.convertTimeToCalendar(x, calendar);
} catch(Throwable e) {
throw logAndConvert(e);
}
......@@ -856,7 +858,7 @@ public class JdbcResultSet extends TraceObject implements ResultSet {
debugCode("getTimestamp(" + columnIndex + ", calendar)");
}
Timestamp x = get(columnIndex).getTimestamp();
return TypeConverter.convertTimestampToCalendar(x, calendar);
return DateTimeUtils.convertTimestampToCalendar(x, calendar);
} catch(Throwable e) {
throw logAndConvert(e);
}
......@@ -876,7 +878,7 @@ public class JdbcResultSet extends TraceObject implements ResultSet {
debugCode("getTimestamp(" + StringUtils.quoteJavaString(columnName) + ", calendar)");
}
Timestamp x = get(columnName).getTimestamp();
return TypeConverter.convertTimestampToCalendar(x, calendar);
return DateTimeUtils.convertTimestampToCalendar(x, calendar);
} catch(Throwable e) {
throw logAndConvert(e);
}
......@@ -1063,7 +1065,7 @@ public class JdbcResultSet extends TraceObject implements ResultSet {
debugCodeCall("getAsciiStream", columnIndex);
String s = get(columnIndex).getString();
// TODO ascii stream: convert the reader to a ascii stream
return s == null ? null : TypeConverter.getInputStream(s);
return s == null ? null : IOUtils.getInputStream(s);
} catch(Throwable e) {
throw logAndConvert(e);
}
......@@ -1081,7 +1083,7 @@ public class JdbcResultSet extends TraceObject implements ResultSet {
debugCodeCall("getAsciiStream", columnName);
String s = get(columnName).getString();
// TODO ascii stream: convert the reader to a ascii stream
return s == null ? null : TypeConverter.getInputStream(s);
return IOUtils.getInputStream(s);
} catch(Throwable e) {
throw logAndConvert(e);
}
......@@ -1685,7 +1687,7 @@ public class JdbcResultSet extends TraceObject implements ResultSet {
debugCode("updateAsciiStream("+columnIndex+", x, "+length+");");
}
checkClosed();
Value v = conn.createClob(TypeConverter.getAsciiReader(x), length);
Value v = conn.createClob(IOUtils.getAsciiReader(x), length);
update(columnIndex, v);
} catch(Throwable e) {
throw logAndConvert(e);
......@@ -1730,7 +1732,7 @@ public class JdbcResultSet extends TraceObject implements ResultSet {
debugCode("updateAsciiStream("+quote(columnName)+", x, "+length+");");
}
checkClosed();
Value v = conn.createClob(TypeConverter.getAsciiReader(x), length);
Value v = conn.createClob(IOUtils.getAsciiReader(x), length);
update(columnName, v);
} catch(Throwable e) {
throw logAndConvert(e);
......
......@@ -338,6 +338,7 @@ public class Message {
public static final int OPERATION_NOT_SUPPORTED_WITH_VIEWS_2 = 90122;
public static final int CANT_MIX_INDEXED_AND_UNINDEXED_PARAMS = 90123;
public static final int FILE_NOT_FOUND_1 = 90124;
public static final int INVALID_CLASS_2 = 90125;
public static SQLException addSQL(SQLException e, String sql) {
if(e.getMessage().indexOf("SQL")>=0) {
......
......@@ -145,6 +145,7 @@
90122=Operation not supported for table {0} when there are views on the table: {1}
90123=Cannot mix indexed and non-indexed parameters
90124=File not found: {0}
90125=Invalid class, expected {0} but got {1}
HY000=General error: {0}
HY004=Unknown data type: {0}
......
......@@ -2,7 +2,7 @@
* Copyright 2004-2006 H2 Group. Licensed under the H2 License, Version 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.util;
package org.h2.result;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
......@@ -12,7 +12,8 @@ import java.sql.SQLException;
import org.h2.engine.SessionInterface;
import org.h2.message.Message;
import org.h2.result.ResultInterface;
import org.h2.util.ObjectArray;
import org.h2.util.StringUtils;
import org.h2.value.DataType;
import org.h2.value.Value;
import org.h2.value.ValueNull;
......
......@@ -68,7 +68,7 @@ public class TcpServer implements Service {
}
}
public static void stopServer(int port, String password, int shutdownMode) {
public static synchronized void stopServer(int port, String password, int shutdownMode) {
TcpServer server = (TcpServer) servers.get("" + port);
if(server == null) {
return;
......@@ -125,9 +125,11 @@ public class TcpServer implements Service {
}
public void start() throws SQLException {
synchronized(TcpServer.class) {
initManagementDb();
serverSocket = NetUtils.createServerSocket(port, ssl);
}
}
public void listen() {
String threadName = Thread.currentThread().getName();
......@@ -146,8 +148,10 @@ public class TcpServer implements Service {
TraceSystem.traceThrowable(e);
}
}
synchronized(TcpServer.class) {
stopManagementDb();
}
}
public boolean isRunning() {
if(serverSocket == null) {
......
......@@ -30,15 +30,41 @@ Initial Developer: H2 Group
${text.adminAllow}
</h3>
<p>
<input type="radio" name="allowOthers" value="false" <c:if test="allowOthers=='false'">checked</c:if>> ${text.adminLocal}<br>
<input type="radio" name="allowOthers" value="true" <c:if test="allowOthers=='true'">checked</c:if>> ${text.adminOthers}<br>
<c:if test="allowOthers=='false'">
<input type="radio" name="allowOthers" value="false" checked="checked">
</c:if>
<c:if test="allowOthers=='true'">
<input type="radio" name="allowOthers" value="false">
</c:if>
${text.adminLocal}<br>
<c:if test="allowOthers=='true'">
<input type="radio" name="allowOthers" value="true" checked="checked">
</c:if>
<c:if test="allowOthers=='false'">
<input type="radio" name="allowOthers" value="true">
</c:if>
${text.adminOthers}<br>
</p>
<h3>
${text.adminConnection}
</h3>
<p>
<input type="radio" name="ssl" value="false" <c:if test="ssl=='false'">checked</c:if>> ${text.adminHttp}<br>
<input type="radio" name="ssl" value="true" <c:if test="ssl=='true'">checked</c:if>> ${text.adminHttps}<br>
<c:if test="ssl=='false'">
<input type="radio" name="ssl" value="false" checked="checked">
</c:if>
<c:if test="ssl=='true'">
<input type="radio" name="ssl" value="false">
</c:if>
${text.adminHttp}<br>
<c:if test="ssl=='true'">
<input type="radio" name="ssl" value="true" checked="checked">
</c:if>
<c:if test="ssl=='false'">
<input type="radio" name="ssl" value="true">
</c:if>
${text.adminHttps}<br>
</p>
<h3>
Port number
......
......@@ -19,12 +19,12 @@ Initial Developer: H2 Group
</head>
<body style="margin: 20px">
<form name="adminLogin" method="post" action="/admin.do?jsessionid=${sessionId}">
<table class="login" cellspacing=0 cellpadding=0>
<table class="login" cellspacing="0" cellpadding="0">
<tr class="login">
<th class="login">${text.adminLogin}</th>
<th class="login"></th>
</tr>
<tr><td class="login" colspan=2></td></tr>
<tr><td class="login" colspan="2"></td></tr>
<tr class="login">
<td class="login">${text.a.password}:</td>
<td class="login"><input type="password" name="password" value="" style="width:200px;"></td>
......
......@@ -8,7 +8,7 @@ Initial Developer: H2 Group
<title>${text.a.title}</title>
<link rel="stylesheet" type="text/css" href="stylesheet.css">
</head>
<body margin=10>
<body margin="10">
<p class="error">
${error}
</p>
......
......@@ -10,12 +10,12 @@ Initial Developer: H2 Group
<link rel="stylesheet" type="text/css" href="stylesheet.css">
</head>
<frameset cols="*" rows="36,*" frameborder="2" framespacing="4" border="4" >
<frame noresize frameborder="0" marginheight=0 marginwidth=0 src="header.jsp?jsessionid=${sessionId}" name="header" scrolling="no">
<frame noresize="noresize" frameborder="0" marginheight="0" marginwidth="0" src="header.jsp?jsessionid=${sessionId}" name="header" scrolling="no">
<frameset cols="200,*" rows="*" frameborder="2" framespacing="4" border="4" >
<frame frameborder="0" marginheight=0 marginwidth=0 src="tables.do?jsessionid=${sessionId}" name="h2menu">
<frame frameborder="0" marginheight="0" marginwidth="0" src="tables.do?jsessionid=${sessionId}" name="h2menu">
<frameset rows="180,*" frameborder="2" framespacing="4" border="4" >
<frame frameborder="0" marginheight=0 marginwidth=0 src="query.jsp?jsessionid=${sessionId}" name="h2query" scrolling="no">
<frame frameborder="0" marginheight=0 marginwidth=0 src="resultHelp.jsp?jsessionid=${sessionId}" name="h2result">
<frame frameborder="0" marginheight="0" marginwidth="0" src="query.jsp?jsessionid=${sessionId}" name="h2query" scrolling="no">
<frame frameborder="0" marginheight="0" marginwidth="0" src="help.jsp?jsessionid=${sessionId}" name="h2result">
</frameset>
</frameset>
</frameset>
......
......@@ -11,7 +11,7 @@ Initial Developer: H2 Group
</head>
<body bgcolor="#FF00FF" class="toolbar">
<form name="header" method="post" action="/header.jsp?jsessionid=${sessionId}">
<table class="toolbar" cellspacing=0 cellpadding=0><tr class="toolbar"><td class="toolbar"
<table class="toolbar" cellspacing="0" cellpadding="0"><tr class="toolbar"><td class="toolbar"
><a href="logout.do?jsessionid=${sessionId}" target="_top"
><img src="icon_disconnect.gif"
onmouseover = "this.className ='icon_hover'"
......@@ -24,7 +24,7 @@ Initial Developer: H2 Group
onmouseout = "this.className ='icon'"
class="icon" alt="${text.toolbar.refresh}" title="${text.toolbar.refresh}" border="1"/></a
><img src="icon_line.gif" class="iconLine" alt=""
/></td><td class="toolbar"><input type="checkbox" name="autocommit" value="autocommit" ${autocommit}
/></td><td class="toolbar"><input type="checkbox" name="autocommit" value="autocommit"
onclick="javascript:if(document.header.autocommit.checked)
top.frames['h2result'].document.location='query.do?jsessionid=${sessionId}&amp;sql=@AUTOCOMMIT+TRUE';
else
......@@ -45,8 +45,12 @@ Initial Developer: H2 Group
/></td><td class="toolbar">&nbsp;${text.toolbar.maxRows}:&nbsp;</td><td class="toolbar"
><select name="rowcount" size="1"
onchange="javascript:top.frames['h2result'].document.location='query.do?jsessionid=${sessionId}&amp;sql=@SET+MAXROWS+'+header.rowcount.value;"
><option value="0">${text.toolbar.all}</option><option value="10000">10000</option><option selected value="1000">1000</option><option value="100"
>100</option><option value="10">10</option></select
><option value="0">${text.toolbar.all}</option>
<option value="10000">10000</option>
<option selected="selected" value="1000">1000</option>
<option value="100">100</option>
<option value="10">10</option>
</select
>&nbsp;</td><td class="toolbar"><a href="javascript:top.frames['h2query'].document.forms['h2query'].submit();"
><img src="icon_run.gif"
onmouseover = "this.className ='icon_hover'"
......@@ -67,17 +71,22 @@ Initial Developer: H2 Group
/></td><td class="toolbar">${text.toolbar.autocomplete}&nbsp;<select name="autocomplete" size="1"
onchange="javascript:top.frames['h2query'].setAutocomplete(this.value)"
><option value="0">${text.toolbar.autocomplete.off}</option>
<option selected value="1">${text.toolbar.autocomplete.normal}</option>
<option selected="selected" value="1">${text.toolbar.autocomplete.normal}</option>
<option value="2">${text.toolbar.autocomplete.full}</option>
</select
></td
><td class="toolbar"
><a href="resultHelp.jsp?jsessionid=${sessionId}" target="h2result"
><a href="help.jsp?jsessionid=${sessionId}" target="h2result"
><img src="icon_help.gif"
onmouseover = "this.className ='icon_hover'"
onmouseout = "this.className ='icon'"
class="icon" alt="${text.a.help}" title="${text.a.help}" border="1"/></a
></td></tr></table>
</form>
<script type="text/javascript">
<!--
document.header.autocommit.checked = '${autocommit}' != '';
//-->
</script>
</body>
</html>
......@@ -3,11 +3,81 @@
Copyright 2004-2006 H2 Group. Licensed under the H2 License, Version 1.0 (http://h2database.com/html/license.html).
Initial Developer: H2 Group
-->
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<title>${text.a.title}</title>
<link rel="stylesheet" type="text/css" href="stylesheet.css">
</head>
<body style="margin: 10px;">
<%@ include file="help.txt" %>
</body>
<body class="result">
<div id="output">
<script type="text/javascript">
<!--
function set(s) {
top.h2query.document.h2query.sql.value = s;
}
//-->
</script>
<h3>${text.helpImportantCommands}</h3>
<table>
<tr><th>${text.helpIcon}</th><th>${text.helpAction}</th></tr>
<tr>
<td style="padding:0px"><img src="icon_help.gif" alt="${text.a.help}"></td>
<td style="vertical-align: middle;">
${text.helpDisplayThis}
</td>
</tr>
<tr>
<td style="padding:0px"><img src="icon_history.gif" alt="${text.toolbar.history}"></td>
<td style="vertical-align: middle;">
${text.helpCommandHistory}
</td>
</tr>
<tr>
<td style="padding:0px"><img src="icon_run.gif" alt="${text.toolbar.run}"></td>
<td style="vertical-align: middle;">
${text.helpExecuteCurrent}
</td>
</tr>
<tr>
<td style="padding:0px"><img src="icon_disconnect.gif" alt="${text.toolbar.disconnect}"></td>
<td style="vertical-align: middle;">
${text.helpDisconnect}
</td>
</tr>
</table>
<h3>${text.helpSampleSQL}</h3>
<table><tr><th>${text.helpOperations}</th><th>${text.helpStatements}</th></tr>
<tr><td><a href="javascript:set('DROP TABLE IF EXISTS TEST;\rCREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR(255));\rINSERT INTO TEST VALUES(1, \'Hello\');\rINSERT INTO TEST VALUES(2, \'World\');\rSELECT * FROM TEST ORDER BY ID;\rUPDATE TEST SET NAME=\'Hi\' WHERE ID=1;\rDELETE FROM TEST WHERE ID=2;');">
${text.helpDropTable}<br>
${text.helpCreateTable}<br>
&nbsp;&nbsp;${text.helpWithColumnsIdName}<br>
${text.helpAddRow}<br>
${text.helpAddAnotherRow}<br>
${text.helpQuery}<br>
${text.helpUpdate}<br>
${text.helpDeleteRow}
</a></td><td>
DROP TABLE IF EXISTS TEST;<br>
CREATE TABLE TEST(ID INT PRIMARY KEY,<br>
&nbsp;&nbsp; NAME VARCHAR(255));<br>
INSERT INTO TEST VALUES(1, 'Hello');<br>
INSERT INTO TEST VALUES(2, 'World');<br>
SELECT * FROM TEST ORDER BY ID;<br>
UPDATE TEST SET NAME='Hi' WHERE ID=1;<br>
DELETE FROM TEST WHERE ID=2;
</td></tr>
</table>
<h3>${text.helpAddDrivers}</h3>
${text.helpAddDriversText}
<p>
${text.helpAddDriversOnlyJava}
</div>
<table id="h2auto" class="autocomp"><tbody></tbody></table>
</body></html>
\ No newline at end of file
<script type="text/javascript">
<!--
function set(s) {
top.h2query.document.h2query.sql.value = s;
}
//-->
</script>
<h3>${text.helpImportantCommands}</h3>
<table>
<tr><th>${text.helpIcon}</th><th>${text.helpAction}</th></tr>
<tr>
<td style="padding:0px"><img src="icon_help.gif" alt="${text.a.help}"></td>
<td style="vertical-align: middle;">
${text.helpDisplayThis}
</td>
</tr>
<tr>
<td style="padding:0px"><img src="icon_history.gif" alt="${text.toolbar.history}"></td>
<td style="vertical-align: middle;">
${text.helpCommandHistory}
</td>
</tr>
<tr>
<td style="padding:0px"><img src="icon_run.gif" alt="${text.toolbar.run}"></td>
<td style="vertical-align: middle;">
${text.helpExecuteCurrent}
</td>
</tr>
<tr>
<td style="padding:0px"><img src="icon_disconnect.gif" alt="${text.toolbar.disconnect}"></td>
<td style="vertical-align: middle;">
${text.helpDisconnect}
</td>
</tr>
</table>
<h3>${text.helpSampleSQL}</h3>
<table><tr><th>${text.helpOperations}</th><th>${text.helpStatements}</th></tr>
<tr><td><a href="javascript:set('DROP TABLE IF EXISTS TEST;\rCREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR(255));\rINSERT INTO TEST VALUES(1, \'Hello\');\rINSERT INTO TEST VALUES(2, \'World\');\rSELECT * FROM TEST ORDER BY ID;\rUPDATE TEST SET NAME=\'Hi\' WHERE ID=1;\rDELETE FROM TEST WHERE ID=2;');">
${text.helpDropTable}<br>
${text.helpCreateTable}<br>
&nbsp;&nbsp;${text.helpWithColumnsIdName}<br>
${text.helpAddRow}<br>
${text.helpAddAnotherRow}<br>
${text.helpQuery}<br>
${text.helpUpdate}<br>
${text.helpDeleteRow}
</a></td><td>
DROP TABLE IF EXISTS TEST;<br>
CREATE TABLE TEST(ID INT PRIMARY KEY,<br>
&nbsp;&nbsp; NAME VARCHAR(255));<br>
INSERT INTO TEST VALUES(1, 'Hello');<br>
INSERT INTO TEST VALUES(2, 'World');<br>
SELECT * FROM TEST ORDER BY ID;<br>
UPDATE TEST SET NAME='Hi' WHERE ID=1;<br>
DELETE FROM TEST WHERE ID=2;
</td></tr>
</table>
<h3>${text.helpAddDrivers}</h3>
${text.helpAddDriversText}
<p>
${text.helpAddDriversOnlyJava}
......@@ -23,12 +23,12 @@ Initial Developer: H2 Group
&nbsp;&nbsp; <a href="admin.do?jsessionid=${sessionId}">${text.login.goAdmin}</a>
&nbsp;&nbsp; <a href="help.jsp?jsessionid=${sessionId}">${text.a.help}</a>
</p>
<table class="login" cellspacing=0 cellpadding=0>
<table class="login" cellspacing="0" cellpadding="0">
<tr class="login">
<th class="login">${text.login.login}</th>
<th class="login"></th>
</tr>
<tr><td class="login" colspan=2></td></tr>
<tr><td class="login" colspan="2"></td></tr>
<tr class="login">
<td class="login">${text.login.savedSetting}:</td>
<td class="login">
......@@ -49,7 +49,7 @@ Initial Developer: H2 Group
</td>
</tr>
<tr class="login">
<td class="login" colspan=2>
<td class="login" colspan="2">
<hr>
</td>
</tr>
......
......@@ -17,7 +17,7 @@ Initial Developer: H2 Group
</script>
</head>
<body margin=10>
<body margin="10">
<h1>Welcome to H2</h1>
<h2><a href="index.jsp">Connect</a></h2>
Login to a database.
......
......@@ -9,6 +9,7 @@ Initial Developer: H2 Group
<title>${text.a.title}</title>
<link rel="stylesheet" type="text/css" href="stylesheet.css" />
<script type="text/javascript">
//<!--
var agent=navigator.userAgent.toLowerCase();
var is_opera = agent.indexOf("opera") >= 0;
......@@ -74,7 +75,7 @@ function help() {
if(pos > 0) {
var s = input.value.substring(0, pos).toUpperCase();
var e = pos-1;
for(; e>=0; e--) {
for(; e>=0; e-=1) {
var ch = s.charAt(e);
if(ch != '_' && (ch < '0' || ch > '9') && (ch < 'A' || ch > 'Z')) {
break;
......@@ -179,7 +180,7 @@ function showAutocomplete() {
showAutocompleteWait=5;
setTimeout('showAutocompleteNow()', 100);
} else {
showAutocompleteWait--;
showAutocompleteWait-=1;
}
}
......@@ -418,6 +419,7 @@ function processAsyncResponse() {
}
}
//-->
</script>
</head>
<body onresize="sizeTextArea();" onload="sizeTextArea();" style="margin: 0px; padding: 0px;">
......
......@@ -16,6 +16,6 @@ Initial Developer: H2 Group
${result}
</div>
<table id="h2auto" name="h2auto" class="autocomp"><tbody></tbody></table>
<table id="h2auto" class="autocomp"><tbody></tbody></table>
</body></html>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<!--
Copyright 2004-2006 H2 Group. Licensed under the H2 License, Version 1.0 (http://h2database.com/html/license.html).
Initial Developer: H2 Group
-->
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<title>${text.a.title}</title>
<link rel="stylesheet" type="text/css" href="stylesheet.css">
</head>
<body class="result">
<div id="output">
<%@ include file="help.txt" %>
</div>
<table id="h2auto" name="h2auto" class="autocomp"><tbody></tbody></table>
</body></html>
......@@ -173,20 +173,20 @@ public abstract class DataPage {
writeString(s);
break;
case Value.TIME:
writeLong(v.getTime().getTime());
writeLong(v.getTimeNoCopy().getTime());
break;
case Value.DATE:
writeLong(v.getDate().getTime());
writeLong(v.getDateNoCopy().getTime());
break;
case Value.TIMESTAMP: {
Timestamp ts = v.getTimestamp();
Timestamp ts = v.getTimestampNoCopy();
writeLong(ts.getTime());
writeInt(ts.getNanos());
break;
}
case Value.JAVA_OBJECT:
case Value.BYTES: {
byte[] b = v.getBytes();
byte[] b = v.getBytesNoCopy();
writeInt(b.length);
write(b, 0, b.length);
break;
......@@ -265,7 +265,7 @@ public abstract class DataPage {
return 1 + getStringLen(v.getString());
case Value.JAVA_OBJECT:
case Value.BYTES: {
int len = v.getBytes().length;
int len = v.getBytesNoCopy().length;
return 1 + getIntLen() + len;
}
case Value.UUID: {
......@@ -273,11 +273,11 @@ public abstract class DataPage {
return 1 + getLongLen(uuid.getHigh()) + getLongLen(uuid.getLow());
}
case Value.TIME:
return 1 + getLongLen(v.getTime().getTime());
return 1 + getLongLen(v.getTimeNoCopy().getTime());
case Value.DATE:
return 1 + getLongLen(v.getDate().getTime());
return 1 + getLongLen(v.getDateNoCopy().getTime());
case Value.TIMESTAMP: {
Timestamp ts = v.getTimestamp();
Timestamp ts = v.getTimestampNoCopy();
return 1 + getLongLen(ts.getTime()) + getIntLen();
}
case Value.BLOB:
......@@ -326,25 +326,26 @@ public abstract class DataPage {
case Value.DECIMAL:
return ValueDecimal.get(new BigDecimal(readString()));
case Value.DATE:
return ValueDate.get(new Date(readLong()));
return ValueDate.getNoCopy(new Date(readLong()));
case Value.TIME:
// need to normalize the year, month and day
return ValueTime.get(new Time(readLong()));
case Value.TIMESTAMP: {
Timestamp ts = new Timestamp(readLong());
ts.setNanos(readInt());
return ValueTimestamp.get(ts);
return ValueTimestamp.getNoCopy(ts);
}
case Value.JAVA_OBJECT: {
int len = readInt();
byte[] b = new byte[len];
read(b, 0, len);
return ValueJavaObject.get(b);
return ValueJavaObject.getNoCopy(b);
}
case Value.BYTES: {
int len = readInt();
byte[] b = new byte[len];
read(b, 0, len);
return ValueBytes.get(b);
return ValueBytes.getNoCopy(b);
}
case Value.UUID:
return ValueUuid.get(readLong(), readLong());
......
......@@ -98,6 +98,8 @@ public class DiskFile implements CacheWriter {
used = new BitField();
deleted = new BitField();
pageOwners = new IntArray();
// init pageOwners
setBlockCount(fileBlockCount);
redoBuffer = new ObjectArray();
}
......
......@@ -160,11 +160,12 @@ public class Column {
if(dt.decimal) {
value = ValueInt.get(0).convertTo(type);
} else if(dt.type==Value.TIMESTAMP) {
value = ValueTimestamp.get(new Timestamp(System.currentTimeMillis()));
value = ValueTimestamp.getNoCopy(new Timestamp(System.currentTimeMillis()));
} else if(dt.type==Value.TIME) {
// need to normalize
value = ValueTime.get(Time.valueOf("0:0:0"));
} else if(dt.type==Value.DATE) {
value = ValueTimestamp.get(new Timestamp(System.currentTimeMillis())).convertTo(dt.type);
value = ValueTimestamp.getNoCopy(new Timestamp(System.currentTimeMillis())).convertTo(dt.type);
} else {
value = ValueString.get("").convertTo(type);
}
......
......@@ -4,6 +4,10 @@
*/
package org.h2.util;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.sql.SQLException;
import org.h2.message.Message;
......@@ -148,4 +152,36 @@ public class ByteUtils {
return target;
}
public static byte[] cloneByteArray(byte[] b) {
int len = b.length;
if(len == 0) {
return b;
}
byte[] copy = new byte[len];
System.arraycopy(b, 0, copy, 0, len);
return copy;
}
public static byte[] serialize(Object obj) throws SQLException {
try {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream os = new ObjectOutputStream(out);
os.writeObject(obj);
return out.toByteArray();
} catch(Throwable e) {
throw Message.getSQLException(Message.SERIALIZATION_FAILED, null, e);
}
}
public static Object deserialize(byte[] data) throws SQLException {
try {
ByteArrayInputStream in = new ByteArrayInputStream(data);
ObjectInputStream is = new ObjectInputStream(in);
Object obj = is.readObject();
return obj;
} catch(Throwable e) {
throw Message.getSQLException(Message.DESERIALIZATION_FAILED, null, e);
}
}
}
......@@ -9,8 +9,8 @@ import java.io.InputStream;
import java.io.Reader;
/**
* The InputStreamReader may read some more bytes than required.
* If this is a problem, use this class
* The regular InputStreamReader may read some more bytes than required.
* If this is a problem, use this class.
*/
public class ExactUTF8InputStreamReader extends Reader {
......
......@@ -4,13 +4,21 @@
*/
package org.h2.util;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.sql.SQLException;
import org.h2.engine.Constants;
import org.h2.message.Message;
public class IOUtils {
......@@ -193,4 +201,37 @@ public class IOUtils {
}
return off < 0 ? -1 : off;
}
public static Reader getReader(InputStream in) throws SQLException {
try {
// InputStreamReader may read some more bytes
return in == null ? null : new InputStreamReader(in, Constants.UTF8);
} catch (UnsupportedEncodingException e) {
throw Message.convert(e);
}
}
public static InputStream getInputStream(String s) throws SQLException {
if(s == null) {
return null;
}
return new ByteArrayInputStream(StringUtils.utf8Encode(s));
}
public static InputStream getInputStream(Reader x) throws SQLException {
return x == null ? null : new ReaderInputStream(x);
}
public static Reader getReader(String s) {
return s == null ? null : new StringReader(s);
}
public static Reader getAsciiReader(InputStream x) throws SQLException {
try {
return x == null ? null : new InputStreamReader(x, "US-ASCII");
} catch (UnsupportedEncodingException e) {
throw Message.convert(e);
}
}
}
/*
* Copyright 2004-2006 H2 Group. Licensed under the H2 License, Version 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.util;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Reader;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.sql.Clob;
import java.sql.Date;
import java.sql.SQLException;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.Calendar;
import org.h2.engine.Constants;
import org.h2.engine.SessionInterface;
import org.h2.jdbc.JdbcBlob;
import org.h2.jdbc.JdbcClob;
import org.h2.jdbc.JdbcConnection;
import org.h2.jdbc.JdbcSQLException;
import org.h2.message.Message;
import org.h2.value.Value;
import org.h2.value.ValueDate;
import org.h2.value.ValueTime;
import org.h2.value.ValueTimestamp;
/**
* @author Thomas
*/
public class TypeConverter {
public static Object getDefaultForPrimitiveType(Class clazz) {
if(clazz == Boolean.TYPE) {
return Boolean.FALSE;
} else if(clazz == Byte.TYPE) {
return new Byte((byte)0);
} else if(clazz == Character.TYPE) {
return new Character((char)0);
} else if(clazz == Short.TYPE) {
return new Short((short)0);
} else if(clazz == Integer.TYPE) {
return new Integer(0);
} else if(clazz == Long.TYPE) {
return new Long(0);
} else if(clazz == Float.TYPE) {
return new Float(0);
} else if(clazz == Double.TYPE) {
return new Double(0);
} else {
throw Message.getInternalError("primitive="+ clazz.toString());
}
}
public static byte[] serialize(Object obj) throws SQLException {
try {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream os = new ObjectOutputStream(out);
os.writeObject(obj);
return out.toByteArray();
} catch(Throwable e) {
throw Message.getSQLException(Message.SERIALIZATION_FAILED, null, e);
}
}
public static Object deserialize(byte[] data) throws SQLException {
try {
ByteArrayInputStream in = new ByteArrayInputStream(data);
ObjectInputStream is = new ObjectInputStream(in);
Object obj = is.readObject();
return obj;
} catch(Throwable e) {
throw Message.getSQLException(Message.DESERIALIZATION_FAILED, null, e);
}
}
public static Reader getReader(InputStream in) throws SQLException {
try {
// InputStreamReader may read some more bytes
return in == null ? null : new InputStreamReader(in, Constants.UTF8);
} catch (UnsupportedEncodingException e) {
throw Message.convert(e);
}
}
public static InputStream getInputStream(String s) throws SQLException {
return new ByteArrayInputStream(StringUtils.utf8Encode(s));
}
public static InputStream getInputStream(Reader x) throws SQLException {
return x == null ? null : new ReaderInputStream(x);
}
public static Reader getReader(String s) {
return new StringReader(s);
}
public static Date convertDateToCalendar(Date x, Calendar calendar) throws SQLException {
return x == null ? x : new Date(getLocalTime(x, calendar));
}
public static Time convertTimeToCalendar(Time x, Calendar calendar) throws SQLException {
return x == null ? x : new Time(getLocalTime(x, calendar));
}
public static Timestamp convertTimestampToCalendar(Timestamp x, Calendar calendar) throws SQLException {
if(x != null) {
Timestamp y = new Timestamp(getLocalTime(x, calendar));
// fix the nano seconds
y.setNanos(x.getNanos());
x = y;
}
return x;
}
public static Value convertDateToUniversal(Date x, Calendar source) throws SQLException {
return ValueDate.get(new Date(TypeConverter.getUniversalTime(source, x)));
}
public static Value convertTimeToUniversal(Time x, Calendar source) throws SQLException {
return ValueTime.get(new Time(TypeConverter.getUniversalTime(source, x)));
}
public static Value convertTimestampToUniversal(Timestamp x, Calendar source) throws SQLException {
Timestamp y = new Timestamp(TypeConverter.getUniversalTime(source, x));
// fix the nano seconds
y.setNanos(x.getNanos());
return ValueTimestamp.get(y);
}
private static long getUniversalTime(Calendar source, java.util.Date x) throws SQLException {
if(source == null) {
throw Message.getInvalidValueException("calendar", null);
}
source = (Calendar)source.clone();
Calendar universal=Calendar.getInstance();
source.setTime(x);
convertTime(source, universal);
return universal.getTime().getTime();
}
private static long getLocalTime(java.util.Date x, Calendar target) throws SQLException {
if(target == null) {
throw Message.getInvalidValueException("calendar", null);
}
target = (Calendar)target.clone();
Calendar local=Calendar.getInstance();
local.setTime(x);
convertTime(local, target);
return target.getTime().getTime();
}
private static void convertTime(Calendar from, Calendar to) {
to.set(Calendar.YEAR, from.get(Calendar.YEAR));
to.set(Calendar.MONTH, from.get(Calendar.MONTH));
to.set(Calendar.DAY_OF_MONTH, from.get(Calendar.DAY_OF_MONTH));
to.set(Calendar.HOUR_OF_DAY, from.get(Calendar.HOUR_OF_DAY));
to.set(Calendar.MINUTE, from.get(Calendar.MINUTE));
to.set(Calendar.SECOND, from.get(Calendar.SECOND));
to.set(Calendar.MILLISECOND, from.get(Calendar.MILLISECOND));
}
public static Reader getAsciiReader(InputStream x) throws SQLException {
try {
return x == null ? null : new InputStreamReader(x, "US-ASCII");
} catch (UnsupportedEncodingException e) {
throw Message.convert(e);
}
}
public static Object convertTo(SessionInterface session, JdbcConnection conn, Value v, Class paramClass) throws JdbcSQLException {
if(paramClass == java.sql.Blob.class) {
return new JdbcBlob(session, conn, v, 0);
} else if(paramClass == Clob.class) {
return new JdbcClob(session, conn, v, 0);
} else {
throw Message.getUnsupportedException();
}
}
}
......@@ -7,21 +7,25 @@ package org.h2.value;
import java.io.InputStream;
import java.io.Reader;
import java.math.BigDecimal;
import java.sql.Clob;
import java.sql.Date;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Time;
import java.sql.Timestamp;
import java.sql.Types;
import java.util.Calendar;
import java.util.HashMap;
import org.h2.engine.Constants;
import org.h2.engine.SessionInterface;
import org.h2.jdbc.JdbcBlob;
import org.h2.jdbc.JdbcClob;
import org.h2.jdbc.JdbcConnection;
import org.h2.jdbc.JdbcSQLException;
import org.h2.message.Message;
import org.h2.util.ByteUtils;
import org.h2.util.ObjectArray;
import org.h2.util.StringUtils;
import org.h2.util.TypeConverter;
public class DataType {
private static ObjectArray types = new ObjectArray();
......@@ -256,7 +260,7 @@ public class DataType {
}
case Value.BYTES: {
byte[] buff = rs.getBytes(columnIndex);
v = buff==null ? (Value)ValueNull.INSTANCE : ValueBytes.get(buff);
v = buff==null ? (Value)ValueNull.INSTANCE : ValueBytes.getNoCopy(buff);
break;
}
case Value.UUID: {
......@@ -345,7 +349,7 @@ public class DataType {
}
case Value.JAVA_OBJECT: {
byte[] buff = rs.getBytes(columnIndex);
v = buff==null ? (Value)ValueNull.INSTANCE : ValueJavaObject.get(buff);
v = buff==null ? (Value)ValueNull.INSTANCE : ValueJavaObject.getNoCopy(buff);
break;
}
default:
......@@ -519,7 +523,7 @@ public class DataType {
if(type == Value.JAVA_OBJECT) {
// serialize JAVA_OBJECTs, even if the type is known
if(Constants.SERIALIZE_JAVA_OBJECTS) {
return ValueJavaObject.get(TypeConverter.serialize(x));
return ValueJavaObject.getNoCopy(ByteUtils.serialize(x));
}
}
if(x instanceof String) {
......@@ -572,7 +576,7 @@ public class DataType {
return ValueArray.get(v);
} else {
if(Constants.SERIALIZE_JAVA_OBJECTS) {
return ValueJavaObject.get(TypeConverter.serialize(x));
return ValueJavaObject.getNoCopy(ByteUtils.serialize(x));
} else {
throw Message.getSQLException(Message.UNKNOWN_DATA_TYPE_1, x.getClass().getName());
}
......@@ -604,79 +608,35 @@ public class DataType {
return false;
}
public static java.util.Date parseDateTime(String s, int type, int errorCode) throws SQLException {
if (s == null) {
return null;
}
try {
int timeStart;
if(type == Value.TIME) {
timeStart = 0;
} else {
timeStart = s.indexOf(' ') + 1;
if(timeStart <= 0) {
// PostgreSQL compatibility
timeStart = s.indexOf('T') + 1;
}
}
int year = 1970, month = 1, day = 1;
if (type != Value.TIME) {
int s1 = s.indexOf('-');
int s2 = s.indexOf('-', s1 + 1);
if(s1 <= 0 || s2 <= s1) {
throw Message.getSQLException(errorCode, s);
}
year = Integer.parseInt(s.substring(0, s1));
month = Integer.parseInt(s.substring(s1 + 1, s2));
int end = timeStart == 0 ? s.length() : timeStart - 1;
day = Integer.parseInt(s.substring(s2 + 1, end));
}
int hour = 0, minute = 0, second = 0, nano = 0;
if (type != Value.DATE) {
int s1 = s.indexOf(':', timeStart);
int s2 = s.indexOf(':', s1 + 1);
int s3 = s.indexOf('.', s2 + 1);
if(s1 <= 0 || s2 <= s1) {
throw Message.getSQLException(errorCode, s);
}
hour = Integer.parseInt(s.substring(timeStart, s1));
minute = Integer.parseInt(s.substring(s1 + 1, s2));
if (s3 < 0) {
second = Integer.parseInt(s.substring(s2 + 1));
public static Object getDefaultForPrimitiveType(Class clazz) {
if(clazz == Boolean.TYPE) {
return Boolean.FALSE;
} else if(clazz == Byte.TYPE) {
return new Byte((byte)0);
} else if(clazz == Character.TYPE) {
return new Character((char)0);
} else if(clazz == Short.TYPE) {
return new Short((short)0);
} else if(clazz == Integer.TYPE) {
return new Integer(0);
} else if(clazz == Long.TYPE) {
return new Long(0);
} else if(clazz == Float.TYPE) {
return new Float(0);
} else if(clazz == Double.TYPE) {
return new Double(0);
} else {
second = Integer.parseInt(s.substring(s2 + 1, s3));
String n = (s + "000000000").substring(s3 + 1, s3 + 10);
nano = Integer.parseInt(n);
}
}
Calendar c = Calendar.getInstance();
c.setLenient(false);
long time;
c.set(Calendar.YEAR, year);
c.set(Calendar.MONTH, month - 1); // january is 0
c.set(Calendar.DAY_OF_MONTH, day);
c.set(Calendar.HOUR_OF_DAY, hour);
c.set(Calendar.MINUTE, minute);
c.set(Calendar.SECOND, second);
if(type != Value.TIMESTAMP) {
c.set(Calendar.MILLISECOND, nano / 1000000);
}
time = c.getTime().getTime();
switch(type) {
case Value.DATE:
return new java.sql.Date(time);
case Value.TIME:
return new java.sql.Time(time);
case Value.TIMESTAMP: {
Timestamp ts = new Timestamp(time);
ts.setNanos(nano);
return ts;
throw Message.getInternalError("primitive="+ clazz.toString());
}
default:
throw Message.getInternalError("type:"+type);
}
} catch(IllegalArgumentException e) {
throw Message.getSQLException(errorCode, s);
public static Object convertTo(SessionInterface session, JdbcConnection conn, Value v, Class paramClass) throws JdbcSQLException {
if(paramClass == java.sql.Blob.class) {
return new JdbcBlob(session, conn, v, 0);
} else if(paramClass == Clob.class) {
return new JdbcClob(session, conn, v, 0);
} else {
throw Message.getUnsupportedException();
}
}
......
......@@ -195,7 +195,7 @@ public class Transfer {
break;
case Value.BYTES:
case Value.JAVA_OBJECT:
writeBytes(v.getBytes());
writeBytes(v.getBytesNoCopy());
break;
case Value.UUID: {
ValueUuid uuid = (ValueUuid) v;
......@@ -210,13 +210,13 @@ public class Transfer {
writeByte(v.getByte());
break;
case Value.TIME:
writeLong(v.getTime().getTime());
writeLong(v.getTimeNoCopy().getTime());
break;
case Value.DATE:
writeLong(v.getDate().getTime());
writeLong(v.getDateNoCopy().getTime());
break;
case Value.TIMESTAMP: {
Timestamp ts = v.getTimestamp();
Timestamp ts = v.getTimestampNoCopy();
writeLong(ts.getTime());
writeInt(ts.getNanos());
break;
......@@ -316,23 +316,23 @@ public class Transfer {
case Value.NULL:
return ValueNull.INSTANCE;
case Value.BYTES:
return ValueBytes.get(readBytes());
return ValueBytes.getNoCopy(readBytes());
case Value.UUID:
return ValueUuid.get(readLong(), readLong());
case Value.JAVA_OBJECT:
return ValueJavaObject.get(readBytes());
return ValueJavaObject.getNoCopy(readBytes());
case Value.BOOLEAN:
return ValueBoolean.get(readBoolean());
case Value.BYTE:
return ValueByte.get(readByte());
case Value.DATE:
return ValueDate.get(new Date(readLong()));
return ValueDate.getNoCopy(new Date(readLong()));
case Value.TIME:
return ValueTime.get(new Time(readLong()));
return ValueTime.getNoCopy(new Time(readLong()));
case Value.TIMESTAMP: {
Timestamp ts = new Timestamp(readLong());
ts.setNanos(readInt());
return ValueTimestamp.get(ts);
return ValueTimestamp.getNoCopy(ts);
}
case Value.DECIMAL:
return ValueDecimal.get(new BigDecimal(readString()));
......
......@@ -22,9 +22,9 @@ import org.h2.message.Message;
import org.h2.store.DataHandler;
import org.h2.tools.SimpleResultSet;
import org.h2.util.ByteUtils;
import org.h2.util.IOUtils;
import org.h2.util.MathUtils;
import org.h2.util.StringUtils;
import org.h2.util.TypeConverter;
/**
* @author Thomas
......@@ -95,18 +95,34 @@ public abstract class Value {
return ((ValueDate) convertTo(Value.DATE)).getDate();
}
public Date getDateNoCopy() throws SQLException {
return ((ValueDate) convertTo(Value.DATE)).getDateNoCopy();
}
public Time getTime() throws SQLException {
return ((ValueTime) convertTo(Value.TIME)).getTime();
}
public Time getTimeNoCopy() throws SQLException {
return ((ValueTime) convertTo(Value.TIME)).getTimeNoCopy();
}
public Timestamp getTimestamp() throws SQLException {
return ((ValueTimestamp) convertTo(Value.TIMESTAMP)).getTimestamp();
}
public Timestamp getTimestampNoCopy() throws SQLException {
return ((ValueTimestamp) convertTo(Value.TIMESTAMP)).getTimestampNoCopy();
}
public byte[] getBytes() throws SQLException {
return ((ValueBytes) convertTo(Value.BYTES)).getBytes();
}
public byte[] getBytesNoCopy() throws SQLException {
return ((ValueBytes) convertTo(Value.BYTES)).getBytesNoCopy();
}
public byte getByte() throws SQLException {
return ((ValueByte) convertTo(Value.BYTE)).getByte();
}
......@@ -136,11 +152,11 @@ public abstract class Value {
}
public InputStream getInputStream() throws SQLException {
return new ByteArrayInputStream(getBytes());
return new ByteArrayInputStream(getBytesNoCopy());
}
public Reader getReader() throws SQLException {
return TypeConverter.getReader(getString());
return IOUtils.getReader(getString());
}
public Value add(Value v) throws SQLException {
......@@ -369,27 +385,29 @@ public abstract class Value {
case DATE: {
switch (getType()) {
case TIME:
return ValueDate.get(new Date(getTime().getTime()));
return ValueDate.get(new Date(getTimeNoCopy().getTime()));
case TIMESTAMP:
return ValueDate.get(new Date(getTimestamp().getTime()));
return ValueDate.get(new Date(getTimestampNoCopy().getTime()));
}
break;
}
case TIME: {
switch (getType()) {
case DATE:
return ValueTime.get(new Time(getDate().getTime()));
// need to normalize the year, month and day
return ValueTime.get(new Time(getDateNoCopy().getTime()));
case TIMESTAMP:
return ValueTime.get(new Time(getTimestamp().getTime()));
// need to normalize the year, month and day
return ValueTime.get(new Time(getTimestampNoCopy().getTime()));
}
break;
}
case TIMESTAMP: {
switch (getType()) {
case TIME:
return ValueTimestamp.get(new Timestamp(getTime().getTime()));
return ValueTimestamp.getNoCopy(new Timestamp(getTimeNoCopy().getTime()));
case DATE:
return ValueTimestamp.get(new Timestamp(getDate().getTime()));
return ValueTimestamp.getNoCopy(new Timestamp(getDateNoCopy().getTime()));
}
break;
}
......@@ -398,7 +416,7 @@ public abstract class Value {
case JAVA_OBJECT:
case BLOB:
case UUID:
return ValueBytes.get(getBytes());
return ValueBytes.getNoCopy(getBytesNoCopy());
}
break;
}
......@@ -406,21 +424,21 @@ public abstract class Value {
switch(getType()) {
case BYTES:
case BLOB:
return ValueBytes.get(getBytes());
return ValueBytes.getNoCopy(getBytesNoCopy());
}
break;
}
case BLOB: {
switch(getType()) {
case BYTES:
return ValueLob.createSmallLob(Value.BLOB, getBytes());
return ValueLob.createSmallLob(Value.BLOB, getBytesNoCopy());
}
break;
}
case UUID: {
switch(getType()) {
case BYTES:
return ValueUuid.get(getBytes());
return ValueUuid.get(getBytesNoCopy());
}
}
}
......@@ -457,9 +475,9 @@ public abstract class Value {
case TIMESTAMP:
return ValueTimestamp.get(ValueTimestamp.parseTimestamp(s.trim()));
case BYTES:
return ValueBytes.get(ByteUtils.convertStringToBytes(s.trim()));
return ValueBytes.getNoCopy(ByteUtils.convertStringToBytes(s.trim()));
case JAVA_OBJECT:
return ValueJavaObject.get(ByteUtils.convertStringToBytes(s.trim()));
return ValueJavaObject.getNoCopy(ByteUtils.convertStringToBytes(s.trim()));
case STRING:
return ValueString.get(s);
case STRING_IGNORECASE:
......
......@@ -5,6 +5,7 @@
package org.h2.value;
import org.h2.engine.Constants;
import org.h2.util.ByteUtils;
/**
* @author Thomas
......@@ -18,6 +19,11 @@ public class ValueBytes extends ValueBytesBase {
}
public static ValueBytes get(byte[] b) {
b = ByteUtils.cloneByteArray(b);
return getNoCopy(b);
}
public static ValueBytes getNoCopy(byte[] b) {
if (b.length == 0) {
return EMPTY;
}
......
......@@ -22,10 +22,14 @@ abstract class ValueBytesBase extends Value {
return "X'" + getString() + "'";
}
public byte[] getBytes() {
public byte[] getBytesNoCopy() {
return value;
}
public byte[] getBytes() {
return ByteUtils.cloneByteArray(value);
}
protected int compareSecure(Value v, CompareMode mode) {
byte[] v2 = ((ValueBytesBase) v).value;
return ByteUtils.compareNotNull(value, v2);
......
......@@ -7,9 +7,9 @@ package org.h2.value;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Calendar;
import org.h2.message.Message;
import org.h2.util.DateTimeUtils;
/**
* @author Thomas
......@@ -20,20 +20,11 @@ public class ValueDate extends Value {
private Date value;
private ValueDate(Date value) {
// this class is mutable - must copy the object
Calendar cal = Calendar.getInstance();
cal.setTime(value);
// TODO gcj: required so that the millis are calculated?
cal.get(Calendar.YEAR);
cal.set(Calendar.MILLISECOND, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.HOUR_OF_DAY, 0);
this.value = new Date(cal.getTime().getTime());
this.value = value;
}
public static Date parseDate(String s) throws SQLException {
return (Date) DataType.parseDateTime(s, Value.DATE, Message.DATE_CONSTANT_1);
return (Date) DateTimeUtils.parseDateTime(s, Value.DATE, Message.DATE_CONSTANT_1);
}
public Date getDate() {
......@@ -41,6 +32,10 @@ public class ValueDate extends Value {
return (Date)value.clone();
}
public Date getDateNoCopy() {
return value;
}
public String getSQL() {
return "DATE '" + getString() + "'";
}
......@@ -77,6 +72,11 @@ public class ValueDate extends Value {
}
public static ValueDate get(Date date) {
date = DateTimeUtils.cloneAndNormalizeDate(date);
return getNoCopy(date);
}
public static ValueDate getNoCopy(Date date) {
return (ValueDate) Value.cache(new ValueDate(date));
}
......
......@@ -32,6 +32,9 @@ public class ValueDecimal extends Value {
private ValueDecimal(BigDecimal value) {
if (value == null) {
throw new NullPointerException();
} else if(!value.getClass().equals(BigDecimal.class)) {
SQLException e = Message.getSQLException(Message.INVALID_CLASS_2, new String[]{BigDecimal.class.getName(), value.getClass().getName()}, null);
throw Message.convertToInternal(e);
}
this.value = value;
}
......@@ -158,7 +161,7 @@ public class ValueDecimal extends Value {
} else if (DEC_ONE.equals(dec)) {
return ONE;
}
// TODO value optimization: find a way to find out size of bigdecimal,
// TODO value optimization: find a way to read size of bigdecimal,
// check max cache size
return (ValueDecimal) Value.cache(new ValueDecimal(dec));
}
......
......@@ -14,7 +14,7 @@ public class ValueJavaObject extends ValueBytesBase {
super(v);
}
public static ValueJavaObject get(byte[] b) {
public static ValueJavaObject getNoCopy(byte[] b) {
if (b.length == 0) {
return EMPTY;
}
......
......@@ -24,7 +24,6 @@ import org.h2.util.FileUtils;
import org.h2.util.IOUtils;
import org.h2.util.RandomUtils;
import org.h2.util.StringUtils;
import org.h2.util.TypeConverter;
/**
* @author Thomas
......@@ -431,6 +430,11 @@ public class ValueLob extends Value {
}
public byte[] getBytes() throws SQLException {
byte[] data = getBytesNoCopy();
return ByteUtils.cloneByteArray(data);
}
public byte[] getBytesNoCopy() throws SQLException {
if (small != null) {
return small;
}
......@@ -457,7 +461,7 @@ public class ValueLob extends Value {
int c = getString().compareTo(v.getString());
return c == 0 ? 0 : (c < 0 ? -1 : 1);
} else {
byte[] v2 = v.getBytes();
byte[] v2 = v.getBytesNoCopy();
return ByteUtils.compareNotNull(getBytes(), v2);
}
}
......@@ -471,7 +475,7 @@ public class ValueLob extends Value {
}
public Reader getReader() throws SQLException {
return TypeConverter.getReader(getInputStream());
return IOUtils.getReader(getInputStream());
}
public InputStream getInputStream() throws SQLException {
......
......@@ -7,26 +7,20 @@ package org.h2.value;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Time;
import java.util.Calendar;
import org.h2.message.Message;
import org.h2.util.DateTimeUtils;
public class ValueTime extends Value {
public static final int PRECISION = 6;
private Time value;
private ValueTime(Time value) {
// this class is mutable - must copy the object
Calendar cal = Calendar.getInstance();
cal.setTime(value);
// TODO gcj: required so that the millis are calculated?
cal.get(Calendar.HOUR_OF_DAY);
cal.set(1970, 0, 1);
this.value = new Time(cal.getTime().getTime());
this.value = value;
}
public static Time parseTime(String s) throws SQLException {
return (Time) DataType.parseDateTime(s, Value.TIME, Message.TIME_CONSTANT_1);
return (Time) DateTimeUtils.parseDateTime(s, Value.TIME, Message.TIME_CONSTANT_1);
}
public Time getTime() {
......@@ -34,6 +28,10 @@ public class ValueTime extends Value {
return (Time)value.clone();
}
public Time getTimeNoCopy() {
return value;
}
public String getSQL() {
return "TIME '" + getString() + "'";
}
......@@ -68,8 +66,13 @@ public class ValueTime extends Value {
prep.setTime(parameterIndex, value);
}
public static ValueTime get(Time date) {
return (ValueTime) Value.cache(new ValueTime(date));
public static ValueTime get(Time time) {
time = DateTimeUtils.cloneAndNormalizeTime(time);
return getNoCopy(time);
}
public static ValueTime getNoCopy(Time time) {
return (ValueTime) Value.cache(new ValueTime(time));
}
// public String getJavaString() {
......
......@@ -10,6 +10,7 @@ import java.sql.SQLException;
import java.sql.Timestamp;
import org.h2.message.Message;
import org.h2.util.DateTimeUtils;
import org.h2.util.MathUtils;
public class ValueTimestamp extends Value {
......@@ -18,22 +19,23 @@ public class ValueTimestamp extends Value {
private Timestamp value;
private ValueTimestamp(Timestamp value) {
// this class is mutable - must copy the object
this.value = (Timestamp)value.clone();
this.value = value;
}
public Timestamp getTimestamp() {
// TODO performance: clone not always required
// this class is mutable - must copy the object
return (Timestamp)value.clone();
}
public Timestamp getTimestampNoCopy() {
return value;
}
public String getSQL() {
return "TIMESTAMP '" + getString() + "'";
}
public static Timestamp parseTimestamp(String s) throws SQLException {
return (Timestamp) DataType.parseDateTime(s, Value.TIMESTAMP, Message.TIMESTAMP_CONSTANT_1);
return (Timestamp) DateTimeUtils.parseDateTime(s, Value.TIMESTAMP, Message.TIMESTAMP_CONSTANT_1);
}
public int getType() {
......@@ -71,8 +73,13 @@ public class ValueTimestamp extends Value {
prep.setTimestamp(parameterIndex, value);
}
public static ValueTimestamp get(Timestamp date) {
return (ValueTimestamp) Value.cache(new ValueTimestamp(date));
public static ValueTimestamp get(Timestamp timestamp) {
timestamp = (Timestamp) timestamp.clone();
return getNoCopy(timestamp);
}
public static ValueTimestamp getNoCopy(Timestamp timestamp) {
return (ValueTimestamp) Value.cache(new ValueTimestamp(timestamp));
}
public Value convertScale(boolean onlyToSmallerScale, int targetScale) throws SQLException {
......@@ -96,7 +103,7 @@ public class ValueTimestamp extends Value {
}
Timestamp t2 = new Timestamp(t);
t2.setNanos(n2);
return ValueTimestamp.get(t2);
return ValueTimestamp.getNoCopy(t2);
}
// public String getJavaString() {
......
......@@ -87,6 +87,14 @@ java -Xmx512m -Xrunhprof:cpu=samples,depth=8 org.h2.tools.RunScript -url jdbc:h2
TestAll test = new TestAll();
test.printSystem();
// TODO check that xml is well formed, and html is more or less.
// PayPal donate - aaa.html/main.html
// maybe use system property for base directory (h2.baseDir)
// feature request: user defined aggregate functions
// auto-upgrade application:
// check if new version is available
// (option: digital signature)
......@@ -351,8 +359,8 @@ java -Xmx512m -Xrunhprof:cpu=samples,depth=8 org.h2.tools.RunScript -url jdbc:h2
beforeTest();
// db
new TestScript().runTest(this);
new TestScriptSimple().runTest(this);
new TestScript().runTest(this);
new TestAutoRecompile().runTest(this);
new TestBatchUpdates().runTest(this);
new TestBigDb().runTest(this);
......@@ -402,6 +410,7 @@ java -Xmx512m -Xrunhprof:cpu=samples,depth=8 org.h2.tools.RunScript -url jdbc:h2
new TestStatement().runTest(this);
new TestTransactionIsolation().runTest(this);
new TestUpdatableResultSet().runTest(this);
new TestZloty().runTest(this);
afterTest();
}
......
......@@ -132,7 +132,7 @@ public class TestTriggersConstraints extends TestBase implements Trigger {
}
}
public void init(Connection conn, String schemaName, String triggerName, String tableName) {
public void init(Connection conn, String schemaName, String triggerName, String tableName) throws SQLException {
this.triggerName = triggerName;
if(!"TEST".equals(tableName)) {
throw new Error("supposed to be TEST");
......
/*
* Copyright 2004-2006 H2 Group. Licensed under the H2 License, Version 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.test.jdbc;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.h2.test.TestBase;
public class TestZloty extends TestBase {
public void test() throws Exception {
testZloty();
testModifyBytes();
}
private static class ZlotyBigDecimal extends BigDecimal {
public ZlotyBigDecimal(String s) {
super(s);
}
private static final long serialVersionUID = -8004563653683501484L;
public int compareTo(BigDecimal bd) {
return -super.compareTo(bd);
}
}
private void testModifyBytes() throws Exception {
deleteDb("zloty");
Connection conn = getConnection("zloty");
conn.createStatement().execute("CREATE TABLE TEST(ID INT, DATA BINARY)");
PreparedStatement prep = conn.prepareStatement("INSERT INTO TEST VALUES(?, ?)");
byte[] shared = new byte[1];
prep.setInt(1, 0);
prep.setBytes(2, shared);
prep.execute();
shared[0] = 1;
prep.setInt(1, 1);
prep.setBytes(2, shared);
prep.execute();
ResultSet rs = conn.createStatement().executeQuery("SELECT * FROM TEST ORDER BY ID");
rs.next();
check(rs.getInt(1), 0);
check(rs.getBytes(2)[0], 0);
rs.next();
check(rs.getInt(1), 1);
check(rs.getBytes(2)[0], 1);
rs.getBytes(2)[0] = 2;
check(rs.getBytes(2)[0], 1);
checkFalse(rs.next());
conn.close();
}
/**
* H2 destroyer application ;->
* @author Maciej Wegorkiewicz
*/
private void testZloty() throws Exception {
deleteDb("zloty");
Connection conn = getConnection("zloty");
conn.createStatement().execute("CREATE TABLE TEST(ID INT, AMOUNT DECIMAL)");
PreparedStatement prep = conn.prepareStatement("INSERT INTO TEST VALUES(?, ?)");
prep.setInt(1, 1);
prep.setBigDecimal(2, new BigDecimal("10.0"));
prep.execute();
prep.setInt(1, 2);
try {
prep.setBigDecimal(2, new ZlotyBigDecimal("11.0"));
prep.execute();
error("unexpected success");
} catch(SQLException e) {
checkNotGeneralException(e);
}
prep.setInt(1, 3);
try {
BigDecimal crappyVal=new BigDecimal("12.100000") {
private static final long serialVersionUID = -7909023971521750844L;
public String toString() { return "12,100000 EURO"; }
};
prep.setBigDecimal(2, crappyVal);
prep.execute();
error("unexpected success");
} catch(SQLException e) {
checkNotGeneralException(e);
}
conn.close();
}
}
select date '+0011-01-01';
> 0011-01-01;
select date'-0010-01-01';
> 0011-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');
> -1;
select datediff('HOUR', timestamp '1234-05-06 10:00:00+01:00', '1234-05-06 10:00:00-02:00');
> 3;
create schema testschema;
create table testschema.test(id int);
create sequence testschema.testseq;
......
......@@ -11,17 +11,16 @@ import java.io.StringReader;
import org.h2.test.TestBase;
import org.h2.util.IOUtils;
import org.h2.util.TypeConverter;
public class TestReader extends TestBase {
public void test() throws Exception {
String s = "\u00ef\u00f6\u00fc";
StringReader r = new StringReader(s);
InputStream in = TypeConverter.getInputStream(r);
InputStream in = IOUtils.getInputStream(r);
byte[] buff = IOUtils.readBytesAndClose(in, 0);
InputStream in2 = new ByteArrayInputStream(buff);
Reader r2 = TypeConverter.getReader(in2);
Reader r2 = IOUtils.getReader(in2);
String s2 = IOUtils.readStringAndClose(r2, Integer.MAX_VALUE);
check(s2, "\u00ef\u00f6\u00fc");
}
......
......@@ -18,12 +18,23 @@ public class TestTools extends TestBase {
public void test() throws Exception {
deleteDb("utils");
testManagementDb();
testResourceGenerator();
testChangePassword();
testServer();
testBackupRunscript();
}
private void testManagementDb() throws Exception {
int count = getSize(2, 10);
for(int i=0; i<count; i++) {
Server server = Server.createTcpServer(new String[]{}).start();
server.stop();
server = Server.createTcpServer(new String[]{"-tcpPassword", "abc"}).start();
server.stop();
}
}
private void testBackupRunscript() throws Exception {
Class.forName("org.h2.Driver");
String url = "jdbc:h2:" + BASE_DIR+ "/utils";
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论