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

--no commit message

--no commit message
上级 0b2f337b
......@@ -3201,7 +3201,7 @@ public class Parser {
} else if (readIf("USER")) {
return parseCreateUser();
} else if (readIf("TRIGGER")) {
return parseCreateTrigger();
return parseCreateTrigger(force);
} else if (readIf("ROLE")) {
return parseCreateRole();
} else if (readIf("SCHEMA")) {
......@@ -3421,7 +3421,7 @@ public class Parser {
return command;
}
private CreateTrigger parseCreateTrigger() throws SQLException {
private CreateTrigger parseCreateTrigger(boolean force) throws SQLException {
boolean ifNotExists = readIfNoExists();
String triggerName = readIdentifierWithSchema(null);
Schema schema = getSchema();
......@@ -3448,6 +3448,7 @@ public class Parser {
String tableName = readIdentifierWithSchema();
checkSchema(schema);
CreateTrigger command = new CreateTrigger(session, getSchema());
command.setForce(force);
command.setTriggerName(triggerName);
command.setIfNotExists(ifNotExists);
command.setBefore(isBefore);
......
......@@ -30,6 +30,7 @@ public class CreateTrigger extends SchemaCommand {
private boolean noWait;
private String tableName;
private String triggerClassName;
private boolean force;
public CreateTrigger(Session session, Schema schema) {
super(session, schema);
......@@ -90,10 +91,14 @@ public class CreateTrigger extends SchemaCommand {
trigger.setQueueSize(queueSize);
trigger.setRowBased(rowBased);
trigger.setTypeMask(typeMask);
trigger.setTriggerClassName(session, triggerClassName);
trigger.setTriggerClassName(session, triggerClassName, force);
db.addSchemaObject(session, trigger);
table.addTrigger(trigger);
return 0;
}
public void setForce(boolean force) {
this.force = force;
}
}
......@@ -4,6 +4,9 @@
*/
package org.h2.constant;
import java.sql.SQLException;
import java.sql.Savepoint;
/**
* This class defines the error codes used for SQL exceptions.
*/
......@@ -895,7 +898,19 @@ public class ErrorCode {
*/
public static final int UNSUPPORTED_CIPHER = 90055;
private int todo;
/**
* The error with code <code>90056</code> is thrown when
* updating or deleting from a table with a foreign key constraint
* that should set the default value, but there is no default value defined.
* Example:
* <pre>
* CREATE TABLE TEST(ID INT, PARENT INT);
* INSERT INTO TEST VALUES(1, 1), (2, 1);
* ALTER TABLE TEST ADD CONSTRAINT TEST_ID_PARENT
* FOREIGN KEY(PARENT) REFERENCES(ID) ON DELETE SET DEFAULT;
* DELETE FROM TEST WHERE ID=1;
* </pre>
*/
public static final int NO_DEFAULT_SET_1 = 90056;
/**
......@@ -908,7 +923,6 @@ public class ErrorCode {
* </pre>
*/
public static final int CONSTRAINT_NOT_FOUND_1 = 90057;
public static final int DUPLICATE_TABLE_ALIAS = 90058;
/**
* The error with code <code>90059</code> is thrown when
......@@ -921,6 +935,16 @@ public class ErrorCode {
* </pre>
*/
public static final int AMBIGUOUS_COLUMN_NAME_1 = 90059;
/**
* The error with code <code>90060</code> is thrown when
* trying to use a file locking mechanism that is not supported.
* Currently only FILE (the default) and SOCKET are supported
* Example:
* <pre>
* jdbc:h2:test;FILE_LOCK=LDAP
* </pre>
*/
public static final int UNSUPPORTED_LOCK_METHOD_1 = 90060;
/**
......@@ -929,6 +953,14 @@ public class ErrorCode {
* It could also be a firewall problem.
*/
public static final int EXCEPTION_OPENING_PORT_2 = 90061;
/**
* The error with code <code>90062</code> is thrown when
* a directory or file could not be created. This can occur when
* trying to create a directory if a file with the same name already
* exists, or vice versa.
*
*/
public static final int FILE_CREATION_FAILED_1 = 90062;
/**
......@@ -940,9 +972,46 @@ public class ErrorCode {
* </pre>
*/
public static final int SAVEPOINT_IS_INVALID_1 = 90063;
/**
* The error with code <code>90064</code> is thrown when
* Savepoint.getSavepointName() is called on an unnamed savepoint.
* Example:
* <pre>
* Savepoint sp = conn.setSavepoint();
* sp.getSavepointName();
* </pre>
*/
public static final int SAVEPOINT_IS_UNNAMED = 90064;
/**
* The error with code <code>90065</code> is thrown when
* Savepoint.getSavepointId() is called on a named savepoint.
* Example:
* <pre>
* Savepoint sp = conn.setSavepoint("Joe");
* sp.getSavepointId();
* </pre>
*/
public static final int SAVEPOINT_IS_NAMED = 90065;
/**
* The error with code <code>90066</code> is thrown when
* the same property appears twice in the database URL or in
* the connection properties.
* Example:
* <pre>
* jdbc:h2:test;LOG=0;LOG=1
* </pre>
*/
public static final int DUPLICATE_PROPERTY_1 = 90066;
/**
* The error with code <code>90067</code> is thrown when
* the connection to the database is lost. A possible reason
* is that the connection has been closed due to a shutdown,
* or that the server is stopped.
*/
public static final int CONNECTION_BROKEN = 90067;
/**
......@@ -961,11 +1030,69 @@ public class ErrorCode {
* </pre>
*/
public static final int ORDER_BY_NOT_IN_RESULT = 90068;
/**
* The error with code <code>90069</code> is thrown when
* trying to create a role if an object with this name already exists.
* Example:
* <pre>
* CREATE ROLE TEST_ROLE;
* CREATE ROLE TEST_ROLE;
* </pre>
*/
public static final int ROLE_ALREADY_EXISTS_1 = 90069;
/**
* The error with code <code>90070</code> is thrown when
* trying to drop or grant a role that does not exists.
* Example:
* <pre>
* DROP ROLE TEST_ROLE_2;
* </pre>
*/
public static final int ROLE_NOT_FOUND_1 = 90070;
/**
* The error with code <code>90071</code> is thrown when
* trying to grant or revoke if no role or user with that name exists.
* Example:
* <pre>
* GRANT SELECT ON TEST TO UNKNOWN;
* </pre>
*/
public static final int USER_OR_ROLE_NOT_FOUND_1 = 90071;
/**
* The error with code <code>90072</code> is thrown when
* trying to grant or revoke if no role or user with that name exists.
* Example:
* <pre>
* GRANT SELECT, TEST_ROLE ON TEST TO SA;
* </pre>
*/
public static final int ROLES_AND_RIGHT_CANNOT_BE_MIXED = 90072;
/**
* The error with code <code>90073</code> is thrown when
* trying to revoke a right that does not or no longer exist.
* Example:
* <pre>
* CREATE USER TEST_USER PASSWORD 'abc';
* REVOKE SELECT ON TEST FROM TEST_USER;
* </pre>
*/
public static final int RIGHT_NOT_FOUND = 90073;
/**
* The error with code <code>90074</code> is thrown when
* trying to grant a role that has already been granted.
* Example:
* <pre>
* CREATE ROLE TEST_ROLE;
* GRANT TEST_ROLE TO SA;
* GRANT TEST_ROLE TO SA;
* </pre>
*/
public static final int ROLE_ALREADY_GRANTED_1 = 90074;
/**
......@@ -990,6 +1117,9 @@ public class ErrorCode {
* </pre>
*/
public static final int FUNCTION_ALIAS_ALREADY_EXISTS_1 = 90076;
private int todo44;
public static final int FUNCTION_ALIAS_NOT_FOUND_1 = 90077;
public static final int SCHEMA_ALREADY_EXISTS_1 = 90078;
public static final int SCHEMA_NOT_FOUND_1 = 90079;
......@@ -1240,6 +1370,8 @@ public class ErrorCode {
*/
public static final int CAN_ONLY_ASSIGN_TO_VARIABLE_1 = 90137;
// next is 90058
/**
* INTERNAL
*/
......
......@@ -401,9 +401,6 @@ private int test;
* INTERNAL
*/
public static int getLogFileDeleteDelay() {
int test;
return getIntSetting(H2_LOG_DELETE_DELAY, 0);
// return getIntSetting(H2_LOG_DELETE_DELAY, 100);
// return getIntSetting(H2_LOG_DELETE_DELAY, Integer.MAX_VALUE);
}
}
......@@ -73,7 +73,7 @@ public class Constants {
public static final int BUILD_ID = 66;
private static final String BUILD = "2008-02-02";
public static final int VERSION_MAJOR = 1;
public static final int VERSION_MINOR = 0;
......@@ -172,8 +172,19 @@ public class Constants {
public static final int VIEW_COST_CACHE_MAX_AGE = 10000; // 10 seconds
public static final int MAX_PARAMETER_INDEX = 100000;
// to slow down dictionary attacks
/**
* The password is hashed this many times
* to slow down dictionary attacks.
*/
public static final int ENCRYPTION_KEY_HASH_ITERATIONS = 1024;
public static final String SCRIPT_SQL = "script.sql";
public static final int CACHE_MIN_RECORDS = 16;
/**
* The delay in milliseconds before an exception about
* a wrong user or password is thrown.
* This slows down dictionary attacks.
* An attacker can still open multiple connections.
*/
public static final long DELAY_WRONG_PASSWORD = 200;
}
......@@ -160,6 +160,13 @@ public class Database implements DataHandler {
String lockMethodName = ci.removeProperty("FILE_LOCK", null);
this.accessModeLog = ci.removeProperty("ACCESS_MODE_LOG", "rw").toLowerCase();
this.accessModeData = ci.removeProperty("ACCESS_MODE_DATA", "rw").toLowerCase();
int testing;
if ("r".equals(accessModeData)) {
readOnly = true;
accessModeLog = "r";
}
this.fileLockMethod = FileLock.getFileLockMethod(lockMethodName);
this.textStorage = ci.getTextStorage();
this.databaseURL = ci.getURL();
......@@ -380,6 +387,11 @@ public class Database implements DataHandler {
public void checkFilePasswordHash(String c, byte[] hash) throws SQLException {
if (!ByteUtils.compareSecure(hash, filePasswordHash) || !StringUtils.equals(c, cipher)) {
try {
Thread.sleep(Constants.DELAY_WRONG_PASSWORD);
} catch (InterruptedException e) {
// ignore
}
throw Message.getSQLException(ErrorCode.WRONG_USER_OR_PASSWORD);
}
}
......@@ -419,7 +431,12 @@ public class Database implements DataHandler {
if (persistent) {
String dataFileName = databaseName + Constants.SUFFIX_DATA_FILE;
if (FileUtils.exists(dataFileName)) {
readOnly = FileUtils.isReadOnly(dataFileName);
int testingReadOnly;
// if it is already read-only because ACCESS_MODE_DATA=r
readOnly = readOnly | FileUtils.isReadOnly(dataFileName);
// readOnly = FileUtils.isReadOnly(dataFileName);
textStorage = isTextStorage(dataFileName, textStorage);
}
}
......@@ -767,6 +784,11 @@ public class Database implements DataHandler {
public User getUser(String name, SQLException notFound) throws SQLException {
User user = (User) users.get(name);
if (user == null) {
try {
Thread.sleep(Constants.DELAY_WRONG_PASSWORD);
} catch (InterruptedException e) {
// ignore
}
throw notFound;
}
return user;
......
......@@ -126,6 +126,11 @@ public class User extends RightOwner {
SHA256 sha = new SHA256();
byte[] hash = sha.getHashWithSalt(buff, salt);
if (!ByteUtils.compareSecure(hash, passwordHash)) {
try {
Thread.sleep(Constants.DELAY_WRONG_PASSWORD);
} catch (InterruptedException e) {
// ignore
}
throw onError;
}
}
......
......@@ -9,9 +9,11 @@ import java.util.Comparator;
import java.util.HashMap;
import org.h2.api.DatabaseEventListener;
import org.h2.constant.SysProperties;
import org.h2.engine.Constants;
import org.h2.engine.Database;
import org.h2.engine.Session;
import org.h2.message.Message;
import org.h2.message.Trace;
import org.h2.store.DataPage;
import org.h2.store.DiskFile;
......@@ -257,6 +259,19 @@ public class LogSystem {
LogFile l = new LogFile(this, 0, fileNamePrefix);
activeLogs.add(l);
}
int checkNoMissing;
if(SysProperties.getIntSetting(SysProperties.H2_LOG_DELETE_DELAY, 0) > 0) {
LogFile last = null;
for(int i=0; i<activeLogs.size();i++) {
LogFile current = (LogFile) activeLogs.get(i);
if(last != null && last.getId() + 1 != current.getId()) {
throw Message.getInternalError("Miissing log file: " + last.getId() + ", " + current.getId());
}
last = current;
}
}
currentLog = (LogFile) activeLogs.get(activeLogs.size() - 1);
}
......
......@@ -47,8 +47,10 @@ public class TriggerObject extends SchemaObjectBase {
this.before = before;
}
public void setTriggerClassName(Session session, String triggerClassName) throws SQLException {
this.triggerClassName = triggerClassName;
private synchronized void load(Session session) throws SQLException {
if (triggerCallback != null) {
return;
}
try {
Connection c2 = session.createConnection(false);
Object obj = session.getDatabase().loadUserClass(triggerClassName).newInstance();
......@@ -60,10 +62,22 @@ public class TriggerObject extends SchemaObjectBase {
}
}
public void setTriggerClassName(Session session, String triggerClassName, boolean force) throws SQLException {
this.triggerClassName = triggerClassName;
try {
load(session);
} catch (SQLException e) {
if (!force) {
throw e;
}
}
}
public void fire(Session session, boolean beforeAction) throws SQLException {
if (rowBased || before != beforeAction) {
return;
}
load(session);
Connection c2 = session.createConnection(false);
try {
triggerCallback.fire(c2, null, null);
......@@ -170,7 +184,7 @@ public class TriggerObject extends SchemaObjectBase {
public String getCreateSQLForCopy(Table table, String quotedName) {
StringBuffer buff = new StringBuffer();
buff.append("CREATE TRIGGER ");
buff.append("CREATE FORCE TRIGGER ");
buff.append(quotedName);
if (before) {
buff.append(" BEFORE ");
......
......@@ -155,13 +155,20 @@ java org.h2.test.TestAll timer
TestAll test = new TestAll();
test.printSystem();
//System.setProperty(SysProperties.H2_LOG_DELETE_DELAY, "20");
//TestRecover.main(new String[0]);
int test2;
// System.setProperty(SysProperties.H2_LOG_DELETE_DELAY, "20");
// TestRecover.main(new String[0]);
/*
out of memory tests
add a 'kill process while altering tables' test case
valentine
create force trigger : test & document
read only databases without having to make the files read-only: test & document
TestSessionsLocks
...?
Automate real power off tests
Extend tests that simulate power off
......@@ -171,8 +178,6 @@ Test delayed log files delete
link to new changelog and roadmap, remove pages from google groups
check ValueByte memory usage
Adjust cache memory usage
// test with garbage at the end of the log file (must be consistently detected as such)
// TestRandomSQL is too random; most statements fails
......@@ -182,6 +187,8 @@ Adjust cache memory usage
Test Recovery with MAX_LOG_FILE_SIZE=1; test with various log file sizes
History:
Security: The database now waits 200 ms before throwing an exception if
the user name or password don't match, to slow down dictionary attacks.
The value cache is now a soft reference cache. This should help save memory.
Large result sets are now a bit faster.
ALTER TABLE ALTER COLUMN RESTART and ALTER SEQUENCE now support an expressions.
......
......@@ -5,6 +5,7 @@
package org.h2.test.bench;
import java.io.FileWriter;
import java.io.InputStream;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
......@@ -71,7 +72,9 @@ public class TestPerformance {
openResults(init);
Properties prop = new Properties();
prop.load(getClass().getResourceAsStream("test.properties"));
InputStream in = getClass().getResourceAsStream("test.properties");
prop.load(in);
in.close();
int size = Integer.parseInt(prop.getProperty("size"));
ArrayList dbs = new ArrayList();
for (int i = 0; i < 100; i++) {
......
......@@ -24,6 +24,15 @@ public class TestReadOnly extends TestBase {
if (config.memory) {
return;
}
testReadOnlyFileAccessMode();
testReadOnlyFiles();
}
private void testReadOnlyFileAccessMode() {
int todo;
}
private void testReadOnlyFiles() throws Exception {
File f = File.createTempFile("test", "temp");
check(f.canWrite());
......
......@@ -112,10 +112,9 @@ public class TestSessionsLocks extends TestBase {
check(done[0]);
break;
} else {
System.out.println("no statement is executing yet");
// no statement is executing yet
}
}
conn2.close();
conn.close();
}
......
......@@ -61,11 +61,11 @@ public class TestTriggersConstraints extends TestBase implements Trigger {
ResultSet rs;
rs = stat.executeQuery("SCRIPT");
checkRows(rs, new String[] {
"CREATE TRIGGER PUBLIC.INS_BEFORE BEFORE INSERT ON PUBLIC.TEST FOR EACH ROW NOWAIT CALL \""
"CREATE FORCE TRIGGER PUBLIC.INS_BEFORE BEFORE INSERT ON PUBLIC.TEST FOR EACH ROW NOWAIT CALL \""
+ getClass().getName() + "\";",
"CREATE TRIGGER PUBLIC.INS_AFTER AFTER INSERT ON PUBLIC.TEST FOR EACH ROW NOWAIT CALL \""
"CREATE FORCE TRIGGER PUBLIC.INS_AFTER AFTER INSERT ON PUBLIC.TEST FOR EACH ROW NOWAIT CALL \""
+ getClass().getName() + "\";",
"CREATE TRIGGER PUBLIC.UPD_BEFORE BEFORE UPDATE ON PUBLIC.TEST FOR EACH ROW NOWAIT CALL \""
"CREATE FORCE TRIGGER PUBLIC.UPD_BEFORE BEFORE UPDATE ON PUBLIC.TEST FOR EACH ROW NOWAIT CALL \""
+ getClass().getName() + "\";" });
while (rs.next()) {
String sql = rs.getString(1);
......
......@@ -9,6 +9,7 @@ import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Random;
......@@ -32,7 +33,7 @@ public class TestKillRestart extends TestBase {
String[] procDef = new String[] { "java", "-cp", "bin", getClass().getName(), "-url", url, "-user", user,
"-password", password };
int len = getSize(1, 10);
int len = getSize(2, 15);
for (int i = 0; i < len; i++) {
Process p = Runtime.getRuntime().exec(procDef);
// InputStream err = p.getErrorStream();
......@@ -97,8 +98,10 @@ public class TestKillRestart extends TestBase {
System.out.println("#Starting...");
conn = DriverManager.getConnection(url, user, password);
stat = conn.createStatement();
stat.execute("DROP ALL OBJECTS");
stat.execute("CREATE TABLE TEST(ID IDENTITY, NAME VARCHAR)");
stat.execute("CREATE TABLE TEST2(ID IDENTITY, NAME VARCHAR)");
stat.execute("CREATE TABLE TEST_META(ID INT)");
PreparedStatement prep = conn.prepareStatement("INSERT INTO TEST(NAME) VALUES(?)");
PreparedStatement prep2 = conn.prepareStatement("INSERT INTO TEST2(NAME) VALUES(?)");
Random r = new Random(0);
......@@ -117,6 +120,9 @@ public class TestKillRestart extends TestBase {
if (i == 100) {
System.out.println("#Running...");
}
if (r.nextInt(100) < 10) {
conn.createStatement().execute("ALTER TABLE TEST_META ALTER COLUMN ID INT DEFAULT 10");
}
if (r.nextBoolean()) {
if (r.nextBoolean()) {
prep.setString(1, new String(new char[r.nextInt(30) * 10]));
......
......@@ -2869,13 +2869,13 @@ create trigger test_trigger before insert on s.test call "org.h2.test.db.TestTri
script NOPASSWORDS NOSETTINGS drop;
> SCRIPT
> ---------------------------------------------------------------------------------------------------------------
> ---------------------------------------------------------------------------------------------------------------------
> -- 0 = SELECT COUNT(*) FROM S.TEST;
> CREATE FORCE TRIGGER S.TEST_TRIGGER BEFORE INSERT ON S.TEST QUEUE 1024 CALL "org.h2.test.db.TestTriggersConstraints";
> CREATE INDEX S.INDEX_ID ON S.TEST(ID);
> CREATE MEMORY TABLE S.TEST( ID INT );
> CREATE SCHEMA S AUTHORIZATION SA;
> CREATE SEQUENCE S.SEQ START WITH 10;
> CREATE TRIGGER S.TEST_TRIGGER BEFORE INSERT ON S.TEST QUEUE 1024 CALL "org.h2.test.db.TestTriggersConstraints";
> CREATE USER IF NOT EXISTS SA PASSWORD '' ADMIN;
> DROP SEQUENCE IF EXISTS S.SEQ;
> DROP TABLE IF EXISTS S.TEST;
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论