Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
慢慢CG
TDengine
提交
a99b708a
T
TDengine
项目概览
慢慢CG
/
TDengine
与 Fork 源项目一致
Fork自
taosdata / TDengine
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
T
TDengine
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
a99b708a
编写于
2月 23, 2021
作者:
Z
zyyang
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
change
上级
106f750b
变更
4
隐藏空白更改
内联
并排
Showing
4 changed file
with
440 addition
and
9 deletion
+440
-9
src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulStatement.java
.../src/main/java/com/taosdata/jdbc/rs/RestfulStatement.java
+20
-2
src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/ImportTest.java
...dbc/src/test/java/com/taosdata/jdbc/cases/ImportTest.java
+1
-1
src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/RestfulConnectionTest.java
...test/java/com/taosdata/jdbc/rs/RestfulConnectionTest.java
+2
-6
src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/RestfulStatementTest.java
.../test/java/com/taosdata/jdbc/rs/RestfulStatementTest.java
+417
-0
未找到文件。
src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulStatement.java
浏览文件 @
a99b708a
package
com.taosdata.jdbc.rs
;
import
com.alibaba.fastjson.JSON
;
import
com.alibaba.fastjson.JSONArray
;
import
com.alibaba.fastjson.JSONObject
;
import
com.taosdata.jdbc.AbstractStatement
;
import
com.taosdata.jdbc.TSDBConstants
;
...
...
@@ -115,24 +116,28 @@ public class RestfulStatement extends AbstractStatement {
throw
TSDBError
.
createSQLException
(
TSDBErrorNumbers
.
ERROR_INVALID_FOR_EXECUTE
,
"not a valid sql for execute: "
+
sql
);
//如果执行了use操作应该将当前Statement的catalog设置为新的database
boolean
result
=
true
;
final
String
url
=
"http://"
+
conn
.
getHost
()
+
":"
+
conn
.
getPort
()
+
"/rest/sql"
;
if
(
SqlSyntaxValidator
.
isUseSql
(
sql
))
{
HttpClientPoolUtil
.
execute
(
url
,
sql
);
this
.
database
=
sql
.
trim
().
replace
(
"use"
,
""
).
trim
();
this
.
conn
.
setCatalog
(
this
.
database
);
result
=
false
;
}
else
if
(
SqlSyntaxValidator
.
isDatabaseUnspecifiedQuery
(
sql
))
{
executeOneQuery
(
url
,
sql
);
}
else
if
(
SqlSyntaxValidator
.
isDatabaseUnspecifiedUpdate
(
sql
))
{
executeOneUpdate
(
url
,
sql
);
result
=
false
;
}
else
{
if
(
SqlSyntaxValidator
.
isValidForExecuteQuery
(
sql
))
{
executeQuery
(
sql
);
}
else
{
executeUpdate
(
sql
);
result
=
false
;
}
}
return
true
;
return
result
;
}
private
ResultSet
executeOneQuery
(
String
url
,
String
sql
)
throws
SQLException
{
...
...
@@ -176,10 +181,23 @@ public class RestfulStatement extends AbstractStatement {
throw
new
SQLException
(
TSDBConstants
.
WrapErrMsg
(
"SQL execution error: "
+
jsonObject
.
getString
(
"desc"
)
+
"\n"
+
"error code: "
+
jsonObject
.
getString
(
"code"
)));
}
this
.
resultSet
=
null
;
this
.
affectedRows
=
Integer
.
parseInt
(
jsonObject
.
getString
(
"rows"
)
);
this
.
affectedRows
=
checkJsonResultSet
(
jsonObject
);
return
this
.
affectedRows
;
}
private
int
checkJsonResultSet
(
JSONObject
jsonObject
)
{
// create ... SQLs should return 0 , and Restful result is this:
// {"status": "succ", "head": ["affected_rows"], "data": [[0]], "rows": 1}
JSONArray
head
=
jsonObject
.
getJSONArray
(
"head"
);
JSONArray
data
=
jsonObject
.
getJSONArray
(
"data"
);
int
rows
=
Integer
.
parseInt
(
jsonObject
.
getString
(
"rows"
));
if
(
head
.
size
()
==
1
&&
"affected_rows"
.
equals
(
head
.
getString
(
0
))
&&
data
.
size
()
==
1
&&
data
.
getJSONArray
(
0
).
getInteger
(
0
)
==
0
&&
rows
==
1
)
{
return
0
;
}
return
rows
;
}
@Override
public
ResultSet
getResultSet
()
throws
SQLException
{
if
(
isClosed
())
...
...
src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/ImportTest.java
浏览文件 @
a99b708a
...
...
@@ -12,7 +12,7 @@ import static org.junit.Assert.assertEquals;
@FixMethodOrder
(
MethodSorters
.
NAME_ASCENDING
)
public
class
ImportTest
{
private
static
Connection
connection
;
static
String
dbName
=
"test"
;
static
String
dbName
=
"test
_import
"
;
static
String
tName
=
"t0"
;
static
String
host
=
"127.0.0.1"
;
private
static
long
ts
;
...
...
src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/RestfulConnectionTest.java
浏览文件 @
a99b708a
package
com.taosdata.jdbc.rs
;
import
com.taosdata.jdbc.TSDBConnection
;
import
com.taosdata.jdbc.TSDBDriver
;
import
com.taosdata.jdbc.TSDBResultSet
;
import
com.taosdata.jdbc.TSDBSubscribe
;
import
org.junit.AfterClass
;
import
org.junit.Assert
;
import
org.junit.BeforeClass
;
import
org.junit.Test
;
import
javax.management.OperationsException
;
import
java.sql.*
;
import
java.util.Properties
;
public
class
RestfulConnectionTest
{
//
private static final String host = "127.0.0.1";
private
static
final
String
host
=
"master"
;
private
static
final
String
host
=
"127.0.0.1"
;
//
private static final String host = "master";
private
static
Connection
conn
;
@Test
...
...
src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/RestfulStatementTest.java
0 → 100644
浏览文件 @
a99b708a
package
com.taosdata.jdbc.rs
;
import
com.taosdata.jdbc.TSDBDriver
;
import
org.junit.AfterClass
;
import
org.junit.Assert
;
import
org.junit.BeforeClass
;
import
org.junit.Test
;
import
java.sql.*
;
import
java.util.Properties
;
import
java.util.UUID
;
public
class
RestfulStatementTest
{
private
static
final
String
host
=
"127.0.0.1"
;
// private static final String host = "master";
private
static
Connection
conn
;
private
static
Statement
stmt
;
@Test
public
void
executeQuery
()
{
try
{
ResultSet
rs
=
stmt
.
executeQuery
(
"show databases"
);
Assert
.
assertNotNull
(
rs
);
ResultSetMetaData
meta
=
rs
.
getMetaData
();
while
(
rs
.
next
())
{
for
(
int
i
=
1
;
i
<=
meta
.
getColumnCount
();
i
++)
{
System
.
out
.
print
(
meta
.
getColumnLabel
(
i
)
+
": "
+
rs
.
getString
(
i
)
+
"\t"
);
}
System
.
out
.
println
();
}
rs
.
close
();
}
catch
(
SQLException
e
)
{
e
.
printStackTrace
();
}
}
@Test
public
void
executeUpdate
()
{
final
String
dbName
=
(
"test_"
+
UUID
.
randomUUID
()).
replace
(
"-"
,
"_"
).
substring
(
0
,
32
);
try
{
int
affectRows
=
stmt
.
executeUpdate
(
"create database "
+
dbName
);
Assert
.
assertEquals
(
0
,
affectRows
);
affectRows
=
stmt
.
executeUpdate
(
"create table "
+
dbName
+
".weather(ts timestamp, temperature float) tags(loc nchar(64))"
);
Assert
.
assertEquals
(
0
,
affectRows
);
affectRows
=
stmt
.
executeUpdate
(
"insert into "
+
dbName
+
".t1 using "
+
dbName
+
".weather tags('北京') values(now, 22.33)"
);
Assert
.
assertEquals
(
1
,
affectRows
);
affectRows
=
stmt
.
executeUpdate
(
"drop database "
+
dbName
);
Assert
.
assertEquals
(
0
,
affectRows
);
}
catch
(
SQLException
e
)
{
e
.
printStackTrace
();
}
}
@Test
public
void
close
()
{
// test in AfterClass method
}
@Test
public
void
getMaxFieldSize
()
throws
SQLException
{
Assert
.
assertEquals
(
16
*
1024
,
stmt
.
getMaxFieldSize
());
}
@Test
(
expected
=
SQLException
.
class
)
public
void
setMaxFieldSize
()
throws
SQLException
{
stmt
.
setMaxFieldSize
(
0
);
stmt
.
setMaxFieldSize
(-
1
);
}
@Test
public
void
getMaxRows
()
throws
SQLException
{
Assert
.
assertEquals
(
0
,
stmt
.
getMaxRows
());
}
@Test
(
expected
=
SQLException
.
class
)
public
void
setMaxRows
()
throws
SQLException
{
stmt
.
setMaxRows
(
0
);
stmt
.
setMaxRows
(-
1
);
}
@Test
public
void
setEscapeProcessing
()
throws
SQLException
{
stmt
.
setEscapeProcessing
(
true
);
stmt
.
setEscapeProcessing
(
false
);
}
@Test
public
void
getQueryTimeout
()
throws
SQLException
{
Assert
.
assertEquals
(
0
,
stmt
.
getQueryTimeout
());
}
@Test
(
expected
=
SQLException
.
class
)
public
void
setQueryTimeout
()
throws
SQLException
{
stmt
.
setQueryTimeout
(
0
);
stmt
.
setQueryTimeout
(-
1
);
}
@Test
(
expected
=
SQLFeatureNotSupportedException
.
class
)
public
void
cancel
()
throws
SQLException
{
stmt
.
cancel
();
}
@Test
public
void
getWarnings
()
throws
SQLException
{
Assert
.
assertNull
(
stmt
.
getWarnings
());
}
@Test
public
void
clearWarnings
()
throws
SQLException
{
stmt
.
clearWarnings
();
}
@Test
(
expected
=
SQLFeatureNotSupportedException
.
class
)
public
void
setCursorName
()
throws
SQLException
{
stmt
.
setCursorName
(
""
);
}
@Test
public
void
execute
()
{
final
String
dbName
=
(
"test_"
+
UUID
.
randomUUID
()).
replace
(
"-"
,
"_"
).
substring
(
0
,
32
);
try
{
boolean
isSelect
=
stmt
.
execute
(
"create database "
+
dbName
);
Assert
.
assertEquals
(
false
,
isSelect
);
int
affectedRows
=
stmt
.
getUpdateCount
();
Assert
.
assertEquals
(
0
,
affectedRows
);
isSelect
=
stmt
.
execute
(
"create table "
+
dbName
+
".weather(ts timestamp, temperature float) tags(loc nchar(64))"
);
Assert
.
assertEquals
(
false
,
isSelect
);
affectedRows
=
stmt
.
getUpdateCount
();
Assert
.
assertEquals
(
0
,
affectedRows
);
isSelect
=
stmt
.
execute
(
"insert into "
+
dbName
+
".t1 using "
+
dbName
+
".weather tags('北京') values(now, 22.33)"
);
Assert
.
assertEquals
(
false
,
isSelect
);
affectedRows
=
stmt
.
getUpdateCount
();
Assert
.
assertEquals
(
1
,
affectedRows
);
isSelect
=
stmt
.
execute
(
"select * from "
+
dbName
+
".weather"
);
Assert
.
assertEquals
(
true
,
isSelect
);
isSelect
=
stmt
.
execute
(
"drop database "
+
dbName
);
Assert
.
assertEquals
(
false
,
isSelect
);
affectedRows
=
stmt
.
getUpdateCount
();
Assert
.
assertEquals
(
0
,
affectedRows
);
}
catch
(
SQLException
e
)
{
e
.
printStackTrace
();
}
}
@Test
public
void
getResultSet
()
{
final
String
dbName
=
(
"test_"
+
UUID
.
randomUUID
()).
replace
(
"-"
,
"_"
).
substring
(
0
,
32
);
try
{
boolean
isSelect
=
stmt
.
execute
(
"create database "
+
dbName
);
Assert
.
assertEquals
(
false
,
isSelect
);
int
affectedRows
=
stmt
.
getUpdateCount
();
Assert
.
assertEquals
(
0
,
affectedRows
);
isSelect
=
stmt
.
execute
(
"create table "
+
dbName
+
".weather(ts timestamp, temperature float) tags(loc nchar(64))"
);
Assert
.
assertEquals
(
false
,
isSelect
);
affectedRows
=
stmt
.
getUpdateCount
();
Assert
.
assertEquals
(
0
,
affectedRows
);
isSelect
=
stmt
.
execute
(
"insert into "
+
dbName
+
".t1 using "
+
dbName
+
".weather tags('北京') values(now, 22.33)"
);
Assert
.
assertEquals
(
false
,
isSelect
);
affectedRows
=
stmt
.
getUpdateCount
();
Assert
.
assertEquals
(
1
,
affectedRows
);
isSelect
=
stmt
.
execute
(
"select * from "
+
dbName
+
".weather"
);
Assert
.
assertEquals
(
true
,
isSelect
);
ResultSet
rs
=
stmt
.
getResultSet
();
Assert
.
assertNotNull
(
rs
);
ResultSetMetaData
meta
=
rs
.
getMetaData
();
Assert
.
assertEquals
(
3
,
meta
.
getColumnCount
());
int
count
=
0
;
while
(
rs
.
next
())
{
for
(
int
i
=
1
;
i
<=
meta
.
getColumnCount
();
i
++)
{
System
.
out
.
print
(
meta
.
getColumnLabel
(
i
)
+
": "
+
rs
.
getString
(
i
)
+
"\t"
);
}
System
.
out
.
println
();
count
++;
}
Assert
.
assertEquals
(
1
,
count
);
isSelect
=
stmt
.
execute
(
"drop database "
+
dbName
);
Assert
.
assertEquals
(
false
,
isSelect
);
affectedRows
=
stmt
.
getUpdateCount
();
Assert
.
assertEquals
(
0
,
affectedRows
);
}
catch
(
SQLException
e
)
{
e
.
printStackTrace
();
}
}
@Test
public
void
getUpdateCount
()
{
// already test in execute method
}
@Test
public
void
getMoreResults
()
throws
SQLException
{
Assert
.
assertEquals
(
false
,
stmt
.
getMoreResults
());
}
@Test
(
expected
=
SQLException
.
class
)
public
void
setFetchDirection
()
throws
SQLException
{
stmt
.
setFetchDirection
(
ResultSet
.
FETCH_FORWARD
);
stmt
.
setFetchDirection
(
ResultSet
.
FETCH_REVERSE
);
stmt
.
setFetchDirection
(
ResultSet
.
FETCH_UNKNOWN
);
stmt
.
setFetchDirection
(-
1
);
}
@Test
public
void
getFetchDirection
()
throws
SQLException
{
Assert
.
assertEquals
(
ResultSet
.
FETCH_FORWARD
,
stmt
.
getFetchDirection
());
}
@Test
(
expected
=
SQLException
.
class
)
public
void
setFetchSize
()
throws
SQLException
{
stmt
.
setFetchSize
(
0
);
stmt
.
setFetchSize
(-
1
);
}
@Test
public
void
getFetchSize
()
throws
SQLException
{
stmt
.
setFetchSize
(
0
);
Assert
.
assertEquals
(
0
,
stmt
.
getFetchSize
());
stmt
.
setFetchSize
(
0
);
}
@Test
public
void
getResultSetConcurrency
()
throws
SQLException
{
Assert
.
assertEquals
(
ResultSet
.
CONCUR_READ_ONLY
,
stmt
.
getResultSetConcurrency
());
}
@Test
public
void
getResultSetType
()
throws
SQLException
{
Assert
.
assertEquals
(
ResultSet
.
TYPE_FORWARD_ONLY
,
stmt
.
getResultSetType
());
}
@Test
public
void
addBatch
()
{
final
String
dbName
=
(
"test_"
+
UUID
.
randomUUID
()).
replace
(
"-"
,
"_"
).
substring
(
0
,
32
);
try
{
stmt
.
addBatch
(
"create database "
+
dbName
);
stmt
.
addBatch
(
"create table "
+
dbName
+
".weather(ts timestamp, temperature float) tags(loc nchar(64))"
);
stmt
.
addBatch
(
"insert into "
+
dbName
+
".t1 using "
+
dbName
+
".weather tags('北京') values(now, 22.33)"
);
stmt
.
addBatch
(
"select * from "
+
dbName
+
".weather"
);
stmt
.
addBatch
(
"drop database "
+
dbName
);
}
catch
(
SQLException
e
)
{
e
.
printStackTrace
();
}
}
@Test
public
void
clearBatch
()
{
final
String
dbName
=
(
"test_"
+
UUID
.
randomUUID
()).
replace
(
"-"
,
"_"
).
substring
(
0
,
32
);
try
{
stmt
.
clearBatch
();
stmt
.
addBatch
(
"create database "
+
dbName
);
stmt
.
addBatch
(
"create table "
+
dbName
+
".weather(ts timestamp, temperature float) tags(loc nchar(64))"
);
stmt
.
addBatch
(
"insert into "
+
dbName
+
".t1 using "
+
dbName
+
".weather tags('北京') values(now, 22.33)"
);
stmt
.
addBatch
(
"select * from "
+
dbName
+
".weather"
);
stmt
.
addBatch
(
"drop database "
+
dbName
);
stmt
.
clearBatch
();
}
catch
(
SQLException
e
)
{
e
.
printStackTrace
();
}
}
@Test
public
void
executeBatch
()
{
final
String
dbName
=
(
"test_"
+
UUID
.
randomUUID
()).
replace
(
"-"
,
"_"
).
substring
(
0
,
32
);
try
{
stmt
.
addBatch
(
"create database "
+
dbName
);
stmt
.
addBatch
(
"create table "
+
dbName
+
".weather(ts timestamp, temperature float) tags(loc nchar(64))"
);
stmt
.
addBatch
(
"insert into "
+
dbName
+
".t1 using "
+
dbName
+
".weather tags('北京') values(now, 22.33)"
);
stmt
.
addBatch
(
"select * from "
+
dbName
+
".weather"
);
stmt
.
addBatch
(
"drop database "
+
dbName
);
int
[]
results
=
stmt
.
executeBatch
();
Assert
.
assertEquals
(
0
,
results
[
0
]);
Assert
.
assertEquals
(
0
,
results
[
1
]);
Assert
.
assertEquals
(
1
,
results
[
2
]);
Assert
.
assertEquals
(
Statement
.
SUCCESS_NO_INFO
,
results
[
3
]);
Assert
.
assertEquals
(
0
,
results
[
4
]);
}
catch
(
SQLException
e
)
{
e
.
printStackTrace
();
}
}
@Test
public
void
getConnection
()
{
try
{
Connection
connection
=
stmt
.
getConnection
();
Assert
.
assertNotNull
(
connection
);
Assert
.
assertTrue
(
this
.
conn
==
connection
);
}
catch
(
SQLException
e
)
{
e
.
printStackTrace
();
}
}
@Test
(
expected
=
SQLFeatureNotSupportedException
.
class
)
public
void
testGetMoreResults
()
throws
SQLException
{
Assert
.
assertEquals
(
false
,
stmt
.
getMoreResults
(
Statement
.
CLOSE_CURRENT_RESULT
));
stmt
.
getMoreResults
(
Statement
.
KEEP_CURRENT_RESULT
);
}
@Test
(
expected
=
SQLFeatureNotSupportedException
.
class
)
public
void
getGeneratedKeys
()
throws
SQLException
{
stmt
.
getGeneratedKeys
();
}
@Test
(
expected
=
SQLFeatureNotSupportedException
.
class
)
public
void
testExecuteUpdate
()
throws
SQLException
{
stmt
.
executeUpdate
(
""
,
1
);
}
@Test
(
expected
=
SQLFeatureNotSupportedException
.
class
)
public
void
testExecuteUpdate1
()
throws
SQLException
{
stmt
.
executeUpdate
(
""
,
new
int
[]{});
}
@Test
(
expected
=
SQLFeatureNotSupportedException
.
class
)
public
void
testExecuteUpdate2
()
throws
SQLException
{
stmt
.
executeUpdate
(
""
,
new
String
[]{});
}
@Test
(
expected
=
SQLFeatureNotSupportedException
.
class
)
public
void
testExecute
()
throws
SQLException
{
stmt
.
execute
(
""
,
1
);
}
@Test
(
expected
=
SQLFeatureNotSupportedException
.
class
)
public
void
testExecute1
()
throws
SQLException
{
stmt
.
execute
(
""
,
new
int
[]{});
}
@Test
(
expected
=
SQLFeatureNotSupportedException
.
class
)
public
void
testExecute2
()
throws
SQLException
{
stmt
.
execute
(
""
,
new
String
[]{});
}
@Test
public
void
getResultSetHoldability
()
throws
SQLException
{
Assert
.
assertEquals
(
ResultSet
.
HOLD_CURSORS_OVER_COMMIT
,
stmt
.
getResultSetHoldability
());
}
@Test
public
void
isClosed
()
{
try
{
Assert
.
assertEquals
(
false
,
stmt
.
isClosed
());
}
catch
(
SQLException
e
)
{
e
.
printStackTrace
();
}
}
@Test
public
void
setPoolable
()
throws
SQLException
{
stmt
.
setPoolable
(
true
);
stmt
.
setPoolable
(
false
);
}
@Test
public
void
isPoolable
()
throws
SQLException
{
Assert
.
assertEquals
(
false
,
stmt
.
isPoolable
());
}
@Test
public
void
closeOnCompletion
()
throws
SQLException
{
stmt
.
closeOnCompletion
();
}
@Test
public
void
isCloseOnCompletion
()
throws
SQLException
{
Assert
.
assertFalse
(
stmt
.
isCloseOnCompletion
());
}
@Test
public
void
unwrap
()
throws
SQLException
{
RestfulStatement
unwrap
=
stmt
.
unwrap
(
RestfulStatement
.
class
);
Assert
.
assertNotNull
(
unwrap
);
}
@Test
public
void
isWrapperFor
()
throws
SQLException
{
Assert
.
assertTrue
(
stmt
.
isWrapperFor
(
RestfulStatement
.
class
));
}
@BeforeClass
public
static
void
beforeClass
()
{
try
{
Class
.
forName
(
"com.taosdata.jdbc.rs.RestfulDriver"
);
Properties
properties
=
new
Properties
();
properties
.
setProperty
(
TSDBDriver
.
PROPERTY_KEY_CHARSET
,
"UTF-8"
);
properties
.
setProperty
(
TSDBDriver
.
PROPERTY_KEY_LOCALE
,
"en_US.UTF-8"
);
properties
.
setProperty
(
TSDBDriver
.
PROPERTY_KEY_TIME_ZONE
,
"UTC-8"
);
conn
=
DriverManager
.
getConnection
(
"jdbc:TAOS-RS://"
+
host
+
":6041/?user=root&password=taosdata"
,
properties
);
stmt
=
conn
.
createStatement
();
}
catch
(
ClassNotFoundException
e
)
{
e
.
printStackTrace
();
}
catch
(
SQLException
e
)
{
e
.
printStackTrace
();
}
}
@AfterClass
public
static
void
afterClass
()
{
try
{
if
(
stmt
!=
null
)
stmt
.
close
();
if
(
conn
!=
null
)
conn
.
close
();
}
catch
(
SQLException
e
)
{
e
.
printStackTrace
();
}
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录