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

Merge pull request #113 from h2database/master

Prepare "transfer ownership"
.checkstyle
.classpath .classpath
.project .project
.settings
benchmark.html
bin bin
data
docs docs
ext ext
error.* error.*
......
...@@ -912,7 +912,8 @@ COMMIT TRANSACTION XID_TEST ...@@ -912,7 +912,8 @@ COMMIT TRANSACTION XID_TEST
"Commands (Other)","GRANT RIGHT"," "Commands (Other)","GRANT RIGHT","
GRANT { SELECT | INSERT | UPDATE | DELETE | ALL } [,...] ON GRANT { SELECT | INSERT | UPDATE | DELETE | ALL } [,...] ON
tableName [,...] TO { PUBLIC | userName | roleName } { { SCHEMA schemaName } | { tableName [,...] } }
TO { PUBLIC | userName | roleName }
"," ","
Grants rights for a table to a user or role. Grants rights for a table to a user or role.
...@@ -963,7 +964,8 @@ PREPARE COMMIT XID_TEST ...@@ -963,7 +964,8 @@ PREPARE COMMIT XID_TEST
"Commands (Other)","REVOKE RIGHT"," "Commands (Other)","REVOKE RIGHT","
REVOKE { SELECT | INSERT | UPDATE | DELETE | ALL } [,...] ON REVOKE { SELECT | INSERT | UPDATE | DELETE | ALL } [,...] ON
tableName [,...] FROM { PUBLIC | userName | roleName } { { SCHEMA schemaName } | { tableName [,...] } }
FROM { PUBLIC | userName | roleName }
"," ","
Removes rights for a table from a user or role. Removes rights for a table from a user or role.
......
...@@ -191,10 +191,11 @@ Afterwards, you can include the database in your Maven 2 project as a dependency ...@@ -191,10 +191,11 @@ Afterwards, you can include the database in your Maven 2 project as a dependency
To create an Eclipse project for H2, use the following steps: To create an Eclipse project for H2, use the following steps:
</p> </p>
<ul><li>Install Subversion and <a href="http://www.eclipse.org">Eclipse</a>. <ul><li>Install Subversion and <a href="http://www.eclipse.org">Eclipse</a>.
</li><li>Get the H2 source code from the Subversion repository:<br /> </li><li>Get the H2 source code from Github:<br />
<code>svn checkout http://h2database.googlecode.com/svn/trunk h2database-read-only</code> <code>git clone https://github.com/h2database/h2database</code>
</li><li>Download all dependencies (Windows):<br /> </li><li>Download all dependencies:<br />
<code>build.bat download</code> <code>build.bat download</code>(Windows)<br />
<code>./build.sh download</code>(otherwise)<br />
</li><li>In Eclipse, create a new Java project from existing source code: </li><li>In Eclipse, create a new Java project from existing source code:
<code>File, New, Project, Java Project, Create project from existing source</code>. <code>File, New, Project, Java Project, Create project from existing source</code>.
</li><li>Select the <code>h2</code> folder, click <code>Next</code> and <code>Finish</code>. </li><li>Select the <code>h2</code> folder, click <code>Next</code> and <code>Finish</code>.
...@@ -251,7 +252,7 @@ If you like to provide patches, please consider the following guidelines to simp ...@@ -251,7 +252,7 @@ If you like to provide patches, please consider the following guidelines to simp
<p> <p>
For legal reasons, patches need to be public in the form of an email to the For legal reasons, patches need to be public in the form of an email to the
<a href="http://groups.google.com/group/h2-database">group</a>, or in the form <a href="http://groups.google.com/group/h2-database">group</a>, or in the form
of an <a href="http://code.google.com/p/h2database/issues/list">issue report or attachment</a>. of an <a href="https://github.com/h2database/h2database/issues">issue report or attachment</a>.
Significant contributions need to include the following statement: Significant contributions need to include the following statement:
</p> </p>
<p> <p>
...@@ -284,7 +285,7 @@ or if you have a feature request: ...@@ -284,7 +285,7 @@ or if you have a feature request:
Please keep test cases as simple and short as possible, Please keep test cases as simple and short as possible,
but so that the problem can still be reproduced. but so that the problem can still be reproduced.
As a template, use: As a template, use:
<a href="http://h2database.googlecode.com/svn/trunk/h2/src/test/org/h2/samples/HelloWorld.java">HelloWorld.java</a>. <a href="https://github.com/h2database/h2database/tree/master/h2/src/test/org/h2/samples/HelloWorld.java">HelloWorld.java</a>.
Method that simply call other methods should be avoided, Method that simply call other methods should be avoided,
as well as unnecessary exception handling. as well as unnecessary exception handling.
Please use the JDBC API and no external tools or libraries. Please use the JDBC API and no external tools or libraries.
...@@ -297,7 +298,7 @@ or if you have a feature request: ...@@ -297,7 +298,7 @@ or if you have a feature request:
<a href="http://groups.google.com/group/h2-database">Google Group</a> <a href="http://groups.google.com/group/h2-database">Google Group</a>
for questions or if you are not sure it's a bug. for questions or if you are not sure it's a bug.
If you are sure it's a bug, you can create an If you are sure it's a bug, you can create an
<a href="http://code.google.com/p/h2database/issues/list">issue</a>, <a href="https://github.com/h2database/h2database/issues">issue</a>,
but you don't need to (sending an email to the group is enough). but you don't need to (sending an email to the group is enough).
Please note that only few people monitor the issue tracking system. Please note that only few people monitor the issue tracking system.
</li><li>For out-of-memory problems, please analyze the problem yourself first, </li><li>For out-of-memory problems, please analyze the problem yourself first,
......
...@@ -20,7 +20,22 @@ Change Log ...@@ -20,7 +20,22 @@ Change Log
<h1>Change Log</h1> <h1>Change Log</h1>
<h2>Next Version (unreleased)</h2> <h2>Next Version (unreleased)</h2>
<ul><li>Java 8 compatibility for "regexp_replace". <ul><li>Issue 609: the spatial index did not support NULL.
</li><li>Granting a schema is now supported.
</li><li>Linked tables did not work when a function-based index is present (Oracle).
</li><li>Creating a user with a null password, salt, or hash threw a NullPointerException.
</li><li>Foreign key: don't add a single column index if column
is leading key of existing index.
</li><li>Pull request #4: Creating and removing temporary tables was getting
slower and slower over time, because an internal object id was allocated but
never de-allocated.
</li><li>Issue 609: the spatial index did not support NULL with update and delete operations.
</li><li>Pull request #2: Add external metadata type support (table type "external")
</li><li>MS SQL Server: the CONVERT method did not work in views
and derived tables.
</li><li>Java 8 compatibility for "regexp_replace".
</li><li>When in cluster mode, and one of the nodes goes down,
we need to log the problem with priority "error", not "debug"
</li></ul> </li></ul>
<h2>Version 1.4.187 Beta (2015-04-10)</h2> <h2>Version 1.4.187 Beta (2015-04-10)</h2>
...@@ -434,4 +449,3 @@ Change Log ...@@ -434,4 +449,3 @@ Change Log
</li></ul> </li></ul>
<!-- [close] { --></div></td></tr></table><!-- } --><!-- analytics --></body></html> <!-- [close] { --></div></td></tr></table><!-- } --><!-- analytics --></body></html>
...@@ -109,7 +109,7 @@ li { ...@@ -109,7 +109,7 @@ li {
<h2>Using H2</h2> <h2>Using H2</h2>
<ul><li><a href="http://h2database.com">H2</a> is <ul><li><a href="http://h2database.com">H2</a> is
<a href="http://code.google.com/p/h2database/source">open source</a>, <a href="https://github.com/h2database/h2database">open source</a>,
<a href="license.html">free to use and distribute</a>. <a href="license.html">free to use and distribute</a>.
</li><li><a href="http://h2database.com/html/download.html">Download</a>: </li><li><a href="http://h2database.com/html/download.html">Download</a>:
<a href="http://repo1.maven.org/maven2/com/h2database/h2/${version}/h2-${version}.jar" class="link">jar</a>, <a href="http://repo1.maven.org/maven2/com/h2database/h2/${version}/h2-${version}.jar" class="link">jar</a>,
......
...@@ -33,7 +33,7 @@ Downloads ...@@ -33,7 +33,7 @@ Downloads
<a href="http://www.h2database.com/h2-${stableVersionDate}.zip">Platform-Independent Zip</a><br /> <a href="http://www.h2database.com/h2-${stableVersionDate}.zip">Platform-Independent Zip</a><br />
</p> </p>
<h3>Download Mirror and Older Versions</h3> <h3>Old Versions</h3>
<p> <p>
<a href="http://code.google.com/p/h2database/downloads/list">Platform-Independent Zip</a><br /> <a href="http://code.google.com/p/h2database/downloads/list">Platform-Independent Zip</a><br />
</p> </p>
...@@ -57,9 +57,9 @@ Downloads ...@@ -57,9 +57,9 @@ Downloads
<a href="http://h2database.com/h2mig_pagestore_addon.jar">Upgrade database from 1.1 to the current version</a> <a href="http://h2database.com/h2mig_pagestore_addon.jar">Upgrade database from 1.1 to the current version</a>
</p> </p>
<h3>Subversion Source Repository</h3> <h3>Git Source Repository</h3>
<p> <p>
<a href="http://code.google.com/p/h2database/source">Google Code</a> <a href="https://github.com/h2database/h2database">Github</a>
</p> </p>
<p> <p>
......
...@@ -91,7 +91,7 @@ Here is the list of known and confirmed issues: ...@@ -91,7 +91,7 @@ Here is the list of known and confirmed issues:
This problem is solved in Install4j 4.1.4. This problem is solved in Install4j 4.1.4.
</li></ul> </li></ul>
<p> <p>
For a complete list, see <a href="http://code.google.com/p/h2database/issues/list">Open Issues</a>. For a complete list, see <a href="https://github.com/h2database/h2database/issues">Open Issues</a>.
</p> </p>
<h3 id="open_source">Is this Database Engine Open Source?</h3> <h3 id="open_source">Is this Database Engine Open Source?</h3>
......
...@@ -371,7 +371,7 @@ H2 1.3, ...@@ -371,7 +371,7 @@ H2 1.3,
*9 When using MVCC (multi version concurrency).<br /> *9 When using MVCC (multi version concurrency).<br />
*10 Derby and HSQLDB *10 Derby and HSQLDB
<a href="http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29">don't hide data patterns well</a>.<br /> <a href="http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29">don't hide data patterns well</a>.<br />
*11 The MULTI_THREADED option is not enabled by default, and not yet supported when using MVCC.<br /> *11 The MULTI_THREADED option is not enabled by default, and with version 1.3.x not supported when using MVCC.<br />
*12 Derby doesn't support the <code>EXPLAIN</code> statement, but it supports runtime statistics and retrieving statement execution plans.<br /> *12 Derby doesn't support the <code>EXPLAIN</code> statement, but it supports runtime statistics and retrieving statement execution plans.<br />
*13 Derby doesn't support the syntax <code>LIMIT .. [OFFSET ..]</code>, however it supports <code>FETCH FIRST .. ROW[S] ONLY</code>.<br /> *13 Derby doesn't support the syntax <code>LIMIT .. [OFFSET ..]</code>, however it supports <code>FETCH FIRST .. ROW[S] ONLY</code>.<br />
*14 Using collations. *14 Using collations.
...@@ -853,15 +853,17 @@ other processes (that could reside on other computers as well) connect to the se ...@@ -853,15 +853,17 @@ other processes (that could reside on other computers as well) connect to the se
<h3>Multithreading Support</h3> <h3>Multithreading Support</h3>
<p> <p>
This database is multithreading-safe. That means, if an application is multi-threaded, it does not need This database is multithreading-safe.
to worry about synchronizing access to the database. Internally, most requests to the same database If an application is multi-threaded, it does not need to worry about synchronizing access to the database.
are synchronized. That means an application can use multiple threads that access the same database An application should normally use one connection per thread.
at the same time, however if one thread executes a long running query, the other threads This database synchronizes access to the same connection, but other databases may not do this.
need to wait. To get higher concurrency, you need to use multiple connections.
</p> </p>
<p> <p>
An application should normally use one connection per thread. This database synchronizes By default, requests to the same database are synchronized.
access to the same connection, but other databases may not do this. That means an application can use multiple threads that access the same database
at the same time, however if one thread executes a long running query, the other threads need to wait.
To enable concurrent database usage, see the setting <code>MULTI_THREADED</code>.
</p> </p>
<h3>Locking, Lock-Timeout, Deadlocks</h3> <h3>Locking, Lock-Timeout, Deadlocks</h3>
...@@ -1382,7 +1384,7 @@ a regular database. ...@@ -1382,7 +1384,7 @@ a regular database.
<p> <p>
If the database is larger than a few megabytes, performance is much better if the database file is split into multiple smaller files, If the database is larger than a few megabytes, performance is much better if the database file is split into multiple smaller files,
because random access in compressed files is not possible. because random access in compressed files is not possible.
See also the sample application <a href="http://code.google.com/p/h2database/source/browse/trunk/h2/src/test/org/h2/samples/ReadOnlyDatabaseInZip.java">ReadOnlyDatabaseInZip</a>. See also the sample application <a href="https://github.com/h2database/h2database/tree/master/h2/src/test/org/h2/samples/ReadOnlyDatabaseInZip.java">ReadOnlyDatabaseInZip</a>.
</p> </p>
<h3>Opening a Corrupted Database</h3> <h3>Opening a Corrupted Database</h3>
......
...@@ -55,11 +55,6 @@ ...@@ -55,11 +55,6 @@
<module name="EmptyStatement"/> <module name="EmptyStatement"/>
<module name="EqualsHashCode"/> <module name="EqualsHashCode"/>
<module name="IllegalInstantiation"/> <module name="IllegalInstantiation"/>
<module name="RedundantThrows">
<property name="allowUnchecked" value="true"/>
<property name="allowSubclasses" value="true"/>
<property name="suppressLoadErrors" value="true"/>
</module>
<module name="SimplifyBooleanExpression"/> <module name="SimplifyBooleanExpression"/>
<module name="SimplifyBooleanReturn"/> <module name="SimplifyBooleanReturn"/>
<module name="InterfaceIsType"/> <module name="InterfaceIsType"/>
......
...@@ -15,8 +15,8 @@ ...@@ -15,8 +15,8 @@
</license> </license>
</licenses> </licenses>
<scm> <scm>
<connection>scm:svn:http://h2database.googlecode.com/svn/trunk</connection> <connection>scm:git:https://github.com/h2database/h2database</connection>
<url>http://h2database.googlecode.com/svn/trunk</url> <url>https://github.com/h2database/h2database</url>
</scm> </scm>
<developers> <developers>
<developer> <developer>
......
...@@ -15,8 +15,8 @@ ...@@ -15,8 +15,8 @@
</license> </license>
</licenses> </licenses>
<scm> <scm>
<connection>scm:svn:http://h2database.googlecode.com/svn/trunk</connection> <connection>scm:git:https://github.com/h2database/h2database</connection>
<url>http://h2database.googlecode.com/svn/trunk</url> <url>https://github.com/h2database/h2database</url>
</scm> </scm>
<developers> <developers>
<developer> <developer>
......
...@@ -27,7 +27,7 @@ Newsletter: prepare (always to BCC) ...@@ -27,7 +27,7 @@ Newsletter: prepare (always to BCC)
Newsletter: send to h2-database-jp@googlegroups.com; h2-database@googlegroups.com; h2database-news@googlegroups.com; ... Newsletter: send to h2-database-jp@googlegroups.com; h2-database@googlegroups.com; h2database-news@googlegroups.com; ...
Add to http://twitter.com Add to http://twitter.com
- tweet: add @geospatialnews for the new geometry type and disk spatial index - tweet: add @geospatialnews for the new geometry type and disk spatial index
Close bugs: http://code.google.com/p/h2database/issues/list Close bugs: https://github.com/h2database/h2database/issues
Update statistics Update statistics
...@@ -4262,10 +4262,15 @@ public class Parser { ...@@ -4262,10 +4262,15 @@ public class Parser {
} }
if (tableClauseExpected) { if (tableClauseExpected) {
if (readIf("ON")) { if (readIf("ON")) {
do { if (readIf("SCHEMA")) {
Table table = readTableOrView(); Schema schema = database.getSchema(readAliasIdentifier());
command.addTable(table); command.setSchema(schema);
} while (readIf(",")); } else {
do {
Table table = readTableOrView();
command.addTable(table);
} while (readIf(","));
}
} }
} }
if (operationType == CommandInterface.GRANT) { if (operationType == CommandInterface.GRANT) {
......
...@@ -199,15 +199,7 @@ public class AlterTableAddConstraint extends SchemaCommand { ...@@ -199,15 +199,7 @@ public class AlterTableAddConstraint extends SchemaCommand {
isOwner = true; isOwner = true;
index.getIndexType().setBelongsToConstraint(true); index.getIndexType().setBelongsToConstraint(true);
} else { } else {
if (db.isStarting()) { index = getIndex(table, indexColumns, true);
// before version 1.3.176, an existing index was used:
// must do the same to avoid
// Unique index or primary key violation:
// "PRIMARY KEY ON """".PAGE_INDEX"
index = getIndex(table, indexColumns, true);
} else {
index = getIndex(table, indexColumns, false);
}
if (index == null) { if (index == null) {
index = createIndex(table, indexColumns, false); index = createIndex(table, indexColumns, false);
isOwner = true; isOwner = true;
......
...@@ -12,8 +12,6 @@ import org.h2.engine.Session; ...@@ -12,8 +12,6 @@ import org.h2.engine.Session;
import org.h2.engine.User; import org.h2.engine.User;
import org.h2.expression.Expression; import org.h2.expression.Expression;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.security.SHA256;
import org.h2.util.StringUtils;
/** /**
* This class represents the statements * This class represents the statements
...@@ -63,15 +61,6 @@ public class AlterUser extends DefineCommand { ...@@ -63,15 +61,6 @@ public class AlterUser extends DefineCommand {
this.password = password; this.password = password;
} }
private char[] getCharArray(Expression e) {
return e.optimize(session).getValue(session).getString().toCharArray();
}
private byte[] getByteArray(Expression e) {
return StringUtils.convertHexToBytes(
e.optimize(session).getValue(session).getString());
}
@Override @Override
public int update() { public int update() {
session.commit(true); session.commit(true);
...@@ -82,12 +71,9 @@ public class AlterUser extends DefineCommand { ...@@ -82,12 +71,9 @@ public class AlterUser extends DefineCommand {
session.getUser().checkAdmin(); session.getUser().checkAdmin();
} }
if (hash != null && salt != null) { if (hash != null && salt != null) {
user.setSaltAndHash(getByteArray(salt), getByteArray(hash)); CreateUser.setSaltAndHash(user, session, salt, hash);
} else { } else {
String name = newName == null ? user.getName() : newName; CreateUser.setPassword(user, session, password);
char[] passwordChars = getCharArray(password);
byte[] userPasswordHash = SHA256.getKeyPasswordHash(name, passwordChars);
user.setUserPasswordHash(userPasswordHash);
} }
break; break;
case CommandInterface.ALTER_USER_RENAME: case CommandInterface.ALTER_USER_RENAME:
......
...@@ -45,13 +45,41 @@ public class CreateUser extends DefineCommand { ...@@ -45,13 +45,41 @@ public class CreateUser extends DefineCommand {
this.password = password; this.password = password;
} }
private char[] getCharArray(Expression e) { /**
return e.optimize(session).getValue(session).getString().toCharArray(); * Set the salt and hash for the given user.
*
* @param user the user
* @param session the session
* @param salt the salt
* @param hash the hash
*/
static void setSaltAndHash(User user, Session session, Expression salt, Expression hash) {
user.setSaltAndHash(getByteArray(session, salt), getByteArray(session, hash));
} }
private byte[] getByteArray(Expression e) { private static byte[] getByteArray(Session session, Expression e) {
return StringUtils.convertHexToBytes( String s = e.optimize(session).getValue(session).getString();
e.optimize(session).getValue(session).getString()); return s == null ? new byte[0] : StringUtils.convertHexToBytes(s);
}
/**
* Set the password for the given user.
*
* @param user the user
* @param session the session
* @param password the password
*/
static void setPassword(User user, Session session, Expression password) {
String pwd = password.optimize(session).getValue(session).getString();
char[] passwordChars = pwd == null ? new char[0] : pwd.toCharArray();
byte[] userPasswordHash;
String userName = user.getName();
if (userName.length() == 0 && passwordChars.length == 0) {
userPasswordHash = new byte[0];
} else {
userPasswordHash = SHA256.getKeyPasswordHash(userName, passwordChars);
}
user.setUserPasswordHash(userPasswordHash);
} }
@Override @Override
...@@ -73,16 +101,9 @@ public class CreateUser extends DefineCommand { ...@@ -73,16 +101,9 @@ public class CreateUser extends DefineCommand {
user.setAdmin(admin); user.setAdmin(admin);
user.setComment(comment); user.setComment(comment);
if (hash != null && salt != null) { if (hash != null && salt != null) {
user.setSaltAndHash(getByteArray(salt), getByteArray(hash)); setSaltAndHash(user, session, salt, hash);
} else if (password != null) { } else if (password != null) {
char[] passwordChars = getCharArray(password); setPassword(user, session, password);
byte[] userPasswordHash;
if (userName.length() == 0 && passwordChars.length == 0) {
userPasswordHash = new byte[0];
} else {
userPasswordHash = SHA256.getKeyPasswordHash(userName, passwordChars);
}
user.setUserPasswordHash(userPasswordHash);
} else { } else {
throw DbException.throwInternalError(); throw DbException.throwInternalError();
} }
......
...@@ -10,11 +10,13 @@ import java.util.ArrayList; ...@@ -10,11 +10,13 @@ import java.util.ArrayList;
import org.h2.api.ErrorCode; import org.h2.api.ErrorCode;
import org.h2.command.CommandInterface; import org.h2.command.CommandInterface;
import org.h2.engine.Database; import org.h2.engine.Database;
import org.h2.engine.DbObject;
import org.h2.engine.Right; import org.h2.engine.Right;
import org.h2.engine.RightOwner; import org.h2.engine.RightOwner;
import org.h2.engine.Role; import org.h2.engine.Role;
import org.h2.engine.Session; import org.h2.engine.Session;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.schema.Schema;
import org.h2.table.Table; import org.h2.table.Table;
import org.h2.util.New; import org.h2.util.New;
...@@ -31,6 +33,7 @@ public class GrantRevoke extends DefineCommand { ...@@ -31,6 +33,7 @@ public class GrantRevoke extends DefineCommand {
private int operationType; private int operationType;
private int rightMask; private int rightMask;
private final ArrayList<Table> tables = New.arrayList(); private final ArrayList<Table> tables = New.arrayList();
private Schema schema;
private RightOwner grantee; private RightOwner grantee;
public GrantRevoke(Session session) { public GrantRevoke(Session session) {
...@@ -105,18 +108,25 @@ public class GrantRevoke extends DefineCommand { ...@@ -105,18 +108,25 @@ public class GrantRevoke extends DefineCommand {
} }
private void grantRight() { private void grantRight() {
Database db = session.getDatabase(); if (schema != null) {
grantRight(schema);
}
for (Table table : tables) { for (Table table : tables) {
Right right = grantee.getRightForTable(table); grantRight(table);
if (right == null) { }
int id = getObjectId(); }
right = new Right(db, id, grantee, rightMask, table);
grantee.grantRight(table, right); private void grantRight(DbObject object) {
db.addDatabaseObject(session, right); Database db = session.getDatabase();
} else { Right right = grantee.getRightForObject(object);
right.setRightMask(right.getRightMask() | rightMask); if (right == null) {
db.updateMeta(session, right); int id = getObjectId();
} right = new Right(db, id, grantee, rightMask, object);
grantee.grantRight(object, right);
db.addDatabaseObject(session, right);
} else {
right.setRightMask(right.getRightMask() | rightMask);
db.updateMeta(session, right);
} }
} }
...@@ -139,23 +149,31 @@ public class GrantRevoke extends DefineCommand { ...@@ -139,23 +149,31 @@ public class GrantRevoke extends DefineCommand {
} }
private void revokeRight() { private void revokeRight() {
if (schema != null) {
revokeRight(schema);
}
for (Table table : tables) { for (Table table : tables) {
Right right = grantee.getRightForTable(table); revokeRight(table);
if (right == null) {
continue;
}
int mask = right.getRightMask();
int newRight = mask & ~rightMask;
Database db = session.getDatabase();
if (newRight == 0) {
db.removeDatabaseObject(session, right);
} else {
right.setRightMask(newRight);
db.updateMeta(session, right);
}
} }
} }
private void revokeRight(DbObject object) {
Right right = grantee.getRightForObject(object);
if (right == null) {
return;
}
int mask = right.getRightMask();
int newRight = mask & ~rightMask;
Database db = session.getDatabase();
if (newRight == 0) {
db.removeDatabaseObject(session, right);
} else {
right.setRightMask(newRight);
db.updateMeta(session, right);
}
}
private void revokeRole(Role grantedRole) { private void revokeRole(Role grantedRole) {
Right right = grantee.getRightForRole(grantedRole); Right right = grantee.getRightForRole(grantedRole);
if (right == null) { if (right == null) {
...@@ -179,6 +197,15 @@ public class GrantRevoke extends DefineCommand { ...@@ -179,6 +197,15 @@ public class GrantRevoke extends DefineCommand {
tables.add(table); tables.add(table);
} }
/**
* Set the specified schema
*
* @param schema the schema
*/
public void setSchema(Schema schema) {
this.schema = schema;
}
@Override @Override
public int getType() { public int getType() {
return operationType; return operationType;
......
...@@ -352,13 +352,20 @@ public class ScriptCommand extends ScriptBase { ...@@ -352,13 +352,20 @@ public class ScriptCommand extends ScriptBase {
} }
// Generate GRANT ... // Generate GRANT ...
for (Right right : db.getAllRights()) { for (Right right : db.getAllRights()) {
Table table = right.getGrantedTable(); DbObject object = right.getGrantedObject();
if (table != null) { if (object != null) {
if (excludeSchema(table.getSchema())) { if (object instanceof Schema) {
continue; if (excludeSchema((Schema) object)) {
} continue;
if (excludeTable(table)) { }
continue; } else if (object instanceof Table) {
Table table = (Table) object;
if (excludeSchema(table.getSchema())) {
continue;
}
if (excludeTable(table)) {
continue;
}
} }
} }
add(right.getCreateSQL(), false); add(right.getCreateSQL(), false);
......
...@@ -919,7 +919,6 @@ public class Database implements DataHandler { ...@@ -919,7 +919,6 @@ public class Database implements DataHandler {
// the moment // the moment
session.log(meta, UndoLogRecord.DELETE, found); session.log(meta, UndoLogRecord.DELETE, found);
} }
objectIds.clear(id);
if (SysProperties.CHECK) { if (SysProperties.CHECK) {
checkMetaFree(session, id); checkMetaFree(session, id);
} }
...@@ -929,6 +928,7 @@ public class Database implements DataHandler { ...@@ -929,6 +928,7 @@ public class Database implements DataHandler {
meta.unlock(session); meta.unlock(session);
session.unlock(meta); session.unlock(meta);
} }
objectIds.clear(id);
} }
} }
......
...@@ -7,6 +7,7 @@ package org.h2.engine; ...@@ -7,6 +7,7 @@ package org.h2.engine;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.message.Trace; import org.h2.message.Trace;
import org.h2.schema.Schema;
import org.h2.table.Table; import org.h2.table.Table;
/** /**
...@@ -46,10 +47,25 @@ public class Right extends DbObjectBase { ...@@ -46,10 +47,25 @@ public class Right extends DbObjectBase {
*/ */
public static final int ALL = SELECT | DELETE | INSERT | UPDATE; public static final int ALL = SELECT | DELETE | INSERT | UPDATE;
/**
* To whom the right is granted.
*/
private RightOwner grantee;
/**
* The granted role, or null if a right was granted.
*/
private Role grantedRole; private Role grantedRole;
/**
* The granted right.
*/
private int grantedRight; private int grantedRight;
private Table grantedTable;
private RightOwner grantee; /**
* The object. If the right is global, this is null.
*/
private DbObject grantedObject;
public Right(Database db, int id, RightOwner grantee, Role grantedRole) { public Right(Database db, int id, RightOwner grantee, Role grantedRole) {
initDbObjectBase(db, id, "RIGHT_" + id, Trace.USER); initDbObjectBase(db, id, "RIGHT_" + id, Trace.USER);
...@@ -58,11 +74,11 @@ public class Right extends DbObjectBase { ...@@ -58,11 +74,11 @@ public class Right extends DbObjectBase {
} }
public Right(Database db, int id, RightOwner grantee, int grantedRight, public Right(Database db, int id, RightOwner grantee, int grantedRight,
Table grantedRightOnTable) { DbObject grantedObject) {
initDbObjectBase(db, id, "" + id, Trace.USER); initDbObjectBase(db, id, "" + id, Trace.USER);
this.grantee = grantee; this.grantee = grantee;
this.grantedRight = grantedRight; this.grantedRight = grantedRight;
this.grantedTable = grantedRightOnTable; this.grantedObject = grantedObject;
} }
private static boolean appendRight(StringBuilder buff, int right, int mask, private static boolean appendRight(StringBuilder buff, int right, int mask,
...@@ -97,8 +113,8 @@ public class Right extends DbObjectBase { ...@@ -97,8 +113,8 @@ public class Right extends DbObjectBase {
return grantedRole; return grantedRole;
} }
public Table getGrantedTable() { public DbObject getGrantedObject() {
return grantedTable; return grantedObject;
} }
public DbObject getGrantee() { public DbObject getGrantee() {
...@@ -112,14 +128,22 @@ public class Right extends DbObjectBase { ...@@ -112,14 +128,22 @@ public class Right extends DbObjectBase {
@Override @Override
public String getCreateSQLForCopy(Table table, String quotedName) { public String getCreateSQLForCopy(Table table, String quotedName) {
return getCreateSQLForCopy(table);
}
private String getCreateSQLForCopy(DbObject object) {
StringBuilder buff = new StringBuilder(); StringBuilder buff = new StringBuilder();
buff.append("GRANT "); buff.append("GRANT ");
if (grantedRole != null) { if (grantedRole != null) {
buff.append(grantedRole.getSQL()); buff.append(grantedRole.getSQL());
} else { } else {
buff.append(getRights()); buff.append(getRights());
if (table != null) { if (object != null) {
buff.append(" ON ").append(table.getSQL()); if (object instanceof Schema) {
buff.append(" ON SCHEMA ").append(object.getSQL());
} else if (object instanceof Table) {
buff.append(" ON ").append(object.getSQL());
}
} }
} }
buff.append(" TO ").append(grantee.getSQL()); buff.append(" TO ").append(grantee.getSQL());
...@@ -128,7 +152,7 @@ public class Right extends DbObjectBase { ...@@ -128,7 +152,7 @@ public class Right extends DbObjectBase {
@Override @Override
public String getCreateSQL() { public String getCreateSQL() {
return getCreateSQLForCopy(grantedTable, null); return getCreateSQLForCopy(grantedObject);
} }
@Override @Override
...@@ -138,14 +162,14 @@ public class Right extends DbObjectBase { ...@@ -138,14 +162,14 @@ public class Right extends DbObjectBase {
@Override @Override
public void removeChildrenAndResources(Session session) { public void removeChildrenAndResources(Session session) {
if (grantedTable != null) { if (grantedRole != null) {
grantee.revokeRight(grantedTable);
} else {
grantee.revokeRole(grantedRole); grantee.revokeRole(grantedRole);
} else {
grantee.revokeRight(grantedObject);
} }
database.removeMeta(session, getId()); database.removeMeta(session, getId());
grantedRole = null; grantedRole = null;
grantedTable = null; grantedObject = null;
grantee = null; grantee = null;
invalidate(); invalidate();
} }
......
...@@ -23,7 +23,7 @@ public abstract class RightOwner extends DbObjectBase { ...@@ -23,7 +23,7 @@ public abstract class RightOwner extends DbObjectBase {
/** /**
* The map of granted rights. * The map of granted rights.
*/ */
private HashMap<Table, Right> grantedRights; private HashMap<DbObject, Right> grantedRights;
protected RightOwner(Database database, int id, String name, protected RightOwner(Database database, int id, String name,
String traceModule) { String traceModule) {
...@@ -55,7 +55,9 @@ public abstract class RightOwner extends DbObjectBase { ...@@ -55,7 +55,9 @@ public abstract class RightOwner extends DbObjectBase {
/** /**
* Check if a right is already granted to this object or to objects that * Check if a right is already granted to this object or to objects that
* were granted to this object. * were granted to this object. The rights for schemas takes
* precedence over rights of tables, in other words, the rights of schemas
* will be valid for every each table in the related schema.
* *
* @param table the table to check * @param table the table to check
* @param rightMask the right mask to check * @param rightMask the right mask to check
...@@ -64,6 +66,14 @@ public abstract class RightOwner extends DbObjectBase { ...@@ -64,6 +66,14 @@ public abstract class RightOwner extends DbObjectBase {
boolean isRightGrantedRecursive(Table table, int rightMask) { boolean isRightGrantedRecursive(Table table, int rightMask) {
Right right; Right right;
if (grantedRights != null) { if (grantedRights != null) {
if (table != null) {
right = grantedRights.get(table.getSchema());
if (right != null) {
if ((right.getRightMask() & rightMask) == rightMask) {
return true;
}
}
}
right = grantedRights.get(table); right = grantedRights.get(table);
if (right != null) { if (right != null) {
if ((right.getRightMask() & rightMask) == rightMask) { if ((right.getRightMask() & rightMask) == rightMask) {
...@@ -85,26 +95,26 @@ public abstract class RightOwner extends DbObjectBase { ...@@ -85,26 +95,26 @@ public abstract class RightOwner extends DbObjectBase {
* Grant a right for the given table. Only one right object per table is * Grant a right for the given table. Only one right object per table is
* supported. * supported.
* *
* @param table the table * @param object the object (table or schema)
* @param right the right * @param right the right
*/ */
public void grantRight(Table table, Right right) { public void grantRight(DbObject object, Right right) {
if (grantedRights == null) { if (grantedRights == null) {
grantedRights = New.hashMap(); grantedRights = New.hashMap();
} }
grantedRights.put(table, right); grantedRights.put(object, right);
} }
/** /**
* Revoke the right for the given table. * Revoke the right for the given object (table or schema).
* *
* @param table the table * @param object the object
*/ */
void revokeRight(Table table) { void revokeRight(DbObject object) {
if (grantedRights == null) { if (grantedRights == null) {
return; return;
} }
grantedRights.remove(table); grantedRights.remove(object);
if (grantedRights.size() == 0) { if (grantedRights.size() == 0) {
grantedRights = null; grantedRights = null;
} }
...@@ -143,16 +153,16 @@ public abstract class RightOwner extends DbObjectBase { ...@@ -143,16 +153,16 @@ public abstract class RightOwner extends DbObjectBase {
} }
/** /**
* Get the 'grant table' right of this object. * Get the 'grant schema' right of this object.
* *
* @param table the granted table * @param object the granted object (table or schema)
* @return the right or null if the right has not been granted * @return the right or null if the right has not been granted
*/ */
public Right getRightForTable(Table table) { public Right getRightForObject(DbObject object) {
if (grantedRights == null) { if (grantedRights == null) {
return null; return null;
} }
return grantedRights.get(table); return grantedRights.get(object);
} }
/** /**
......
...@@ -2479,9 +2479,15 @@ public class Function extends Expression implements FunctionCall { ...@@ -2479,9 +2479,15 @@ public class Function extends Expression implements FunctionCall {
break; break;
} }
case CONVERT: { case CONVERT: {
buff.append(args[0].getSQL()).append(','). if (database.getMode().swapConvertFunctionParameters) {
append(new Column(null, dataType, precision, buff.append(new Column(null, dataType, precision,
scale, displaySize).getCreateSQL()).
append(',').append(args[0].getSQL());
} else {
buff.append(args[0].getSQL()).append(',').
append(new Column(null, dataType, precision,
scale, displaySize).getCreateSQL()); scale, displaySize).getCreateSQL());
}
break; break;
} }
case EXTRACT: { case EXTRACT: {
......
...@@ -769,10 +769,8 @@ public class JdbcDatabaseMetaData extends TraceObject implements ...@@ -769,10 +769,8 @@ public class JdbcDatabaseMetaData extends TraceObject implements
} }
/** /**
* Gets the list of table types. This call returns a result set with three * Gets the list of table types. This call returns a result set with five
* records: "SYSTEM TABLE", "TABLE", "and "VIEW". * records: "SYSTEM TABLE", "TABLE", "VIEW", "TABLE LINK" and "EXTERNAL".
* The result set is sorted by TABLE_TYPE.
*
* <ul> * <ul>
* <li>1 TABLE_TYPE (String) table type * <li>1 TABLE_TYPE (String) table type
* </li></ul> * </li></ul>
......
...@@ -6,7 +6,6 @@ ...@@ -6,7 +6,6 @@
package org.h2.mvstore; package org.h2.mvstore;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
...@@ -471,14 +470,18 @@ public class Page { ...@@ -471,14 +470,18 @@ public class Page {
public void setChild(int index, Page c) { public void setChild(int index, Page c) {
if (c == null) { if (c == null) {
long oldCount = children[index].count; long oldCount = children[index].count;
children = Arrays.copyOf(children, children.length); // this is slightly slower:
// children = Arrays.copyOf(children, children.length);
children = children.clone();
PageReference ref = new PageReference(null, 0, 0); PageReference ref = new PageReference(null, 0, 0);
children[index] = ref; children[index] = ref;
totalCount -= oldCount; totalCount -= oldCount;
} else if (c != children[index].page || } else if (c != children[index].page ||
c.getPos() != children[index].pos) { c.getPos() != children[index].pos) {
long oldCount = children[index].count; long oldCount = children[index].count;
children = Arrays.copyOf(children, children.length); // this is slightly slower:
// children = Arrays.copyOf(children, children.length);
children = children.clone();
PageReference ref = new PageReference(c, c.pos, c.totalCount); PageReference ref = new PageReference(c, c.pos, c.totalCount);
children[index] = ref; children[index] = ref;
totalCount += c.totalCount - oldCount; totalCount += c.totalCount - oldCount;
...@@ -492,7 +495,9 @@ public class Page { ...@@ -492,7 +495,9 @@ public class Page {
* @param key the new key * @param key the new key
*/ */
public void setKey(int index, Object key) { public void setKey(int index, Object key) {
keys = Arrays.copyOf(keys, keys.length); // this is slightly slower:
// keys = Arrays.copyOf(keys, keys.length);
keys = keys.clone();
Object old = keys[index]; Object old = keys[index];
DataType keyType = map.getKeyType(); DataType keyType = map.getKeyType();
int mem = keyType.getMemory(key); int mem = keyType.getMemory(key);
...@@ -512,7 +517,9 @@ public class Page { ...@@ -512,7 +517,9 @@ public class Page {
*/ */
public Object setValue(int index, Object value) { public Object setValue(int index, Object value) {
Object old = values[index]; Object old = values[index];
values = Arrays.copyOf(values, values.length); // this is slightly slower:
// values = Arrays.copyOf(values, values.length);
values = values.clone();
DataType valueType = map.getValueType(); DataType valueType = map.getValueType();
addMemory(valueType.getMemory(value) - addMemory(valueType.getMemory(value) -
valueType.getMemory(old)); valueType.getMemory(old));
......
...@@ -6,7 +6,6 @@ ...@@ -6,7 +6,6 @@
package org.h2.mvstore.db; package org.h2.mvstore.db;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
...@@ -125,7 +124,7 @@ public class MVSecondaryIndex extends BaseIndex implements MVIndex { ...@@ -125,7 +124,7 @@ public class MVSecondaryIndex extends BaseIndex implements MVIndex {
if (indexType.isUnique()) { if (indexType.isUnique()) {
Value[] array = ((ValueArray) v).getList(); Value[] array = ((ValueArray) v).getList();
// don't change the original value // don't change the original value
array = Arrays.copyOf(array, array.length); array = array.clone();
array[keyColumns - 1] = ValueLong.get(Long.MIN_VALUE); array[keyColumns - 1] = ValueLong.get(Long.MIN_VALUE);
ValueArray unique = ValueArray.get(array); ValueArray unique = ValueArray.get(array);
SearchRow row = convertToSearchRow((ValueArray) v); SearchRow row = convertToSearchRow((ValueArray) v);
......
...@@ -171,6 +171,7 @@ public class MVSpatialIndex extends BaseIndex implements SpatialIndex, MVIndex { ...@@ -171,6 +171,7 @@ public class MVSpatialIndex extends BaseIndex implements SpatialIndex, MVIndex {
try { try {
Value old = map.remove(key); Value old = map.remove(key);
if (old == null) { if (old == null) {
old = map.remove(key);
throw DbException.get(ErrorCode.ROW_NOT_FOUND_WHEN_DELETING_1, throw DbException.get(ErrorCode.ROW_NOT_FOUND_WHEN_DELETING_1,
getSQL() + ": " + row.getKey()); getSQL() + ": " + row.getKey());
} }
...@@ -211,12 +212,9 @@ public class MVSpatialIndex extends BaseIndex implements SpatialIndex, MVIndex { ...@@ -211,12 +212,9 @@ public class MVSpatialIndex extends BaseIndex implements SpatialIndex, MVIndex {
} }
private SpatialKey getKey(SearchRow row) { private SpatialKey getKey(SearchRow row) {
if (row == null) {
return null;
}
Value v = row.getValue(columnIds[0]); Value v = row.getValue(columnIds[0]);
if (v == ValueNull.INSTANCE) { if (v == ValueNull.INSTANCE) {
return null; return new SpatialKey(row.getKey());
} }
Geometry g = ((ValueGeometry) v.convertTo(Value.GEOMETRY)).getGeometryNoCopy(); Geometry g = ((ValueGeometry) v.convertTo(Value.GEOMETRY)).getGeometryNoCopy();
Envelope env = g.getEnvelopeInternal(); Envelope env = g.getEnvelopeInternal();
......
...@@ -10,6 +10,7 @@ import java.util.ArrayList; ...@@ -10,6 +10,7 @@ import java.util.ArrayList;
import org.h2.mvstore.DataUtils; import org.h2.mvstore.DataUtils;
import org.h2.mvstore.WriteBuffer; import org.h2.mvstore.WriteBuffer;
import org.h2.mvstore.type.DataType; import org.h2.mvstore.type.DataType;
import org.h2.util.New;
/** /**
* A spatial data type. This class supports up to 31 dimensions. Each dimension * A spatial data type. This class supports up to 31 dimensions. Each dimension
...@@ -83,11 +84,12 @@ public class SpatialDataType implements DataType { ...@@ -83,11 +84,12 @@ public class SpatialDataType implements DataType {
@Override @Override
public void write(WriteBuffer buff, Object obj) { public void write(WriteBuffer buff, Object obj) {
if (obj == null) { SpatialKey k = (SpatialKey) obj;
if (k.isNull()) {
buff.putVarInt(-1); buff.putVarInt(-1);
buff.putVarLong(k.getId());
return; return;
} }
SpatialKey k = (SpatialKey) obj;
int flags = 0; int flags = 0;
for (int i = 0; i < dimensions; i++) { for (int i = 0; i < dimensions; i++) {
if (k.min(i) == k.max(i)) { if (k.min(i) == k.max(i)) {
...@@ -108,7 +110,8 @@ public class SpatialDataType implements DataType { ...@@ -108,7 +110,8 @@ public class SpatialDataType implements DataType {
public Object read(ByteBuffer buff) { public Object read(ByteBuffer buff) {
int flags = DataUtils.readVarInt(buff); int flags = DataUtils.readVarInt(buff);
if (flags == -1) { if (flags == -1) {
return null; long id = DataUtils.readVarLong(buff);
return new SpatialKey(id);
} }
float[] minMax = new float[dimensions * 2]; float[] minMax = new float[dimensions * 2];
for (int i = 0; i < dimensions; i++) { for (int i = 0; i < dimensions; i++) {
...@@ -136,6 +139,9 @@ public class SpatialDataType implements DataType { ...@@ -136,6 +139,9 @@ public class SpatialDataType implements DataType {
public boolean isOverlap(Object objA, Object objB) { public boolean isOverlap(Object objA, Object objB) {
SpatialKey a = (SpatialKey) objA; SpatialKey a = (SpatialKey) objA;
SpatialKey b = (SpatialKey) objB; SpatialKey b = (SpatialKey) objB;
if (a.isNull() || b.isNull()) {
return false;
}
for (int i = 0; i < dimensions; i++) { for (int i = 0; i < dimensions; i++) {
if (a.max(i) < b.min(i) || a.min(i) > b.max(i)) { if (a.max(i) < b.min(i) || a.min(i) > b.max(i)) {
return false; return false;
...@@ -151,8 +157,11 @@ public class SpatialDataType implements DataType { ...@@ -151,8 +157,11 @@ public class SpatialDataType implements DataType {
* @param add the value * @param add the value
*/ */
public void increaseBounds(Object bounds, Object add) { public void increaseBounds(Object bounds, Object add) {
SpatialKey b = (SpatialKey) bounds;
SpatialKey a = (SpatialKey) add; SpatialKey a = (SpatialKey) add;
SpatialKey b = (SpatialKey) bounds;
if (a.isNull() || b.isNull()) {
return;
}
for (int i = 0; i < dimensions; i++) { for (int i = 0; i < dimensions; i++) {
b.setMin(i, Math.min(b.min(i), a.min(i))); b.setMin(i, Math.min(b.min(i), a.min(i)));
b.setMax(i, Math.max(b.max(i), a.max(i))); b.setMax(i, Math.max(b.max(i), a.max(i)));
...@@ -167,8 +176,11 @@ public class SpatialDataType implements DataType { ...@@ -167,8 +176,11 @@ public class SpatialDataType implements DataType {
* @return the area * @return the area
*/ */
public float getAreaIncrease(Object objA, Object objB) { public float getAreaIncrease(Object objA, Object objB) {
SpatialKey a = (SpatialKey) objA;
SpatialKey b = (SpatialKey) objB; SpatialKey b = (SpatialKey) objB;
SpatialKey a = (SpatialKey) objA;
if (a.isNull() || b.isNull()) {
return 0;
}
float min = a.min(0); float min = a.min(0);
float max = a.max(0); float max = a.max(0);
float areaOld = max - min; float areaOld = max - min;
...@@ -196,6 +208,11 @@ public class SpatialDataType implements DataType { ...@@ -196,6 +208,11 @@ public class SpatialDataType implements DataType {
float getCombinedArea(Object objA, Object objB) { float getCombinedArea(Object objA, Object objB) {
SpatialKey a = (SpatialKey) objA; SpatialKey a = (SpatialKey) objA;
SpatialKey b = (SpatialKey) objB; SpatialKey b = (SpatialKey) objB;
if (a.isNull()) {
return getArea(b);
} else if (b.isNull()) {
return getArea(a);
}
float area = 1; float area = 1;
for (int i = 0; i < dimensions; i++) { for (int i = 0; i < dimensions; i++) {
float min = Math.min(a.min(i), b.min(i)); float min = Math.min(a.min(i), b.min(i));
...@@ -205,6 +222,17 @@ public class SpatialDataType implements DataType { ...@@ -205,6 +222,17 @@ public class SpatialDataType implements DataType {
return area; return area;
} }
private float getArea(SpatialKey a) {
if (a.isNull()) {
return 0;
}
float area = 1;
for (int i = 0; i < dimensions; i++) {
area *= a.max(i) - a.min(i);
}
return area;
}
/** /**
* Check whether a contains b. * Check whether a contains b.
* *
...@@ -215,6 +243,9 @@ public class SpatialDataType implements DataType { ...@@ -215,6 +243,9 @@ public class SpatialDataType implements DataType {
public boolean contains(Object objA, Object objB) { public boolean contains(Object objA, Object objB) {
SpatialKey a = (SpatialKey) objA; SpatialKey a = (SpatialKey) objA;
SpatialKey b = (SpatialKey) objB; SpatialKey b = (SpatialKey) objB;
if (a.isNull() || b.isNull()) {
return false;
}
for (int i = 0; i < dimensions; i++) { for (int i = 0; i < dimensions; i++) {
if (a.min(i) > b.min(i) || a.max(i) < b.max(i)) { if (a.min(i) > b.min(i) || a.max(i) < b.max(i)) {
return false; return false;
...@@ -234,6 +265,9 @@ public class SpatialDataType implements DataType { ...@@ -234,6 +265,9 @@ public class SpatialDataType implements DataType {
public boolean isInside(Object objA, Object objB) { public boolean isInside(Object objA, Object objB) {
SpatialKey a = (SpatialKey) objA; SpatialKey a = (SpatialKey) objA;
SpatialKey b = (SpatialKey) objB; SpatialKey b = (SpatialKey) objB;
if (a.isNull() || b.isNull()) {
return false;
}
for (int i = 0; i < dimensions; i++) { for (int i = 0; i < dimensions; i++) {
if (a.min(i) <= b.min(i) || a.max(i) >= b.max(i)) { if (a.min(i) <= b.min(i) || a.max(i) >= b.max(i)) {
return false; return false;
...@@ -249,8 +283,11 @@ public class SpatialDataType implements DataType { ...@@ -249,8 +283,11 @@ public class SpatialDataType implements DataType {
* @return the bounding box * @return the bounding box
*/ */
Object createBoundingBox(Object objA) { Object createBoundingBox(Object objA) {
float[] minMax = new float[dimensions * 2];
SpatialKey a = (SpatialKey) objA; SpatialKey a = (SpatialKey) objA;
if (a.isNull()) {
return a;
}
float[] minMax = new float[dimensions * 2];
for (int i = 0; i < dimensions; i++) { for (int i = 0; i < dimensions; i++) {
minMax[i + i] = a.min(i); minMax[i + i] = a.min(i);
minMax[i + i + 1] = a.max(i); minMax[i + i + 1] = a.max(i);
...@@ -267,6 +304,10 @@ public class SpatialDataType implements DataType { ...@@ -267,6 +304,10 @@ public class SpatialDataType implements DataType {
* @return the indexes of the extremes * @return the indexes of the extremes
*/ */
public int[] getExtremes(ArrayList<Object> list) { public int[] getExtremes(ArrayList<Object> list) {
list = getNotNull(list);
if (list.size() == 0) {
return null;
}
SpatialKey bounds = (SpatialKey) createBoundingBox(list.get(0)); SpatialKey bounds = (SpatialKey) createBoundingBox(list.get(0));
SpatialKey boundsInner = (SpatialKey) createBoundingBox(bounds); SpatialKey boundsInner = (SpatialKey) createBoundingBox(bounds);
for (int i = 0; i < dimensions; i++) { for (int i = 0; i < dimensions; i++) {
...@@ -311,6 +352,27 @@ public class SpatialDataType implements DataType { ...@@ -311,6 +352,27 @@ public class SpatialDataType implements DataType {
return new int[] { firstIndex, lastIndex }; return new int[] { firstIndex, lastIndex };
} }
ArrayList<Object> getNotNull(ArrayList<Object> list) {
ArrayList<Object> result = null;
for (Object o : list) {
SpatialKey a = (SpatialKey) o;
if (a.isNull()) {
result = New.arrayList();
break;
}
}
if (result == null) {
return list;
}
for (Object o : list) {
SpatialKey a = (SpatialKey) o;
if (!a.isNull()) {
result.add(a);
}
}
return result;
}
private void increaseMaxInnerBounds(Object bounds, Object add) { private void increaseMaxInnerBounds(Object bounds, Object add) {
SpatialKey b = (SpatialKey) bounds; SpatialKey b = (SpatialKey) bounds;
SpatialKey a = (SpatialKey) add; SpatialKey a = (SpatialKey) add;
......
...@@ -70,6 +70,10 @@ public class SpatialKey { ...@@ -70,6 +70,10 @@ public class SpatialKey {
return id; return id;
} }
public boolean isNull() {
return minMax.length == 0;
}
@Override @Override
public String toString() { public String toString() {
StringBuilder buff = new StringBuilder(); StringBuilder buff = new StringBuilder();
......
...@@ -299,7 +299,8 @@ COMMIT TRANSACTION transactionName ...@@ -299,7 +299,8 @@ COMMIT TRANSACTION transactionName
Sets the resolution of an in-doubt transaction to 'commit'." Sets the resolution of an in-doubt transaction to 'commit'."
"Commands (Other)","GRANT RIGHT"," "Commands (Other)","GRANT RIGHT","
GRANT { SELECT | INSERT | UPDATE | DELETE | ALL } [,...] ON GRANT { SELECT | INSERT | UPDATE | DELETE | ALL } [,...] ON
tableName [,...] TO { PUBLIC | userName | roleName } { { SCHEMA schemaName } | { tableName [,...] } }
TO { PUBLIC | userName | roleName }
"," ","
Grants rights for a table to a user or role." Grants rights for a table to a user or role."
"Commands (Other)","GRANT ALTER ANY SCHEMA"," "Commands (Other)","GRANT ALTER ANY SCHEMA","
...@@ -320,7 +321,8 @@ PREPARE COMMIT newTransactionName ...@@ -320,7 +321,8 @@ PREPARE COMMIT newTransactionName
Prepares committing a transaction." Prepares committing a transaction."
"Commands (Other)","REVOKE RIGHT"," "Commands (Other)","REVOKE RIGHT","
REVOKE { SELECT | INSERT | UPDATE | DELETE | ALL } [,...] ON REVOKE { SELECT | INSERT | UPDATE | DELETE | ALL } [,...] ON
tableName [,...] FROM { PUBLIC | userName | roleName } { { SCHEMA schemaName } | { tableName [,...] } }
FROM { PUBLIC | userName | roleName }
"," ","
Removes rights for a table from a user or role." Removes rights for a table from a user or role."
"Commands (Other)","REVOKE ROLE"," "Commands (Other)","REVOKE ROLE","
......
...@@ -151,7 +151,7 @@ public class WebApp { ...@@ -151,7 +151,7 @@ public class WebApp {
"jsp".equals(suffix)) { "jsp".equals(suffix)) {
cache = false; cache = false;
mimeType = "text/html"; mimeType = "text/html";
if (session == null && !file.startsWith(WebServer.TRANSFER)) { if (session == null) {
session = server.createNewSession(hostAddr); session = server.createNewSession(hostAddr);
if (!"notAllowed.jsp".equals(file)) { if (!"notAllowed.jsp".equals(file)) {
file = "index.do"; file = "index.do";
...@@ -239,8 +239,6 @@ public class WebApp { ...@@ -239,8 +239,6 @@ public class WebApp {
file = autoCompleteList(); file = autoCompleteList();
} else if ("tools.do".equals(file)) { } else if ("tools.do".equals(file)) {
file = tools(); file = tools();
} else if ("transfer.do".equals(file)) {
file = "transfer.jsp";
} else { } else {
file = "error.jsp"; file = "error.jsp";
} }
......
...@@ -6,7 +6,6 @@ ...@@ -6,7 +6,6 @@
package org.h2.server.web; package org.h2.server.web;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
...@@ -32,7 +31,6 @@ import org.h2.message.DbException; ...@@ -32,7 +31,6 @@ import org.h2.message.DbException;
import org.h2.server.Service; import org.h2.server.Service;
import org.h2.server.ShutdownHandler; import org.h2.server.ShutdownHandler;
import org.h2.store.fs.FileUtils; import org.h2.store.fs.FileUtils;
import org.h2.util.IOUtils;
import org.h2.util.JdbcUtils; import org.h2.util.JdbcUtils;
import org.h2.util.MathUtils; import org.h2.util.MathUtils;
import org.h2.util.NetUtils; import org.h2.util.NetUtils;
...@@ -48,8 +46,6 @@ import org.h2.util.Utils; ...@@ -48,8 +46,6 @@ import org.h2.util.Utils;
*/ */
public class WebServer implements Service { public class WebServer implements Service {
static final String TRANSFER = "transfer";
static final String[][] LANGUAGES = { static final String[][] LANGUAGES = {
{ "cs", "\u010ce\u0161tina" }, { "cs", "\u010ce\u0161tina" },
{ "de", "Deutsch" }, { "de", "Deutsch" },
...@@ -170,17 +166,6 @@ public class WebServer implements Service { ...@@ -170,17 +166,6 @@ public class WebServer implements Service {
*/ */
byte[] getFile(String file) throws IOException { byte[] getFile(String file) throws IOException {
trace("getFile <" + file + ">"); trace("getFile <" + file + ">");
if (file.startsWith(TRANSFER + "/") && new File(TRANSFER).exists()) {
file = file.substring(TRANSFER.length() + 1);
if (!isSimpleName(file)) {
return null;
}
File f = new File(TRANSFER, file);
if (!f.exists()) {
return null;
}
return IOUtils.readBytesAndClose(new FileInputStream(f), -1);
}
byte[] data = Utils.getResource("/org/h2/server/web/res/" + file); byte[] data = Utils.getResource("/org/h2/server/web/res/" + file);
if (data == null) { if (data == null) {
trace(" null"); trace(" null");
......
...@@ -7,12 +7,9 @@ package org.h2.server.web; ...@@ -7,12 +7,9 @@ package org.h2.server.web;
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
import java.io.BufferedOutputStream; import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.net.Socket; import java.net.Socket;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.util.Iterator; import java.util.Iterator;
...@@ -37,7 +34,6 @@ class WebThread extends WebApp implements Runnable { ...@@ -37,7 +34,6 @@ class WebThread extends WebApp implements Runnable {
protected final Socket socket; protected final Socket socket;
private final Thread thread; private final Thread thread;
private InputStream input; private InputStream input;
private int headerBytes;
private String ifModifiedSince; private String ifModifiedSince;
WebThread(Socket socket, WebServer server) { WebThread(Socket socket, WebServer server) {
...@@ -210,12 +206,10 @@ class WebThread extends WebApp implements Runnable { ...@@ -210,12 +206,10 @@ class WebThread extends WebApp implements Runnable {
private String readHeaderLine() throws IOException { private String readHeaderLine() throws IOException {
StringBuilder buff = new StringBuilder(); StringBuilder buff = new StringBuilder();
while (true) { while (true) {
headerBytes++;
int c = input.read(); int c = input.read();
if (c == -1) { if (c == -1) {
throw new IOException("Unexpected EOF"); throw new IOException("Unexpected EOF");
} else if (c == '\r') { } else if (c == '\r') {
headerBytes++;
if (input.read() == '\n') { if (input.read() == '\n') {
return buff.length() > 0 ? buff.toString() : null; return buff.length() > 0 ? buff.toString() : null;
} }
...@@ -320,7 +314,7 @@ class WebThread extends WebApp implements Runnable { ...@@ -320,7 +314,7 @@ class WebThread extends WebApp implements Runnable {
} }
} }
if (multipart) { if (multipart) {
uploadMultipart(input, len); // not supported
} else if (session != null && len > 0) { } else if (session != null && len > 0) {
byte[] bytes = DataUtils.newBytes(len); byte[] bytes = DataUtils.newBytes(len);
for (int pos = 0; pos < len;) { for (int pos = 0; pos < len;) {
...@@ -332,45 +326,6 @@ class WebThread extends WebApp implements Runnable { ...@@ -332,45 +326,6 @@ class WebThread extends WebApp implements Runnable {
return keepAlive; return keepAlive;
} }
private void uploadMultipart(InputStream in, int len) throws IOException {
if (!new File(WebServer.TRANSFER).exists()) {
return;
}
String fileName = "temp.bin";
headerBytes = 0;
String boundary = readHeaderLine();
while (true) {
String line = readHeaderLine();
if (line == null) {
break;
}
int index = line.indexOf("filename=\"");
if (index > 0) {
fileName = line.substring(index +
"filename=\"".length(), line.lastIndexOf('"'));
}
trace(" " + line);
}
if (!WebServer.isSimpleName(fileName)) {
return;
}
len -= headerBytes;
File file = new File(WebServer.TRANSFER, fileName);
OutputStream out = new FileOutputStream(file);
IOUtils.copy(in, out, len);
out.close();
// remove the boundary
RandomAccessFile f = new RandomAccessFile(file, "rw");
int testSize = (int) Math.min(f.length(), Constants.IO_BUFFER_SIZE);
f.seek(f.length() - testSize);
byte[] bytes = DataUtils.newBytes(Constants.IO_BUFFER_SIZE);
f.readFully(bytes, 0, testSize);
String s = new String(bytes, "ASCII");
int x = s.lastIndexOf(boundary);
f.setLength(f.length() - testSize + x - 2);
f.close();
}
private static String getHeaderLineValue(String line) { private static String getHeaderLineValue(String line) {
return line.substring(line.indexOf(':') + 1).trim(); return line.substring(line.indexOf(':') + 1).trim();
} }
......
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<!--
Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
and the EPL 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>Upload</title>
<link rel="stylesheet" type="text/css" href="stylesheet.css" />
</head>
<body>
<form action="transfer.do" method="post" enctype="multipart/form-data">
<p>
File:<br />
<input name="file" type="file" size="50" /><br /><br />
<input type="submit" value="Upload" />
</p>
</form>
</body></html>
...@@ -352,7 +352,7 @@ public class FileLock implements Runnable { ...@@ -352,7 +352,7 @@ public class FileLock implements Runnable {
save(); save();
sleep(2 * sleep); sleep(2 * sleep);
if (!load().equals(properties)) { if (!load().equals(properties)) {
throw getExceptionAlreadyInUse("Locked by another process"); throw getExceptionAlreadyInUse("Locked by another process: " + fileName);
} }
FileUtils.delete(fileName); FileUtils.delete(fileName);
if (!FileUtils.createFile(fileName)) { if (!FileUtils.createFile(fileName)) {
......
...@@ -246,7 +246,7 @@ public class LobStorageMap implements LobStorageInterface { ...@@ -246,7 +246,7 @@ public class LobStorageMap implements LobStorageInterface {
throw DbException.throwInternalError("Length is different"); throw DbException.throwInternalError("Length is different");
} }
Object[] value = lobMap.get(oldLobId); Object[] value = lobMap.get(oldLobId);
value = Arrays.copyOf(value, value.length); value = value.clone();
byte[] streamStoreId = (byte[]) value[0]; byte[] streamStoreId = (byte[]) value[0];
long lobId = generateLobId(); long lobId = generateLobId();
value[1] = tableId; value[1] = tableId;
......
...@@ -474,7 +474,7 @@ public class FilePathEncrypt extends FilePathWrapper { ...@@ -474,7 +474,7 @@ public class FilePathEncrypt extends FilePathWrapper {
updateTweak(tweak); updateTweak(tweak);
if (i + CIPHER_BLOCK_SIZE + CIPHER_BLOCK_SIZE > len && if (i + CIPHER_BLOCK_SIZE + CIPHER_BLOCK_SIZE > len &&
i + CIPHER_BLOCK_SIZE < len) { i + CIPHER_BLOCK_SIZE < len) {
tweakEnd = Arrays.copyOf(tweak, CIPHER_BLOCK_SIZE); tweakEnd = tweak.clone();
updateTweak(tweak); updateTweak(tweak);
} }
} }
......
...@@ -312,14 +312,14 @@ public class FileUtils { ...@@ -312,14 +312,14 @@ public class FileUtils {
} }
/** /**
* Try to delete a file (ignore errors). * Try to delete a file or directory (ignoring errors).
* *
* @param fileName the file name * @param path the file or directory name
* @return true if it worked * @return true if it worked
*/ */
public static boolean tryDelete(String fileName) { public static boolean tryDelete(String path) {
try { try {
FilePath.get(fileName).delete(); FilePath.get(path).delete();
return true; return true;
} catch (Exception e) { } catch (Exception e) {
return false; return false;
......
...@@ -893,6 +893,7 @@ public class MetaTable extends Table { ...@@ -893,6 +893,7 @@ public class MetaTable extends Table {
add(rows, Table.TABLE_LINK); add(rows, Table.TABLE_LINK);
add(rows, Table.SYSTEM_TABLE); add(rows, Table.SYSTEM_TABLE);
add(rows, Table.VIEW); add(rows, Table.VIEW);
add(rows, Table.EXTERNAL_TABLE_ENGINE);
break; break;
} }
case CATALOGS: { case CATALOGS: {
...@@ -1127,8 +1128,19 @@ public class MetaTable extends Table { ...@@ -1127,8 +1128,19 @@ public class MetaTable extends Table {
String rightType = grantee.getType() == DbObject.USER ? String rightType = grantee.getType() == DbObject.USER ?
"USER" : "ROLE"; "USER" : "ROLE";
if (role == null) { if (role == null) {
Table granted = r.getGrantedTable(); DbObject object = r.getGrantedObject();
String tableName = identifier(granted.getName()); Schema schema = null;
Table table = null;
if (object != null) {
if (object instanceof Schema) {
schema = (Schema) object;
} else if (object instanceof Table) {
table = (Table) object;
schema = table.getSchema();
}
}
String tableName = (table != null) ? identifier(table.getName()) : "";
String schemaName = (schema != null) ? identifier(schema.getName()) : "";
if (!checkIndex(session, tableName, indexFrom, indexTo)) { if (!checkIndex(session, tableName, indexFrom, indexTo)) {
continue; continue;
} }
...@@ -1142,9 +1154,9 @@ public class MetaTable extends Table { ...@@ -1142,9 +1154,9 @@ public class MetaTable extends Table {
// RIGHTS // RIGHTS
r.getRights(), r.getRights(),
// TABLE_SCHEMA // TABLE_SCHEMA
identifier(granted.getSchema().getName()), schemaName,
// TABLE_NAME // TABLE_NAME
identifier(granted.getName()), tableName,
// ID // ID
"" + r.getId() "" + r.getId()
); );
...@@ -1374,7 +1386,11 @@ public class MetaTable extends Table { ...@@ -1374,7 +1386,11 @@ public class MetaTable extends Table {
} }
case TABLE_PRIVILEGES: { case TABLE_PRIVILEGES: {
for (Right r : database.getAllRights()) { for (Right r : database.getAllRights()) {
Table table = r.getGrantedTable(); DbObject object = r.getGrantedObject();
if (!(object instanceof Table)) {
continue;
}
Table table = (Table) object;
if (table == null || hideTable(table, session)) { if (table == null || hideTable(table, session)) {
continue; continue;
} }
...@@ -1389,7 +1405,11 @@ public class MetaTable extends Table { ...@@ -1389,7 +1405,11 @@ public class MetaTable extends Table {
} }
case COLUMN_PRIVILEGES: { case COLUMN_PRIVILEGES: {
for (Right r : database.getAllRights()) { for (Right r : database.getAllRights()) {
Table table = r.getGrantedTable(); DbObject object = r.getGrantedObject();
if (!(object instanceof Table)) {
continue;
}
Table table = (Table) object;
if (table == null || hideTable(table, session)) { if (table == null || hideTable(table, session)) {
continue; continue;
} }
......
...@@ -385,7 +385,7 @@ public abstract class Table extends SchemaObjectBase { ...@@ -385,7 +385,7 @@ public abstract class Table extends SchemaObjectBase {
} }
ArrayList<Right> rights = database.getAllRights(); ArrayList<Right> rights = database.getAllRights();
for (Right right : rights) { for (Right right : rights) {
if (right.getGrantedTable() == this) { if (right.getGrantedObject() == this) {
children.add(right); children.add(right);
} }
} }
...@@ -510,7 +510,7 @@ public abstract class Table extends SchemaObjectBase { ...@@ -510,7 +510,7 @@ public abstract class Table extends SchemaObjectBase {
database.removeSchemaObject(session, constraint); database.removeSchemaObject(session, constraint);
} }
for (Right right : database.getAllRights()) { for (Right right : database.getAllRights()) {
if (right.getGrantedTable() == this) { if (right.getGrantedObject() == this) {
database.removeDatabaseObject(session, right); database.removeDatabaseObject(session, right);
} }
} }
......
...@@ -14,6 +14,7 @@ import java.sql.Statement; ...@@ -14,6 +14,7 @@ import java.sql.Statement;
import java.sql.Types; import java.sql.Types;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import org.h2.api.ErrorCode; import org.h2.api.ErrorCode;
import org.h2.command.Prepared; import org.h2.command.Prepared;
...@@ -334,7 +335,19 @@ public class TableLink extends Table { ...@@ -334,7 +335,19 @@ public class TableLink extends Table {
return columnName; return columnName;
} }
private void addIndex(ArrayList<Column> list, IndexType indexType) { private void addIndex(List<Column> list, IndexType indexType) {
// bind the index to the leading recognized columns in the index
// (null columns might come from a function-based index)
int firstNull = list.indexOf(null);
if (firstNull == 0) {
trace.info("Omitting linked index - no recognized columns.");
return;
} else if (firstNull > 0) {
trace.info("Unrecognized columns in linked index. " +
"Registering the index against the leading {0} " +
"recognized columns of {1} total columns.", firstNull, list.size());
list = list.subList(0, firstNull);
}
Column[] cols = new Column[list.size()]; Column[] cols = new Column[list.size()];
list.toArray(cols); list.toArray(cols);
Index index = new LinkedIndex(this, 0, IndexColumn.wrap(cols), indexType); Index index = new LinkedIndex(this, 0, IndexColumn.wrap(cols), indexType);
......
...@@ -45,14 +45,16 @@ public class Profiler implements Runnable { ...@@ -45,14 +45,16 @@ public class Profiler implements Runnable {
"sun," + "sun," +
"com.sun.," + "com.sun.," +
"com.google.common.," + "com.google.common.," +
"com.mongodb." "com.mongodb.," +
"org.bson.,"
).split(","); ).split(",");
private final String[] ignorePackages = ( private final String[] ignorePackages = (
"java," + "java," +
"sun," + "sun," +
"com.sun.," + "com.sun.," +
"com.google.common.," + "com.google.common.," +
"com.mongodb." "com.mongodb.," +
"org.bson"
).split(","); ).split(",");
private final String[] ignoreThreads = ( private final String[] ignoreThreads = (
"java.lang.Object.wait," + "java.lang.Object.wait," +
......
...@@ -282,8 +282,11 @@ public class SourceCompiler { ...@@ -282,8 +282,11 @@ public class SourceCompiler {
.getStandardFileManager(null, null, null)); .getStandardFileManager(null, null, null));
ArrayList<JavaFileObject> compilationUnits = new ArrayList<JavaFileObject>(); ArrayList<JavaFileObject> compilationUnits = new ArrayList<JavaFileObject>();
compilationUnits.add(new StringJavaFileObject(fullClassName, source)); compilationUnits.add(new StringJavaFileObject(fullClassName, source));
JAVA_COMPILER.getTask(writer, fileManager, null, null, // can not concurrently compile
synchronized (JAVA_COMPILER) {
JAVA_COMPILER.getTask(writer, fileManager, null, null,
null, compilationUnits).call(); null, compilationUnits).call();
}
String err = writer.toString(); String err = writer.toString();
throwSyntaxError(err); throwSyntaxError(err);
try { try {
...@@ -333,7 +336,7 @@ public class SourceCompiler { ...@@ -333,7 +336,7 @@ public class SourceCompiler {
}.execute(); }.execute();
} }
private static void javacSun(File javaFile) { private static synchronized void javacSun(File javaFile) {
PrintStream old = System.err; PrintStream old = System.err;
ByteArrayOutputStream buff = new ByteArrayOutputStream(); ByteArrayOutputStream buff = new ByteArrayOutputStream();
PrintStream temp = new PrintStream(buff); PrintStream temp = new PrintStream(buff);
...@@ -344,6 +347,7 @@ public class SourceCompiler { ...@@ -344,6 +347,7 @@ public class SourceCompiler {
Object javac = JAVAC_SUN.newInstance(); Object javac = JAVAC_SUN.newInstance();
compile.invoke(javac, (Object) new String[] { compile.invoke(javac, (Object) new String[] {
"-sourcepath", COMPILE_DIR, "-sourcepath", COMPILE_DIR,
// "-Xlint:unchecked",
"-d", COMPILE_DIR, "-d", COMPILE_DIR,
"-encoding", "UTF-8", "-encoding", "UTF-8",
javaFile.getAbsolutePath() }); javaFile.getAbsolutePath() });
......
...@@ -95,7 +95,7 @@ $$<rdf:RDF xmlns="http://usefulinc.com/ns/doap#" xmlns:rdf="http://www.w3.org/19 ...@@ -95,7 +95,7 @@ $$<rdf:RDF xmlns="http://usefulinc.com/ns/doap#" xmlns:rdf="http://www.w3.org/19
<category rdf:resource="http://projects.apache.org/category/library"/> <category rdf:resource="http://projects.apache.org/category/library"/>
<category rdf:resource="http://projects.apache.org/category/network-server"/> <category rdf:resource="http://projects.apache.org/category/network-server"/>
<license rdf:resource="http://usefulinc.com/doap/licenses/mpl"/> <license rdf:resource="http://usefulinc.com/doap/licenses/mpl"/>
<bug-database rdf:resource="http://code.google.com/p/h2database/issues/list"/> <bug-database rdf:resource="https://github.com/h2database/h2database/issues"/>
<download-page rdf:resource="http://h2database.com/html/download.html"/> <download-page rdf:resource="http://h2database.com/html/download.html"/>
<shortdesc xml:lang="en">H2 Database Engine</shortdesc> <shortdesc xml:lang="en">H2 Database Engine</shortdesc>
<description xml:lang="en"> <description xml:lang="en">
...@@ -110,8 +110,8 @@ $$<rdf:RDF xmlns="http://usefulinc.com/ns/doap#" xmlns:rdf="http://www.w3.org/19 ...@@ -110,8 +110,8 @@ $$<rdf:RDF xmlns="http://usefulinc.com/ns/doap#" xmlns:rdf="http://www.w3.org/19
</description> </description>
<repository> <repository>
<SVNRepository> <SVNRepository>
<browse rdf:resource="http://code.google.com/p/h2database/source/browse"/> <browse rdf:resource="https://github.com/h2database/h2database"/>
<location rdf:resource="http://h2database.googlecode.com/svn/trunk"/> <location rdf:resource="https://github.com/h2database/h2database"/>
</SVNRepository> </SVNRepository>
</repository> </repository>
<mailing-list rdf:resource="http://groups.google.com/group/h2-database"/> <mailing-list rdf:resource="http://groups.google.com/group/h2-database"/>
......
...@@ -33,8 +33,8 @@ public class TestAlter extends TestBase { ...@@ -33,8 +33,8 @@ public class TestAlter extends TestBase {
@Override @Override
public void test() throws Exception { public void test() throws Exception {
deleteDb("alter"); deleteDb(getTestName());
conn = getConnection("alter"); conn = getConnection(getTestName());
stat = conn.createStatement(); stat = conn.createStatement();
testAlterTableAlterColumnAsSelfColumn(); testAlterTableAlterColumnAsSelfColumn();
testAlterTableDropColumnWithReferences(); testAlterTableDropColumnWithReferences();
...@@ -49,7 +49,7 @@ public class TestAlter extends TestBase { ...@@ -49,7 +49,7 @@ public class TestAlter extends TestBase {
testAlterTableAddColumnAfter(); testAlterTableAddColumnAfter();
testAlterTableModifyColumn(); testAlterTableModifyColumn();
conn.close(); conn.close();
deleteDb("alter"); deleteDb(getTestName());
} }
private void testAlterTableAlterColumnAsSelfColumn() throws SQLException { private void testAlterTableAlterColumnAsSelfColumn() throws SQLException {
...@@ -121,7 +121,7 @@ public class TestAlter extends TestBase { ...@@ -121,7 +121,7 @@ public class TestAlter extends TestBase {
stat.execute("alter table test alter id rename to id2"); stat.execute("alter table test alter id rename to id2");
// disconnect and reconnect // disconnect and reconnect
conn.close(); conn.close();
conn = getConnection("alter"); conn = getConnection(getTestName());
stat = conn.createStatement(); stat = conn.createStatement();
stat.execute("insert into test values(1)"); stat.execute("insert into test values(1)");
assertThrows(ErrorCode.CHECK_CONSTRAINT_VIOLATED_1, stat). assertThrows(ErrorCode.CHECK_CONSTRAINT_VIOLATED_1, stat).
......
...@@ -145,6 +145,18 @@ public class TestCases extends TestBase { ...@@ -145,6 +145,18 @@ public class TestCases extends TestBase {
"foreign key(a_id) references a(id)"); "foreign key(a_id) references a(id)");
stat.execute("update a set x=200"); stat.execute("update a set x=200");
stat.execute("drop table if exists a, b"); stat.execute("drop table if exists a, b");
stat.execute("drop all objects");
stat.execute("create table parent(id int primary key)");
stat.execute("create table child(id int, parent_id int, x int)");
stat.execute("create index y on child(parent_id, x)");
stat.execute("alter table child add constraint z " +
"foreign key(parent_id) references parent(id)");
ResultSet rs = stat.executeQuery(
"select * from information_schema.indexes where table_name = 'CHILD'");
while (rs.next()) {
assertEquals("Y", rs.getString("index_name"));
}
conn.close(); conn.close();
} }
......
差异被折叠。
...@@ -771,3 +771,4 @@ young sweep clearer accounting disappeared donor oome ken jorissen nesterov ...@@ -771,3 +771,4 @@ young sweep clearer accounting disappeared donor oome ken jorissen nesterov
degradation failures fashion disjunctive mentioned conjunctive misses broke degradation failures fashion disjunctive mentioned conjunctive misses broke
authenticate orphaned registrations topology planner authenticate orphaned registrations topology planner
zepfred frederico thimel arnaud manipulating strongly lots aquiles younger needing zepfred frederico thimel arnaud manipulating strongly lots aquiles younger needing
unrecognized five omitting registering
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论