stmt query
This commit is contained in:
parent
54fe93f77e
commit
c4cfcef6e9
|
@ -88,6 +88,7 @@ typedef struct SValueNode {
|
||||||
double d;
|
double d;
|
||||||
char* p;
|
char* p;
|
||||||
} datum;
|
} datum;
|
||||||
|
int64_t typeData;
|
||||||
char unit;
|
char unit;
|
||||||
} SValueNode;
|
} SValueNode;
|
||||||
|
|
||||||
|
|
|
@ -1747,23 +1747,51 @@ static int32_t jsonToDatum(const SJson* pJson, void* pObj) {
|
||||||
break;
|
break;
|
||||||
case TSDB_DATA_TYPE_BOOL:
|
case TSDB_DATA_TYPE_BOOL:
|
||||||
code = tjsonGetBoolValue(pJson, jkValueDatum, &pNode->datum.b);
|
code = tjsonGetBoolValue(pJson, jkValueDatum, &pNode->datum.b);
|
||||||
|
*(bool*)&pNode->typeData = pNode->datum.b;
|
||||||
break;
|
break;
|
||||||
case TSDB_DATA_TYPE_TINYINT:
|
case TSDB_DATA_TYPE_TINYINT:
|
||||||
|
code = tjsonGetBigIntValue(pJson, jkValueDatum, &pNode->datum.i);
|
||||||
|
*(int8_t*)&pNode->typeData = pNode->datum.i;
|
||||||
|
break;
|
||||||
case TSDB_DATA_TYPE_SMALLINT:
|
case TSDB_DATA_TYPE_SMALLINT:
|
||||||
|
code = tjsonGetBigIntValue(pJson, jkValueDatum, &pNode->datum.i);
|
||||||
|
*(int16_t*)&pNode->typeData = pNode->datum.i;
|
||||||
|
break;
|
||||||
case TSDB_DATA_TYPE_INT:
|
case TSDB_DATA_TYPE_INT:
|
||||||
|
code = tjsonGetBigIntValue(pJson, jkValueDatum, &pNode->datum.i);
|
||||||
|
*(int32_t*)&pNode->typeData = pNode->datum.i;
|
||||||
|
break;
|
||||||
case TSDB_DATA_TYPE_BIGINT:
|
case TSDB_DATA_TYPE_BIGINT:
|
||||||
|
code = tjsonGetBigIntValue(pJson, jkValueDatum, &pNode->datum.i);
|
||||||
|
*(int64_t*)&pNode->typeData = pNode->datum.i;
|
||||||
|
break;
|
||||||
case TSDB_DATA_TYPE_TIMESTAMP:
|
case TSDB_DATA_TYPE_TIMESTAMP:
|
||||||
code = tjsonGetBigIntValue(pJson, jkValueDatum, &pNode->datum.i);
|
code = tjsonGetBigIntValue(pJson, jkValueDatum, &pNode->datum.i);
|
||||||
|
*(int64_t*)&pNode->typeData = pNode->datum.i;
|
||||||
break;
|
break;
|
||||||
case TSDB_DATA_TYPE_UTINYINT:
|
case TSDB_DATA_TYPE_UTINYINT:
|
||||||
|
code = tjsonGetUBigIntValue(pJson, jkValueDatum, &pNode->datum.u);
|
||||||
|
*(uint8_t*)&pNode->typeData = pNode->datum.u;
|
||||||
|
break;
|
||||||
case TSDB_DATA_TYPE_USMALLINT:
|
case TSDB_DATA_TYPE_USMALLINT:
|
||||||
|
code = tjsonGetUBigIntValue(pJson, jkValueDatum, &pNode->datum.u);
|
||||||
|
*(uint16_t*)&pNode->typeData = pNode->datum.u;
|
||||||
|
break;
|
||||||
case TSDB_DATA_TYPE_UINT:
|
case TSDB_DATA_TYPE_UINT:
|
||||||
|
code = tjsonGetUBigIntValue(pJson, jkValueDatum, &pNode->datum.u);
|
||||||
|
*(uint32_t*)&pNode->typeData = pNode->datum.u;
|
||||||
|
break;
|
||||||
case TSDB_DATA_TYPE_UBIGINT:
|
case TSDB_DATA_TYPE_UBIGINT:
|
||||||
code = tjsonGetUBigIntValue(pJson, jkValueDatum, &pNode->datum.u);
|
code = tjsonGetUBigIntValue(pJson, jkValueDatum, &pNode->datum.u);
|
||||||
|
*(uint64_t*)&pNode->typeData = pNode->datum.u;
|
||||||
break;
|
break;
|
||||||
case TSDB_DATA_TYPE_FLOAT:
|
case TSDB_DATA_TYPE_FLOAT:
|
||||||
|
code = tjsonGetDoubleValue(pJson, jkValueDatum, &pNode->datum.d);
|
||||||
|
*(float*)&pNode->typeData = pNode->datum.d;
|
||||||
|
break;
|
||||||
case TSDB_DATA_TYPE_DOUBLE:
|
case TSDB_DATA_TYPE_DOUBLE:
|
||||||
code = tjsonGetDoubleValue(pJson, jkValueDatum, &pNode->datum.d);
|
code = tjsonGetDoubleValue(pJson, jkValueDatum, &pNode->datum.d);
|
||||||
|
*(double*)&pNode->typeData = pNode->datum.d;
|
||||||
break;
|
break;
|
||||||
case TSDB_DATA_TYPE_NCHAR:
|
case TSDB_DATA_TYPE_NCHAR:
|
||||||
case TSDB_DATA_TYPE_VARCHAR:
|
case TSDB_DATA_TYPE_VARCHAR:
|
||||||
|
|
|
@ -867,21 +867,18 @@ void nodesClearList(SNodeList* pList) {
|
||||||
void* nodesGetValueFromNode(SValueNode* pNode) {
|
void* nodesGetValueFromNode(SValueNode* pNode) {
|
||||||
switch (pNode->node.resType.type) {
|
switch (pNode->node.resType.type) {
|
||||||
case TSDB_DATA_TYPE_BOOL:
|
case TSDB_DATA_TYPE_BOOL:
|
||||||
return (void*)&pNode->datum.b;
|
|
||||||
case TSDB_DATA_TYPE_TINYINT:
|
case TSDB_DATA_TYPE_TINYINT:
|
||||||
case TSDB_DATA_TYPE_SMALLINT:
|
case TSDB_DATA_TYPE_SMALLINT:
|
||||||
case TSDB_DATA_TYPE_INT:
|
case TSDB_DATA_TYPE_INT:
|
||||||
case TSDB_DATA_TYPE_BIGINT:
|
case TSDB_DATA_TYPE_BIGINT:
|
||||||
case TSDB_DATA_TYPE_TIMESTAMP:
|
case TSDB_DATA_TYPE_TIMESTAMP:
|
||||||
return (void*)&pNode->datum.i;
|
|
||||||
case TSDB_DATA_TYPE_UTINYINT:
|
case TSDB_DATA_TYPE_UTINYINT:
|
||||||
case TSDB_DATA_TYPE_USMALLINT:
|
case TSDB_DATA_TYPE_USMALLINT:
|
||||||
case TSDB_DATA_TYPE_UINT:
|
case TSDB_DATA_TYPE_UINT:
|
||||||
case TSDB_DATA_TYPE_UBIGINT:
|
case TSDB_DATA_TYPE_UBIGINT:
|
||||||
return (void*)&pNode->datum.u;
|
|
||||||
case TSDB_DATA_TYPE_FLOAT:
|
case TSDB_DATA_TYPE_FLOAT:
|
||||||
case TSDB_DATA_TYPE_DOUBLE:
|
case TSDB_DATA_TYPE_DOUBLE:
|
||||||
return (void*)&pNode->datum.d;
|
return (void*)&pNode->typeData;
|
||||||
case TSDB_DATA_TYPE_NCHAR:
|
case TSDB_DATA_TYPE_NCHAR:
|
||||||
case TSDB_DATA_TYPE_VARCHAR:
|
case TSDB_DATA_TYPE_VARCHAR:
|
||||||
case TSDB_DATA_TYPE_VARBINARY:
|
case TSDB_DATA_TYPE_VARBINARY:
|
||||||
|
@ -893,6 +890,68 @@ void* nodesGetValueFromNode(SValueNode* pNode) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int32_t nodesSetValueNodeValue(SValueNode* pNode, void *value) {
|
||||||
|
switch (pNode->node.resType.type) {
|
||||||
|
case TSDB_DATA_TYPE_BOOL:
|
||||||
|
pNode->datum.b = *(bool*)value;
|
||||||
|
*(bool*)pNode->typeData = pNode->datum.b;
|
||||||
|
break;
|
||||||
|
case TSDB_DATA_TYPE_TINYINT:
|
||||||
|
pNode->datum.i = *(int8_t*)value;
|
||||||
|
*(int8_t*)pNode->typeData = pNode->datum.i;
|
||||||
|
break;
|
||||||
|
case TSDB_DATA_TYPE_SMALLINT:
|
||||||
|
pNode->datum.i = *(int16_t*)value;
|
||||||
|
*(int16_t*)pNode->typeData = pNode->datum.i;
|
||||||
|
break;
|
||||||
|
case TSDB_DATA_TYPE_INT:
|
||||||
|
pNode->datum.i = *(int32_t*)value;
|
||||||
|
*(int32_t*)pNode->typeData = pNode->datum.i;
|
||||||
|
break;
|
||||||
|
case TSDB_DATA_TYPE_BIGINT:
|
||||||
|
pNode->datum.i = *(int64_t*)value;
|
||||||
|
*(int64_t*)pNode->typeData = pNode->datum.i;
|
||||||
|
break;
|
||||||
|
case TSDB_DATA_TYPE_TIMESTAMP:
|
||||||
|
pNode->datum.i = *(int64_t*)value;
|
||||||
|
*(int64_t*)pNode->typeData = pNode->datum.i;
|
||||||
|
break;
|
||||||
|
case TSDB_DATA_TYPE_UTINYINT:
|
||||||
|
pNode->datum.u = *(int8_t*)value;
|
||||||
|
*(int8_t*)pNode->typeData = pNode->datum.u;
|
||||||
|
break;
|
||||||
|
case TSDB_DATA_TYPE_USMALLINT:
|
||||||
|
pNode->datum.u = *(int16_t*)value;
|
||||||
|
*(int16_t*)pNode->typeData = pNode->datum.u;
|
||||||
|
break;
|
||||||
|
case TSDB_DATA_TYPE_UINT:
|
||||||
|
pNode->datum.u = *(int32_t*)value;
|
||||||
|
*(int32_t*)pNode->typeData = pNode->datum.u;
|
||||||
|
break;
|
||||||
|
case TSDB_DATA_TYPE_UBIGINT:
|
||||||
|
pNode->datum.u = *(uint64_t*)value;
|
||||||
|
*(uint64_t*)pNode->typeData = pNode->datum.u;
|
||||||
|
break;
|
||||||
|
case TSDB_DATA_TYPE_FLOAT:
|
||||||
|
pNode->datum.d = *(float*)value;
|
||||||
|
*(float*)pNode->typeData = pNode->datum.d;
|
||||||
|
break;
|
||||||
|
case TSDB_DATA_TYPE_DOUBLE:
|
||||||
|
pNode->datum.d = *(double*)value;
|
||||||
|
*(double*)pNode->typeData = pNode->datum.d;
|
||||||
|
break;
|
||||||
|
case TSDB_DATA_TYPE_NCHAR:
|
||||||
|
case TSDB_DATA_TYPE_VARCHAR:
|
||||||
|
case TSDB_DATA_TYPE_VARBINARY:
|
||||||
|
pNode->datum.p = (char*)value;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return TSDB_CODE_QRY_APP_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TSDB_CODE_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
char* nodesGetStrValueFromNode(SValueNode* pNode) {
|
char* nodesGetStrValueFromNode(SValueNode* pNode) {
|
||||||
switch (pNode->node.resType.type) {
|
switch (pNode->node.resType.type) {
|
||||||
case TSDB_DATA_TYPE_BOOL: {
|
case TSDB_DATA_TYPE_BOOL: {
|
||||||
|
|
|
@ -473,27 +473,66 @@ static EDealRes translateValue(STranslateContext* pCxt, SValueNode* pVal) {
|
||||||
break;
|
break;
|
||||||
case TSDB_DATA_TYPE_BOOL:
|
case TSDB_DATA_TYPE_BOOL:
|
||||||
pVal->datum.b = (0 == strcasecmp(pVal->literal, "true"));
|
pVal->datum.b = (0 == strcasecmp(pVal->literal, "true"));
|
||||||
|
*(bool*)&pVal->typeData = pVal->datum.b;
|
||||||
break;
|
break;
|
||||||
case TSDB_DATA_TYPE_TINYINT:
|
case TSDB_DATA_TYPE_TINYINT:{
|
||||||
case TSDB_DATA_TYPE_SMALLINT:
|
char* endPtr = NULL;
|
||||||
case TSDB_DATA_TYPE_INT:
|
pVal->datum.i = strtoll(pVal->literal, &endPtr, 10);
|
||||||
|
*(int8_t*)&pVal->typeData = pVal->datum.i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TSDB_DATA_TYPE_SMALLINT:{
|
||||||
|
char* endPtr = NULL;
|
||||||
|
pVal->datum.i = strtoll(pVal->literal, &endPtr, 10);
|
||||||
|
*(int16_t*)&pVal->typeData = pVal->datum.i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TSDB_DATA_TYPE_INT:{
|
||||||
|
char* endPtr = NULL;
|
||||||
|
pVal->datum.i = strtoll(pVal->literal, &endPtr, 10);
|
||||||
|
*(int32_t*)&pVal->typeData = pVal->datum.i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
case TSDB_DATA_TYPE_BIGINT: {
|
case TSDB_DATA_TYPE_BIGINT: {
|
||||||
char* endPtr = NULL;
|
char* endPtr = NULL;
|
||||||
pVal->datum.i = strtoll(pVal->literal, &endPtr, 10);
|
pVal->datum.i = strtoll(pVal->literal, &endPtr, 10);
|
||||||
|
*(int64_t*)&pVal->typeData = pVal->datum.i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TSDB_DATA_TYPE_UTINYINT:{
|
||||||
|
char* endPtr = NULL;
|
||||||
|
pVal->datum.u = strtoull(pVal->literal, &endPtr, 10);
|
||||||
|
*(uint8_t*)&pVal->typeData = pVal->datum.u;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TSDB_DATA_TYPE_USMALLINT:{
|
||||||
|
char* endPtr = NULL;
|
||||||
|
pVal->datum.u = strtoull(pVal->literal, &endPtr, 10);
|
||||||
|
*(uint16_t*)&pVal->typeData = pVal->datum.u;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TSDB_DATA_TYPE_UINT:{
|
||||||
|
char* endPtr = NULL;
|
||||||
|
pVal->datum.u = strtoull(pVal->literal, &endPtr, 10);
|
||||||
|
*(uint32_t*)&pVal->typeData = pVal->datum.u;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TSDB_DATA_TYPE_UTINYINT:
|
|
||||||
case TSDB_DATA_TYPE_USMALLINT:
|
|
||||||
case TSDB_DATA_TYPE_UINT:
|
|
||||||
case TSDB_DATA_TYPE_UBIGINT: {
|
case TSDB_DATA_TYPE_UBIGINT: {
|
||||||
char* endPtr = NULL;
|
char* endPtr = NULL;
|
||||||
pVal->datum.u = strtoull(pVal->literal, &endPtr, 10);
|
pVal->datum.u = strtoull(pVal->literal, &endPtr, 10);
|
||||||
|
*(uint64_t*)&pVal->typeData = pVal->datum.u;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TSDB_DATA_TYPE_FLOAT:{
|
||||||
|
char* endPtr = NULL;
|
||||||
|
pVal->datum.d = strtold(pVal->literal, &endPtr);
|
||||||
|
*(float*)&pVal->typeData = pVal->datum.d;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TSDB_DATA_TYPE_FLOAT:
|
|
||||||
case TSDB_DATA_TYPE_DOUBLE: {
|
case TSDB_DATA_TYPE_DOUBLE: {
|
||||||
char* endPtr = NULL;
|
char* endPtr = NULL;
|
||||||
pVal->datum.d = strtold(pVal->literal, &endPtr);
|
pVal->datum.d = strtold(pVal->literal, &endPtr);
|
||||||
|
*(double*)&pVal->typeData = pVal->datum.d;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TSDB_DATA_TYPE_VARCHAR:
|
case TSDB_DATA_TYPE_VARCHAR:
|
||||||
|
@ -511,6 +550,7 @@ static EDealRes translateValue(STranslateContext* pCxt, SValueNode* pVal) {
|
||||||
TSDB_CODE_SUCCESS) {
|
TSDB_CODE_SUCCESS) {
|
||||||
return generateDealNodeErrMsg(pCxt, TSDB_CODE_PAR_WRONG_VALUE_TYPE, pVal->literal);
|
return generateDealNodeErrMsg(pCxt, TSDB_CODE_PAR_WRONG_VALUE_TYPE, pVal->literal);
|
||||||
}
|
}
|
||||||
|
*(int64_t*)&pVal->typeData = pVal->datum.i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TSDB_DATA_TYPE_NCHAR:
|
case TSDB_DATA_TYPE_NCHAR:
|
||||||
|
|
|
@ -11,7 +11,8 @@
|
||||||
|
|
||||||
int32_t shortColList[] = {TSDB_DATA_TYPE_TIMESTAMP, TSDB_DATA_TYPE_INT};
|
int32_t shortColList[] = {TSDB_DATA_TYPE_TIMESTAMP, TSDB_DATA_TYPE_INT};
|
||||||
int32_t fullColList[] = {TSDB_DATA_TYPE_TIMESTAMP, TSDB_DATA_TYPE_BOOL, TSDB_DATA_TYPE_TINYINT, TSDB_DATA_TYPE_UTINYINT, TSDB_DATA_TYPE_SMALLINT, TSDB_DATA_TYPE_USMALLINT, TSDB_DATA_TYPE_INT, TSDB_DATA_TYPE_UINT, TSDB_DATA_TYPE_BIGINT, TSDB_DATA_TYPE_UBIGINT, TSDB_DATA_TYPE_FLOAT, TSDB_DATA_TYPE_DOUBLE, TSDB_DATA_TYPE_BINARY, TSDB_DATA_TYPE_NCHAR};
|
int32_t fullColList[] = {TSDB_DATA_TYPE_TIMESTAMP, TSDB_DATA_TYPE_BOOL, TSDB_DATA_TYPE_TINYINT, TSDB_DATA_TYPE_UTINYINT, TSDB_DATA_TYPE_SMALLINT, TSDB_DATA_TYPE_USMALLINT, TSDB_DATA_TYPE_INT, TSDB_DATA_TYPE_UINT, TSDB_DATA_TYPE_BIGINT, TSDB_DATA_TYPE_UBIGINT, TSDB_DATA_TYPE_FLOAT, TSDB_DATA_TYPE_DOUBLE, TSDB_DATA_TYPE_BINARY, TSDB_DATA_TYPE_NCHAR};
|
||||||
int32_t bindColTypeList[] = {TSDB_DATA_TYPE_TIMESTAMP};
|
int32_t bindColTypeList[] = {TSDB_DATA_TYPE_TIMESTAMP, TSDB_DATA_TYPE_INT, TSDB_DATA_TYPE_FLOAT};
|
||||||
|
int32_t optrIdxList[] = {3, 5, 2};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char* oper;
|
char* oper;
|
||||||
|
@ -161,6 +162,8 @@ typedef struct {
|
||||||
int32_t bindRowNum; //row num for once bind
|
int32_t bindRowNum; //row num for once bind
|
||||||
int32_t bindColTypeNum;
|
int32_t bindColTypeNum;
|
||||||
int32_t* bindColTypeList;
|
int32_t* bindColTypeList;
|
||||||
|
int32_t optrIdxListNum;
|
||||||
|
int32_t* optrIdxList;
|
||||||
int32_t runTimes;
|
int32_t runTimes;
|
||||||
int32_t caseIdx; // static case idx
|
int32_t caseIdx; // static case idx
|
||||||
int32_t caseNum; // num in static case list
|
int32_t caseNum; // num in static case list
|
||||||
|
@ -180,6 +183,8 @@ CaseCtrl gCaseCtrl = {
|
||||||
.bindRowNum = 0,
|
.bindRowNum = 0,
|
||||||
// .bindColTypeNum = 0,
|
// .bindColTypeNum = 0,
|
||||||
// .bindColTypeList = NULL,
|
// .bindColTypeList = NULL,
|
||||||
|
// .optrIdxListNum = 0,
|
||||||
|
// .optrIdxList = NULL,
|
||||||
.checkParamNum = false,
|
.checkParamNum = false,
|
||||||
.printRes = true,
|
.printRes = true,
|
||||||
.runTimes = 0,
|
.runTimes = 0,
|
||||||
|
@ -188,6 +193,11 @@ CaseCtrl gCaseCtrl = {
|
||||||
.caseRunIdx = -1,
|
.caseRunIdx = -1,
|
||||||
// .caseRunNum = -1,
|
// .caseRunNum = -1,
|
||||||
|
|
||||||
|
|
||||||
|
.optrIdxListNum = tListLen(optrIdxList),
|
||||||
|
.optrIdxList = optrIdxList,
|
||||||
|
.bindColTypeNum = tListLen(bindColTypeList),
|
||||||
|
.bindColTypeList = bindColTypeList,
|
||||||
.caseIdx = 22,
|
.caseIdx = 22,
|
||||||
.caseNum = 1,
|
.caseNum = 1,
|
||||||
.caseRunNum = 1,
|
.caseRunNum = 1,
|
||||||
|
@ -338,14 +348,18 @@ void generateInsertSQL(BindData *data) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void bpAppendOperatorParam(BindData *data, int32_t *len, int32_t dataType) {
|
void bpAppendOperatorParam(BindData *data, int32_t *len, int32_t dataType, int32_t idx) {
|
||||||
OperInfo *pInfo = NULL;
|
OperInfo *pInfo = NULL;
|
||||||
|
|
||||||
|
if (gCaseCtrl.optrIdxListNum > 0) {
|
||||||
|
pInfo = &operInfo[gCaseCtrl.optrIdxList[idx]];
|
||||||
|
} else {
|
||||||
if (TSDB_DATA_TYPE_VARCHAR == dataType || TSDB_DATA_TYPE_NCHAR == dataType) {
|
if (TSDB_DATA_TYPE_VARCHAR == dataType || TSDB_DATA_TYPE_NCHAR == dataType) {
|
||||||
pInfo = &operInfo[varoperatorList[rand() % tListLen(varoperatorList)]];
|
pInfo = &operInfo[varoperatorList[rand() % tListLen(varoperatorList)]];
|
||||||
} else {
|
} else {
|
||||||
pInfo = &operInfo[operatorList[rand() % tListLen(operatorList)]];
|
pInfo = &operInfo[operatorList[rand() % tListLen(operatorList)]];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch (pInfo->paramNum) {
|
switch (pInfo->paramNum) {
|
||||||
case 2:
|
case 2:
|
||||||
|
@ -416,7 +430,7 @@ void generateQuerySQL(BindData *data, int32_t tblIdx) {
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
bpAppendOperatorParam(data, &len, data->pBind[c].buffer_type);
|
bpAppendOperatorParam(data, &len, data->pBind[c].buffer_type, c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue