Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
H
h2database
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
Administrator
h2database
Commits
7e8d5029
提交
7e8d5029
authored
7 年前
作者:
andrei
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'master' of
https://github.com/h2database/h2database
into issue_435
上级
4d3bd656
d5337d82
显示空白字符变更
内嵌
并排
正在显示
4 个修改的文件
包含
131 行增加
和
114 行删除
+131
-114
AlterTableAddConstraint.java
h2/src/main/org/h2/command/ddl/AlterTableAddConstraint.java
+11
-11
JdbcConnection.java
h2/src/main/org/h2/jdbc/JdbcConnection.java
+8
-0
CreateCluster.java
h2/src/main/org/h2/tools/CreateCluster.java
+86
-103
TestConnection.java
h2/src/test/org/h2/test/jdbc/TestConnection.java
+26
-0
没有找到文件。
h2/src/main/org/h2/command/ddl/AlterTableAddConstraint.java
浏览文件 @
7e8d5029
...
...
@@ -244,20 +244,20 @@ public class AlterTableAddConstraint extends SchemaCommand {
}
int
id
=
getObjectId
();
String
name
=
generateConstraintName
(
table
);
ConstraintReferential
ref
=
new
ConstraintReferential
(
getSchema
(),
ConstraintReferential
ref
Constraint
=
new
ConstraintReferential
(
getSchema
(),
id
,
name
,
table
);
ref
.
setColumns
(
indexColumns
);
ref
.
setIndex
(
index
,
isOwner
);
ref
.
setRefTable
(
refTable
);
ref
.
setRefColumns
(
refIndexColumns
);
ref
.
setRefIndex
(
refIndex
,
isRefOwner
);
ref
Constraint
.
setColumns
(
indexColumns
);
ref
Constraint
.
setIndex
(
index
,
isOwner
);
ref
Constraint
.
setRefTable
(
refTable
);
ref
Constraint
.
setRefColumns
(
refIndexColumns
);
ref
Constraint
.
setRefIndex
(
refIndex
,
isRefOwner
);
if
(
checkExisting
)
{
ref
.
checkExistingData
(
session
);
ref
Constraint
.
checkExistingData
(
session
);
}
constraint
=
ref
;
ref
Table
.
addConstraint
(
constraint
);
ref
.
setDeleteAction
(
dele
teAction
);
ref
.
setUpdateAction
(
updateAction
)
;
refTable
.
addConstraint
(
refConstraint
)
;
ref
Constraint
.
setDeleteAction
(
deleteAction
);
ref
Constraint
.
setUpdateAction
(
upda
teAction
);
constraint
=
refConstraint
;
break
;
}
default
:
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/jdbc/JdbcConnection.java
浏览文件 @
7e8d5029
...
...
@@ -30,9 +30,11 @@ import java.util.ArrayList;
import
java.util.Collections
;
import
java.util.HashMap
;
import
java.util.Map
;
import
java.util.Objects
;
import
java.util.Properties
;
import
java.util.concurrent.Executor
;
import
java.util.regex.Pattern
;
import
org.h2.api.ErrorCode
;
import
org.h2.command.CommandInterface
;
import
org.h2.engine.ConnectionInfo
;
...
...
@@ -1738,6 +1740,12 @@ public class JdbcConnection extends TraceObject
}
checkClosed
();
// no change to property: Ignore call. This early exit fixes a problem with websphere liberty
// resetting the client info of a pooled connection to its initial values.
if
(
Objects
.
equals
(
value
,
getClientInfo
(
name
)))
{
return
;
}
if
(
isInternalProperty
(
name
))
{
throw
new
SQLClientInfoException
(
"Property name '"
+
name
+
" is used internally by H2."
,
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/tools/CreateCluster.java
浏览文件 @
7e8d5029
...
...
@@ -13,14 +13,15 @@ import java.sql.DriverManager;
import
java.sql.ResultSet
;
import
java.sql.SQLException
;
import
java.sql.Statement
;
import
org.h2.api.ErrorCode
;
import
org.h2.engine.Constants
;
import
org.h2.util.IOUtils
;
import
org.h2.util.JdbcUtils
;
import
java.util.concurrent.ExecutionException
;
import
java.util.concurrent.ExecutorService
;
import
java.util.concurrent.Executors
;
import
java.util.concurrent.Future
;
import
org.h2.util.Tool
;
/**
* Creates a cluster from a standalone database.
* Creates a cluster from a stand
-
alone database.
* <br />
* Copies a database to another location if required.
* @h2.resource
...
...
@@ -100,116 +101,98 @@ public class CreateCluster extends Tool {
private
static
void
process
(
String
urlSource
,
String
urlTarget
,
String
user
,
String
password
,
String
serverList
)
throws
SQLException
{
Connection
connSource
=
null
,
connTarget
=
null
;
Statement
statSource
=
null
,
statTarget
=
null
;
PipedReader
pipeReader
=
null
;
try
{
org
.
h2
.
Driver
.
load
();
// verify that the database doesn't exist,
// or if it exists (an old cluster instance), it is deleted
boolean
exists
=
true
;
try
{
connTarget
=
DriverManager
.
getConnection
(
urlTarget
+
";IFEXISTS=TRUE;CLUSTER="
+
Constants
.
CLUSTERING_ENABLED
,
user
,
password
);
Statement
stat
=
connTarget
.
createStatement
();
stat
.
execute
(
"DROP ALL OBJECTS DELETE FILES"
);
stat
.
close
();
exists
=
false
;
connTarget
.
close
();
}
catch
(
SQLException
e
)
{
if
(
e
.
getErrorCode
()
==
ErrorCode
.
DATABASE_NOT_FOUND_1
)
{
// database does not exists yet - ok
exists
=
false
;
}
else
{
throw
e
;
}
}
if
(
exists
)
{
throw
new
SQLException
(
"Target database must not yet exist. Please delete it first: "
+
urlTarget
);
}
try
(
Connection
connSource
=
DriverManager
.
getConnection
(
// use cluster='' so connecting is possible
// even if the cluster is enabled
connSource
=
DriverManager
.
getConnection
(
urlSource
+
";CLUSTER=''"
,
user
,
password
);
statSource
=
connSource
.
createStatement
();
urlSource
+
";CLUSTER=''"
,
user
,
password
);
Statement
statSource
=
connSource
.
createStatement
())
{
// enable the exclusive mode and close other connections,
// so that data can't change while restoring the second database
statSource
.
execute
(
"SET EXCLUSIVE 2"
);
pipeReader
=
new
PipedReader
();
try
{
/*
* Pipe writer is used + closed in the inner class, in a
* separate thread (needs to be final). It should be initialized
* within try{} so an exception could be caught if creation
* fails. In that scenario, the the writer should be null and
* needs no closing, and the main goal is that finally{} should
* bring the source DB out of exclusive mode, and close the
* reader.
*/
final
PipedWriter
pipeWriter
=
new
PipedWriter
(
pipeReader
);
performTransfer
(
statSource
,
urlTarget
,
user
,
password
,
serverList
);
}
finally
{
// switch back to the regular mode
statSource
.
execute
(
"SET EXCLUSIVE FALSE"
);
}
}
}
// Backup data from source database in script form.
// Start writing to pipe writer in separate thread.
final
ResultSet
rs
=
statSource
.
executeQuery
(
"SCRIPT"
);
private
static
void
performTransfer
(
Statement
statSource
,
String
urlTarget
,
String
user
,
String
password
,
String
serverList
)
throws
SQLException
{
// Delete the target database first.
connTarget
=
DriverManager
.
getConnection
(
try
(
Connection
connTarget
=
DriverManager
.
getConnection
(
urlTarget
+
";CLUSTER=''"
,
user
,
password
);
statTarget
=
connTarget
.
createStatement
();
Statement
statTarget
=
connTarget
.
createStatement
())
{
statTarget
.
execute
(
"DROP ALL OBJECTS DELETE FILES"
);
connTarget
.
close
();
}
try
(
PipedReader
pipeReader
=
new
PipedReader
())
{
Future
<?>
threadFuture
=
startWriter
(
pipeReader
,
statSource
);
new
Thread
(
new
Runnable
(){
@Override
public
void
run
()
{
// Read data from pipe reader, restore on target.
try
(
Connection
connTarget
=
DriverManager
.
getConnection
(
urlTarget
,
user
,
password
);
Statement
statTarget
=
connTarget
.
createStatement
())
{
RunScript
.
execute
(
connTarget
,
pipeReader
);
// Check if the writer encountered any exception
try
{
while
(
rs
.
next
())
{
pipeWriter
.
write
(
rs
.
getString
(
1
)
+
"\n"
);
}
}
catch
(
SQLException
ex
)
{
throw
new
IllegalStateException
(
"Producing script from the source DB is failing."
,
ex
);
}
catch
(
IOException
ex
)
{
throw
new
IllegalStateException
(
"Producing script from the source DB is failing."
,
ex
);
}
finally
{
IOUtils
.
closeSilently
(
pipeWriter
);
}
}
threadFuture
.
get
();
}
catch
(
ExecutionException
ex
)
{
throw
new
SQLException
(
ex
.
getCause
());
}
catch
(
InterruptedException
ex
)
{
throw
new
SQLException
(
ex
);
}
).
start
();
// Read data from pipe reader, restore on target.
connTarget
=
DriverManager
.
getConnection
(
urlTarget
,
user
,
password
);
RunScript
.
execute
(
connTarget
,
pipeReader
);
statTarget
=
connTarget
.
createStatement
();
// set the cluster to the serverList on both databases
statSource
.
executeUpdate
(
"SET CLUSTER '"
+
serverList
+
"'"
);
statTarget
.
executeUpdate
(
"SET CLUSTER '"
+
serverList
+
"'"
);
}
}
catch
(
IOException
ex
)
{
throw
new
SQLException
(
ex
);
}
finally
{
// switch back to the regular mode
statSource
.
execute
(
"SET EXCLUSIVE FALSE"
);
}
}
finally
{
IOUtils
.
closeSilently
(
pipeReader
);
JdbcUtils
.
closeSilently
(
statSource
);
JdbcUtils
.
closeSilently
(
statTarget
);
JdbcUtils
.
closeSilently
(
connSource
);
JdbcUtils
.
closeSilently
(
connTarget
);
}
private
static
Future
<?>
startWriter
(
final
PipedReader
pipeReader
,
final
Statement
statSource
)
throws
SQLException
,
IOException
{
final
ExecutorService
thread
=
Executors
.
newFixedThreadPool
(
1
);
// Since exceptions cannot be thrown across thread boundaries, return
// the task's future so we can check manually
Future
<?>
threadFuture
=
thread
.
submit
(
new
Runnable
()
{
@Override
public
void
run
()
{
/*
* If the creation of the piped writer fails, the reader will
* throw an IOException as soon as read() is called:
* IOException - if the pipe is broken, unconnected, closed,
* or an I/O error occurs.
* The reader's IOException will then trigger the finally{} that
* releases exclusive mode on the source DB.
*/
try
(
final
PipedWriter
pipeWriter
=
new
PipedWriter
(
pipeReader
);
final
ResultSet
rs
=
statSource
.
executeQuery
(
"SCRIPT"
))
{
while
(
rs
.
next
())
{
pipeWriter
.
write
(
rs
.
getString
(
1
)
+
"\n"
);
}
}
catch
(
SQLException
|
IOException
ex
)
{
throw
new
IllegalStateException
(
"Producing script from the source DB is failing."
,
ex
);
}
}
});
thread
.
shutdown
();
return
threadFuture
;
}
}
This diff is collapsed.
Click to expand it.
h2/src/test/org/h2/test/jdbc/TestConnection.java
浏览文件 @
7e8d5029
...
...
@@ -13,6 +13,8 @@ import java.sql.SQLException;
import
java.sql.Statement
;
import
java.util.Properties
;
/**
* Tests the client info
*/
...
...
@@ -35,6 +37,7 @@ public class TestConnection extends TestBase {
testSetSupportedClientInfoProperties
();
testSetUnsupportedClientInfoProperties
();
testSetInternalProperty
();
testSetInternalPropertyToInitialValue
();
testSetGetSchema
();
}
...
...
@@ -48,6 +51,29 @@ public class TestConnection extends TestBase {
conn
.
close
();
}
/**
* Test that no exception is thrown if the client info of a connection managed in a connection pool is reset
* to its initial values.
*
* This is needed when using h2 in websphere liberty.
*/
private
void
testSetInternalPropertyToInitialValue
()
throws
SQLException
{
// Use MySQL-mode since this allows all property names
// (apart from h2 internal names).
Connection
conn
=
getConnection
(
"clientInfoMySQL;MODE=MySQL"
);
String
numServersPropertyName
=
"numServers"
;
String
numServers
=
conn
.
getClientInfo
(
numServersPropertyName
);
conn
.
setClientInfo
(
numServersPropertyName
,
numServers
);
assertEquals
(
conn
.
getClientInfo
(
numServersPropertyName
),
numServers
);
conn
.
close
();
}
private
void
testSetUnsupportedClientInfoProperties
()
throws
SQLException
{
Connection
conn
=
getConnection
(
"clientInfo"
);
...
...
This diff is collapsed.
Click to expand it.
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论