Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
taosdata
TDengine
提交
c15bba01
T
TDengine
项目概览
taosdata
/
TDengine
1 年多 前同步成功
通知
1185
Star
22016
Fork
4786
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
1
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
T
TDengine
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
1
Issue
1
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
c15bba01
编写于
4月 28, 2022
作者:
P
plum-lihui
浏览文件
操作
浏览文件
下载
差异文件
Merge branch '3.0' of github.com:taosdata/TDengine into 3.0
上级
1d2e37e6
c934d009
变更
12
展开全部
隐藏空白更改
内联
并排
Showing
12 changed file
with
235 addition
and
200 deletion
+235
-200
example/src/tstream.c
example/src/tstream.c
+6
-3
include/client/taos.h
include/client/taos.h
+38
-40
include/common/trow.h
include/common/trow.h
+28
-1
include/libs/stream/tstream.h
include/libs/stream/tstream.h
+0
-19
source/client/src/tmq.c
source/client/src/tmq.c
+3
-1
source/dnode/mnode/impl/src/mndDef.c
source/dnode/mnode/impl/src/mndDef.c
+6
-0
source/dnode/mnode/impl/src/mndStream.c
source/dnode/mnode/impl/src/mndStream.c
+9
-2
source/dnode/vnode/src/meta/metaQuery.c
source/dnode/vnode/src/meta/metaQuery.c
+2
-2
source/dnode/vnode/src/tq/tq.c
source/dnode/vnode/src/tq/tq.c
+1
-1
source/libs/executor/src/executorimpl.c
source/libs/executor/src/executorimpl.c
+140
-131
tests/system-test/fulltest.sh
tests/system-test/fulltest.sh
+1
-0
tests/test-all.sh
tests/test-all.sh
+1
-0
未找到文件。
example/src/tstream.c
浏览文件 @
c15bba01
...
...
@@ -78,11 +78,14 @@ int32_t create_stream() {
taos_free_result
(
pRes
);
/*const char* sql = "select min(k), max(k), sum(k) from tu1";*/
const
char
*
sql
=
"select min(k), max(k), sum(k) as sum_of_k from st1"
;
/*const char* sql = "select min(k), max(k), sum(k) as sum_of_k from st1";*/
/*const char* sql = "select sum(k) from tu1 interval(10m)";*/
pRes
=
tmq_create_stream
(
pConn
,
"stream1"
,
"out1"
,
sql
);
/*pRes = tmq_create_stream(pConn, "stream1", "out1", sql);*/
pRes
=
taos_query
(
pConn
,
"create stream stream1 trigger window_close as select min(k), max(k), sum(k) as sum_of_k from tu1 interval(10m)"
);
if
(
taos_errno
(
pRes
)
!=
0
)
{
printf
(
"failed to create stream
out
1, reason:%s
\n
"
,
taos_errstr
(
pRes
));
printf
(
"failed to create stream
stream
1, reason:%s
\n
"
,
taos_errstr
(
pRes
));
return
-
1
;
}
taos_free_result
(
pRes
);
...
...
include/client/taos.h
浏览文件 @
c15bba01
...
...
@@ -86,9 +86,9 @@ typedef struct taosField {
}
TAOS_FIELD
;
#ifdef WINDOWS
#define DLL_EXPORT
__declspec(dllexport)
#define DLL_EXPORT
__declspec(dllexport)
#else
#define DLL_EXPORT
#define DLL_EXPORT
#endif
typedef
void
(
*
__taos_async_fn_t
)(
void
*
param
,
TAOS_RES
*
,
int
code
);
...
...
@@ -123,42 +123,42 @@ DLL_EXPORT int taos_options(TSDB_OPTION option, const void *arg, ...);
DLL_EXPORT
setConfRet
taos_set_config
(
const
char
*
config
);
DLL_EXPORT
int
taos_init
(
void
);
DLL_EXPORT
TAOS
*
taos_connect
(
const
char
*
ip
,
const
char
*
user
,
const
char
*
pass
,
const
char
*
db
,
uint16_t
port
);
DLL_EXPORT
TAOS
*
taos_connect_l
(
const
char
*
ip
,
int
ipLen
,
const
char
*
user
,
int
userLen
,
const
char
*
pass
,
int
passLen
,
DLL_EXPORT
TAOS
*
taos_connect_l
(
const
char
*
ip
,
int
ipLen
,
const
char
*
user
,
int
userLen
,
const
char
*
pass
,
int
passLen
,
const
char
*
db
,
int
dbLen
,
uint16_t
port
);
DLL_EXPORT
TAOS
*
taos_connect_auth
(
const
char
*
ip
,
const
char
*
user
,
const
char
*
auth
,
const
char
*
db
,
uint16_t
port
);
DLL_EXPORT
void
taos_close
(
TAOS
*
taos
);
const
char
*
taos_data_type
(
int
type
);
DLL_EXPORT
TAOS_STMT
*
taos_stmt_init
(
TAOS
*
taos
);
DLL_EXPORT
int
taos_stmt_prepare
(
TAOS_STMT
*
stmt
,
const
char
*
sql
,
unsigned
long
length
);
DLL_EXPORT
int
taos_stmt_set_tbname_tags
(
TAOS_STMT
*
stmt
,
const
char
*
name
,
TAOS_MULTI_BIND
*
tags
);
DLL_EXPORT
int
taos_stmt_set_tbname
(
TAOS_STMT
*
stmt
,
const
char
*
name
);
DLL_EXPORT
int
taos_stmt_set_sub_tbname
(
TAOS_STMT
*
stmt
,
const
char
*
name
);
DLL_EXPORT
int
taos_stmt_is_insert
(
TAOS_STMT
*
stmt
,
int
*
insert
);
DLL_EXPORT
int
taos_stmt_num_params
(
TAOS_STMT
*
stmt
,
int
*
nums
);
DLL_EXPORT
int
taos_stmt_get_param
(
TAOS_STMT
*
stmt
,
int
idx
,
int
*
type
,
int
*
bytes
);
DLL_EXPORT
int
taos_stmt_bind_param
(
TAOS_STMT
*
stmt
,
TAOS_MULTI_BIND
*
bind
);
DLL_EXPORT
int
taos_stmt_bind_param_batch
(
TAOS_STMT
*
stmt
,
TAOS_MULTI_BIND
*
bind
);
DLL_EXPORT
int
taos_stmt_bind_single_param_batch
(
TAOS_STMT
*
stmt
,
TAOS_MULTI_BIND
*
bind
,
int
colIdx
);
DLL_EXPORT
int
taos_stmt_add_batch
(
TAOS_STMT
*
stmt
);
DLL_EXPORT
int
taos_stmt_execute
(
TAOS_STMT
*
stmt
);
DLL_EXPORT
TAOS_RES
*
taos_stmt_use_result
(
TAOS_STMT
*
stmt
);
DLL_EXPORT
int
taos_stmt_close
(
TAOS_STMT
*
stmt
);
DLL_EXPORT
char
*
taos_stmt_errstr
(
TAOS_STMT
*
stmt
);
DLL_EXPORT
int
taos_stmt_affected_rows
(
TAOS_STMT
*
stmt
);
DLL_EXPORT
int
taos_stmt_affected_rows_once
(
TAOS_STMT
*
stmt
);
DLL_EXPORT
TAOS_RES
*
taos_query
(
TAOS
*
taos
,
const
char
*
sql
);
DLL_EXPORT
TAOS_RES
*
taos_query_l
(
TAOS
*
taos
,
const
char
*
sql
,
int
sqlLen
);
DLL_EXPORT
TAOS_ROW
taos_fetch_row
(
TAOS_RES
*
res
);
DLL_EXPORT
int
taos_result_precision
(
TAOS_RES
*
res
);
// get the time precision of result
DLL_EXPORT
void
taos_free_result
(
TAOS_RES
*
res
);
DLL_EXPORT
int
taos_field_count
(
TAOS_RES
*
res
);
DLL_EXPORT
int
taos_num_fields
(
TAOS_RES
*
res
);
DLL_EXPORT
int
taos_affected_rows
(
TAOS_RES
*
res
);
DLL_EXPORT
TAOS
*
taos_connect_auth
(
const
char
*
ip
,
const
char
*
user
,
const
char
*
auth
,
const
char
*
db
,
uint16_t
port
);
DLL_EXPORT
void
taos_close
(
TAOS
*
taos
);
const
char
*
taos_data_type
(
int
type
);
DLL_EXPORT
TAOS_STMT
*
taos_stmt_init
(
TAOS
*
taos
);
DLL_EXPORT
int
taos_stmt_prepare
(
TAOS_STMT
*
stmt
,
const
char
*
sql
,
unsigned
long
length
);
DLL_EXPORT
int
taos_stmt_set_tbname_tags
(
TAOS_STMT
*
stmt
,
const
char
*
name
,
TAOS_MULTI_BIND
*
tags
);
DLL_EXPORT
int
taos_stmt_set_tbname
(
TAOS_STMT
*
stmt
,
const
char
*
name
);
DLL_EXPORT
int
taos_stmt_set_sub_tbname
(
TAOS_STMT
*
stmt
,
const
char
*
name
);
DLL_EXPORT
int
taos_stmt_is_insert
(
TAOS_STMT
*
stmt
,
int
*
insert
);
DLL_EXPORT
int
taos_stmt_num_params
(
TAOS_STMT
*
stmt
,
int
*
nums
);
DLL_EXPORT
int
taos_stmt_get_param
(
TAOS_STMT
*
stmt
,
int
idx
,
int
*
type
,
int
*
bytes
);
DLL_EXPORT
int
taos_stmt_bind_param
(
TAOS_STMT
*
stmt
,
TAOS_MULTI_BIND
*
bind
);
DLL_EXPORT
int
taos_stmt_bind_param_batch
(
TAOS_STMT
*
stmt
,
TAOS_MULTI_BIND
*
bind
);
DLL_EXPORT
int
taos_stmt_bind_single_param_batch
(
TAOS_STMT
*
stmt
,
TAOS_MULTI_BIND
*
bind
,
int
colIdx
);
DLL_EXPORT
int
taos_stmt_add_batch
(
TAOS_STMT
*
stmt
);
DLL_EXPORT
int
taos_stmt_execute
(
TAOS_STMT
*
stmt
);
DLL_EXPORT
TAOS_RES
*
taos_stmt_use_result
(
TAOS_STMT
*
stmt
);
DLL_EXPORT
int
taos_stmt_close
(
TAOS_STMT
*
stmt
);
DLL_EXPORT
char
*
taos_stmt_errstr
(
TAOS_STMT
*
stmt
);
DLL_EXPORT
int
taos_stmt_affected_rows
(
TAOS_STMT
*
stmt
);
DLL_EXPORT
int
taos_stmt_affected_rows_once
(
TAOS_STMT
*
stmt
);
DLL_EXPORT
TAOS_RES
*
taos_query
(
TAOS
*
taos
,
const
char
*
sql
);
DLL_EXPORT
TAOS_RES
*
taos_query_l
(
TAOS
*
taos
,
const
char
*
sql
,
int
sqlLen
);
DLL_EXPORT
TAOS_ROW
taos_fetch_row
(
TAOS_RES
*
res
);
DLL_EXPORT
int
taos_result_precision
(
TAOS_RES
*
res
);
// get the time precision of result
DLL_EXPORT
void
taos_free_result
(
TAOS_RES
*
res
);
DLL_EXPORT
int
taos_field_count
(
TAOS_RES
*
res
);
DLL_EXPORT
int
taos_num_fields
(
TAOS_RES
*
res
);
DLL_EXPORT
int
taos_affected_rows
(
TAOS_RES
*
res
);
DLL_EXPORT
TAOS_FIELD
*
taos_fetch_fields
(
TAOS_RES
*
res
);
DLL_EXPORT
int
taos_select_db
(
TAOS
*
taos
,
const
char
*
db
);
...
...
@@ -271,10 +271,8 @@ DLL_EXPORT int64_t tmq_get_response_offset(tmq_message_t *message);
/* --------------------TMPORARY INTERFACE FOR TESTING--------------------- */
#if 0
DLL_EXPORT TAOS_RES *tmq_create_topic(TAOS *taos, const char *name, const char *sql, int sqlLen);
#endif
DLL_EXPORT TAOS_RES *tmq_create_stream(TAOS *taos, const char *streamName, const char *tbName, const char *sql);
#endif
/* ------------------------------ TMQ END -------------------------------- */
#if 1 // Shuduo: temporary enable for app build
typedef
void
(
*
TAOS_SUBSCRIBE_CALLBACK
)(
TAOS_SUB
*
tsub
,
TAOS_RES
*
res
,
void
*
param
,
int
code
);
...
...
include/common/trow.h
浏览文件 @
c15bba01
...
...
@@ -595,6 +595,34 @@ static FORCE_INLINE int32_t tdSRowSetInfo(SRowBuilder *pBuilder, int32_t nCols,
return
TSDB_CODE_SUCCESS
;
}
/**
* @brief
*
* @param pBuilder
* @param nCols
* @param nBoundCols use -1 if not available
* @param flen
* @return FORCE_INLINE
*/
static
FORCE_INLINE
int32_t
tdSRowSetTpInfo
(
SRowBuilder
*
pBuilder
,
int32_t
nCols
,
int32_t
flen
)
{
pBuilder
->
flen
=
flen
;
pBuilder
->
nCols
=
nCols
;
if
(
pBuilder
->
flen
<=
0
||
pBuilder
->
nCols
<=
0
)
{
TASSERT
(
0
);
terrno
=
TSDB_CODE_INVALID_PARA
;
return
terrno
;
}
#ifdef TD_SUPPORT_BITMAP
// the primary TS key is stored separatedly
pBuilder
->
nBitmaps
=
(
int16_t
)
TD_BITMAP_BYTES
(
pBuilder
->
nCols
-
1
);
#else
pBuilder
->
nBitmaps
=
0
;
pBuilder
->
nBoundBitmaps
=
0
;
#endif
return
TSDB_CODE_SUCCESS
;
}
/**
* @brief To judge row type: STpRow/SKvRow
*
...
...
@@ -1385,7 +1413,6 @@ static void tdSRowPrint(STSRow *row, STSchema *pSchema, const char* tag) {
}
printf
(
"
\n
"
);
}
#ifdef TROW_ORIGIN_HZ
typedef
struct
{
uint32_t
nRows
;
...
...
include/libs/stream/tstream.h
浏览文件 @
c15bba01
...
...
@@ -35,19 +35,6 @@ enum {
STREAM_CREATED_BY__SMA
,
};
#if 0
// pipe -> fetch/pipe queue
// merge -> merge queue
// write -> write queue
enum {
TASK_DISPATCH_MSG__SND_PIPE = 1,
TASK_DISPATCH_MSG__SND_MERGE,
TASK_DISPATCH_MSG__VND_PIPE,
TASK_DISPATCH_MSG__VND_MERGE,
TASK_DISPATCH_MSG__VND_WRITE,
};
#endif
typedef
struct
{
int32_t
nodeId
;
// 0 for snode
SEpSet
epSet
;
...
...
@@ -100,10 +87,6 @@ typedef struct {
int8_t
reserved
;
}
STaskSinkFetch
;
typedef
struct
{
int8_t
reserved
;
}
STaskSinkShow
;
enum
{
TASK_SOURCE__SCAN
=
1
,
TASK_SOURCE__PIPE
,
...
...
@@ -128,7 +111,6 @@ enum {
TASK_SINK__TABLE
,
TASK_SINK__SMA
,
TASK_SINK__FETCH
,
TASK_SINK__SHOW
,
};
typedef
struct
{
...
...
@@ -155,7 +137,6 @@ typedef struct {
STaskSinkTb
tbSink
;
STaskSinkSma
smaSink
;
STaskSinkFetch
fetchSink
;
STaskSinkShow
showSink
;
};
// dispatch
...
...
source/client/src/tmq.c
浏览文件 @
c15bba01
...
...
@@ -667,7 +667,7 @@ tmq_resp_err_t tmq_subscribe(tmq_t* tmq, const tmq_list_t* topic_list) {
if
(
code
!=
0
)
goto
FAIL
;
while
(
TSDB_CODE_MND_CONSUMER_NOT_READY
==
tmqAskEp
(
tmq
,
false
))
{
tscDebug
(
"not ready, retry"
);
tscDebug
(
"
consumer
not ready, retry"
);
taosMsleep
(
500
);
}
...
...
@@ -693,6 +693,7 @@ void tmq_conf_set_offset_commit_cb(tmq_conf_t* conf, tmq_commit_cb* cb) {
conf
->
commitCb
=
cb
;
}
#if 0
TAOS_RES* tmq_create_stream(TAOS* taos, const char* streamName, const char* tbName, const char* sql) {
STscObj* pTscObj = (STscObj*)taos;
SRequestObj* pRequest = NULL;
...
...
@@ -777,6 +778,7 @@ _return:
return pRequest;
}
#endif
#if 0
int32_t tmqGetSkipLogNum(tmq_message_t* tmq_message) {
...
...
source/dnode/mnode/impl/src/mndDef.c
浏览文件 @
c15bba01
...
...
@@ -418,6 +418,9 @@ int32_t tEncodeSStreamObj(SCoder *pEncoder, const SStreamObj *pObj) {
if
(
tEncodeI32
(
pEncoder
,
pObj
->
version
)
<
0
)
return
-
1
;
if
(
tEncodeI8
(
pEncoder
,
pObj
->
status
)
<
0
)
return
-
1
;
if
(
tEncodeI8
(
pEncoder
,
pObj
->
createdBy
)
<
0
)
return
-
1
;
if
(
tEncodeI8
(
pEncoder
,
pObj
->
trigger
)
<
0
)
return
-
1
;
if
(
tEncodeI32
(
pEncoder
,
pObj
->
triggerParam
)
<
0
)
return
-
1
;
if
(
tEncodeI64
(
pEncoder
,
pObj
->
waterMark
)
<
0
)
return
-
1
;
if
(
tEncodeI32
(
pEncoder
,
pObj
->
fixedSinkVgId
)
<
0
)
return
-
1
;
if
(
tEncodeI64
(
pEncoder
,
pObj
->
smaId
)
<
0
)
return
-
1
;
if
(
tEncodeCStr
(
pEncoder
,
pObj
->
sql
)
<
0
)
return
-
1
;
...
...
@@ -464,6 +467,9 @@ int32_t tDecodeSStreamObj(SCoder *pDecoder, SStreamObj *pObj) {
if
(
tDecodeI32
(
pDecoder
,
&
pObj
->
version
)
<
0
)
return
-
1
;
if
(
tDecodeI8
(
pDecoder
,
&
pObj
->
status
)
<
0
)
return
-
1
;
if
(
tDecodeI8
(
pDecoder
,
&
pObj
->
createdBy
)
<
0
)
return
-
1
;
if
(
tDecodeI8
(
pDecoder
,
&
pObj
->
trigger
)
<
0
)
return
-
1
;
if
(
tDecodeI32
(
pDecoder
,
&
pObj
->
triggerParam
)
<
0
)
return
-
1
;
if
(
tDecodeI64
(
pDecoder
,
&
pObj
->
waterMark
)
<
0
)
return
-
1
;
if
(
tDecodeI32
(
pDecoder
,
&
pObj
->
fixedSinkVgId
)
<
0
)
return
-
1
;
if
(
tDecodeI64
(
pDecoder
,
&
pObj
->
smaId
)
<
0
)
return
-
1
;
if
(
tDecodeCStrAlloc
(
pDecoder
,
&
pObj
->
sql
)
<
0
)
return
-
1
;
...
...
source/dnode/mnode/impl/src/mndStream.c
浏览文件 @
c15bba01
...
...
@@ -308,6 +308,8 @@ static int32_t mndCreateStream(SMnode *pMnode, SNodeMsg *pReq, SCMCreateStreamRe
streamObj
.
smaId
=
0
;
/*streamObj.physicalPlan = "";*/
streamObj
.
logicalPlan
=
"not implemented"
;
streamObj
.
trigger
=
pCreate
->
triggerType
;
streamObj
.
waterMark
=
pCreate
->
watermark
;
STrans
*
pTrans
=
mndTransCreate
(
pMnode
,
TRN_POLICY_RETRY
,
TRN_TYPE_CREATE_STREAM
,
&
pReq
->
rpcMsg
);
if
(
pTrans
==
NULL
)
{
...
...
@@ -431,7 +433,7 @@ static int32_t mndRetrieveStream(SNodeMsg *pReq, SShowObj *pShow, SSDataBlock *p
SStreamObj
*
pStream
=
NULL
;
while
(
numOfRows
<
rows
)
{
pShow
->
pIter
=
sdbFetch
(
pSdb
,
SDB_
TOPIC
,
pShow
->
pIter
,
(
void
**
)
&
pStream
);
pShow
->
pIter
=
sdbFetch
(
pSdb
,
SDB_
STREAM
,
pShow
->
pIter
,
(
void
**
)
&
pStream
);
if
(
pShow
->
pIter
==
NULL
)
break
;
SColumnInfoData
*
pColInfo
;
...
...
@@ -471,8 +473,13 @@ static int32_t mndRetrieveStream(SNodeMsg *pReq, SShowObj *pShow, SSDataBlock *p
pColInfo
=
taosArrayGet
(
pBlock
->
pDataBlock
,
cols
++
);
colDataAppend
(
pColInfo
,
numOfRows
,
(
const
char
*
)
&
pStream
->
trigger
,
false
);
numOfRows
++
;
sdbRelease
(
pSdb
,
pStream
);
}
return
0
;
pShow
->
numOfRows
+=
numOfRows
;
return
numOfRows
;
}
static
void
mndCancelGetNextStream
(
SMnode
*
pMnode
,
void
*
pIter
)
{
...
...
source/dnode/vnode/src/meta/metaQuery.c
浏览文件 @
c15bba01
...
...
@@ -159,7 +159,7 @@ SSchemaWrapper *metaGetTableSchema(SMeta *pMeta, tb_uid_t uid, int32_t sver, boo
// decode
pBuf
=
pVal
;
pSW
=
taosMemoryMalloc
(
sizeof
(
pSW
));
pSW
=
taosMemoryMalloc
(
sizeof
(
SSchemaWrapper
));
tCoderInit
(
&
coder
,
TD_LITTLE_ENDIAN
,
pVal
,
vLen
,
TD_DECODER
);
tDecodeSSchemaWrapper
(
&
coder
,
pSW
);
...
...
@@ -436,4 +436,4 @@ void *metaGetSmaInfoByIndex(SMeta *pMeta, int64_t indexUid, bool isDecode) {
return
NULL
;
}
#endif
\ No newline at end of file
#endif
source/dnode/vnode/src/tq/tq.c
浏览文件 @
c15bba01
...
...
@@ -864,7 +864,7 @@ int32_t tqExpandTask(STQ* pTq, SStreamTask* pTask, int32_t parallel) {
}
int32_t
tqProcessTaskDeploy
(
STQ
*
pTq
,
char
*
msg
,
int32_t
msgLen
)
{
SStreamTask
*
pTask
=
taosMemory
Malloc
(
sizeof
(
SStreamTask
));
SStreamTask
*
pTask
=
taosMemory
Calloc
(
1
,
sizeof
(
SStreamTask
));
if
(
pTask
==
NULL
)
{
return
-
1
;
}
...
...
source/libs/executor/src/executorimpl.c
浏览文件 @
c15bba01
此差异已折叠。
点击以展开。
tests/system-test/fulltest.sh
浏览文件 @
c15bba01
#!/bin/bash
set
-e
set
-x
python3 ./test.py
-f
0-others/taosShell.py
...
...
tests/test-all.sh
浏览文件 @
c15bba01
...
...
@@ -93,6 +93,7 @@ function runSimCaseOneByOnefq {
if
[[
$line
=
~ ^./test.sh
*
]]
||
[[
$line
=
~ ^run
*
]]
;
then
#case=`echo $line | grep sim$ |awk '{print $NF}'`
case
=
`
echo
$line
|
grep
-o
".*
\.
sim"
|awk
'{print $NF}'
`
echo
"
$line
running ..."
start_time
=
`
date
+%s
`
date
+%F
\
%T
|
tee
-a
out.log
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录