Merge pull request #11369 from taosdata/feature/3.0_liaohj
test[query]:update the script.
This commit is contained in:
commit
c828ed3793
|
@ -400,7 +400,7 @@ TEST(testCase, show_vgroup_Test) {
|
||||||
taos_free_result(pRes);
|
taos_free_result(pRes);
|
||||||
taos_close(pConn);
|
taos_close(pConn);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
TEST(testCase, create_multiple_tables) {
|
TEST(testCase, create_multiple_tables) {
|
||||||
TAOS* pConn = taos_connect("localhost", "root", "taosdata", NULL, 0);
|
TAOS* pConn = taos_connect("localhost", "root", "taosdata", NULL, 0);
|
||||||
|
@ -653,6 +653,7 @@ TEST(testCase, projection_query_stables) {
|
||||||
taos_free_result(pRes);
|
taos_free_result(pRes);
|
||||||
taos_close(pConn);
|
taos_close(pConn);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
TEST(testCase, agg_query_tables) {
|
TEST(testCase, agg_query_tables) {
|
||||||
TAOS* pConn = taos_connect("localhost", "root", "taosdata", NULL, 0);
|
TAOS* pConn = taos_connect("localhost", "root", "taosdata", NULL, 0);
|
||||||
|
@ -661,7 +662,7 @@ TEST(testCase, agg_query_tables) {
|
||||||
TAOS_RES* pRes = taos_query(pConn, "use abc1");
|
TAOS_RES* pRes = taos_query(pConn, "use abc1");
|
||||||
taos_free_result(pRes);
|
taos_free_result(pRes);
|
||||||
|
|
||||||
pRes = taos_query(pConn, "select count(*) from tu");
|
pRes = taos_query(pConn, "select length('abc') from tu");
|
||||||
if (taos_errno(pRes) != 0) {
|
if (taos_errno(pRes) != 0) {
|
||||||
printf("failed to select from table, reason:%s\n", taos_errstr(pRes));
|
printf("failed to select from table, reason:%s\n", taos_errstr(pRes));
|
||||||
taos_free_result(pRes);
|
taos_free_result(pRes);
|
||||||
|
|
|
@ -609,6 +609,12 @@ typedef struct SSessionAggOperatorInfo {
|
||||||
SColumnInfoData timeWindowData; // query time window info for scalar function execution.
|
SColumnInfoData timeWindowData; // query time window info for scalar function execution.
|
||||||
} SSessionAggOperatorInfo;
|
} SSessionAggOperatorInfo;
|
||||||
|
|
||||||
|
typedef struct STimeSliceOperatorInfo {
|
||||||
|
SOptrBasicInfo binfo;
|
||||||
|
SInterval interval;
|
||||||
|
SGroupResInfo groupResInfo; // multiple results build supporter
|
||||||
|
} STimeSliceOperatorInfo;
|
||||||
|
|
||||||
typedef struct SStateWindowOperatorInfo {
|
typedef struct SStateWindowOperatorInfo {
|
||||||
SOptrBasicInfo binfo;
|
SOptrBasicInfo binfo;
|
||||||
SAggSupporter aggSup;
|
SAggSupporter aggSup;
|
||||||
|
@ -707,16 +713,15 @@ SOperatorInfo* createStatewindowOperatorInfo(SOperatorInfo* downstream, SExprInf
|
||||||
|
|
||||||
SOperatorInfo* createPartitionOperatorInfo(SOperatorInfo* downstream, SExprInfo* pExprInfo, int32_t numOfCols, SSDataBlock* pResultBlock, SArray* pGroupColList,
|
SOperatorInfo* createPartitionOperatorInfo(SOperatorInfo* downstream, SExprInfo* pExprInfo, int32_t numOfCols, SSDataBlock* pResultBlock, SArray* pGroupColList,
|
||||||
SExecTaskInfo* pTaskInfo, const STableGroupInfo* pTableGroupInfo);
|
SExecTaskInfo* pTaskInfo, const STableGroupInfo* pTableGroupInfo);
|
||||||
|
SOperatorInfo* createTimeSliceOperatorInfo(SOperatorInfo* downstream, SExprInfo* pExprInfo, int32_t numOfCols, SSDataBlock* pResultBlock, SExecTaskInfo* pTaskInfo);
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
SOperatorInfo* createTableSeqScanOperatorInfo(void* pTsdbReadHandle, STaskRuntimeEnv* pRuntimeEnv);
|
SOperatorInfo* createTableSeqScanOperatorInfo(void* pTsdbReadHandle, STaskRuntimeEnv* pRuntimeEnv);
|
||||||
SOperatorInfo* createAllTimeIntervalOperatorInfo(STaskRuntimeEnv* pRuntimeEnv, SOperatorInfo* downstream,
|
|
||||||
SExprInfo* pExpr, int32_t numOfOutput);
|
|
||||||
|
|
||||||
SOperatorInfo* createMultiTableTimeIntervalOperatorInfo(STaskRuntimeEnv* pRuntimeEnv, SOperatorInfo* downstream,
|
SOperatorInfo* createMultiTableTimeIntervalOperatorInfo(STaskRuntimeEnv* pRuntimeEnv, SOperatorInfo* downstream,
|
||||||
SExprInfo* pExpr, int32_t numOfOutput);
|
SExprInfo* pExpr, int32_t numOfOutput);
|
||||||
SOperatorInfo* createAllMultiTableTimeIntervalOperatorInfo(STaskRuntimeEnv* pRuntimeEnv, SOperatorInfo* downstream,
|
SOperatorInfo* createAllMultiTableTimeIntervalOperatorInfo(STaskRuntimeEnv* pRuntimeEnv, SOperatorInfo* downstream,
|
||||||
SExprInfo* pExpr, int32_t numOfOutput);
|
SExprInfo* pExpr, int32_t numOfOutput);
|
||||||
SOperatorInfo* createTagScanOperatorInfo(STaskRuntimeEnv* pRuntimeEnv, SExprInfo* pExpr, int32_t numOfOutput);
|
SOperatorInfo* createTagScanOperatorInfo(SReaderHandle* pReaderHandle, SExprInfo* pExpr, int32_t numOfOutput);
|
||||||
|
|
||||||
SOperatorInfo* createJoinOperatorInfo(SOperatorInfo** pdownstream, int32_t numOfDownstream, SSchema* pSchema,
|
SOperatorInfo* createJoinOperatorInfo(SOperatorInfo** pdownstream, int32_t numOfDownstream, SSchema* pSchema,
|
||||||
int32_t numOfOutput);
|
int32_t numOfOutput);
|
||||||
|
|
|
@ -5429,58 +5429,48 @@ static SSDataBlock* doAllIntervalAgg(SOperatorInfo *pOperator, bool* newgroup) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
STableIntervalOperatorInfo* pIntervalInfo = pOperator->info;
|
STimeSliceOperatorInfo* pSliceInfo = pOperator->info;
|
||||||
|
|
||||||
STaskRuntimeEnv* pRuntimeEnv = pOperator->pRuntimeEnv;
|
|
||||||
if (pOperator->status == OP_RES_TO_RETURN) {
|
if (pOperator->status == OP_RES_TO_RETURN) {
|
||||||
// toSDatablock(&pRuntimeEnv->groupResInfo, pRuntimeEnv, pIntervalInfo->pRes);
|
// toSDatablock(&pRuntimeEnv->groupResInfo, pRuntimeEnv, pIntervalInfo->pRes);
|
||||||
|
if (pSliceInfo->binfo.pRes->info.rows == 0 || !hasRemainDataInCurrentGroup(&pSliceInfo->groupResInfo)) {
|
||||||
if (pIntervalInfo->binfo.pRes->info.rows == 0 || !hasRemainDataInCurrentGroup(&pRuntimeEnv->groupResInfo)) {
|
|
||||||
doSetOperatorCompleted(pOperator);
|
doSetOperatorCompleted(pOperator);
|
||||||
}
|
}
|
||||||
|
|
||||||
return pIntervalInfo->binfo.pRes;
|
return pSliceInfo->binfo.pRes;
|
||||||
}
|
}
|
||||||
|
|
||||||
STaskAttr* pQueryAttr = pRuntimeEnv->pQueryAttr;
|
int32_t order = TSDB_ORDER_ASC;
|
||||||
int32_t order = pQueryAttr->order.order;
|
// STimeWindow win = pQueryAttr->window;
|
||||||
STimeWindow win = pQueryAttr->window;
|
|
||||||
|
|
||||||
SOperatorInfo* downstream = pOperator->pDownstream[0];
|
SOperatorInfo* downstream = pOperator->pDownstream[0];
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
publishOperatorProfEvent(downstream, QUERY_PROF_BEFORE_OPERATOR_EXEC);
|
publishOperatorProfEvent(downstream, QUERY_PROF_BEFORE_OPERATOR_EXEC);
|
||||||
SSDataBlock* pBlock = downstream->getNextFn(downstream, newgroup);
|
SSDataBlock* pBlock = downstream->getNextFn(downstream, newgroup);
|
||||||
publishOperatorProfEvent(downstream, QUERY_PROF_AFTER_OPERATOR_EXEC);
|
publishOperatorProfEvent(downstream, QUERY_PROF_AFTER_OPERATOR_EXEC);
|
||||||
|
|
||||||
if (pBlock == NULL) {
|
if (pBlock == NULL) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// setTagValue(pOperator, pRuntimeEnv->current->pTable, pIntervalInfo->pCtx, pOperator->numOfOutput);
|
// setTagValue(pOperator, pRuntimeEnv->current->pTable, pIntervalInfo->pCtx, pOperator->numOfOutput);
|
||||||
|
|
||||||
// the pDataBlock are always the same one, no need to call this again
|
// the pDataBlock are always the same one, no need to call this again
|
||||||
setInputDataBlock(pOperator, pIntervalInfo->binfo.pCtx, pBlock, pQueryAttr->order.order);
|
setInputDataBlock(pOperator, pSliceInfo->binfo.pCtx, pBlock, order);
|
||||||
hashAllIntervalAgg(pOperator, &pIntervalInfo->binfo.resultRowInfo, pBlock, 0);
|
hashAllIntervalAgg(pOperator, &pSliceInfo->binfo.resultRowInfo, pBlock, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// restore the value
|
// restore the value
|
||||||
pQueryAttr->order.order = order;
|
|
||||||
pQueryAttr->window = win;
|
|
||||||
|
|
||||||
pOperator->status = OP_RES_TO_RETURN;
|
pOperator->status = OP_RES_TO_RETURN;
|
||||||
closeAllResultRows(&pIntervalInfo->binfo.resultRowInfo);
|
closeAllResultRows(&pSliceInfo->binfo.resultRowInfo);
|
||||||
setTaskStatus(pOperator->pTaskInfo, TASK_COMPLETED);
|
setTaskStatus(pOperator->pTaskInfo, TASK_COMPLETED);
|
||||||
finalizeQueryResult(pIntervalInfo->binfo.pCtx, pOperator->numOfOutput);
|
finalizeQueryResult(pSliceInfo->binfo.pCtx, pOperator->numOfOutput);
|
||||||
|
|
||||||
initGroupResInfo(&pRuntimeEnv->groupResInfo, &pIntervalInfo->binfo.resultRowInfo);
|
initGroupResInfo(&pSliceInfo->groupResInfo, &pSliceInfo->binfo.resultRowInfo);
|
||||||
// toSDatablock(&pRuntimeEnv->groupResInfo, pRuntimeEnv, pIntervalInfo->pRes);
|
// toSDatablock(&pRuntimeEnv->groupResInfo, pRuntimeEnv, pSliceInfo->pRes);
|
||||||
|
|
||||||
if (pIntervalInfo->binfo.pRes->info.rows == 0 || !hasRemainDataInCurrentGroup(&pRuntimeEnv->groupResInfo)) {
|
if (pSliceInfo->binfo.pRes->info.rows == 0 || !hasRemainDataInCurrentGroup(&pSliceInfo->groupResInfo)) {
|
||||||
pOperator->status = OP_EXEC_DONE;
|
pOperator->status = OP_EXEC_DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return pIntervalInfo->binfo.pRes->info.rows == 0 ? NULL : pIntervalInfo->binfo.pRes;
|
return pSliceInfo->binfo.pRes->info.rows == 0 ? NULL : pSliceInfo->binfo.pRes;
|
||||||
}
|
}
|
||||||
|
|
||||||
static SSDataBlock* doSTableIntervalAgg(SOperatorInfo* pOperator, bool* newgroup) {
|
static SSDataBlock* doSTableIntervalAgg(SOperatorInfo* pOperator, bool* newgroup) {
|
||||||
|
@ -6238,28 +6228,34 @@ _error:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
SOperatorInfo* createAllTimeIntervalOperatorInfo(STaskRuntimeEnv* pRuntimeEnv, SOperatorInfo* downstream,
|
SOperatorInfo* createTimeSliceOperatorInfo(SOperatorInfo* downstream, SExprInfo* pExprInfo, int32_t numOfCols, SSDataBlock* pResultBlock, SExecTaskInfo* pTaskInfo) {
|
||||||
SExprInfo* pExpr, int32_t numOfOutput) {
|
STimeSliceOperatorInfo* pInfo = taosMemoryCalloc(1, sizeof(STimeSliceOperatorInfo));
|
||||||
STableIntervalOperatorInfo* pInfo = taosMemoryCalloc(1, sizeof(STableIntervalOperatorInfo));
|
SOperatorInfo* pOperator = taosMemoryCalloc(1, sizeof(SOperatorInfo));
|
||||||
|
if (pOperator == NULL || pInfo == NULL) {
|
||||||
|
goto _error;
|
||||||
|
}
|
||||||
|
|
||||||
// pInfo->binfo.pCtx = createSqlFunctionCtx(pRuntimeEnv, pExpr, numOfOutput, &pInfo->binfo.rowCellInfoOffset);
|
|
||||||
// pInfo->binfo.pRes = createOutputBuf(pExpr, numOfOutput, pResultInfo->capacity);
|
|
||||||
initResultRowInfo(&pInfo->binfo.resultRowInfo, 8);
|
initResultRowInfo(&pInfo->binfo.resultRowInfo, 8);
|
||||||
|
|
||||||
SOperatorInfo* pOperator = taosMemoryCalloc(1, sizeof(SOperatorInfo));
|
pOperator->name = "TimeSliceOperator";
|
||||||
|
|
||||||
pOperator->name = "AllTimeIntervalAggOperator";
|
|
||||||
// pOperator->operatorType = OP_AllTimeWindow;
|
// pOperator->operatorType = OP_AllTimeWindow;
|
||||||
pOperator->blockingOptr = true;
|
pOperator->blockingOptr = true;
|
||||||
pOperator->status = OP_NOT_OPENED;
|
pOperator->status = OP_NOT_OPENED;
|
||||||
pOperator->pExpr = pExpr;
|
pOperator->pExpr = pExprInfo;
|
||||||
pOperator->numOfOutput = numOfOutput;
|
pOperator->numOfOutput = numOfCols;
|
||||||
pOperator->info = pInfo;
|
pOperator->info = pInfo;
|
||||||
pOperator->getNextFn = doAllIntervalAgg;
|
pOperator->pTaskInfo = pTaskInfo;
|
||||||
pOperator->closeFn = destroyBasicOperatorInfo;
|
pOperator->getNextFn = doAllIntervalAgg;
|
||||||
|
pOperator->closeFn = destroyBasicOperatorInfo;
|
||||||
|
|
||||||
int32_t code = appendDownstream(pOperator, &downstream, 1);
|
int32_t code = appendDownstream(pOperator, &downstream, 1);
|
||||||
return pOperator;
|
return pOperator;
|
||||||
|
|
||||||
|
_error:
|
||||||
|
taosMemoryFree(pInfo);
|
||||||
|
taosMemoryFree(pOperator);
|
||||||
|
pTaskInfo->code = TSDB_CODE_OUT_OF_MEMORY;
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
SOperatorInfo* createStatewindowOperatorInfo(SOperatorInfo* downstream, SExprInfo* pExpr, int32_t numOfCols, SSDataBlock* pResBlock, SExecTaskInfo* pTaskInfo) {
|
SOperatorInfo* createStatewindowOperatorInfo(SOperatorInfo* downstream, SExprInfo* pExpr, int32_t numOfCols, SSDataBlock* pResBlock, SExecTaskInfo* pTaskInfo) {
|
||||||
|
|
|
@ -98,15 +98,15 @@ if $data01 != 2 then
|
||||||
return -1
|
return -1
|
||||||
endi
|
endi
|
||||||
|
|
||||||
|
#
|
||||||
print ====> select count(*) from (select * from dev_001) session(ts,5a)
|
#print ====> select count(*) from (select * from dev_001) session(ts,5a)
|
||||||
sql select _wstartts, count(*) from (select * from dev_001) session(ts,5a)
|
#sql select _wstartts, count(*) from (select * from dev_001) session(ts,5a)
|
||||||
if $rows != 15 then
|
#if $rows != 15 then
|
||||||
return -1
|
# return -1
|
||||||
endi
|
#endi
|
||||||
if $data01 != 2 then
|
#if $data01 != 2 then
|
||||||
return -1
|
# return -1
|
||||||
endi
|
#endi
|
||||||
|
|
||||||
print ====> select count(*) from dev_001 session(ts,1s)
|
print ====> select count(*) from dev_001 session(ts,1s)
|
||||||
sql select _wstartts, count(*) from dev_001 session(ts,1s)
|
sql select _wstartts, count(*) from dev_001 session(ts,1s)
|
||||||
|
@ -117,14 +117,14 @@ if $data01 != 5 then
|
||||||
return -1
|
return -1
|
||||||
endi
|
endi
|
||||||
|
|
||||||
print ====> select count(*) from (select * from dev_001) session(ts,1s)
|
#print ====> select count(*) from (select * from dev_001) session(ts,1s)
|
||||||
sql select _wstartts, count(*) from (select * from dev_001) session(ts,1s)
|
#sql select _wstartts, count(*) from (select * from dev_001) session(ts,1s)
|
||||||
if $rows != 12 then
|
#if $rows != 12 then
|
||||||
return -1
|
# return -1
|
||||||
endi
|
#endi
|
||||||
if $data01 != 5 then
|
#if $data01 != 5 then
|
||||||
return -1
|
# return -1
|
||||||
endi
|
#endi
|
||||||
|
|
||||||
print ====> select count(*) from dev_001 session(ts,1000a)
|
print ====> select count(*) from dev_001 session(ts,1000a)
|
||||||
sql select _wstartts, count(*) from dev_001 session(ts,1000a)
|
sql select _wstartts, count(*) from dev_001 session(ts,1000a)
|
||||||
|
@ -135,14 +135,14 @@ if $data01 != 5 then
|
||||||
return -1
|
return -1
|
||||||
endi
|
endi
|
||||||
|
|
||||||
print ====> select count(*) from (select * from dev_001) session(ts,1000a)
|
#print ====> select count(*) from (select * from dev_001) session(ts,1000a)
|
||||||
sql select _wstartts, count(*) from (select * from dev_001) session(ts,1000a)
|
#sql select _wstartts, count(*) from (select * from dev_001) session(ts,1000a)
|
||||||
if $rows != 12 then
|
#if $rows != 12 then
|
||||||
return -1
|
# return -1
|
||||||
endi
|
#endi
|
||||||
if $data01 != 5 then
|
#if $data01 != 5 then
|
||||||
return -1
|
# return -1
|
||||||
endi
|
#endi
|
||||||
|
|
||||||
print ====> select count(*) from dev_001 session(ts,1m)
|
print ====> select count(*) from dev_001 session(ts,1m)
|
||||||
sql select _wstartts, count(*) from dev_001 session(ts,1m)
|
sql select _wstartts, count(*) from dev_001 session(ts,1m)
|
||||||
|
@ -153,14 +153,14 @@ if $data01 != 8 then
|
||||||
return -1
|
return -1
|
||||||
endi
|
endi
|
||||||
|
|
||||||
print ====> select count(*) from (select * from dev_001) session(ts,1m)
|
#print ====> select count(*) from (select * from dev_001) session(ts,1m)
|
||||||
sql select _wstartts, count(*) from (select * from dev_001) session(ts,1m)
|
#sql select _wstartts, count(*) from (select * from dev_001) session(ts,1m)
|
||||||
if $rows != 9 then
|
#if $rows != 9 then
|
||||||
return -1
|
# return -1
|
||||||
endi
|
#endi
|
||||||
if $data01 != 8 then
|
#if $data01 != 8 then
|
||||||
return -1
|
# return -1
|
||||||
endi
|
#endi
|
||||||
|
|
||||||
print ====> select count(*) from dev_001 session(ts,1h)
|
print ====> select count(*) from dev_001 session(ts,1h)
|
||||||
sql select _wstartts, count(*) from dev_001 session(ts,1h)
|
sql select _wstartts, count(*) from dev_001 session(ts,1h)
|
||||||
|
@ -171,14 +171,14 @@ if $data01 != 11 then
|
||||||
return -1
|
return -1
|
||||||
endi
|
endi
|
||||||
|
|
||||||
print ====> select count(*) from (select * from dev_001) session(ts,1h)
|
#print ====> select count(*) from (select * from dev_001) session(ts,1h)
|
||||||
sql select _wstartts, count(*) from (select * from dev_001) session(ts,1h)
|
#sql select _wstartts, count(*) from (select * from dev_001) session(ts,1h)
|
||||||
if $rows != 6 then
|
#if $rows != 6 then
|
||||||
return -1
|
# return -1
|
||||||
endi
|
#endi
|
||||||
if $data01 != 11 then
|
#if $data01 != 11 then
|
||||||
return -1
|
# return -1
|
||||||
endi
|
#endi
|
||||||
|
|
||||||
print ====> select count(*) from dev_001 session(ts,1d)
|
print ====> select count(*) from dev_001 session(ts,1d)
|
||||||
sql select _wstartts, count(*) from dev_001 session(ts,1d)
|
sql select _wstartts, count(*) from dev_001 session(ts,1d)
|
||||||
|
@ -189,14 +189,14 @@ if $data01 != 13 then
|
||||||
return -1
|
return -1
|
||||||
endi
|
endi
|
||||||
|
|
||||||
print ====> select count(*) from (select * from dev_001) session(ts,1d)
|
#print ====> select count(*) from (select * from dev_001) session(ts,1d)
|
||||||
sql select _wstartts, count(*) from (select * from dev_001) session(ts,1d)
|
#sql select _wstartts, count(*) from (select * from dev_001) session(ts,1d)
|
||||||
if $rows != 4 then
|
#if $rows != 4 then
|
||||||
return -1
|
# return -1
|
||||||
endi
|
#endi
|
||||||
if $data01 != 13 then
|
#if $data01 != 13 then
|
||||||
return -1
|
# return -1
|
||||||
endi
|
#endi
|
||||||
|
|
||||||
print ====> select count(*) from dev_001 session(ts,1w)
|
print ====> select count(*) from dev_001 session(ts,1w)
|
||||||
sql select _wstartts, count(*) from dev_001 session(ts,1w)
|
sql select _wstartts, count(*) from dev_001 session(ts,1w)
|
||||||
|
@ -207,14 +207,14 @@ if $data01 != 15 then
|
||||||
return -1
|
return -1
|
||||||
endi
|
endi
|
||||||
|
|
||||||
print ====> select count(*) from (select * from dev_001) session(ts,1w)
|
#print ====> select count(*) from (select * from dev_001) session(ts,1w)
|
||||||
sql select _wstartts, count(*) from (select * from dev_001) session(ts,1w)
|
#sql select _wstartts, count(*) from (select * from dev_001) session(ts,1w)
|
||||||
if $rows != 2 then
|
#if $rows != 2 then
|
||||||
return -1
|
# return -1
|
||||||
endi
|
#endi
|
||||||
if $data01 != 15 then
|
#if $data01 != 15 then
|
||||||
return -1
|
# return -1
|
||||||
endi
|
#endi
|
||||||
|
|
||||||
|
|
||||||
print ====> leastsquares not supported yet.
|
print ====> leastsquares not supported yet.
|
||||||
|
|
Loading…
Reference in New Issue