提交 a0f72ec6 authored 作者: Thomas Mueller's avatar Thomas Mueller

--no commit message

--no commit message
上级 b625f78f
#Mon Jan 29 22:49:09 CET 2007 #Sun Mar 04 13:24:22 CET 2007
benchmark.drivers.dir=D\:/data/java
javac=javac javac=javac
benchmark.drivers.dir=D\:/data/java
version.name.maven=1.0.20070117 version.name.maven=1.0.20070117
jdk=1.4 jdk=1.4
...@@ -15,9 +15,9 @@ Frequently Asked Questions ...@@ -15,9 +15,9 @@ Frequently Asked Questions
<h3>Are there any known bugs? When is the next release?</h3> <h3>Are there any known bugs? When is the next release?</h3>
Usually, bugs get fixes as they are found. There is a release every few weeks. Usually, bugs get fixes as they are found. There is a release every few weeks.
Here is the list of known and confirmed issues as of Here is the list of known and confirmed issues as of
2007-01-30: 2007-03-04:
<ul> <ul>
<li>Can not build using ant with JDK 1.3 at the moment. However most things are fixed. <li>Can not build using the test cases ant with JDK 1.3 at the moment. However most things are fixed.
</li><li>Some problems have been found with right outer join. Internally, it is converted to left outer join, which </li><li>Some problems have been found with right outer join. Internally, it is converted to left outer join, which
does not always produce the correct results when used in combination with other joins. does not always produce the correct results when used in combination with other joins.
</li></ul> </li></ul>
......
...@@ -267,7 +267,7 @@ It looks like the development of this database has stopped. The last release was ...@@ -267,7 +267,7 @@ It looks like the development of this database has stopped. The last release was
<td><a href="http://sql-workbench.net">SQL Workbench/J</a></td> <td><a href="http://sql-workbench.net">SQL Workbench/J</a></td>
<td>Free DBMS-independent SQL Tool.</td> <td>Free DBMS-independent SQL Tool.</td>
</tr><tr> </tr><tr>
<td><a href="http://squirrelsql.org">SQuirreL SQL Client</a></td> <td><a href="http://www.squirrelsql.org">SQuirreL SQL Client</a></td>
<td>Graphical tool to view the structure of a database, browse the data, issue SQL commands etc.</td> <td>Graphical tool to view the structure of a database, browse the data, issue SQL commands etc.</td>
</tr><tr> </tr><tr>
<td><a href="http://dbcopyplugin.sf.net">SQuirreL DB Copy Plugin</a></td> <td><a href="http://dbcopyplugin.sf.net">SQuirreL DB Copy Plugin</a></td>
......
...@@ -35,13 +35,28 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch. ...@@ -35,13 +35,28 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch.
<h2>Change Log</h2> <h2>Change Log</h2>
<h3>Version 1.0 (Current)</h3> <h3>Version 1.0 (Current)</h3>
<h3>Version 1.0 / 2007-02-TODO</h3><ul> <h3>Version 1.0 / 2007-03-04</h3><ul>
<li>SCRIPT did not work correctly with BLOB or CLOB data. Fixed. <li>System sequences (automatically created sequences for IDENTITY or AUTO_INCREMENT columns) are now
random (UUIDs) to avoid clashes when merging databases using RUNSCRIPT.
</li><li>The precision for linked tables was not correct for some data types, for example VARCHAR. Fixed.
</li><li>Many problems and bugs in the XA support (package javax.sql) have been fixed.
</li><li>Now the server tool (org.h2.tools.Server) terminates with an exit code if a problem occured.
</li><li>The JDBC driver is now loaded if the JdbcDataSource class is loaded.
</li><li>After renaming a user the password becomes invalid. This is now documented.
</li><li>XAResource.recover didn't work. Fixed.
</li><li>XAResource.recover did throw an exception with the code XAER_OUTSIDE if there
was no connection. Now the code is XAER_RMERR.
</li><li>SCRIPT did not work correctly with BLOB or CLOB data. Fixed.
</li><li>BACKUP TO 'test.zip' now works with encrypted databases and CLOB and BLOB data.
</li><li>The function CASE WHEN ... didn't convert the returned value to the same data type,
resulting in unexpected behavior in many cases. Fixed.
</li><li>Truncating a table is now allowed if the table references another table
(but still not allowed if the table is references by another table).
</li><li>ORDER BY picked the wrong column if the same column name (but with a different table name) </li><li>ORDER BY picked the wrong column if the same column name (but with a different table name)
was used twice in the select list. was used twice in the select list.
</li><li>When a subquery was used in the select list of a query, and GROUP BY was used at the same time, </li><li>When a subquery was used in the select list of a query, and GROUP BY was used at the same time,
a NullPointerException could occur. Fixed. a NullPointerException could occur. Fixed.
</li><li>ORDER BY did not work when DISTINCT was used at the same timein some situations. Fixed. </li><li>ORDER BY did not work when DISTINCT was used at the same time in some situations. Fixed.
</li><li>When using IN(...) on a case insensitive column (VARCHAR_IGNORECASE), </li><li>When using IN(...) on a case insensitive column (VARCHAR_IGNORECASE),
an incorrect optimization was made and the result was wrong sometimes. an incorrect optimization was made and the result was wrong sometimes.
</li></ul> </li></ul>
...@@ -1540,10 +1555,16 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch. ...@@ -1540,10 +1555,16 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch.
</li><li>Improve command line consistency (+/- options, or true false options) </li><li>Improve command line consistency (+/- options, or true false options)
</li><li>Allow to use the catalog name in statements: [[catalog.]schema.]object </li><li>Allow to use the catalog name in statements: [[catalog.]schema.]object
</li><li>Support curtimestamp (like curtime, curdate) </li><li>Support curtimestamp (like curtime, curdate)
</li><li>Support ANALYZE {TABLE|INDEX} tablename COMPUTE|ESTIMATE|DELETE STATISTICS ptnOption options </li><li>Support ANALYZE {TABLE|INDEX} tableName COMPUTE|ESTIMATE|DELETE STATISTICS ptnOption options
</li><li>Support Sequoia (Continuent.org) </li><li>Support Sequoia (Continuent.org)
</li><li>Dynamic length numbers / special methods for DataPage.writeByte / writeShort / Ronni Nielsen </li><li>Dynamic length numbers / special methods for DataPage.writeByte / writeShort / Ronni Nielsen
</li><li>Pluggable tracing system, ThreadPool, (AvalonDB / deebee / Paul Hammant) </li><li>Pluggable tracing system, ThreadPool, (AvalonDB / deebee / Paul Hammant)
</li><li>Recursive Queries (see details)
</li><li>Use index on boolean flag (see details)
</li><li>Add build for embedded database only
</li><li>Release locks (shared or exclusive) on demand
</li><li>Support catalog names
</li><li>Add object id to metadata tables
</li></ul> </li></ul>
<h3>Not Planned</h3> <h3>Not Planned</h3>
......
...@@ -3189,8 +3189,6 @@ public class Parser { ...@@ -3189,8 +3189,6 @@ public class Parser {
if(readIf("(")) { if(readIf("(")) {
String[] cols = parseColumnList(false); String[] cols = parseColumnList(false);
command.setColumnNames(cols); command.setColumnNames(cols);
if(recursive) { if(recursive) {
ObjectArray columns = new ObjectArray(); ObjectArray columns = new ObjectArray();
for(int i=0; i<cols.length; i++) { for(int i=0; i<cols.length; i++) {
...@@ -3200,10 +3198,7 @@ public class Parser { ...@@ -3200,10 +3198,7 @@ public class Parser {
recursiveTable.setTemporary(true); recursiveTable.setTemporary(true);
session.addLocalTempTable(recursiveTable); session.addLocalTempTable(recursiveTable);
} }
} }
String select = StringCache.getNew(sqlCommand.substring(parseIndex)); String select = StringCache.getNew(sqlCommand.substring(parseIndex));
read("AS"); read("AS");
try { try {
......
...@@ -72,7 +72,9 @@ public class Backup extends Prepared { ...@@ -72,7 +72,9 @@ public class Backup extends Prepared {
backupFile(out, fn); backupFile(out, fn);
db.setProgress(DatabaseEventListener.STATE_BACKUP_FILE, name, i, max); db.setProgress(DatabaseEventListener.STATE_BACKUP_FILE, name, i, max);
} }
ArrayList fileList = FileLister.getDatabaseFiles(db.getDatabasePath(), name, true); String prefix = db.getDatabasePath();
String dir = FileUtils.getParent(prefix);
ArrayList fileList = FileLister.getDatabaseFiles(dir, name, true);
for(int i=0; i<fileList.size(); i++) { for(int i=0; i<fileList.size(); i++) {
fn = (String) fileList.get(i); fn = (String) fileList.get(i);
if(fn.endsWith(Constants.SUFFIX_HASH_FILE) || fn.endsWith(Constants.SUFFIX_LOB_FILE)) { if(fn.endsWith(Constants.SUFFIX_HASH_FILE) || fn.endsWith(Constants.SUFFIX_LOB_FILE)) {
...@@ -97,7 +99,7 @@ public class Backup extends Prepared { ...@@ -97,7 +99,7 @@ public class Backup extends Prepared {
int pos = -1; int pos = -1;
int max = file.getReadCount(); int max = file.getReadCount();
while(true) { while(true) {
pos = file.readDirect(pos, out); pos = file.copyDirect(pos, out);
if(pos < 0) { if(pos < 0) {
break; break;
} }
......
...@@ -14,8 +14,8 @@ package org.h2.engine; ...@@ -14,8 +14,8 @@ package org.h2.engine;
* - Run FindBugs * - Run FindBugs
* - Update latest version in build.html: http://mirrors.ibiblio.org/pub/mirrors/maven2/com/h2database/h2/ * - Update latest version in build.html: http://mirrors.ibiblio.org/pub/mirrors/maven2/com/h2database/h2/
* - ant jarClient, check jar file size * - ant jarClient, check jar file size
* - Compiling with JDK 1.3, 1.4, 1.5 and 1.6
* *
* - Compile with JDK 1.3, 1.4, 1.5 and 1.6:
* set path=C:\jdk1.3.1_19\bin;%PATH% * set path=C:\jdk1.3.1_19\bin;%PATH%
* set JAVA_HOME=C:\jdk1.3.1_19 * set JAVA_HOME=C:\jdk1.3.1_19
* ant codeswitch_jdk13 * ant codeswitch_jdk13
...@@ -24,19 +24,12 @@ package org.h2.engine; ...@@ -24,19 +24,12 @@ package org.h2.engine;
* set JAVA_HOME=C:\Programme\Java\jdk1.6.0 * set JAVA_HOME=C:\Programme\Java\jdk1.6.0
* ant codeswitch_jdk16 * ant codeswitch_jdk16
* ant compile * ant compile
*
* set path=C:\Programme\Java\jdk1.6.0\bin;%PATH%
* set JAVA_HOME=C:\Programme\Java\jdk1.6.0\bin
* ant codeswitch_jdk16
* ant compile
*
* ant codeswitch_jdk14 * ant codeswitch_jdk14
* *
* - Change FAQ (next release planned, known bugs) * - Change FAQ (next release planned, known bugs)
* - Check version, change build number in Constants.java and build.xml * - Check version, change build number in Constants.java and build.xml
* - Check code coverage * - Check code coverage
* - No " Message.getInternalError" (must be "throw Message.getInternalError") * - No " Message.getInternalError" (must be "throw Message.getInternalError")
* - space#ifdef', space#endif
* - No TODO in the docs * - No TODO in the docs
* - Run regression test with JDK 1.4 and 1.5 * - Run regression test with JDK 1.4 and 1.5
* - Change version(s) in performance.html; use latest versions of other databases * - Change version(s) in performance.html; use latest versions of other databases
...@@ -50,8 +43,8 @@ package org.h2.engine; ...@@ -50,8 +43,8 @@ package org.h2.engine;
* - PDF (15 min) * - PDF (15 min)
* - footer * - footer
* - front page * - front page
* - tables (optimal size) * - orphan control
* - orphan control, page breaks * - tables (optimal size), page breaks
* - table of contents * - table of contents
* - Switch off auto-build * - Switch off auto-build
* - ant all * - ant all
...@@ -73,8 +66,8 @@ package org.h2.engine; ...@@ -73,8 +66,8 @@ package org.h2.engine;
*/ */
public class Constants { public class Constants {
public static final int BUILD_ID = 42; public static final int BUILD_ID = 44;
private static final String BUILD = "2007-02-06"; private static final String BUILD = "2007-03-04";
public static final int VERSION_MAJOR = 1; public static final int VERSION_MAJOR = 1;
public static final int VERSION_MINOR = 0; public static final int VERSION_MINOR = 0;
......
...@@ -362,7 +362,9 @@ public class Function extends Expression implements FunctionCall { ...@@ -362,7 +362,9 @@ public class Function extends Expression implements FunctionCall {
return v0; return v0;
} }
Expression result = v0.getBoolean().booleanValue() ? args[1] : args[2]; Expression result = v0.getBoolean().booleanValue() ? args[1] : args[2];
return result.getValue(session); Value v = result.getValue(session);
v = v.convertTo(dataType);
return v;
} }
case COALESCE: { case COALESCE: {
for (int i = 0; i < args.length; i++) { for (int i = 0; i < args.length; i++) {
......
...@@ -35,9 +35,7 @@ public class ViewIndex extends Index { ...@@ -35,9 +35,7 @@ public class ViewIndex extends Index {
private Value[] lastParameters; private Value[] lastParameters;
private long lastEvaluated; private long lastEvaluated;
private LocalResult lastResult; private LocalResult lastResult;
private boolean recursive;
private int todoRecursiveMustBePrivate;
public boolean recursive;
private int recurseLevel; private int recurseLevel;
private LocalResult recursiveResult; private LocalResult recursiveResult;
...@@ -45,12 +43,9 @@ public class ViewIndex extends Index { ...@@ -45,12 +43,9 @@ public class ViewIndex extends Index {
super(view, 0, null, null, IndexType.createNonUnique(false)); super(view, 0, null, null, IndexType.createNonUnique(false));
this.querySQL = querySQL; this.querySQL = querySQL;
this.originalParameters = originalParameters; this.originalParameters = originalParameters;
int test;
this.recursive = recursive; this.recursive = recursive;
columns = new Column[0]; columns = new Column[0];
params = new Parameter[0]; params = new Parameter[0];
} }
public String getPlanSQL() { public String getPlanSQL() {
...@@ -244,4 +239,8 @@ public class ViewIndex extends Index { ...@@ -244,4 +239,8 @@ public class ViewIndex extends Index {
throw Message.getUnsupportedException(); throw Message.getUnsupportedException();
} }
public void setRecursive(boolean value) {
this.recursive = value;
}
} }
...@@ -52,6 +52,10 @@ Serializable, Referenceable { ...@@ -52,6 +52,10 @@ Serializable, Referenceable {
private String password = ""; private String password = "";
private String url = ""; private String url = "";
static {
org.h2.Driver.load();
}
public JdbcDataSource() { public JdbcDataSource() {
initFactory(); initFactory();
int id = getNextId(TraceObject.DATA_SOURCE); int id = getNextId(TraceObject.DATA_SOURCE);
......
...@@ -21,6 +21,7 @@ public class JdbcDataSourceFactory implements ObjectFactory { ...@@ -21,6 +21,7 @@ public class JdbcDataSourceFactory implements ObjectFactory {
private Trace trace; private Trace trace;
static { static {
org.h2.Driver.load();
traceSystem = new TraceSystem(Constants.CLIENT_TRACE_DIRECTORY + "h2datasource" + Constants.SUFFIX_TRACE_FILE); traceSystem = new TraceSystem(Constants.CLIENT_TRACE_DIRECTORY + "h2datasource" + Constants.SUFFIX_TRACE_FILE);
traceSystem.setLevelFile(TraceSystem.DEBUG); traceSystem.setLevelFile(TraceSystem.DEBUG);
} }
......
...@@ -42,13 +42,20 @@ implements XAConnection, XAResource, JdbcConnectionListener ...@@ -42,13 +42,20 @@ implements XAConnection, XAResource, JdbcConnectionListener
private JdbcConnection conn; private JdbcConnection conn;
private ArrayList listeners = new ArrayList(); private ArrayList listeners = new ArrayList();
private Xid currentTransaction; private Xid currentTransaction;
private int currentTransactionId;
private static int nextTransactionId;
JdbcXAConnection(JdbcDataSourceFactory factory, int id, String url, String user, String password) { static {
org.h2.Driver.load();
}
JdbcXAConnection(JdbcDataSourceFactory factory, int id, String url, String user, String password) throws SQLException {
this.factory = factory; this.factory = factory;
setTrace(factory.getTrace(), TraceObject.XA_DATA_SOURCE, id); setTrace(factory.getTrace(), TraceObject.XA_DATA_SOURCE, id);
this.url = url; this.url = url;
this.user = user; this.user = user;
this.password = password; this.password = password;
getConnection();
} }
public XAResource getXAResource() throws SQLException { public XAResource getXAResource() throws SQLException {
...@@ -128,7 +135,7 @@ implements XAConnection, XAResource, JdbcConnectionListener ...@@ -128,7 +135,7 @@ implements XAConnection, XAResource, JdbcConnectionListener
Statement stat = null; Statement stat = null;
try { try {
stat = conn.createStatement(); stat = conn.createStatement();
ResultSet rs = stat.executeQuery("SELECT * FROM INFORMATION_SCHEMA.IN_DOUBT ORDER BY ID"); ResultSet rs = stat.executeQuery("SELECT * FROM INFORMATION_SCHEMA.IN_DOUBT ORDER BY TRANSACTION");
ArrayList list = new ArrayList(); ArrayList list = new ArrayList();
while(rs.next()) { while(rs.next()) {
String tid = rs.getString("TRANSACTION"); String tid = rs.getString("TRANSACTION");
...@@ -141,8 +148,8 @@ implements XAConnection, XAResource, JdbcConnectionListener ...@@ -141,8 +148,8 @@ implements XAConnection, XAResource, JdbcConnectionListener
list.toArray(result); list.toArray(result);
return result; return result;
} catch(SQLException e) { } catch(SQLException e) {
getTrace().debug("throw XAException.XAER_OUTSIDE", e); getTrace().debug("throw XAException.XAER_RMERR", e);
throw new XAException(XAException.XAER_OUTSIDE); throw new XAException(XAException.XAER_RMERR);
} finally { } finally {
JdbcUtils.closeSilently(stat); JdbcUtils.closeSilently(stat);
} }
...@@ -151,28 +158,29 @@ implements XAConnection, XAResource, JdbcConnectionListener ...@@ -151,28 +158,29 @@ implements XAConnection, XAResource, JdbcConnectionListener
private void checkOpen() throws XAException { private void checkOpen() throws XAException {
if(conn == null) { if(conn == null) {
getTrace().debug("conn==null"); getTrace().debug("conn==null");
throw new XAException(XAException.XAER_OUTSIDE); throw new XAException(XAException.XAER_RMERR);
} }
} }
public int prepare(Xid xid) throws XAException { public int prepare(Xid xid) throws XAException {
debugCode("prepare("+quoteXid(xid)+")"); debugCode("prepare("+quoteXid(xid)+")");
checkOpen(); checkOpen();
if(currentTransaction != xid) { if(!currentTransaction.equals(xid)) {
getTrace().debug("throw XAException.XAER_INVAL"); getTrace().debug("throw XAException.XAER_INVAL");
throw new XAException(XAException.XAER_INVAL); throw new XAException(XAException.XAER_INVAL);
} }
Statement stat = null; Statement stat = null;
try { try {
stat = conn.createStatement(); stat = conn.createStatement();
stat.execute("PREPARE COMMIT"); currentTransactionId = nextTransactionId++;
stat.execute("PREPARE COMMIT TX_" + currentTransactionId);
} catch(SQLException e) { } catch(SQLException e) {
throw convertException(e); throw convertException(e);
} finally { } finally {
JdbcUtils.closeSilently(stat); JdbcUtils.closeSilently(stat);
} }
getTrace().debug("return TMSUCCESS"); getTrace().debug("return XA_OK");
return TMSUCCESS; return XA_OK;
} }
public void forget(Xid xid) throws XAException { public void forget(Xid xid) throws XAException {
...@@ -188,6 +196,7 @@ implements XAConnection, XAResource, JdbcConnectionListener ...@@ -188,6 +196,7 @@ implements XAConnection, XAResource, JdbcConnectionListener
throw convertException(e); throw convertException(e);
} }
getTrace().debug("rolled back"); getTrace().debug("rolled back");
currentTransaction = null;
} }
public void end(Xid xid, int flags) throws XAException { public void end(Xid xid, int flags) throws XAException {
...@@ -195,12 +204,10 @@ implements XAConnection, XAResource, JdbcConnectionListener ...@@ -195,12 +204,10 @@ implements XAConnection, XAResource, JdbcConnectionListener
if(flags == TMSUSPEND) { if(flags == TMSUSPEND) {
return; return;
} }
if(currentTransaction != xid) { if(!currentTransaction.equals(xid)) {
getTrace().debug("throw XAException.XAER_OUTSIDE"); getTrace().debug("throw XAException.XAER_OUTSIDE");
throw new XAException(XAException.XAER_OUTSIDE); throw new XAException(XAException.XAER_OUTSIDE);
} }
getTrace().debug("currentTransaction=null");
currentTransaction = null;
} }
private String quoteFlags(int flags) { private String quoteFlags(int flags) {
...@@ -229,6 +236,12 @@ implements XAConnection, XAResource, JdbcConnectionListener ...@@ -229,6 +236,12 @@ implements XAConnection, XAResource, JdbcConnectionListener
if((flags & XAResource.TMSUSPEND) != 0) { if((flags & XAResource.TMSUSPEND) != 0) {
buff.append("|XAResource.TMSUSPEND"); buff.append("|XAResource.TMSUSPEND");
} }
if ((flags & XAResource.XA_OK) != 0) {
buff.append("|XAResource.XA_OK");
}
if ((flags & XAResource.XA_RDONLY) != 0) {
buff.append("|XAResource.XA_RDONLY");
}
if(buff.length() == 0) { if(buff.length() == 0) {
buff.append("|XAResource.TMNOFLAGS"); buff.append("|XAResource.TMNOFLAGS");
} }
...@@ -274,12 +287,21 @@ implements XAConnection, XAResource, JdbcConnectionListener ...@@ -274,12 +287,21 @@ implements XAConnection, XAResource, JdbcConnectionListener
public void commit(Xid xid, boolean onePhase) throws XAException { public void commit(Xid xid, boolean onePhase) throws XAException {
debugCode("commit("+quoteXid(xid)+", "+onePhase+")"); debugCode("commit("+quoteXid(xid)+", "+onePhase+")");
Statement stat = null;
try { try {
if (onePhase) {
conn.commit(); conn.commit();
} else {
stat = conn.createStatement();
stat.execute("COMMIT TRANSACTION TX_" + currentTransactionId);
}
} catch(SQLException e) { } catch(SQLException e) {
throw convertException(e); throw convertException(e);
} finally {
JdbcUtils.closeSilently(stat);
} }
getTrace().debug("committed"); getTrace().debug("committed");
currentTransaction = null;
} }
//#endif //#endif
......
...@@ -253,6 +253,7 @@ ALTER USER userName RENAME TO newUserName ...@@ -253,6 +253,7 @@ ALTER USER userName RENAME TO newUserName
"," ","
Renames a user. Renames a user.
The user name is converted to uppercase if it is not quoted (with double quotes). The user name is converted to uppercase if it is not quoted (with double quotes).
After renaming a user the password becomes invalid and needs to be changed as well.
Admin rights are required to execute this command. Admin rights are required to execute this command.
"," ","
ALTER USER TOM RENAME TO THOMAS ALTER USER TOM RENAME TO THOMAS
......
...@@ -125,4 +125,8 @@ public class SecureFileStore extends FileStore { ...@@ -125,4 +125,8 @@ public class SecureFileStore extends FileStore {
} }
} }
public boolean isEncrypted() {
return true;
}
} }
...@@ -662,13 +662,13 @@ public class DiskFile implements CacheWriter { ...@@ -662,13 +662,13 @@ public class DiskFile implements CacheWriter {
} }
} }
public synchronized int readDirect(int pos, OutputStream out) throws SQLException { public synchronized int copyDirect(int pos, OutputStream out) throws SQLException {
try { try {
if(pos < 0) { if(pos < 0) {
// read the header // read the header
byte[] buffer = new byte[OFFSET]; byte[] buffer = new byte[OFFSET];
file.seek(0); file.seek(0);
file.readFully(buffer, 0, OFFSET); file.readFullyDirect(buffer, 0, OFFSET);
out.write(buffer); out.write(buffer);
return 0; return 0;
} }
...@@ -697,6 +697,11 @@ public class DiskFile implements CacheWriter { ...@@ -697,6 +697,11 @@ public class DiskFile implements CacheWriter {
if(blockCount > 1) { if(blockCount > 1) {
file.readFully(s.getBytes(), blockSize, blockCount * blockSize - blockSize); file.readFully(s.getBytes(), blockSize, blockCount * blockSize - blockSize);
} }
if(file.isEncrypted()) {
s.reset();
go(pos);
file.readFullyDirect(s.getBytes(), 0, blockCount * blockSize);
}
out.write(s.getBytes(), 0, blockCount * blockSize); out.write(s.getBytes(), 0, blockCount * blockSize);
return pos + blockCount; return pos + blockCount;
} catch (Exception e) { } catch (Exception e) {
......
...@@ -285,4 +285,8 @@ public class FileStore { ...@@ -285,4 +285,8 @@ public class FileStore {
autoDeleteReference = null; autoDeleteReference = null;
} }
public boolean isEncrypted() {
return false;
}
} }
...@@ -29,6 +29,7 @@ import org.h2.value.ValueNull; ...@@ -29,6 +29,7 @@ import org.h2.value.ValueNull;
import org.h2.value.ValueString; import org.h2.value.ValueString;
import org.h2.value.ValueTime; import org.h2.value.ValueTime;
import org.h2.value.ValueTimestamp; import org.h2.value.ValueTimestamp;
import org.h2.value.ValueUuid;
/** /**
* @author Thomas * @author Thomas
...@@ -215,7 +216,7 @@ public class Column { ...@@ -215,7 +216,7 @@ public class Column {
} }
public void convertAutoIncrementToSequence(Session session, Schema schema, int id, boolean temporary) throws SQLException { public void convertAutoIncrementToSequence(Session session, Schema schema, int id, boolean temporary) throws SQLException {
if(!getAutoIncrement()) { if(!autoIncrement) {
throw Message.getInternalError(); throw Message.getInternalError();
} }
if(originalSQL.equals("IDENTITY")) { if(originalSQL.equals("IDENTITY")) {
...@@ -223,7 +224,10 @@ public class Column { ...@@ -223,7 +224,10 @@ public class Column {
} }
String sequenceName; String sequenceName;
for(int i=0; ; i++) { for(int i=0; ; i++) {
sequenceName = "SYSTEM_SEQUENCE_" + i; ValueUuid uuid = ValueUuid.getNewRandom();
String s = uuid.getString();
s = s.replace('-', '_').toUpperCase();
sequenceName = "SYSTEM_SEQUENCE_" + s;
if(schema.findSequence(sequenceName) == null) { if(schema.findSequence(sequenceName) == null) {
break; break;
} }
......
...@@ -10,6 +10,7 @@ import java.util.HashSet; ...@@ -10,6 +10,7 @@ import java.util.HashSet;
import org.h2.api.DatabaseEventListener; import org.h2.api.DatabaseEventListener;
import org.h2.constraint.Constraint; import org.h2.constraint.Constraint;
import org.h2.constraint.ConstraintReferential;
import org.h2.engine.Constants; import org.h2.engine.Constants;
import org.h2.engine.DbObject; import org.h2.engine.DbObject;
import org.h2.engine.Session; import org.h2.engine.Session;
...@@ -439,8 +440,11 @@ public class TableData extends Table implements RecordReader { ...@@ -439,8 +440,11 @@ public class TableData extends Table implements RecordReader {
if(!(c.getConstraintType().equals(Constraint.REFERENTIAL))) { if(!(c.getConstraintType().equals(Constraint.REFERENTIAL))) {
continue; continue;
} }
ConstraintReferential ref = (ConstraintReferential) c;
if(ref.getRefTable() == this) {
return false; return false;
} }
}
return true; return true;
} }
......
...@@ -66,7 +66,6 @@ public class TableLink extends Table { ...@@ -66,7 +66,6 @@ public class TableLink extends Table {
long precision = rs.getInt("COLUMN_SIZE"); long precision = rs.getInt("COLUMN_SIZE");
int scale = rs.getInt("DECIMAL_DIGITS"); int scale = rs.getInt("DECIMAL_DIGITS");
int type = DataType.convertSQLTypeToValueType(sqlType); int type = DataType.convertSQLTypeToValueType(sqlType);
precision = Math.max(precision, DataType.getDataType(type).defaultPrecision);
Column col = new Column(n, type, precision, scale); Column col = new Column(n, type, precision, scale);
col.setTable(this, i++); col.setTable(this, i++);
columnList.add(col); columnList.add(col);
...@@ -87,7 +86,6 @@ public class TableLink extends Table { ...@@ -87,7 +86,6 @@ public class TableLink extends Table {
long precision = rsMeta.getPrecision(i+1); long precision = rsMeta.getPrecision(i+1);
int scale = rsMeta.getScale(i+1); int scale = rsMeta.getScale(i+1);
int type = DataType.convertSQLTypeToValueType(sqlType); int type = DataType.convertSQLTypeToValueType(sqlType);
precision = Math.max(precision, DataType.getDataType(type).defaultPrecision);
Column col = new Column(n, type, precision, scale); Column col = new Column(n, type, precision, scale);
col.setTable(this, i++); col.setTable(this, i++);
columnList.add(col); columnList.add(col);
......
...@@ -28,8 +28,6 @@ public class TableView extends Table { ...@@ -28,8 +28,6 @@ public class TableView extends Table {
private boolean invalid; private boolean invalid;
private Query viewQuery; private Query viewQuery;
private ViewIndex index; private ViewIndex index;
private int test;
private boolean recursive; private boolean recursive;
public TableView(Schema schema, int id, String name, String querySQL, ObjectArray params, String[] columnNames, Session session) throws SQLException { public TableView(Schema schema, int id, String name, String querySQL, ObjectArray params, String[] columnNames, Session session) throws SQLException {
...@@ -82,14 +80,13 @@ public class TableView extends Table { ...@@ -82,14 +80,13 @@ public class TableView extends Table {
cols = new Column[0]; cols = new Column[0];
invalid = true; invalid = true;
int testing;
if(columnNames != null) { if(columnNames != null) {
cols = new Column[columnNames.length]; cols = new Column[columnNames.length];
for(int i=0; i<columnNames.length; i++) { for(int i=0; i<columnNames.length; i++) {
cols[i] = new Column(columnNames[i], Value.STRING, 255, 0); cols[i] = new Column(columnNames[i], Value.STRING, 255, 0);
} }
invalid = false; invalid = false;
index.recursive=true; index.setRecursive(true);
recursive = true; recursive = true;
} }
......
...@@ -18,6 +18,7 @@ import java.sql.SQLException; ...@@ -18,6 +18,7 @@ import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream; import java.util.zip.ZipOutputStream;
import org.h2.message.Message; import org.h2.message.Message;
...@@ -195,5 +196,37 @@ public class Backup { ...@@ -195,5 +196,37 @@ public class Backup {
} }
} }
/**
* INTERNAL
*/
public static void restoreFiles(String zipFileName, String directory) throws IOException, SQLException {
File file = new File(zipFileName);
if(!file.exists()) {
throw new IOException("File not found: " + zipFileName);
}
FileInputStream in = null;
try {
in = new FileInputStream(file);
ZipInputStream zipIn = new ZipInputStream(in);
while(true) {
ZipEntry entry = zipIn.getNextEntry();
if(entry == null) {
break;
}
String fileName = entry.getName();
FileOutputStream out = null;
try {
out = new FileOutputStream(new File(directory, fileName));
IOUtils.copy(zipIn, out);
} finally {
IOUtils.closeSilently(out);
}
zipIn.closeEntry();
}
zipIn.closeEntry();
zipIn.close();
} finally {
IOUtils.closeSilently(in);
}
}
} }
...@@ -28,6 +28,7 @@ public class Server implements Runnable { ...@@ -28,6 +28,7 @@ public class Server implements Runnable {
private String name; private String name;
private Service service; private Service service;
private static final int EXIT_ERROR = 1;
private void showUsage() { private void showUsage() {
System.out.println("java "+getClass().getName() + " [options]"); System.out.println("java "+getClass().getName() + " [options]");
...@@ -69,6 +70,7 @@ public class Server implements Runnable { ...@@ -69,6 +70,7 @@ public class Server implements Runnable {
* The command line interface for this tool. * The command line interface for this tool.
* The options must be split into strings like this: "-baseDir", "/temp/data",... * The options must be split into strings like this: "-baseDir", "/temp/data",...
* By default, -tcp, -web, -browser and -odbc are started. * By default, -tcp, -web, -browser and -odbc are started.
* If there is a problem starting a service, the program terminates with an exit code of 1.
* The following options are supported: * The following options are supported:
* <ul> * <ul>
* <li>-help or -? (print the list of options) * <li>-help or -? (print the list of options)
...@@ -105,10 +107,13 @@ public class Server implements Runnable { ...@@ -105,10 +107,13 @@ public class Server implements Runnable {
* @throws SQLException * @throws SQLException
*/ */
public static void main(String[] args) throws SQLException { public static void main(String[] args) throws SQLException {
new Server().run(args); int exitCode = new Server().run(args);
if(exitCode != 0) {
System.exit(exitCode);
}
} }
private void run(String[] args) throws SQLException { private int run(String[] args) throws SQLException {
boolean tcpStart = false, odbcStart = false, webStart = false, ftpStart = false; boolean tcpStart = false, odbcStart = false, webStart = false, ftpStart = false;
boolean browserStart = false; boolean browserStart = false;
boolean tcpShutdown = false, tcpShutdownForce = false; boolean tcpShutdown = false, tcpShutdownForce = false;
...@@ -119,7 +124,7 @@ public class Server implements Runnable { ...@@ -119,7 +124,7 @@ public class Server implements Runnable {
String a = args[i]; String a = args[i];
if(a.equals("-?") || a.equals("-help")) { if(a.equals("-?") || a.equals("-help")) {
showUsage(); showUsage();
return; return EXIT_ERROR;
} else if(a.equals("-web")) { } else if(a.equals("-web")) {
startDefaultServers = false; startDefaultServers = false;
webStart = true; webStart = true;
...@@ -145,6 +150,7 @@ public class Server implements Runnable { ...@@ -145,6 +150,7 @@ public class Server implements Runnable {
browserStart = true; browserStart = true;
} }
} }
int exitCode = 0;
if(startDefaultServers) { if(startDefaultServers) {
tcpStart = true; tcpStart = true;
odbcStart = true; odbcStart = true;
...@@ -163,6 +169,7 @@ public class Server implements Runnable { ...@@ -163,6 +169,7 @@ public class Server implements Runnable {
} catch(SQLException e) { } catch(SQLException e) {
// ignore (status is displayed) // ignore (status is displayed)
e.printStackTrace(); e.printStackTrace();
exitCode = EXIT_ERROR;
} }
System.out.println(tcp.getStatus()); System.out.println(tcp.getStatus());
} }
...@@ -173,6 +180,7 @@ public class Server implements Runnable { ...@@ -173,6 +180,7 @@ public class Server implements Runnable {
} catch(SQLException e) { } catch(SQLException e) {
// ignore (status is displayed) // ignore (status is displayed)
e.printStackTrace(); e.printStackTrace();
exitCode = EXIT_ERROR;
} }
System.out.println(odbc.getStatus()); System.out.println(odbc.getStatus());
} }
...@@ -183,6 +191,7 @@ public class Server implements Runnable { ...@@ -183,6 +191,7 @@ public class Server implements Runnable {
} catch(SQLException e) { } catch(SQLException e) {
// ignore (status is displayed) // ignore (status is displayed)
e.printStackTrace(); e.printStackTrace();
exitCode = EXIT_ERROR;
} }
System.out.println(web.getStatus()); System.out.println(web.getStatus());
// start browser anyway (even if the server is already running) // start browser anyway (even if the server is already running)
...@@ -199,9 +208,11 @@ public class Server implements Runnable { ...@@ -199,9 +208,11 @@ public class Server implements Runnable {
} catch(SQLException e) { } catch(SQLException e) {
// ignore (status is displayed) // ignore (status is displayed)
e.printStackTrace(); e.printStackTrace();
exitCode = EXIT_ERROR;
} }
System.out.println(ftp.getStatus()); System.out.println(ftp.getStatus());
} }
return exitCode;
} }
/** /**
......
...@@ -55,8 +55,15 @@ public class IOUtils { ...@@ -55,8 +55,15 @@ public class IOUtils {
} }
public static long copyAndCloseInput(InputStream in, OutputStream out) throws IOException { public static long copyAndCloseInput(InputStream in, OutputStream out) throws IOException {
long written = 0;
try { try {
return copy(in, out);
} finally {
in.close();
}
}
public static long copy(InputStream in, OutputStream out) throws IOException {
long written = 0;
byte[] buffer = new byte[4 * 1024]; byte[] buffer = new byte[4 * 1024];
while(true) { while(true) {
int len = in.read(buffer); int len = in.read(buffer);
...@@ -66,9 +73,6 @@ public class IOUtils { ...@@ -66,9 +73,6 @@ public class IOUtils {
out.write(buffer, 0, len); out.write(buffer, 0, len);
written += len; written += len;
} }
} finally {
in.close();
}
return written; return written;
} }
......
...@@ -9,6 +9,10 @@ import java.sql.ResultSet; ...@@ -9,6 +9,10 @@ import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
//#ifdef JDK14
import javax.sql.XAConnection;
//#endif
public class JdbcUtils { public class JdbcUtils {
public static void closeSilently(Statement stat) { public static void closeSilently(Statement stat) {
...@@ -49,4 +53,16 @@ public class JdbcUtils { ...@@ -49,4 +53,16 @@ public class JdbcUtils {
return rs; return rs;
} }
//#ifdef JDK14
public static void closeSilently(XAConnection conn) {
if(conn != null) {
try {
conn.close();
} catch(SQLException e) {
// ignore
}
}
}
//#endif
} }
...@@ -10,6 +10,45 @@ INSERT INTO CHANNEL VALUES('H2 Database Engine' , ...@@ -10,6 +10,45 @@ INSERT INTO CHANNEL VALUES('H2 Database Engine' ,
CREATE TABLE ITEM(ID INT PRIMARY KEY, TITLE VARCHAR, ISSUED TIMESTAMP, DESC VARCHAR); CREATE TABLE ITEM(ID INT PRIMARY KEY, TITLE VARCHAR, ISSUED TIMESTAMP, DESC VARCHAR);
INSERT INTO ITEM VALUES(22,
'New version available: 1.0 / 2007-03-04', '2007-03-04 12:00:00',
'A new version of H2 is available for <a href="http://www.h2database.com">download</a>.
<br />
<b>Changes and new functionality:</b>
<ul>
<li>System sequences (automatically created sequences for IDENTITY or AUTO_INCREMENT columns) are now
random (UUIDs) to avoid clashes when merging databases using RUNSCRIPT.
</li><li>Now the server tool (org.h2.tools.Server) terminates with an exit code if a problem occured.
</li><li>The JDBC driver is now loaded if the JdbcDataSource class is loaded.
</li><li>After renaming a user the password becomes invalid. This is now documented.
</li><li>Truncating a table is now allowed if the table references another table
(but still not allowed if the table is references by another table).
</li>
</ul>
<b>Bugfixes:</b>
<ul>
<li>The precision for linked tables was not correct for some data types, for example VARCHAR. Fixed.
</li><li>Many problems and bugs in the XA support (package javax.sql) have been fixed.
</li><li>ORDER BY picked the wrong column if the same column name (but with a different table name)
was used twice in the select list.
</li><li>When a subquery was used in the select list of a query, and GROUP BY was used at the same time,
a NullPointerException could occur. Fixed.
</li><li>ORDER BY did not work when DISTINCT was used at the same time in some situations. Fixed.
</li><li>When using IN(...) on a case insensitive column (VARCHAR_IGNORECASE),
an incorrect optimization was made and the result was wrong sometimes.
</li><li>XAResource.recover didn''t work. Fixed.
</li><li>XAResource.recover did throw an exception with the code XAER_OUTSIDE if there
was no connection. Now the code is XAER_RMERR.
</li><li>SCRIPT did not work correctly with BLOB or CLOB data. Fixed.
</li><li>BACKUP TO ''test.zip'' now works with encrypted databases and CLOB and BLOB data.
</li><li>The function CASE WHEN ... didn''t convert the returned value to the same data type,
resulting in unexpected behavior in many cases. Fixed.
</li>
</ul>
For future plans, see the new ''Roadmap'' page on the web site.
</ul>
');
INSERT INTO ITEM VALUES(21, INSERT INTO ITEM VALUES(21,
'New version available: 1.0 / 2007-01-30', '2007-01-30 12:00:00', 'New version available: 1.0 / 2007-01-30', '2007-01-30 12:00:00',
'A new version of H2 is available for <a href="http://www.h2database.com">download</a>. 'A new version of H2 is available for <a href="http://www.h2database.com">download</a>.
...@@ -546,44 +585,6 @@ For details see also the history. The plans for the next release are: ...@@ -546,44 +585,6 @@ For details see also the history. The plans for the next release are:
</li></ul> </li></ul>
'); ');
INSERT INTO ITEM VALUES(4,
'New version available: 0.9 Beta / 2006-07-14', '2006-07-14 12:00:00',
'A new version of H2 is available for <a href="http://www.h2database.com">download</a>.
<br />
<b>Changes and new functionality:</b>
<ul>
<li>The cache size is now measured in blocks and no longer in rows.
Manually setting the cache size is no longer necessary in most cases.
</li><li>CREATE VIEW now supports a column list: CREATE VIEW TEST_V(A, B) AS ...
</li><li>New column IS_GENERATED in the metadata tables SEQUENCES and INDEXES.
</li><li>ResultSetMetaData.isNullable is now implemented.
</li><li>Optimization: data conversion of constants was not optimized.
</li><li>Optimization: deterministic subqueries are evaluated only once.
</li><li>Compatibility: ''T'', ''Y'', ''YES'', ''F'', ''N'', ''NO'' (case insensitive) can now also be converted to boolean.
</li><li>Compatibility: SUBSTRING(string FROM start FOR length).
</li><li>Compatibility: TRIM(whitespace FROM string).
</li><li>LIKE ... ESCAPE: The escape character may now also be an expression.
</li><li>IF EXISTS / IF NOT EXISTS implemented for the remaining CREATE / DROP statements.
</li><li>An exception was thrown if a scalar subquery returned no rows. Now NULL is returned.
</li><li>Objects of unknown type are no longer serialized to a byte array.
</li><li>Reduced jar file size: The regression tests are no longer included in the jar file.
</li></ul>
<b>Bugfixes:</b>
<ul>
<li>Issue #123: The connection to the server is lost if an abnormal exception occurs.
</li><li>Issue #124: Adding a column didn''t work when the table contains a referential integrity check.
</li><li>Issue #125: Foreign key constraints of local temporary tables are not dropped when the table is dropped.
</li><li>Issue #126: It is possible to create multiple primary keys for the same table.
</li><li>A few bugs in the CSV tool have been fixed.
</li></ul>
For details see also the history. The plans for the next release are:
<ul>
<li>Bugfixes, write more tests, more bugfixes, more tests.
</li><li>Proposal for changed license.
</li><li>For other plans, see the new ''Roadmap'' part on the web site.
</li></ul>
');
SELECT 'newsfeed-rss.xml' FILE, SELECT 'newsfeed-rss.xml' FILE,
XMLSTARTDOC() || XMLSTARTDOC() ||
XMLNODE('rss', XMLATTR('version', '2.0'), XMLNODE('rss', XMLATTR('version', '2.0'),
......
...@@ -9,6 +9,7 @@ import java.util.Properties; ...@@ -9,6 +9,7 @@ import java.util.Properties;
import org.h2.server.TcpServer; import org.h2.server.TcpServer;
import org.h2.test.jdbc.*; import org.h2.test.jdbc.*;
import org.h2.test.jdbc.xa.TestXA;
import org.h2.test.db.*; import org.h2.test.db.*;
import org.h2.test.server.TestNestedLoop; import org.h2.test.server.TestNestedLoop;
import org.h2.test.synth.TestBtreeIndex; import org.h2.test.synth.TestBtreeIndex;
...@@ -87,107 +88,29 @@ java -Xmx512m -Xrunhprof:cpu=samples,depth=8 org.h2.tools.RunScript -url jdbc:h2 ...@@ -87,107 +88,29 @@ java -Xmx512m -Xrunhprof:cpu=samples,depth=8 org.h2.tools.RunScript -url jdbc:h2
TestAll test = new TestAll(); TestAll test = new TestAll();
test.printSystem(); test.printSystem();
// run TestHalt // TODO: fix Hibernate dialect bug / Bordea Felix (lost email)
// When you run SCRIPT DROP it drops the tables but not the autoincrement values.
// When I try to restore the db I get errors that the already exist.
// The workaround is to drop all objects at the beginning which seems to work fine.
// deebee.tar.gz
// WHERE FLAG does not use index, but WHERE FLAG=TRUE does
//
// drop table test;
// CREATE TABLE test (id int, flag BIT NOT NULL);
// CREATE INDEX idx_flag ON test(flag);
// CREATE INDEX idx_id ON test(id);
// insert into test values(1, false), (2, true), (3, false), (4, true);
// ALTER TABLE test ALTER COLUMN id SELECTIVITY 100;
// ALTER TABLE test ALTER COLUMN flag SELECTIVITY 1;
// EXPLAIN SELECT * FROM test WHERE id=2 AND flag=true;
// EXPLAIN SELECT * FROM test WHERE id between 2 and 3 AND flag=true;
// EXPLAIN SELECT * FROM test WHERE id=2 AND flag;
//
// ALTER TABLE test ALTER COLUMN id SELECTIVITY 1;
// ALTER TABLE test ALTER COLUMN flag SELECTIVITY 100;
// EXPLAIN SELECT * FROM test WHERE id=2 AND flag=true;
// EXPLAIN SELECT * FROM test WHERE id between 2 and 3 AND flag=true;
// EXPLAIN SELECT * FROM test WHERE id=2 AND flag;
// DROP VIEW IF EXISTS TEST_REC;
// DROP VIEW IF EXISTS TEST_2;
// DROP TABLE IF EXISTS TEST;
//
// CREATE TABLE TEST(ID INT PRIMARY KEY, PARENT INT, NAME VARCHAR(255));
// INSERT INTO TEST VALUES(1, NULL, 'Root');
// INSERT INTO TEST VALUES(2, 1, 'Plant');
// INSERT INTO TEST VALUES(3, 1, 'Animal');
// INSERT INTO TEST VALUES(4, 2, 'Tree');
// INSERT INTO TEST VALUES(5, 2, 'Flower');
// INSERT INTO TEST VALUES(6, 3, 'Elephant');
// INSERT INTO TEST VALUES(7, 3, 'Dog');
//
// CREATE FORCE VIEW TEST_2(ID, PARENT, NAME) AS SELECT ID, PARENT, NAME FROM TEST_REC;
//
// CREATE FORCE VIEW TEST_REC(ID, PARENT, NAME) AS
// SELECT ID, PARENT, NAME FROM TEST T
// WHERE PARENT IS NULL
// UNION ALL
// SELECT T.ID, T.PARENT, T.NAME
// FROM TEST T, TEST_2 R
// WHERE 1=0 AND T.PARENT=R.ID;
//
// SELECT * FROM TEST_REC;
// DROP VIEW IF EXISTS TEST_REC;
// DROP VIEW IF EXISTS TEST_2;
// DROP TABLE IF EXISTS TEST;
//
// CREATE TABLE TEST(ID INT PRIMARY KEY, PARENT INT, NAME VARCHAR(255));
// INSERT INTO TEST VALUES(1, NULL, 'Root');
// INSERT INTO TEST VALUES(2, 1, 'Plant');
// INSERT INTO TEST VALUES(3, 1, 'Animal');
// INSERT INTO TEST VALUES(4, 2, 'Tree');
// INSERT INTO TEST VALUES(5, 2, 'Flower');
// INSERT INTO TEST VALUES(6, 3, 'Elephant');
// INSERT INTO TEST VALUES(7, 3, 'Dog');
//
// CREATE VIEW RECURSIVE TEST_REC(ID, PARENT, NAME, LEVEL) AS
// SELECT ID, PARENT, NAME, 0 FROM TEST T
// WHERE PARENT IS NULL
// UNION ALL
// SELECT T.ID, T.PARENT, T.NAME, CAST(R.LEVEL AS INT)+1
// FROM TEST T, TEST_REC R
// WHERE T.PARENT=R.ID;
//
// SELECT * FROM TEST_REC;
// TODO backup : lobs are not backed up
// DROP TABLE IF EXISTS TEST;
// CREATE TABLE TEST(ID INT PRIMARY KEY, DATA CLOB);
// INSERT INTO TEST VALUES(1, space(10000));
// INSERT INTO TEST VALUES(2, 'World');
// drop table bar;
// drop table foo;
// create table FOO(id integer primary key);
// create table BAR(fooId integer);
// alter table bar add foreign key (fooid) references foo (id);
// truncate table bar;
// drop table FOO;
// create table FOO (ID int, A number(18, 2));
// insert into FOO (ID, A) values (1, 10.0), (2, 20.0);
// select SUM (CASE when ID=1 then 0 ELSE A END) col0 from Foo;
// run TestHalt
// hot backup: test, test encrypted database // document backup command
// BACKUP: compare sql syntax with other databases
// Hot backup (incremental backup, online backup): backup data, log, index? files // WHERE FLAG does not use index, but WHERE FLAG=TRUE does
// drop table test;
// CREATE TABLE test (id int, flag BIT NOT NULL);
// CREATE INDEX idx_flag ON test(flag);
// CREATE INDEX idx_id ON test(id);
// insert into test values(1, false), (2, true), (3, false), (4, true);
// ALTER TABLE test ALTER COLUMN id SELECTIVITY 100;
// ALTER TABLE test ALTER COLUMN flag SELECTIVITY 1;
// EXPLAIN SELECT * FROM test WHERE id=2 AND flag=true;
// EXPLAIN SELECT * FROM test WHERE id between 2 and 3 AND flag=true;
// EXPLAIN SELECT * FROM test WHERE id=2 AND flag;
//
// ALTER TABLE test ALTER COLUMN id SELECTIVITY 1;
// ALTER TABLE test ALTER COLUMN flag SELECTIVITY 100;
// EXPLAIN SELECT * FROM test WHERE id=2 AND flag=true;
// EXPLAIN SELECT * FROM test WHERE id between 2 and 3 AND flag=true;
// EXPLAIN SELECT * FROM test WHERE id=2 AND flag;
// h2 // h2
// update FOO set a = dateadd('second', 4320000, a); // update FOO set a = dateadd('second', 4320000, a);
...@@ -200,9 +123,6 @@ java -Xmx512m -Xrunhprof:cpu=samples,depth=8 org.h2.tools.RunScript -url jdbc:h2 ...@@ -200,9 +123,6 @@ java -Xmx512m -Xrunhprof:cpu=samples,depth=8 org.h2.tools.RunScript -url jdbc:h2
// oracle // oracle
// update FOO set a = a + INTERVAL '4320000' SECOND; // update FOO set a = a + INTERVAL '4320000' SECOND;
// test backup
// backup: lobs, index
// GroovyServlet // GroovyServlet
// Cluster: hot deploy (adding a node on runtime) // Cluster: hot deploy (adding a node on runtime)
...@@ -527,6 +447,7 @@ java -Xmx512m -Xrunhprof:cpu=samples,depth=8 org.h2.tools.RunScript -url jdbc:h2 ...@@ -527,6 +447,7 @@ java -Xmx512m -Xrunhprof:cpu=samples,depth=8 org.h2.tools.RunScript -url jdbc:h2
new TestStatement().runTest(this); new TestStatement().runTest(this);
new TestTransactionIsolation().runTest(this); new TestTransactionIsolation().runTest(this);
new TestUpdatableResultSet().runTest(this); new TestUpdatableResultSet().runTest(this);
new TestXA().runTest(this);
new TestZloty().runTest(this); new TestZloty().runTest(this);
afterTest(); afterTest();
......
...@@ -19,7 +19,7 @@ public class TestLinkedTable extends TestBase { ...@@ -19,7 +19,7 @@ public class TestLinkedTable extends TestBase {
Connection conn = DriverManager.getConnection("jdbc:h2:"+BASE_DIR+"/linked1", "sa1", "abc"); Connection conn = DriverManager.getConnection("jdbc:h2:"+BASE_DIR+"/linked1", "sa1", "abc");
Statement stat = conn.createStatement(); Statement stat = conn.createStatement();
stat.execute("CREATE TEMP TABLE TEST_TEMP(ID INT PRIMARY KEY)"); stat.execute("CREATE TEMP TABLE TEST_TEMP(ID INT PRIMARY KEY)");
stat.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR(255), XT TINYINT, XD DECIMAL(10,2), XTS TIMESTAMP, XBY BINARY(255), XBO BIT, XSM SMALLINT, XBI BIGINT, XBL BLOB, XDA DATE, XTI TIME, XCL CLOB, XDO DOUBLE)"); stat.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR(200), XT TINYINT, XD DECIMAL(10,2), XTS TIMESTAMP, XBY BINARY(255), XBO BIT, XSM SMALLINT, XBI BIGINT, XBL BLOB, XDA DATE, XTI TIME, XCL CLOB, XDO DOUBLE)");
stat.execute("CREATE INDEX IDXNAME ON TEST(NAME)"); stat.execute("CREATE INDEX IDXNAME ON TEST(NAME)");
stat.execute("INSERT INTO TEST VALUES(0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL)"); stat.execute("INSERT INTO TEST VALUES(0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL)");
stat.execute("INSERT INTO TEST VALUES(1, 'Hello', -1, 10.30, '2001-02-03 11:22:33.4455', X'FF0102', TRUE, 3000, 1234567890123456789, X'1122AA', DATE '0002-01-01', TIME '00:00:00', 'J\u00fcrg', 2.25)"); stat.execute("INSERT INTO TEST VALUES(1, 'Hello', -1, 10.30, '2001-02-03 11:22:33.4455', X'FF0102', TRUE, 3000, 1234567890123456789, X'1122AA', DATE '0002-01-01', TIME '00:00:00', 'J\u00fcrg', 2.25)");
...@@ -45,6 +45,10 @@ public class TestLinkedTable extends TestBase { ...@@ -45,6 +45,10 @@ public class TestLinkedTable extends TestBase {
stat.execute("CREATE LINKED TABLE IF NOT EXISTS LINK_TEST('org.h2.Driver', 'jdbc:h2:"+BASE_DIR+"/linked1', 'sa1', 'abc', 'TEST')"); stat.execute("CREATE LINKED TABLE IF NOT EXISTS LINK_TEST('org.h2.Driver', 'jdbc:h2:"+BASE_DIR+"/linked1', 'sa1', 'abc', 'TEST')");
stat.execute("CREATE LINKED TABLE IF NOT EXISTS LINK_TEST('org.h2.Driver', 'jdbc:h2:"+BASE_DIR+"/linked1', 'sa1', 'abc', 'TEST')"); stat.execute("CREATE LINKED TABLE IF NOT EXISTS LINK_TEST('org.h2.Driver', 'jdbc:h2:"+BASE_DIR+"/linked1', 'sa1', 'abc', 'TEST')");
testRow(stat, "LINK_TEST"); testRow(stat, "LINK_TEST");
ResultSet rs = stat.executeQuery("SELECT * FROM LINK_TEST");
ResultSetMetaData meta = rs.getMetaData();
check(10, meta.getPrecision(1));
check(200, meta.getPrecision(2));
conn.close(); conn.close();
conn = DriverManager.getConnection("jdbc:h2:"+BASE_DIR+"/linked2", "sa2", "def"); conn = DriverManager.getConnection("jdbc:h2:"+BASE_DIR+"/linked2", "sa2", "def");
...@@ -52,7 +56,7 @@ public class TestLinkedTable extends TestBase { ...@@ -52,7 +56,7 @@ public class TestLinkedTable extends TestBase {
stat.execute("INSERT INTO LINK_TEST VALUES(3, 'Link Test', 30, 100.05, '2005-12-31 12:34:56.789', X'FFEECC33', FALSE, 1, -1234567890123456789, X'4455FF', DATE '9999-12-31', TIME '23:59:59', 'George', -2.5)"); stat.execute("INSERT INTO LINK_TEST VALUES(3, 'Link Test', 30, 100.05, '2005-12-31 12:34:56.789', X'FFEECC33', FALSE, 1, -1234567890123456789, X'4455FF', DATE '9999-12-31', TIME '23:59:59', 'George', -2.5)");
ResultSet rs = stat.executeQuery("SELECT COUNT(*) FROM LINK_TEST"); rs = stat.executeQuery("SELECT COUNT(*) FROM LINK_TEST");
rs.next(); rs.next();
check(rs.getInt(1), 4); check(rs.getInt(1), 4);
......
...@@ -8,6 +8,7 @@ import java.sql.*; ...@@ -8,6 +8,7 @@ import java.sql.*;
import org.h2.api.DatabaseEventListener; import org.h2.api.DatabaseEventListener;
import org.h2.test.TestBase; import org.h2.test.TestBase;
import org.h2.tools.Backup;
public class TestOpenClose extends TestBase implements DatabaseEventListener { public class TestOpenClose extends TestBase implements DatabaseEventListener {
...@@ -18,10 +19,38 @@ public class TestOpenClose extends TestBase implements DatabaseEventListener { ...@@ -18,10 +19,38 @@ public class TestOpenClose extends TestBase implements DatabaseEventListener {
} }
public void test() throws Exception { public void test() throws Exception {
testBackup(false);
testBackup(true);
testCase(); testCase();
testReconnectFast(); testReconnectFast();
} }
private void testBackup(boolean encrypt) throws Exception {
deleteDb(BASE_DIR, "openClose");
String url;
if(encrypt) {
url = "jdbc:h2:"+BASE_DIR+"/openClose;CIPHER=XTEA";
} else {
url = "jdbc:h2:"+BASE_DIR+"/openClose";
}
org.h2.Driver.load();
Connection conn = DriverManager.getConnection(url, "sa", "abc def");
Statement stat = conn.createStatement();
stat.execute("CREATE TABLE TEST(C CLOB)");
stat.execute("INSERT INTO TEST VALUES(SPACE(10000))");
stat.execute("BACKUP TO '"+BASE_DIR+"/test.zip'");
conn.close();
deleteDb(BASE_DIR, "openClose");
Backup.restoreFiles(BASE_DIR + "/test.zip", BASE_DIR);
conn = DriverManager.getConnection(url, "sa", "abc def");
stat = conn.createStatement();
ResultSet rs = stat.executeQuery("SELECT * FROM TEST");
rs.next();
check(rs.getString(1).length(), 10000);
checkFalse(rs.next());
conn.close();
}
private void testReconnectFast() throws Exception { private void testReconnectFast() throws Exception {
deleteDb(BASE_DIR, "openClose"); deleteDb(BASE_DIR, "openClose");
String url = "jdbc:h2:"+BASE_DIR+"/openClose;DATABASE_EVENT_LISTENER='" + TestOpenClose.class.getName()+"'"; String url = "jdbc:h2:"+BASE_DIR+"/openClose;DATABASE_EVENT_LISTENER='" + TestOpenClose.class.getName()+"'";
......
...@@ -10,6 +10,8 @@ import java.sql.Statement; ...@@ -10,6 +10,8 @@ import java.sql.Statement;
import javax.sql.ConnectionEvent; import javax.sql.ConnectionEvent;
import javax.sql.ConnectionEventListener; import javax.sql.ConnectionEventListener;
import javax.sql.XAConnection; import javax.sql.XAConnection;
import javax.transaction.xa.XAResource;
import javax.transaction.xa.Xid;
import org.h2.jdbcx.JdbcDataSource; import org.h2.jdbcx.JdbcDataSource;
import org.h2.test.TestBase; import org.h2.test.TestBase;
...@@ -55,7 +57,10 @@ public class TestDataSource extends TestBase { ...@@ -55,7 +57,10 @@ public class TestDataSource extends TestBase {
public void connectionErrorOccurred(ConnectionEvent event) { public void connectionErrorOccurred(ConnectionEvent event) {
} }
}); });
XAResource res = xaConn.getXAResource();
Connection conn = xaConn.getConnection(); Connection conn = xaConn.getConnection();
Xid[] list = res.recover(XAResource.TMSTARTRSCAN);
check(list.length, 0);
Statement stat = conn.createStatement(); Statement stat = conn.createStatement();
stat.execute("SELECT * FROM DUAL"); stat.execute("SELECT * FROM DUAL");
conn.close(); conn.close();
......
...@@ -7,7 +7,7 @@ package org.h2.test.jdbc; ...@@ -7,7 +7,7 @@ package org.h2.test.jdbc;
import java.sql.Connection; import java.sql.Connection;
import org.h2.jdbcx.JdbcDataSource; import org.h2.jdbcx.JdbcDataSource;
public class TestXA { public class TestXASimple {
int notYetImplemented; int notYetImplemented;
......
/*
* Copyright 2004-2006 H2 Group. Licensed under the H2 License, Version 1.0 (http://h2database.com/html/license.html).
* Initial Developer: James Devenish
*/
package org.h2.test.jdbc.xa;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import javax.sql.XAConnection;
import javax.sql.XADataSource;
import javax.transaction.xa.XAResource;
import javax.transaction.xa.Xid;
import org.h2.jdbcx.JdbcDataSource;
import org.h2.test.TestBase;
import org.h2.util.JdbcUtils;
public class TestXA extends TestBase {
private static final String DB_NAME1 = "xadb1";
private static final String DB_NAME2 = "xadb2";
private static final String DB_URL1 = "jdbc:h2:file:" + BASE_DIR + "/" + DB_NAME1;
private static final String DB_URL2 = "jdbc:h2:file:" + BASE_DIR + "/" + DB_NAME2;
public void test() throws Exception {
deleteDb(BASE_DIR, "xa");
testXA(true);
deleteDb(BASE_DIR, DB_NAME1);
deleteDb(BASE_DIR, DB_NAME2);
testXA(false);
}
private void testXA(boolean useOneDatabase) {
XAConnection xaConn1 = null;
XAConnection xaConn2 = null;
Connection conn1 = null;
Connection conn2 = null;
Statement stat1 = null;
Statement stat2 = null;
try {
trace("xads1 = createXADatasource1()");
XADataSource xaDs1 = createXADatasource(useOneDatabase, DB_URL1);
trace("xads2 = createXADatasource2()");
XADataSource xaDs2 = createXADatasource(useOneDatabase, DB_URL2);
trace("xacon1 = xads1.getXAConnection()");
xaConn1 = xaDs1.getXAConnection();
trace("xacon2 = xads2.getXAConnection()");
xaConn2 = xaDs2.getXAConnection();
trace("xares1 = xacon1.getXAResource()");
XAResource xares1 = xaConn1.getXAResource();
trace("xares2 = xacon2.getXAResource()");
XAResource xares2 = xaConn2.getXAResource();
trace("xares1.recover(XAResource.TMSTARTRSCAN)");
Xid[] xids1 = xares1.recover(XAResource.TMSTARTRSCAN);
if ((xids1 == null) || (xids1.length == 0)) {
trace("xares1.recover(XAResource.TMSTARTRSCAN): 0");
} else {
trace("xares1.recover(XAResource.TMSTARTRSCAN): " + xids1.length);
}
trace("xares2.recover(XAResource.TMSTARTRSCAN)");
Xid[] xids2 = xares2.recover(XAResource.TMSTARTRSCAN);
if ((xids2 == null) || (xids2.length == 0)) {
trace("xares2.recover(XAResource.TMSTARTRSCAN): 0");
} else {
trace("xares2.recover(XAResource.TMSTARTRSCAN): " + xids2.length);
}
trace("con1 = xacon1.getConnection()");
conn1 = xaConn1.getConnection();
trace("stmt1 = con1.createStatement()");
stat1 = conn1.createStatement();
trace("con2 = xacon2.getConnection()");
conn2 = xaConn2.getConnection();
trace("stmt2 = con2.createStatement()");
stat2 = conn2.createStatement();
if (useOneDatabase) {
trace("stmt1.executeUpdate(\"DROP TABLE xatest1\")");
try {
stat1.executeUpdate("DROP TABLE xatest1");
} catch (SQLException e) {
}
trace("stmt2.executeUpdate(\"DROP TABLE xatest2\")");
try {
stat2.executeUpdate("DROP TABLE xatest2");
} catch (SQLException e) {
}
} else {
trace("stmt1.executeUpdate(\"DROP TABLE xatest\")");
try {
stat1.executeUpdate("DROP TABLE xatest");
} catch (SQLException e) {
}
trace("stmt2.executeUpdate(\"DROP TABLE xatest\")");
try {
stat2.executeUpdate("DROP TABLE xatest");
} catch (SQLException e) {
}
}
if (useOneDatabase) {
trace("stmt1.executeUpdate(\"CREATE TABLE xatest1 (id INT PRIMARY KEY, value INT)\")");
stat1.executeUpdate("CREATE TABLE xatest1 (id INT PRIMARY KEY, value INT)");
trace("stmt2.executeUpdate(\"CREATE TABLE xatest2 (id INT PRIMARY KEY, value INT)\")");
stat2.executeUpdate("CREATE TABLE xatest2 (id INT PRIMARY KEY, value INT)");
} else {
trace("stmt1.executeUpdate(\"CREATE TABLE xatest (id INT PRIMARY KEY, value INT)\")");
stat1.executeUpdate("CREATE TABLE xatest (id INT PRIMARY KEY, value INT)");
trace("stmt2.executeUpdate(\"CREATE TABLE xatest (id INT PRIMARY KEY, value INT)\")");
stat2.executeUpdate("CREATE TABLE xatest (id INT PRIMARY KEY, value INT)");
}
if (useOneDatabase) {
trace("stmt1.executeUpdate(\"INSERT INTO xatest1 VALUES (1, 0)\")");
stat1.executeUpdate("INSERT INTO xatest1 VALUES (1, 0)");
trace("stmt2.executeUpdate(\"INSERT INTO xatest2 VALUES (2, 0)\")");
stat2.executeUpdate("INSERT INTO xatest2 VALUES (2, 0)");
} else {
trace("stmt1.executeUpdate(\"INSERT INTO xatest VALUES (1, 0)\")");
stat1.executeUpdate("INSERT INTO xatest VALUES (1, 0)");
trace("stmt2.executeUpdate(\"INSERT INTO xatest VALUES (2, 0)\")");
stat2.executeUpdate("INSERT INTO xatest VALUES (2, 0)");
}
Xid xid1 = null;
Xid xid2 = null;
if (useOneDatabase) {
xid1 = new TestXid(1);
xid2 = new TestXid(2);
} else {
xid1 = new TestXid(1);
xid2 = xid1;
}
if (useOneDatabase) {
trace("xares1.start(xid1, XAResource.TMNOFLAGS)");
xares1.start(xid1, XAResource.TMNOFLAGS);
trace("xares2.start(xid2, XAResource.TMJOIN)");
xares2.start(xid2, XAResource.TMJOIN);
} else {
trace("xares1.start(xid1, XAResource.TMNOFLAGS)");
xares1.start(xid1, XAResource.TMNOFLAGS);
trace("xares2.start(xid2, XAResource.TMNOFLAGS)");
xares2.start(xid2, XAResource.TMNOFLAGS);
}
if (useOneDatabase) {
trace("stmt1.executeUpdate(\"UPDATE xatest1 SET value=1 WHERE id=1\")");
stat1.executeUpdate("UPDATE xatest1 SET value=1 WHERE id=1");
trace("stmt2.executeUpdate(\"UPDATE xatest2 SET value=1 WHERE id=2\")");
stat2.executeUpdate("UPDATE xatest2 SET value=1 WHERE id=2");
} else {
trace("stmt1.executeUpdate(\"UPDATE xatest SET value=1 WHERE id=1\")");
stat1.executeUpdate("UPDATE xatest SET value=1 WHERE id=1");
trace("stmt2.executeUpdate(\"UPDATE xatest SET value=1 WHERE id=2\")");
stat2.executeUpdate("UPDATE xatest SET value=1 WHERE id=2");
}
trace("xares1.end(xid1, XAResource.TMSUCCESS)");
xares1.end(xid1, XAResource.TMSUCCESS);
trace("xares2.end(xid2, XAResource.TMSUCCESS)");
xares2.end(xid2, XAResource.TMSUCCESS);
int ret1;
int ret2;
trace("ret1 = xares1.prepare(xid1)");
ret1 = xares1.prepare(xid1);
trace("xares1.prepare(xid1): " + ret1);
trace("ret2 = xares2.prepare(xid2)");
ret2 = xares2.prepare(xid2);
trace("xares2.prepare(xid2): " + ret2);
if ((ret1 != XAResource.XA_OK) && (ret1 != XAResource.XA_RDONLY)) {
throw new IllegalStateException("xares1.prepare(xid1) must return XA_OK or XA_RDONLY");
}
if ((ret2 != XAResource.XA_OK) && (ret2 != XAResource.XA_RDONLY)) {
throw new IllegalStateException("xares2.prepare(xid2) must return XA_OK or XA_RDONLY");
}
if (ret1 == XAResource.XA_OK) {
trace("xares1.commit(xid1, false)");
xares1.commit(xid1, false);
}
if (ret2 == XAResource.XA_OK) {
trace("xares2.commit(xid2, false)");
xares2.commit(xid2, false);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JdbcUtils.closeSilently(stat1);
JdbcUtils.closeSilently(stat2);
JdbcUtils.closeSilently(conn1);
JdbcUtils.closeSilently(conn2);
JdbcUtils.closeSilently(xaConn1);
JdbcUtils.closeSilently(xaConn2);
}
}
private XADataSource createXADatasource(boolean useOneDatabase, String url) throws SQLException {
JdbcDataSource ds = new JdbcDataSource();
ds.setPassword("");
ds.setUser("sa");
if (useOneDatabase) {
ds.setURL(getURL("xa", true));
} else {
ds.setURL(url);
}
return ds;
}
}
/*
* Copyright 2004-2006 H2 Group. Licensed under the H2 License, Version 1.0 (http://h2database.com/html/license.html).
* Initial Developer: James Devenish
*/
package org.h2.test.jdbc.xa;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.text.NumberFormat;
import javax.transaction.xa.Xid;
public class TestXid implements Xid {
private static final NumberFormat NF;
private static int fXidCounter;
private int fFormatId;
private byte[] fGlobalTransactionId;
private byte[] fBranchQualifier;
private int fId;
private long fCreationTime;
static {
NumberFormat nf = NumberFormat.getIntegerInstance();
nf.setMaximumIntegerDigits(5);
nf.setMinimumIntegerDigits(5);
nf.setGroupingUsed(false);
NF = nf;
}
public static void main(String[] args) {
new TestXid();
}
public TestXid() {
this(1);
}
public TestXid(int branch) {
synchronized (TestXid.class) {
fXidCounter++;
fId = fXidCounter;
}
fCreationTime = System.currentTimeMillis();
String host;
try {
InetAddress ia = InetAddress.getLocalHost();
host = ia.getHostName();
} catch (UnknownHostException e) {
host = "localhost";
}
fFormatId = 0;
fGlobalTransactionId = new byte[MAXGTRIDSIZE];
fBranchQualifier = new byte[MAXBQUALSIZE];
StringBuffer sb;
byte[] ba;
sb = new StringBuffer();
sb.append(host);
sb.append(":");
sb.append(fId);
sb.append(":");
sb.append(fCreationTime);
// System.out.println("global transaction id: " + sb.toString());
ba = sb.toString().getBytes();
for (int i = 0; i < MAXGTRIDSIZE; i++) {
fGlobalTransactionId[i] = (byte) ' ';
}
for (int i = 0; i < ba.length; i++) {
fGlobalTransactionId[i] = ba[i];
}
sb = new StringBuffer(NF.format(branch));
// System.out.println("branch qualifier: " + sb.toString());
ba = sb.toString().getBytes();
for (int i = 0; i < MAXBQUALSIZE; i++) {
fBranchQualifier[i] = (byte) ' ';
}
for (int i = 0; i < ba.length; i++) {
fBranchQualifier[i] = ba[i];
}
}
public int getFormatId() {
return fFormatId;
}
public byte[] getGlobalTransactionId() {
return fGlobalTransactionId;
}
public byte[] getBranchQualifier() {
return fBranchQualifier;
}
}
create table FOO (ID int, A number(18, 2));
insert into FOO (ID, A) values (1, 10.0), (2, 20.0);
select SUM (CASE when ID=1 then 0 ELSE A END) col0 from Foo;
> 20.00;
drop table FOO;
select (SELECT true)+1 GROUP BY 1; select (SELECT true)+1 GROUP BY 1;
> 2; > 2;
create table FOO (ID int, A number(18, 2)); create table FOO (ID int, A number(18, 2));
......
...@@ -441,5 +441,12 @@ yyyy zeile zero zeros zeta zip zloty zone zwj zwnj ...@@ -441,5 +441,12 @@ yyyy zeile zero zeros zeta zip zloty zone zwj zwnj
unavailable repeating sponsored indonesian yuliantoro joko indonesia unlike unavailable repeating sponsored indonesian yuliantoro joko indonesia unlike
truncating ronni ptn avalon nielsen hammant picked sequoia continuent deebee paul
lister testa testb tar von
### check those again:
populate slowly xacon inser maxbqualsize counter regards attaching official xatest xids rmerr xadb rdonly occured maxgtridsize bordea con patches suffixer risky
### evaluatable > evaluable ### evaluatable > evaluable
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论