Merge pull request #11679 from taosdata/feature/TD-14481-3.0
feat: trow refactor and support print debug log
This commit is contained in:
commit
b7444ad917
|
@ -269,6 +269,8 @@ typedef struct SSchema {
|
||||||
#define SSCHMEA_BYTES(s) ((s)->bytes)
|
#define SSCHMEA_BYTES(s) ((s)->bytes)
|
||||||
#define SSCHMEA_NAME(s) ((s)->name)
|
#define SSCHMEA_NAME(s) ((s)->name)
|
||||||
|
|
||||||
|
STSchema* tdGetSTSChemaFromSSChema(SSchema** pSchema, int32_t nCols);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char name[TSDB_TABLE_FNAME_LEN];
|
char name[TSDB_TABLE_FNAME_LEN];
|
||||||
int8_t igExists;
|
int8_t igExists;
|
||||||
|
|
|
@ -219,7 +219,7 @@ static FORCE_INLINE void *tdKVRowColVal(STSRow *pRow, SKvRowIdx *pIdx) { return
|
||||||
|
|
||||||
#define TD_ROW_OFFSET(p) ((p)->toffset); // During ParseInsert when without STSchema, how to get the offset for STpRow?
|
#define TD_ROW_OFFSET(p) ((p)->toffset); // During ParseInsert when without STSchema, how to get the offset for STpRow?
|
||||||
|
|
||||||
void tdMergeBitmap(uint8_t *srcBitmap, int32_t srcLen, uint8_t *dstBitmap);
|
void tdMergeBitmap(uint8_t *srcBitmap, int32_t nBits, uint8_t *dstBitmap);
|
||||||
static FORCE_INLINE void tdRowCopy(void *dst, STSRow *row) { memcpy(dst, row, TD_ROW_LEN(row)); }
|
static FORCE_INLINE void tdRowCopy(void *dst, STSRow *row) { memcpy(dst, row, TD_ROW_LEN(row)); }
|
||||||
static FORCE_INLINE int32_t tdSetBitmapValTypeI(void *pBitmap, int16_t colIdx, TDRowValT valType);
|
static FORCE_INLINE int32_t tdSetBitmapValTypeI(void *pBitmap, int16_t colIdx, TDRowValT valType);
|
||||||
static FORCE_INLINE int32_t tdSetBitmapValTypeII(void *pBitmap, int16_t colIdx, TDRowValT valType);
|
static FORCE_INLINE int32_t tdSetBitmapValTypeII(void *pBitmap, int16_t colIdx, TDRowValT valType);
|
||||||
|
@ -308,8 +308,8 @@ static FORCE_INLINE int32_t tdSetBitmapValTypeII(void *pBitmap, int16_t colIdx,
|
||||||
// use literal value directly and not use formula to simplify the codes
|
// use literal value directly and not use formula to simplify the codes
|
||||||
switch (nOffset) {
|
switch (nOffset) {
|
||||||
case 0:
|
case 0:
|
||||||
|
*pDestByte = ((*pDestByte) & 0x3F) | (valType << 6);
|
||||||
// set the value and clear other partitions for offset 0
|
// set the value and clear other partitions for offset 0
|
||||||
*pDestByte = (valType << 6);
|
|
||||||
// *pDestByte |= (valType << 6);
|
// *pDestByte |= (valType << 6);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
|
@ -417,8 +417,8 @@ static FORCE_INLINE int32_t tdSetBitmapValTypeI(void *pBitmap, int16_t colIdx, T
|
||||||
// use literal value directly and not use formula to simplify the codes
|
// use literal value directly and not use formula to simplify the codes
|
||||||
switch (nOffset) {
|
switch (nOffset) {
|
||||||
case 0:
|
case 0:
|
||||||
|
*pDestByte = ((*pDestByte) & 0x7F) | (valType << 7);
|
||||||
// set the value and clear other partitions for offset 0
|
// set the value and clear other partitions for offset 0
|
||||||
*pDestByte = (valType << 7);
|
|
||||||
// *pDestByte |= (valType << 7);
|
// *pDestByte |= (valType << 7);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
|
@ -1107,11 +1107,11 @@ static FORCE_INLINE bool tdSTSRowIterNext(STSRowIter *pIter, col_id_t colId, col
|
||||||
if (TD_IS_TP_ROW(pIter->pRow)) {
|
if (TD_IS_TP_ROW(pIter->pRow)) {
|
||||||
STColumn *pCol = NULL;
|
STColumn *pCol = NULL;
|
||||||
STSchema *pSchema = pIter->pSchema;
|
STSchema *pSchema = pIter->pSchema;
|
||||||
while (pIter->colIdx <= pSchema->numOfCols) {
|
while (pIter->colIdx < pSchema->numOfCols) {
|
||||||
pCol = &pSchema->columns[pIter->colIdx]; // 1st column of schema is primary TS key
|
pCol = &pSchema->columns[pIter->colIdx]; // 1st column of schema is primary TS key
|
||||||
if (colId == pCol->colId) {
|
if (colId == pCol->colId) {
|
||||||
break;
|
break;
|
||||||
} else if (colId < pCol->colId) {
|
} else if (pCol->colId < colId) {
|
||||||
++pIter->colIdx;
|
++pIter->colIdx;
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1237,6 +1237,101 @@ static FORCE_INLINE int32_t dataColGetNEleLen(SDataCol *pDataCol, int32_t rows,
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void tdSCellValPrint(SCellVal *pVal, int8_t colType) {
|
||||||
|
if (tdValTypeIsNull(pVal->valType)) {
|
||||||
|
printf("NULL ");
|
||||||
|
return;
|
||||||
|
} else if (tdValTypeIsNone(pVal->valType)) {
|
||||||
|
printf("NONE ");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (colType) {
|
||||||
|
case TSDB_DATA_TYPE_BOOL:
|
||||||
|
printf("%s ", (*(int8_t *)pVal->val) == 0 ? "false" : "true");
|
||||||
|
break;
|
||||||
|
case TSDB_DATA_TYPE_TINYINT:
|
||||||
|
printf("%" PRIi8 " ", *(int8_t *)pVal->val);
|
||||||
|
break;
|
||||||
|
case TSDB_DATA_TYPE_SMALLINT:
|
||||||
|
printf("%" PRIi16 " ", *(int16_t *)pVal->val);
|
||||||
|
break;
|
||||||
|
case TSDB_DATA_TYPE_INT:
|
||||||
|
printf("%" PRIi32 " ", *(int32_t *)pVal->val);
|
||||||
|
break;
|
||||||
|
case TSDB_DATA_TYPE_BIGINT:
|
||||||
|
printf("%" PRIi64 " ", *(int64_t *)pVal->val);
|
||||||
|
break;
|
||||||
|
case TSDB_DATA_TYPE_FLOAT:
|
||||||
|
printf("%f ", *(float *)pVal->val);
|
||||||
|
break;
|
||||||
|
case TSDB_DATA_TYPE_DOUBLE:
|
||||||
|
printf("%lf ", *(double *)pVal->val);
|
||||||
|
break;
|
||||||
|
case TSDB_DATA_TYPE_VARCHAR:
|
||||||
|
printf("VARCHAR ");
|
||||||
|
break;
|
||||||
|
case TSDB_DATA_TYPE_TIMESTAMP:
|
||||||
|
printf("%" PRIi64 " ", *(int64_t *)pVal->val);
|
||||||
|
break;
|
||||||
|
case TSDB_DATA_TYPE_NCHAR:
|
||||||
|
printf("NCHAR ");
|
||||||
|
break;
|
||||||
|
case TSDB_DATA_TYPE_UTINYINT:
|
||||||
|
printf("%" PRIu8 " ", *(uint8_t *)pVal->val);
|
||||||
|
break;
|
||||||
|
case TSDB_DATA_TYPE_USMALLINT:
|
||||||
|
printf("%" PRIu16 " ", *(uint16_t *)pVal->val);
|
||||||
|
break;
|
||||||
|
case TSDB_DATA_TYPE_UINT:
|
||||||
|
printf("%" PRIu32 " ", *(uint32_t *)pVal->val);
|
||||||
|
break;
|
||||||
|
case TSDB_DATA_TYPE_UBIGINT:
|
||||||
|
printf("%" PRIu64 " ", *(uint64_t *)pVal->val);
|
||||||
|
break;
|
||||||
|
case TSDB_DATA_TYPE_JSON:
|
||||||
|
printf("JSON ");
|
||||||
|
break;
|
||||||
|
case TSDB_DATA_TYPE_VARBINARY:
|
||||||
|
printf("VARBIN ");
|
||||||
|
break;
|
||||||
|
case TSDB_DATA_TYPE_DECIMAL:
|
||||||
|
printf("DECIMAL ");
|
||||||
|
break;
|
||||||
|
case TSDB_DATA_TYPE_BLOB:
|
||||||
|
printf("BLOB ");
|
||||||
|
break;
|
||||||
|
case TSDB_DATA_TYPE_MEDIUMBLOB:
|
||||||
|
printf("MedBLOB ");
|
||||||
|
break;
|
||||||
|
// case TSDB_DATA_TYPE_BINARY:
|
||||||
|
// printf("BINARY ");
|
||||||
|
// break;
|
||||||
|
case TSDB_DATA_TYPE_MAX:
|
||||||
|
printf("UNDEF ");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("UNDEF ");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tdSRowPrint(STSRow *row, STSchema *pSchema) {
|
||||||
|
STSRowIter iter = {0};
|
||||||
|
tdSTSRowIterInit(&iter, pSchema);
|
||||||
|
tdSTSRowIterReset(&iter, row);
|
||||||
|
printf(">>>");
|
||||||
|
for (int i = 0; i < pSchema->numOfCols; ++i) {
|
||||||
|
STColumn *stCol = pSchema->columns + i;
|
||||||
|
SCellVal sVal = {.valType = 255, .val = NULL};
|
||||||
|
if (!tdSTSRowIterNext(&iter, stCol->colId, stCol->type, &sVal)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ASSERT(sVal.valType == 0 || sVal.valType == 1 || sVal.valType == 2);
|
||||||
|
tdSCellValPrint(&sVal, stCol->type);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef TROW_ORIGIN_HZ
|
#ifdef TROW_ORIGIN_HZ
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t nRows;
|
uint32_t nRows;
|
||||||
|
|
|
@ -3646,3 +3646,27 @@ void tFreeSCMCreateStreamReq(SCMCreateStreamReq *pReq) {
|
||||||
taosMemoryFreeClear(pReq->sql);
|
taosMemoryFreeClear(pReq->sql);
|
||||||
taosMemoryFreeClear(pReq->ast);
|
taosMemoryFreeClear(pReq->ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
STSchema *tdGetSTSChemaFromSSChema(SSchema **pSchema, int32_t nCols) {
|
||||||
|
STSchemaBuilder schemaBuilder = {0};
|
||||||
|
if (tdInitTSchemaBuilder(&schemaBuilder, 0) < 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < nCols; i++) {
|
||||||
|
SSchema *schema = *pSchema + i;
|
||||||
|
if (tdAddColToSchema(&schemaBuilder, schema->type, schema->flags, schema->colId, schema->bytes) < 0) {
|
||||||
|
tdDestroyTSchemaBuilder(&schemaBuilder);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
STSchema *pNSchema = tdGetSchemaFromBuilder(&schemaBuilder);
|
||||||
|
if (pNSchema == NULL) {
|
||||||
|
tdDestroyTSchemaBuilder(&schemaBuilder);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
tdDestroyTSchemaBuilder(&schemaBuilder);
|
||||||
|
return pNSchema;
|
||||||
|
}
|
||||||
|
|
|
@ -24,8 +24,7 @@ const uint8_t tdVTypeByte[2][3] = {{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// 1 bit
|
// 1 bit
|
||||||
TD_VTYPE_NORM_BYTE_I,
|
TD_VTYPE_NORM_BYTE_I, TD_VTYPE_NULL_BYTE_I,
|
||||||
TD_VTYPE_NULL_BYTE_I,
|
|
||||||
TD_VTYPE_NULL_BYTE_I, // padding
|
TD_VTYPE_NULL_BYTE_I, // padding
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,17 +223,40 @@ static uint8_t tdGetMergedBitmapByte(uint8_t byte) {
|
||||||
* @brief Merge bitmap from 2 bits to 1 bits, and the memory buffer should be guaranteed by the invoker.
|
* @brief Merge bitmap from 2 bits to 1 bits, and the memory buffer should be guaranteed by the invoker.
|
||||||
*
|
*
|
||||||
* @param srcBitmap
|
* @param srcBitmap
|
||||||
* @param srcLen
|
* @param nBits
|
||||||
* @param dstBitmap
|
* @param dstBitmap
|
||||||
*/
|
*/
|
||||||
void tdMergeBitmap(uint8_t *srcBitmap, int32_t srcLen, uint8_t *dstBitmap) {
|
void tdMergeBitmap(uint8_t *srcBitmap, int32_t nBits, uint8_t *dstBitmap) {
|
||||||
int32_t i = 0, j = 0;
|
int32_t i = 0, j = 0;
|
||||||
|
int32_t nBytes = TD_BITMAP_BYTES(nBits);
|
||||||
|
int32_t nStrictBytes = nBits / 4;
|
||||||
|
int32_t nPartialBits = nBits - nStrictBytes * 4;
|
||||||
|
|
||||||
if (srcLen > 0) {
|
switch (nPartialBits) {
|
||||||
|
case 0:
|
||||||
|
// NOTHING TODO
|
||||||
|
break;
|
||||||
|
case 1: {
|
||||||
|
void *lastByte = POINTER_SHIFT(srcBitmap, nStrictBytes);
|
||||||
|
*(uint8_t *)lastByte &= 0xC0;
|
||||||
|
} break;
|
||||||
|
case 2: {
|
||||||
|
void *lastByte = POINTER_SHIFT(srcBitmap, nStrictBytes);
|
||||||
|
*(uint8_t *)lastByte &= 0xF0;
|
||||||
|
} break;
|
||||||
|
case 3: {
|
||||||
|
void *lastByte = POINTER_SHIFT(srcBitmap, nStrictBytes);
|
||||||
|
*(uint8_t *)lastByte &= 0xFC;
|
||||||
|
} break;
|
||||||
|
default:
|
||||||
|
ASSERT(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nBytes > 0) {
|
||||||
dstBitmap[j] = (tdGetMergedBitmapByte(srcBitmap[i]) << 4);
|
dstBitmap[j] = (tdGetMergedBitmapByte(srcBitmap[i]) << 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((++i) < srcLen) {
|
while ((++i) < nBytes) {
|
||||||
if ((i & 1) == 0) {
|
if ((i & 1) == 0) {
|
||||||
dstBitmap[j] = (tdGetMergedBitmapByte(srcBitmap[i]) << 4);
|
dstBitmap[j] = (tdGetMergedBitmapByte(srcBitmap[i]) << 4);
|
||||||
} else {
|
} else {
|
||||||
|
@ -391,7 +413,8 @@ STSRow *tdRowDup(STSRow *row) {
|
||||||
* @param bitmapMode default is 0(2 bits), otherwise 1(1 bit)
|
* @param bitmapMode default is 0(2 bits), otherwise 1(1 bit)
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
int tdAppendValToDataCol(SDataCol *pCol, TDRowValT valType, const void *val, int numOfRows, int maxPoints, int8_t bitmapMode) {
|
int tdAppendValToDataCol(SDataCol *pCol, TDRowValT valType, const void *val, int numOfRows, int maxPoints,
|
||||||
|
int8_t bitmapMode) {
|
||||||
TASSERT(pCol != NULL);
|
TASSERT(pCol != NULL);
|
||||||
|
|
||||||
// Assume that the columns not specified during insert/upsert mean None.
|
// Assume that the columns not specified during insert/upsert mean None.
|
||||||
|
@ -537,7 +560,8 @@ int32_t tdAppendSTSRowToDataCol(STSRow *pRow, STSchema *pSchema, SDataCols *pCol
|
||||||
return TSDB_CODE_SUCCESS;
|
return TSDB_CODE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tdMergeDataCols(SDataCols *target, SDataCols *source, int rowsToMerge, int *pOffset, bool forceSetNull, TDRowVerT maxVer) {
|
int tdMergeDataCols(SDataCols *target, SDataCols *source, int rowsToMerge, int *pOffset, bool forceSetNull,
|
||||||
|
TDRowVerT maxVer) {
|
||||||
ASSERT(rowsToMerge > 0 && rowsToMerge <= source->numOfRows);
|
ASSERT(rowsToMerge > 0 && rowsToMerge <= source->numOfRows);
|
||||||
ASSERT(target->numOfCols == source->numOfCols);
|
ASSERT(target->numOfCols == source->numOfCols);
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
|
@ -558,7 +582,8 @@ int tdMergeDataCols(SDataCols *target, SDataCols *source, int rowsToMerge, int *
|
||||||
if (tdGetColDataOfRow(&sVal, source->cols + j, i + (*pOffset), source->bitmapMode) < 0) {
|
if (tdGetColDataOfRow(&sVal, source->cols + j, i + (*pOffset), source->bitmapMode) < 0) {
|
||||||
TASSERT(0);
|
TASSERT(0);
|
||||||
}
|
}
|
||||||
tdAppendValToDataCol(target->cols + j, sVal.valType, sVal.val, target->numOfRows, target->maxPoints, target->bitmapMode);
|
tdAppendValToDataCol(target->cols + j, sVal.valType, sVal.val, target->numOfRows, target->maxPoints,
|
||||||
|
target->bitmapMode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
++target->numOfRows;
|
++target->numOfRows;
|
||||||
|
@ -605,7 +630,8 @@ static void tdMergeTwoDataCols(SDataCols *target, SDataCols *src1, int *iter1, i
|
||||||
if (tdGetColDataOfRow(&sVal, src1->cols + i, *iter1, src1->bitmapMode) < 0) {
|
if (tdGetColDataOfRow(&sVal, src1->cols + i, *iter1, src1->bitmapMode) < 0) {
|
||||||
TASSERT(0);
|
TASSERT(0);
|
||||||
}
|
}
|
||||||
tdAppendValToDataCol(&(target->cols[i]), sVal.valType, sVal.val, target->numOfRows, target->maxPoints, target->bitmapMode);
|
tdAppendValToDataCol(&(target->cols[i]), sVal.valType, sVal.val, target->numOfRows, target->maxPoints,
|
||||||
|
target->bitmapMode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -621,12 +647,14 @@ static void tdMergeTwoDataCols(SDataCols *target, SDataCols *src1, int *iter1, i
|
||||||
TASSERT(0);
|
TASSERT(0);
|
||||||
}
|
}
|
||||||
if (src2->cols[i].len > 0 && !tdValTypeIsNull(sVal.valType)) {
|
if (src2->cols[i].len > 0 && !tdValTypeIsNull(sVal.valType)) {
|
||||||
tdAppendValToDataCol(&(target->cols[i]), sVal.valType, sVal.val, target->numOfRows, target->maxPoints, target->bitmapMode);
|
tdAppendValToDataCol(&(target->cols[i]), sVal.valType, sVal.val, target->numOfRows, target->maxPoints,
|
||||||
|
target->bitmapMode);
|
||||||
} else if (!forceSetNull && key1 == key2 && src1->cols[i].len > 0) {
|
} else if (!forceSetNull && key1 == key2 && src1->cols[i].len > 0) {
|
||||||
if (tdGetColDataOfRow(&sVal, src1->cols + i, *iter1, src1->bitmapMode) < 0) {
|
if (tdGetColDataOfRow(&sVal, src1->cols + i, *iter1, src1->bitmapMode) < 0) {
|
||||||
TASSERT(0);
|
TASSERT(0);
|
||||||
}
|
}
|
||||||
tdAppendValToDataCol(&(target->cols[i]), sVal.valType, sVal.val, target->numOfRows, target->maxPoints, target->bitmapMode);
|
tdAppendValToDataCol(&(target->cols[i]), sVal.valType, sVal.val, target->numOfRows, target->maxPoints,
|
||||||
|
target->bitmapMode);
|
||||||
} else if (target->cols[i].len > 0) {
|
} else if (target->cols[i].len > 0) {
|
||||||
dataColSetNullAt(&target->cols[i], target->numOfRows, true, target->bitmapMode);
|
dataColSetNullAt(&target->cols[i], target->numOfRows, true, target->bitmapMode);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1350,7 +1350,7 @@ int tsdbWriteBlockImpl(STsdb *pRepo, STable *pTable, SDFile *pDFile, SDFile *pDF
|
||||||
if (tBitmaps > 0) {
|
if (tBitmaps > 0) {
|
||||||
bptr = POINTER_SHIFT(pBlockData, lsize + flen);
|
bptr = POINTER_SHIFT(pBlockData, lsize + flen);
|
||||||
if (isSuper && !tdDataColsIsBitmapI(pDataCols)) {
|
if (isSuper && !tdDataColsIsBitmapI(pDataCols)) {
|
||||||
tdMergeBitmap((uint8_t *)pDataCol->pBitmap, nBitmaps, (uint8_t *)pDataCol->pBitmap);
|
tdMergeBitmap((uint8_t *)pDataCol->pBitmap, rowsToWrite, (uint8_t *)pDataCol->pBitmap);
|
||||||
}
|
}
|
||||||
tBitmapsLen =
|
tBitmapsLen =
|
||||||
tsCompressTinyint((char *)pDataCol->pBitmap, tBitmaps, tBitmaps, bptr, tBitmaps + COMP_OVERFLOW_BYTES,
|
tsCompressTinyint((char *)pDataCol->pBitmap, tBitmaps, tBitmaps, bptr, tBitmaps + COMP_OVERFLOW_BYTES,
|
||||||
|
|
|
@ -305,7 +305,7 @@ int tsdbLoadBlockDataCols(SReadH *pReadh, SBlock *pBlock, SBlockInfo *pBlkInfo,
|
||||||
SDataCol *pDataCol = pReadh->pDCols[0]->cols + i;
|
SDataCol *pDataCol = pReadh->pDCols[0]->cols + i;
|
||||||
if (pDataCol->bitmap) {
|
if (pDataCol->bitmap) {
|
||||||
ASSERT(pDataCol->colId != PRIMARYKEY_TIMESTAMP_COL_ID);
|
ASSERT(pDataCol->colId != PRIMARYKEY_TIMESTAMP_COL_ID);
|
||||||
tdMergeBitmap(pDataCol->pBitmap, TD_BITMAP_BYTES(pReadh->pDCols[0]->numOfRows), pDataCol->pBitmap);
|
tdMergeBitmap(pDataCol->pBitmap, pReadh->pDCols[0]->numOfRows, pDataCol->pBitmap);
|
||||||
tdDataColsSetBitmapI(pReadh->pDCols[0]);
|
tdDataColsSetBitmapI(pReadh->pDCols[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue