Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
H
h2database
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
Administrator
h2database
Commits
26414c8e
提交
26414c8e
authored
4月 03, 2008
作者:
Thomas Mueller
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
--no commit message
--no commit message
上级
07470668
显示空白字符变更
内嵌
并排
正在显示
18 个修改的文件
包含
197 行增加
和
147 行删除
+197
-147
ScriptBase.java
h2/src/main/org/h2/command/dml/ScriptBase.java
+2
-2
SysProperties.java
h2/src/main/org/h2/constant/SysProperties.java
+18
-0
Constants.java
h2/src/main/org/h2/engine/Constants.java
+0
-7
Database.java
h2/src/main/org/h2/engine/Database.java
+5
-33
Engine.java
h2/src/main/org/h2/engine/Engine.java
+56
-8
Session.java
h2/src/main/org/h2/engine/Session.java
+4
-1
User.java
h2/src/main/org/h2/engine/User.java
+4
-17
Aggregate.java
h2/src/main/org/h2/expression/Aggregate.java
+2
-2
BaseIndex.java
h2/src/main/org/h2/index/BaseIndex.java
+4
-3
BtreeCursor.java
h2/src/main/org/h2/index/BtreeCursor.java
+3
-1
BtreeIndex.java
h2/src/main/org/h2/index/BtreeIndex.java
+2
-2
MultiVersionCursor.java
h2/src/main/org/h2/index/MultiVersionCursor.java
+25
-24
MultiVersionIndex.java
h2/src/main/org/h2/index/MultiVersionIndex.java
+32
-33
ScanIndex.java
h2/src/main/org/h2/index/ScanIndex.java
+1
-1
TreeIndex.java
h2/src/main/org/h2/index/TreeIndex.java
+4
-4
RowList.java
h2/src/main/org/h2/result/RowList.java
+1
-1
TestAll.java
h2/src/test/org/h2/test/TestAll.java
+32
-7
dictionary.txt
h2/src/tools/org/h2/build/doc/dictionary.txt
+2
-1
没有找到文件。
h2/src/main/org/h2/command/dml/ScriptBase.java
浏览文件 @
26414c8e
...
@@ -79,8 +79,8 @@ public abstract class ScriptBase extends Prepared implements DataHandler {
...
@@ -79,8 +79,8 @@ public abstract class ScriptBase extends Prepared implements DataHandler {
}
}
protected
String
getFileName
()
throws
SQLException
{
protected
String
getFileName
()
throws
SQLException
{
if
(
file
Name
!
=
null
)
{
if
(
file
!=
null
&&
fileName
=
=
null
)
{
fileName
=
file
==
null
?
null
:
file
.
getValue
(
session
).
getString
();
fileName
=
file
.
getValue
(
session
).
getString
();
if
(
fileName
==
null
||
fileName
.
trim
().
length
()
==
0
)
{
if
(
fileName
==
null
||
fileName
.
trim
().
length
()
==
0
)
{
fileName
=
"script.sql"
;
fileName
=
"script.sql"
;
}
}
...
...
h2/src/main/org/h2/constant/SysProperties.java
浏览文件 @
26414c8e
...
@@ -158,6 +158,24 @@ public class SysProperties {
...
@@ -158,6 +158,24 @@ public class SysProperties {
*/
*/
public
static
final
int
DEFAULT_LOCK_MODE
=
getIntSetting
(
"h2.defaultLockMode"
,
Constants
.
LOCK_MODE_READ_COMMITTED
);
public
static
final
int
DEFAULT_LOCK_MODE
=
getIntSetting
(
"h2.defaultLockMode"
,
Constants
.
LOCK_MODE_READ_COMMITTED
);
/**
* System property <code>h2.delayWrongPasswordMin</code> (default: 200).<br />
* The minimum delay in milliseconds before an exception is thrown for using
* the wrong user name or password. This slows down brute force attacks. The
* delay is reset to this value after a successful login. Unsuccessful
* logins will double the time until DELAY_WRONG_PASSWORD_MAX.
*/
public
static
final
int
DELAY_WRONG_PASSWORD_MIN
=
getIntSetting
(
"h2.delayWrongPasswordMin"
,
200
);
/**
* System property <code>h2.delayWrongPasswordMax</code> (default: 0).<br />
* The maximum delay in milliseconds before an exception is thrown for using
* the wrong user name or password. This slows down brute force attacks. The
* delay is reset after a successful login. The value 0 means there is no
* maximum delay.
*/
public
static
final
int
DELAY_WRONG_PASSWORD_MAX
=
getIntSetting
(
"h2.delayWrongPasswordMax"
,
0
);
/**
/**
* System property <code>h2.emergencySpaceInitial</code> (default: 262144).<br />
* System property <code>h2.emergencySpaceInitial</code> (default: 262144).<br />
* Size of 'reserve' file to detect disk full problems early.
* Size of 'reserve' file to detect disk full problems early.
...
...
h2/src/main/org/h2/engine/Constants.java
浏览文件 @
26414c8e
...
@@ -191,11 +191,4 @@ public class Constants {
...
@@ -191,11 +191,4 @@ public class Constants {
public
static
final
String
SCRIPT_SQL
=
"script.sql"
;
public
static
final
String
SCRIPT_SQL
=
"script.sql"
;
public
static
final
int
CACHE_MIN_RECORDS
=
16
;
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
;
}
}
h2/src/main/org/h2/engine/Database.java
浏览文件 @
26414c8e
...
@@ -396,15 +396,8 @@ public class Database implements DataHandler {
...
@@ -396,15 +396,8 @@ public class Database implements DataHandler {
return
store
;
return
store
;
}
}
public
void
checkFilePasswordHash
(
String
c
,
byte
[]
hash
)
throws
SQLException
{
public
boolean
validateFilePasswordHash
(
String
c
,
byte
[]
hash
)
throws
SQLException
{
if
(!
ByteUtils
.
compareSecure
(
hash
,
filePasswordHash
)
||
!
StringUtils
.
equals
(
c
,
cipher
))
{
return
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
);
}
}
}
private
void
openFileData
()
throws
SQLException
{
private
void
openFileData
()
throws
SQLException
{
...
@@ -789,35 +782,14 @@ public class Database implements DataHandler {
...
@@ -789,35 +782,14 @@ public class Database implements DataHandler {
return
(
UserDataType
)
userDataTypes
.
get
(
name
);
return
(
UserDataType
)
userDataTypes
.
get
(
name
);
}
}
/**
public
User
getUser
(
String
name
)
throws
SQLException
{
* Get the user with the given name. If there is no such user, this method
User
user
=
findUser
(
name
);
* waits a short amount of time (to make rainbow table attacks harder) and
* then throws the exception that is passed. There is only one exception
* both for wrong user and for wrong password, to make it harder to get the
* list of user names.
*
* @param name the user name
* @param notFound the exception that should be thrown if the user does not
* exist
* @throws SQLException if the user does not exist
*/
public
User
getUser
(
String
name
,
SQLException
notFound
)
throws
SQLException
{
User
user
=
(
User
)
users
.
get
(
name
);
if
(
user
==
null
)
{
if
(
user
==
null
)
{
try
{
throw
Message
.
getSQLException
(
ErrorCode
.
USER_NOT_FOUND_1
,
name
);
Thread
.
sleep
(
Constants
.
DELAY_WRONG_PASSWORD
);
}
catch
(
InterruptedException
e
)
{
// ignore
}
throw
notFound
;
}
}
return
user
;
return
user
;
}
}
public
User
getUser
(
String
name
)
throws
SQLException
{
return
getUser
(
name
,
Message
.
getSQLException
(
ErrorCode
.
USER_NOT_FOUND_1
,
name
));
}
public
synchronized
Session
createUserSession
(
User
user
)
throws
SQLException
{
public
synchronized
Session
createUserSession
(
User
user
)
throws
SQLException
{
if
(
exclusiveSession
!=
null
)
{
if
(
exclusiveSession
!=
null
)
{
throw
Message
.
getSQLException
(
ErrorCode
.
DATABASE_IS_IN_EXCLUSIVE_MODE
);
throw
Message
.
getSQLException
(
ErrorCode
.
DATABASE_IS_IN_EXCLUSIVE_MODE
);
...
...
h2/src/main/org/h2/engine/Engine.java
浏览文件 @
26414c8e
...
@@ -12,8 +12,10 @@ import org.h2.command.CommandInterface;
...
@@ -12,8 +12,10 @@ import org.h2.command.CommandInterface;
import
org.h2.command.Parser
;
import
org.h2.command.Parser
;
import
org.h2.command.dml.SetTypes
;
import
org.h2.command.dml.SetTypes
;
import
org.h2.constant.ErrorCode
;
import
org.h2.constant.ErrorCode
;
import
org.h2.constant.SysProperties
;
import
org.h2.message.Message
;
import
org.h2.message.Message
;
import
org.h2.message.Trace
;
import
org.h2.message.Trace
;
import
org.h2.util.RandomUtils
;
import
org.h2.util.StringUtils
;
import
org.h2.util.StringUtils
;
/**
/**
...
@@ -22,10 +24,9 @@ import org.h2.util.StringUtils;
...
@@ -22,10 +24,9 @@ import org.h2.util.StringUtils;
* This is a singleton class.
* This is a singleton class.
*/
*/
public
class
Engine
{
public
class
Engine
{
// TODO use a 'engine'/'master' database to allow shut down the server,
// view & kill sessions and so on
private
static
final
Engine
INSTANCE
=
new
Engine
();
private
static
final
Engine
INSTANCE
=
new
Engine
();
private
static
long
delayWrongPassword
=
SysProperties
.
DELAY_WRONG_PASSWORD_MIN
;
private
final
HashMap
databases
=
new
HashMap
();
private
final
HashMap
databases
=
new
HashMap
();
private
Engine
()
{
private
Engine
()
{
...
@@ -73,12 +74,16 @@ public class Engine {
...
@@ -73,12 +74,16 @@ public class Engine {
}
}
if
(
user
==
null
)
{
if
(
user
==
null
)
{
try
{
try
{
database
.
checkFilePasswordHash
(
cipher
,
ci
.
getFilePasswordHash
());
boolean
correct
=
database
.
validateFilePasswordHash
(
cipher
,
ci
.
getFilePasswordHash
());
// create the exception here so it is not possible from the stack trace
if
(
correct
)
{
// to see if the user name was wrong or the password
user
=
database
.
findUser
(
ci
.
getUserName
());
SQLException
wrongUserOrPassword
=
Message
.
getSQLException
(
ErrorCode
.
WRONG_USER_OR_PASSWORD
);
if
(
user
==
null
)
{
user
=
database
.
getUser
(
ci
.
getUserName
(),
wrongUserOrPassword
);
correct
=
false
;
user
.
checkUserPasswordHash
(
ci
.
getUserPasswordHash
(),
wrongUserOrPassword
);
}
else
{
correct
=
user
.
validateUserPasswordHash
(
ci
.
getUserPasswordHash
());
}
}
validateUserAndPassword
(
correct
);
if
(
opened
&&
!
user
.
getAdmin
())
{
if
(
opened
&&
!
user
.
getAdmin
())
{
// reset - because the user is not an admin, and has no
// reset - because the user is not an admin, and has no
// right to listen to exceptions
// right to listen to exceptions
...
@@ -158,4 +163,47 @@ public class Engine {
...
@@ -158,4 +163,47 @@ public class Engine {
databases
.
remove
(
name
);
databases
.
remove
(
name
);
}
}
/**
* This method is called after validating user name and password. If user
* name and password were correct, the sleep time is reset, otherwise this
* method waits some time (to make brute force / rainbow table attacks
* harder) and then throws a 'wrong user or password' exception. The delay
* is a bit randomized to protect against timing attacks. Also the delay
* doubles after each unsuccessful logins, to make brute force attacks harder.
*
* There is only one exception both for wrong user and for wrong password,
* to make it harder to get the list of user names. This method must only be
* called from one place, so it is not possible from the stack trace to see
* if the user name was wrong or the password.
*
* @param correct if the user name or the password was correct
* @throws SQLException the exception 'wrong user or password'
*/
public
static
synchronized
void
validateUserAndPassword
(
boolean
correct
)
throws
SQLException
{
int
min
=
SysProperties
.
DELAY_WRONG_PASSWORD_MIN
;
if
(
correct
)
{
delayWrongPassword
=
min
;
}
else
{
long
delay
=
delayWrongPassword
;
if
(
min
>
0
)
{
// a bit more to protect against timing attacks
delay
+=
Math
.
abs
(
RandomUtils
.
getSecureLong
()
%
100
);
try
{
Thread
.
sleep
(
delay
);
}
catch
(
InterruptedException
e
)
{
// ignore
}
}
int
max
=
SysProperties
.
DELAY_WRONG_PASSWORD_MAX
;
if
(
max
<=
0
)
{
max
=
Integer
.
MAX_VALUE
;
}
delayWrongPassword
+=
delayWrongPassword
;
if
(
delayWrongPassword
>
max
||
delayWrongPassword
<
0
)
{
delayWrongPassword
=
max
;
}
throw
Message
.
getSQLException
(
ErrorCode
.
WRONG_USER_OR_PASSWORD
);
}
}
}
}
h2/src/main/org/h2/engine/Session.java
浏览文件 @
26414c8e
...
@@ -659,7 +659,10 @@ public class Session implements SessionInterface {
...
@@ -659,7 +659,10 @@ public class Session implements SessionInterface {
return
database
;
return
database
;
}
}
public
void
unlinkAtCommit
(
Value
v
)
{
public
void
unlinkAtCommit
(
ValueLob
v
)
{
if
(
SysProperties
.
CHECK
&&
!
v
.
isLinked
())
{
throw
Message
.
getInternalError
();
}
if
(
unlinkMap
==
null
)
{
if
(
unlinkMap
==
null
)
{
unlinkMap
=
new
HashMap
();
unlinkMap
=
new
HashMap
();
}
}
...
...
h2/src/main/org/h2/engine/User.java
浏览文件 @
26414c8e
...
@@ -149,28 +149,15 @@ public class User extends RightOwner {
...
@@ -149,28 +149,15 @@ public class User extends RightOwner {
}
}
/**
/**
* Check the password of this user. If the password is wrong, this method
* Check the password of this user.
* waits a short amount of time (to make S attacks harder) and then throws
* the exception that is passed. There is only one exception both for wrong
* user and for wrong password, to make it harder to get the list of user
* names.
*
*
* @param userPasswordHash the password data (the user password hash)
* @param userPasswordHash the password data (the user password hash)
* @param onError the exception that should be thrown if the password does
* @return true if the user password hash is correct
* not match
* @throws SQLException if the password does not match
*/
*/
public
void
checkUserPasswordHash
(
byte
[]
userPasswordHash
,
SQLException
onError
)
throws
SQLException
{
public
boolean
validateUserPasswordHash
(
byte
[]
userPasswordHash
)
{
SHA256
sha
=
new
SHA256
();
SHA256
sha
=
new
SHA256
();
byte
[]
hash
=
sha
.
getHashWithSalt
(
userPasswordHash
,
salt
);
byte
[]
hash
=
sha
.
getHashWithSalt
(
userPasswordHash
,
salt
);
if
(!
ByteUtils
.
compareSecure
(
hash
,
passwordHash
))
{
return
ByteUtils
.
compareSecure
(
hash
,
passwordHash
);
try
{
Thread
.
sleep
(
Constants
.
DELAY_WRONG_PASSWORD
);
}
catch
(
InterruptedException
e
)
{
// ignore
}
throw
onError
;
}
}
}
/**
/**
...
...
h2/src/main/org/h2/expression/Aggregate.java
浏览文件 @
26414c8e
...
@@ -169,11 +169,11 @@ public class Aggregate extends Expression {
...
@@ -169,11 +169,11 @@ public class Aggregate extends Expression {
first
=
!
first
;
first
=
!
first
;
}
}
Cursor
cursor
=
index
.
findFirstOrLast
(
session
,
first
);
Cursor
cursor
=
index
.
findFirstOrLast
(
session
,
first
);
SearchRow
row
=
cursor
.
getSearchRow
();
Value
v
;
Value
v
;
if
(
cursor
==
null
)
{
if
(
row
==
null
)
{
v
=
ValueNull
.
INSTANCE
;
v
=
ValueNull
.
INSTANCE
;
}
else
{
}
else
{
SearchRow
row
=
cursor
.
getSearchRow
();
v
=
row
.
getValue
(
index
.
getColumns
()[
0
].
getColumnId
());
v
=
row
.
getValue
(
index
.
getColumns
()[
0
].
getColumnId
());
}
}
return
v
;
return
v
;
...
...
h2/src/main/org/h2/index/BaseIndex.java
浏览文件 @
26414c8e
...
@@ -115,11 +115,12 @@ public abstract class BaseIndex extends SchemaObjectBase implements Index {
...
@@ -115,11 +115,12 @@ public abstract class BaseIndex extends SchemaObjectBase implements Index {
public
abstract
boolean
canGetFirstOrLast
();
public
abstract
boolean
canGetFirstOrLast
();
/**
/**
* Find the first (or last) value of this index.
* Find the first (or last) value of this index. The cursor returned is
* positioned on the correct row, or on null if no row has been found.
*
*
* @param session the session
* @param session the session
* @param first true for the first value, false for the last
* @param first true for the first value, false for the last
* @return a cursor
or null
* @return a cursor
(never null)
*/
*/
public
abstract
Cursor
findFirstOrLast
(
Session
session
,
boolean
first
)
throws
SQLException
;
public
abstract
Cursor
findFirstOrLast
(
Session
session
,
boolean
first
)
throws
SQLException
;
...
...
h2/src/main/org/h2/index/BtreeCursor.java
浏览文件 @
26414c8e
...
@@ -92,7 +92,9 @@ public class BtreeCursor implements Cursor {
...
@@ -92,7 +92,9 @@ public class BtreeCursor implements Cursor {
}
}
public
boolean
previous
()
throws
SQLException
{
public
boolean
previous
()
throws
SQLException
{
if
(
currentSearchRow
!=
null
)
{
top
.
page
.
previous
(
this
,
top
.
position
);
top
.
page
.
previous
(
this
,
top
.
position
);
}
return
currentSearchRow
!=
null
;
return
currentSearchRow
!=
null
;
}
}
...
...
h2/src/main/org/h2/index/BtreeIndex.java
浏览文件 @
26414c8e
...
@@ -345,7 +345,7 @@ public class BtreeIndex extends BaseIndex implements RecordReader {
...
@@ -345,7 +345,7 @@ public class BtreeIndex extends BaseIndex implements RecordReader {
return
cursor
;
return
cursor
;
}
}
}
}
return
null
;
return
cursor
;
}
else
{
}
else
{
BtreePage
root
=
getRoot
(
session
);
BtreePage
root
=
getRoot
(
session
);
BtreeCursor
cursor
=
new
BtreeCursor
(
session
,
this
,
null
);
BtreeCursor
cursor
=
new
BtreeCursor
(
session
,
this
,
null
);
...
@@ -361,7 +361,7 @@ public class BtreeIndex extends BaseIndex implements RecordReader {
...
@@ -361,7 +361,7 @@ public class BtreeIndex extends BaseIndex implements RecordReader {
return
cursor
;
return
cursor
;
}
}
}
while
(
cursor
.
previous
());
}
while
(
cursor
.
previous
());
return
null
;
return
cursor
;
}
}
}
}
...
...
h2/src/main/org/h2/index/MultiVersionCursor.java
浏览文件 @
26414c8e
...
@@ -26,6 +26,7 @@ public class MultiVersionCursor implements Cursor {
...
@@ -26,6 +26,7 @@ public class MultiVersionCursor implements Cursor {
private
boolean
onBase
;
private
boolean
onBase
;
private
boolean
end
;
private
boolean
end
;
private
boolean
needNewDelta
,
needNewBase
;
private
boolean
needNewDelta
,
needNewBase
;
private
boolean
reverse
;
MultiVersionCursor
(
Session
session
,
MultiVersionIndex
index
,
Cursor
base
,
Cursor
delta
,
Object
sync
)
throws
SQLException
{
MultiVersionCursor
(
Session
session
,
MultiVersionIndex
index
,
Cursor
base
,
Cursor
delta
,
Object
sync
)
throws
SQLException
{
this
.
session
=
session
;
this
.
session
=
session
;
...
@@ -36,34 +37,25 @@ public class MultiVersionCursor implements Cursor {
...
@@ -36,34 +37,25 @@ public class MultiVersionCursor implements Cursor {
needNewDelta
=
needNewBase
=
true
;
needNewDelta
=
needNewBase
=
true
;
}
}
private
void
loadNext
(
boolean
base
)
throws
SQLException
{
void
loadCurrent
(
)
throws
SQLException
{
synchronized
(
sync
)
{
synchronized
(
sync
)
{
if
(
base
)
{
if
(
baseCursor
.
next
())
{
baseRow
=
baseCursor
.
getSearchRow
();
baseRow
=
baseCursor
.
getSearchRow
();
}
else
{
baseRow
=
null
;
}
}
else
{
if
(
deltaCursor
.
next
())
{
deltaRow
=
deltaCursor
.
get
();
deltaRow
=
deltaCursor
.
get
();
}
else
{
needNewDelta
=
false
;
deltaRow
=
null
;
needNewBase
=
false
;
}
}
}
}
}
}
private
void
load
Previous
(
boolean
base
)
throws
SQLException
{
private
void
load
Next
(
boolean
base
)
throws
SQLException
{
synchronized
(
sync
)
{
synchronized
(
sync
)
{
if
(
base
)
{
if
(
base
)
{
if
(
baseCursor
.
previous
(
))
{
if
(
step
(
baseCursor
))
{
baseRow
=
baseCursor
.
getSearchRow
();
baseRow
=
baseCursor
.
getSearchRow
();
}
else
{
}
else
{
baseRow
=
null
;
baseRow
=
null
;
}
}
}
else
{
}
else
{
if
(
deltaCursor
.
previous
(
))
{
if
(
step
(
deltaCursor
))
{
deltaRow
=
deltaCursor
.
get
();
deltaRow
=
deltaCursor
.
get
();
}
else
{
}
else
{
deltaRow
=
null
;
deltaRow
=
null
;
...
@@ -72,10 +64,14 @@ public class MultiVersionCursor implements Cursor {
...
@@ -72,10 +64,14 @@ public class MultiVersionCursor implements Cursor {
}
}
}
}
private
boolean
step
(
Cursor
cursor
)
throws
SQLException
{
return
reverse
?
cursor
.
previous
()
:
cursor
.
next
();
}
public
Row
get
()
throws
SQLException
{
public
Row
get
()
throws
SQLException
{
synchronized
(
sync
)
{
synchronized
(
sync
)
{
if
(
SysProperties
.
CHECK
&&
end
)
{
if
(
end
)
{
throw
Message
.
getInternalError
()
;
return
null
;
}
}
return
onBase
?
baseCursor
.
get
()
:
deltaCursor
.
get
();
return
onBase
?
baseCursor
.
get
()
:
deltaCursor
.
get
();
}
}
...
@@ -92,8 +88,8 @@ public class MultiVersionCursor implements Cursor {
...
@@ -92,8 +88,8 @@ public class MultiVersionCursor implements Cursor {
public
SearchRow
getSearchRow
()
throws
SQLException
{
public
SearchRow
getSearchRow
()
throws
SQLException
{
synchronized
(
sync
)
{
synchronized
(
sync
)
{
if
(
SysProperties
.
CHECK
&&
end
)
{
if
(
end
)
{
throw
Message
.
getInternalError
()
;
return
null
;
}
}
return
onBase
?
baseCursor
.
getSearchRow
()
:
deltaCursor
.
getSearchRow
();
return
onBase
?
baseCursor
.
getSearchRow
()
:
deltaCursor
.
getSearchRow
();
}
}
...
@@ -186,8 +182,13 @@ public class MultiVersionCursor implements Cursor {
...
@@ -186,8 +182,13 @@ public class MultiVersionCursor implements Cursor {
}
}
}
}
public
boolean
previous
()
{
public
boolean
previous
()
throws
SQLException
{
throw
Message
.
getInternalError
();
reverse
=
true
;
try
{
return
next
();
}
finally
{
reverse
=
false
;
}
}
}
}
}
h2/src/main/org/h2/index/MultiVersionIndex.java
浏览文件 @
26414c8e
...
@@ -31,6 +31,7 @@ public class MultiVersionIndex implements Index {
...
@@ -31,6 +31,7 @@ public class MultiVersionIndex implements Index {
private
final
TreeIndex
delta
;
private
final
TreeIndex
delta
;
private
final
TableData
table
;
private
final
TableData
table
;
private
final
Object
sync
;
private
final
Object
sync
;
private
final
Column
firstColumn
;
public
MultiVersionIndex
(
Index
base
,
TableData
table
)
throws
SQLException
{
public
MultiVersionIndex
(
Index
base
,
TableData
table
)
throws
SQLException
{
this
.
base
=
base
;
this
.
base
=
base
;
...
@@ -38,6 +39,7 @@ public class MultiVersionIndex implements Index {
...
@@ -38,6 +39,7 @@ public class MultiVersionIndex implements Index {
IndexType
deltaIndexType
=
IndexType
.
createNonUnique
(
false
);
IndexType
deltaIndexType
=
IndexType
.
createNonUnique
(
false
);
this
.
delta
=
new
TreeIndex
(
table
,
-
1
,
"DELTA"
,
base
.
getIndexColumns
(),
deltaIndexType
);
this
.
delta
=
new
TreeIndex
(
table
,
-
1
,
"DELTA"
,
base
.
getIndexColumns
(),
deltaIndexType
);
this
.
sync
=
base
.
getDatabase
();
this
.
sync
=
base
.
getDatabase
();
this
.
firstColumn
=
base
.
getColumns
()[
0
];
}
}
public
void
add
(
Session
session
,
Row
row
)
throws
SQLException
{
public
void
add
(
Session
session
,
Row
row
)
throws
SQLException
{
...
@@ -76,42 +78,39 @@ public class MultiVersionIndex implements Index {
...
@@ -76,42 +78,39 @@ public class MultiVersionIndex implements Index {
}
}
public
boolean
canGetFirstOrLast
()
{
public
boolean
canGetFirstOrLast
()
{
// TODO in many cases possible, but more complicated
return
base
.
canGetFirstOrLast
()
&&
delta
.
canGetFirstOrLast
();
return
false
;
}
}
public
Cursor
findFirstOrLast
(
Session
session
,
boolean
first
)
throws
SQLException
{
public
Cursor
findFirstOrLast
(
Session
session
,
boolean
first
)
throws
SQLException
{
int
test
;
if
(
first
)
{
throw
Message
.
getUnsupportedException
();
// TODO optimization: this loops through NULL elements
Cursor
cursor
=
find
(
session
,
null
,
null
);
// if (first) {
while
(
cursor
.
next
())
{
// // TODO optimization: this loops through NULL elements
SearchRow
row
=
cursor
.
getSearchRow
();
// Cursor cursor = find(session, null, false, null);
Value
v
=
row
.
getValue
(
firstColumn
.
getColumnId
());
// while (cursor.next()) {
if
(
v
!=
ValueNull
.
INSTANCE
)
{
// SearchRow row = cursor.getSearchRow();
return
cursor
;
// Value v = row.getValue(columnIds[0]);
}
// if (v != ValueNull.INSTANCE) {
}
// return cursor;
return
cursor
;
// }
}
else
{
// }
Cursor
baseCursor
=
base
.
findFirstOrLast
(
session
,
false
);
// return null;
Cursor
deltaCursor
=
delta
.
findFirstOrLast
(
session
,
false
);
// } else {
MultiVersionCursor
cursor
=
new
MultiVersionCursor
(
session
,
this
,
baseCursor
,
deltaCursor
,
sync
);
// BtreePage root = getRoot(session);
cursor
.
loadCurrent
();
// BtreeCursor cursor = new BtreeCursor(session, this, null);
// TODO optimization: this loops through NULL elements
// root.last(cursor);
while
(
cursor
.
previous
())
{
// // TODO optimization: this loops through NULL elements
SearchRow
row
=
cursor
.
getSearchRow
();
// do {
if
(
row
==
null
)
{
// SearchRow row = cursor.getSearchRow();
break
;
// if (row == null) {
}
// break;
Value
v
=
row
.
getValue
(
firstColumn
.
getColumnId
());
// }
if
(
v
!=
ValueNull
.
INSTANCE
)
{
// Value v = row.getValue(columnIds[0]);
return
cursor
;
// if (v != ValueNull.INSTANCE) {
}
// return cursor;
}
// }
return
cursor
;
// } while (cursor.previous());
}
// return null;
// }
}
}
public
double
getCost
(
Session
session
,
int
[]
masks
)
throws
SQLException
{
public
double
getCost
(
Session
session
,
int
[]
masks
)
throws
SQLException
{
...
...
h2/src/main/org/h2/index/ScanIndex.java
浏览文件 @
26414c8e
...
@@ -166,7 +166,7 @@ public class ScanIndex extends BaseIndex {
...
@@ -166,7 +166,7 @@ public class ScanIndex extends BaseIndex {
for
(
int
i
=
0
;
i
<
row
.
getColumnCount
();
i
++)
{
for
(
int
i
=
0
;
i
<
row
.
getColumnCount
();
i
++)
{
Value
v
=
row
.
getValue
(
i
);
Value
v
=
row
.
getValue
(
i
);
if
(
v
.
isLinked
())
{
if
(
v
.
isLinked
())
{
session
.
unlinkAtCommit
(
v
);
session
.
unlinkAtCommit
(
(
ValueLob
)
v
);
}
}
}
}
}
}
...
...
h2/src/main/org/h2/index/TreeIndex.java
浏览文件 @
26414c8e
...
@@ -382,7 +382,7 @@ public class TreeIndex extends BaseIndex {
...
@@ -382,7 +382,7 @@ public class TreeIndex extends BaseIndex {
return
cursor
;
return
cursor
;
}
}
}
}
return
null
;
return
cursor
;
}
else
{
}
else
{
TreeNode
x
=
root
,
n
;
TreeNode
x
=
root
,
n
;
while
(
x
!=
null
)
{
while
(
x
!=
null
)
{
...
@@ -392,10 +392,10 @@ public class TreeIndex extends BaseIndex {
...
@@ -392,10 +392,10 @@ public class TreeIndex extends BaseIndex {
}
}
x
=
n
;
x
=
n
;
}
}
TreeCursor
cursor
=
new
TreeCursor
(
this
,
x
,
null
,
null
);
if
(
x
==
null
)
{
if
(
x
==
null
)
{
return
null
;
return
cursor
;
}
}
TreeCursor
cursor
=
new
TreeCursor
(
this
,
x
,
null
,
null
);
// TODO optimization: this loops through NULL elements
// TODO optimization: this loops through NULL elements
do
{
do
{
SearchRow
row
=
cursor
.
getSearchRow
();
SearchRow
row
=
cursor
.
getSearchRow
();
...
@@ -407,7 +407,7 @@ public class TreeIndex extends BaseIndex {
...
@@ -407,7 +407,7 @@ public class TreeIndex extends BaseIndex {
return
cursor
;
return
cursor
;
}
}
}
while
(
cursor
.
previous
());
}
while
(
cursor
.
previous
());
return
null
;
return
cursor
;
}
}
}
}
...
...
h2/src/main/org/h2/result/RowList.java
浏览文件 @
26414c8e
...
@@ -157,7 +157,7 @@ public class RowList {
...
@@ -157,7 +157,7 @@ public class RowList {
// the table id is 0 if it was linked when writing
// the table id is 0 if it was linked when writing
// a temporary entry
// a temporary entry
if
(
lob
.
getTableId
()
==
0
)
{
if
(
lob
.
getTableId
()
==
0
)
{
session
.
unlinkAtCommit
(
v
);
session
.
unlinkAtCommit
(
lob
);
}
}
}
}
values
[
i
]
=
v
;
values
[
i
]
=
v
;
...
...
h2/src/test/org/h2/test/TestAll.java
浏览文件 @
26414c8e
...
@@ -159,15 +159,42 @@ java org.h2.test.TestAll timer
...
@@ -159,15 +159,42 @@ java org.h2.test.TestAll timer
/*
/*
test # in h2 console (other languages)
delay on wrong password: double the time, randomized, reset on right password
optimize where x not in (select):
SELECT c FROM color LEFT OUTER JOIN (SELECT c FROM TABLE(c
VARCHAR= ?)) p ON color.c = p.c WHERE p.c IS NULL;
drop table test;
create table test(id int);
select * from test t1 inner join test t2
inner join test t3 on t3.id=t2.id on t1.id=t2.id;
-- supported by PostgreSQL, Derby,...;
not supported by MySQL,...
wrong password should be synchronized outside:
wrong password should delay other wrong password,
but not right password
javadocs: constructors are not listed (JdbcConnectionPoolManager)
JdbcConnectionPoolManager pm =
new JdbcConnectionPoolManager();
pm.setDataSource(ds);
pm.setMaxConnection(10);
pm.setTimeout(10);
pm.start();
or:
JdbcConnectionPoolManager pm =
new JdbcConnectionPoolManager();
pm.setDataSource(ds).
setMaxConnection(10).setTimeout(10).start();
include in the execution times in the debug log.
include in the execution times in the debug log.
(for each SQL statement ran)
(for each SQL statement ran)
SQL:checksum:1ms SELECT * FROM TEST
SQL:checksum:1ms SELECT * FROM TEST
checksum: not including values, case insensitive
checksum: not including values, case insensitive
make everything translatable
Derby doesn't optimize it
Derby doesn't optimize it
drop table test;
drop table test;
create table test(id int, version int, idx int);
create table test(id int, version int, idx int);
...
@@ -183,10 +210,6 @@ create index idx_test on test(id, version, idx);
...
@@ -183,10 +210,6 @@ create index idx_test on test(id, version, idx);
@LOOP 1000 select max(idx)+1 from test where id=1 and version=2;
@LOOP 1000 select max(idx)+1 from test where id=1 and version=2;
-- should be direct query
-- should be direct query
Fix ScriptBase.getFileName()
Fix Shell.java 159 (close PreparedStatement)
Browser problems:
Browser problems:
There has been a reported incompatibility with the
There has been a reported incompatibility with the
RealPlayer Browser Record Plugin 1.0 when using Firefox 2.0 and Vista
RealPlayer Browser Record Plugin 1.0 when using Firefox 2.0 and Vista
...
@@ -240,6 +263,7 @@ The tools in the H2 Console are now translatable.
...
@@ -240,6 +263,7 @@ The tools in the H2 Console are now translatable.
Invalid inline views threw confusing SQL exceptions.
Invalid inline views threw confusing SQL exceptions.
The Japanese translation of the error messages and the
The Japanese translation of the error messages and the
H2 Console has been improved. Thanks a lot to Masahiro IKEMOTO.
H2 Console has been improved. Thanks a lot to Masahiro IKEMOTO.
Optimization for MIN() and MAX() when using MVCC.
Roadmap:
Roadmap:
...
@@ -441,6 +465,7 @@ Roadmap:
...
@@ -441,6 +465,7 @@ Roadmap:
* Run all tests with the current settings.
* Run all tests with the current settings.
*/
*/
private
void
test
()
throws
Exception
{
private
void
test
()
throws
Exception
{
System
.
out
.
println
();
System
.
out
.
println
();
System
.
out
.
println
(
"Test big:"
+
big
+
" net:"
+
networked
+
" cipher:"
+
cipher
+
" memory:"
+
memory
+
" log:"
+
logMode
+
" diskResult:"
+
diskResult
+
" mvcc:"
+
mvcc
+
" deleteIndex:"
+
deleteIndex
);
System
.
out
.
println
(
"Test big:"
+
big
+
" net:"
+
networked
+
" cipher:"
+
cipher
+
" memory:"
+
memory
+
" log:"
+
logMode
+
" diskResult:"
+
diskResult
+
" mvcc:"
+
mvcc
+
" deleteIndex:"
+
deleteIndex
);
beforeTest
();
beforeTest
();
...
...
h2/src/tools/org/h2/build/doc/dictionary.txt
浏览文件 @
26414c8e
...
@@ -488,4 +488,5 @@ greenwich sqli informix pointbase fbj pervasive jtds ifx syb mimer sybase
...
@@ -488,4 +488,5 @@ greenwich sqli informix pointbase fbj pervasive jtds ifx syb mimer sybase
frontbase intersys maxwidth belonging learning mono typical toggle winexe
frontbase intersys maxwidth belonging learning mono typical toggle winexe
hider ikvmc invert recycle filtering lesser recycled assertion runner teradata
hider ikvmc invert recycle filtering lesser recycled assertion runner teradata
christian lgpl elapsed ncr disposed heureuse tera years retrieves unlocked
christian lgpl elapsed ncr disposed heureuse tera years retrieves unlocked
selecting vista everywhere locations zones fragment svg thought
selecting vista everywhere locations zones fragment svg thought constructors
\ No newline at end of file
doubles validating
\ No newline at end of file
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论