decimal testing
This commit is contained in:
parent
51fe4bd0c3
commit
cdc6d6eaf4
|
@ -3440,6 +3440,8 @@ typedef struct {
|
||||||
int8_t source; // TD_REQ_FROM_TAOX-taosX or TD_REQ_FROM_APP-taosClient
|
int8_t source; // TD_REQ_FROM_TAOX-taosX or TD_REQ_FROM_APP-taosClient
|
||||||
uint32_t compress; // TSDB_ALTER_TABLE_UPDATE_COLUMN_COMPRESS
|
uint32_t compress; // TSDB_ALTER_TABLE_UPDATE_COLUMN_COMPRESS
|
||||||
SArray* pMultiTag; // TSDB_ALTER_TABLE_ADD_MULTI_TAGS
|
SArray* pMultiTag; // TSDB_ALTER_TABLE_ADD_MULTI_TAGS
|
||||||
|
// for Add column
|
||||||
|
STypeMod typeMod;
|
||||||
} SVAlterTbReq;
|
} SVAlterTbReq;
|
||||||
|
|
||||||
int32_t tEncodeSVAlterTbReq(SEncoder* pEncoder, const SVAlterTbReq* pReq);
|
int32_t tEncodeSVAlterTbReq(SEncoder* pEncoder, const SVAlterTbReq* pReq);
|
||||||
|
|
|
@ -10965,6 +10965,7 @@ int32_t tEncodeSVAlterTbReq(SEncoder *pEncoder, const SVAlterTbReq *pReq) {
|
||||||
TAOS_CHECK_EXIT(tEncodeI8(pEncoder, pReq->type));
|
TAOS_CHECK_EXIT(tEncodeI8(pEncoder, pReq->type));
|
||||||
TAOS_CHECK_EXIT(tEncodeI8(pEncoder, pReq->flags));
|
TAOS_CHECK_EXIT(tEncodeI8(pEncoder, pReq->flags));
|
||||||
TAOS_CHECK_EXIT(tEncodeI32v(pEncoder, pReq->bytes));
|
TAOS_CHECK_EXIT(tEncodeI32v(pEncoder, pReq->bytes));
|
||||||
|
TAOS_CHECK_EXIT(tEncodeI32(pEncoder, pReq->typeMod));
|
||||||
break;
|
break;
|
||||||
case TSDB_ALTER_TABLE_DROP_COLUMN:
|
case TSDB_ALTER_TABLE_DROP_COLUMN:
|
||||||
TAOS_CHECK_EXIT(tEncodeCStr(pEncoder, pReq->colName));
|
TAOS_CHECK_EXIT(tEncodeCStr(pEncoder, pReq->colName));
|
||||||
|
@ -11021,6 +11022,7 @@ int32_t tEncodeSVAlterTbReq(SEncoder *pEncoder, const SVAlterTbReq *pReq) {
|
||||||
TAOS_CHECK_EXIT(tEncodeI8(pEncoder, pReq->flags));
|
TAOS_CHECK_EXIT(tEncodeI8(pEncoder, pReq->flags));
|
||||||
TAOS_CHECK_EXIT(tEncodeI32v(pEncoder, pReq->bytes));
|
TAOS_CHECK_EXIT(tEncodeI32v(pEncoder, pReq->bytes));
|
||||||
TAOS_CHECK_EXIT(tEncodeU32(pEncoder, pReq->compress));
|
TAOS_CHECK_EXIT(tEncodeU32(pEncoder, pReq->compress));
|
||||||
|
TAOS_CHECK_EXIT(tEncodeI32(pEncoder, pReq->typeMod));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -11046,6 +11048,9 @@ static int32_t tDecodeSVAlterTbReqCommon(SDecoder *pDecoder, SVAlterTbReq *pReq)
|
||||||
TAOS_CHECK_EXIT(tDecodeI8(pDecoder, &pReq->type));
|
TAOS_CHECK_EXIT(tDecodeI8(pDecoder, &pReq->type));
|
||||||
TAOS_CHECK_EXIT(tDecodeI8(pDecoder, &pReq->flags));
|
TAOS_CHECK_EXIT(tDecodeI8(pDecoder, &pReq->flags));
|
||||||
TAOS_CHECK_EXIT(tDecodeI32v(pDecoder, &pReq->bytes));
|
TAOS_CHECK_EXIT(tDecodeI32v(pDecoder, &pReq->bytes));
|
||||||
|
if (!tDecodeIsEnd(pDecoder)) {
|
||||||
|
TAOS_CHECK_EXIT(tDecodeI32(pDecoder, &pReq->typeMod));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case TSDB_ALTER_TABLE_DROP_COLUMN:
|
case TSDB_ALTER_TABLE_DROP_COLUMN:
|
||||||
TAOS_CHECK_EXIT(tDecodeCStr(pDecoder, &pReq->colName));
|
TAOS_CHECK_EXIT(tDecodeCStr(pDecoder, &pReq->colName));
|
||||||
|
@ -11109,6 +11114,9 @@ static int32_t tDecodeSVAlterTbReqCommon(SDecoder *pDecoder, SVAlterTbReq *pReq)
|
||||||
TAOS_CHECK_EXIT(tDecodeI8(pDecoder, &pReq->flags));
|
TAOS_CHECK_EXIT(tDecodeI8(pDecoder, &pReq->flags));
|
||||||
TAOS_CHECK_EXIT(tDecodeI32v(pDecoder, &pReq->bytes));
|
TAOS_CHECK_EXIT(tDecodeI32v(pDecoder, &pReq->bytes));
|
||||||
TAOS_CHECK_EXIT(tDecodeU32(pDecoder, &pReq->compress));
|
TAOS_CHECK_EXIT(tDecodeU32(pDecoder, &pReq->compress));
|
||||||
|
if (!tDecodeIsEnd(pDecoder)) {
|
||||||
|
TAOS_CHECK_EXIT(tDecodeI32(pDecoder, &pReq->typeMod));
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -428,6 +428,15 @@ int32_t metaCloneEntry(const SMetaEntry *pEntry, SMetaEntry **ppEntry) {
|
||||||
metaCloneEntryFree(ppEntry);
|
metaCloneEntryFree(ppEntry);
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
if (pEntry->pExtSchemas && pEntry->colCmpr.nCols > 0) {
|
||||||
|
(*ppEntry)->pExtSchemas = taosMemoryCalloc(pEntry->colCmpr.nCols, sizeof(SExtSchema));
|
||||||
|
if (!(*ppEntry)->pExtSchemas) {
|
||||||
|
code = terrno;
|
||||||
|
metaCloneEntryFree(ppEntry);
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
memcpy((*ppEntry)->pExtSchemas, pEntry->pExtSchemas, sizeof(SExtSchema) * pEntry->colCmpr.nCols);
|
||||||
|
}
|
||||||
|
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,6 +69,36 @@ int32_t updataTableColCmpr(SColCmprWrapper *pWp, SSchema *pSchema, int8_t add, u
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int32_t addTableExtSchema(SMetaEntry *pEntry, const SSchema *pColumn, int32_t newColNum, SExtSchema *pExtSchema) {
|
||||||
|
// no need to add ext schema when no column needs ext schemas
|
||||||
|
if (!HAS_TYPE_MOD(pColumn) && !pEntry->pExtSchemas) return 0;
|
||||||
|
if (!pEntry->pExtSchemas) {
|
||||||
|
// add a column which needs ext schema
|
||||||
|
// set all extschemas to zero for all columns alrady existed
|
||||||
|
pEntry->pExtSchemas = (SExtSchema *)taosMemoryCalloc(newColNum, sizeof(SExtSchema));
|
||||||
|
} else {
|
||||||
|
// already has columns with ext schema
|
||||||
|
pEntry->pExtSchemas = (SExtSchema *)taosMemoryRealloc(pEntry->pExtSchemas, sizeof(SExtSchema) * newColNum);
|
||||||
|
}
|
||||||
|
if (!pEntry->pExtSchemas) return terrno;
|
||||||
|
pEntry->pExtSchemas[newColNum - 1] = *pExtSchema;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t dropTableExtSchema(SMetaEntry *pEntry, int32_t dropColId, int32_t newColNum) {
|
||||||
|
// no ext schema, no need to drop
|
||||||
|
if (!pEntry->pExtSchemas) return 0;
|
||||||
|
if (dropColId == newColNum) {
|
||||||
|
// drop the last column
|
||||||
|
pEntry->pExtSchemas[dropColId - 1] = (SExtSchema){0};
|
||||||
|
} else {
|
||||||
|
// drop a column in the middle
|
||||||
|
memmove(pEntry->pExtSchemas + dropColId, pEntry->pExtSchemas + dropColId + 1,
|
||||||
|
(newColNum - dropColId) * sizeof(SExtSchema));
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int metaUpdateMetaRsp(tb_uid_t uid, char *tbName, SSchemaWrapper *pSchema, STableMetaRsp *pMetaRsp) {
|
int metaUpdateMetaRsp(tb_uid_t uid, char *tbName, SSchemaWrapper *pSchema, STableMetaRsp *pMetaRsp) {
|
||||||
pMetaRsp->pSchemas = taosMemoryMalloc(pSchema->nCols * sizeof(SSchema));
|
pMetaRsp->pSchemas = taosMemoryMalloc(pSchema->nCols * sizeof(SSchema));
|
||||||
if (NULL == pMetaRsp->pSchemas) {
|
if (NULL == pMetaRsp->pSchemas) {
|
||||||
|
|
|
@ -21,6 +21,8 @@ extern int32_t metaFetchEntryByUid(SMeta *pMeta, int64_t uid, SMetaEntry **ppEnt
|
||||||
extern int32_t metaFetchEntryByName(SMeta *pMeta, const char *name, SMetaEntry **ppEntry);
|
extern int32_t metaFetchEntryByName(SMeta *pMeta, const char *name, SMetaEntry **ppEntry);
|
||||||
extern void metaFetchEntryFree(SMetaEntry **ppEntry);
|
extern void metaFetchEntryFree(SMetaEntry **ppEntry);
|
||||||
extern int32_t updataTableColCmpr(SColCmprWrapper *pWp, SSchema *pSchema, int8_t add, uint32_t compress);
|
extern int32_t updataTableColCmpr(SColCmprWrapper *pWp, SSchema *pSchema, int8_t add, uint32_t compress);
|
||||||
|
extern int32_t addTableExtSchema(SMetaEntry* pEntry, const SSchema* pColumn, int32_t newColNum, SExtSchema* pExtSchema);
|
||||||
|
extern int32_t dropTableExtSchema(SMetaEntry* pEntry, int32_t dropColId, int32_t newColNum);
|
||||||
|
|
||||||
static int32_t metaCheckCreateSuperTableReq(SMeta *pMeta, int64_t version, SVCreateStbReq *pReq) {
|
static int32_t metaCheckCreateSuperTableReq(SMeta *pMeta, int64_t version, SVCreateStbReq *pReq) {
|
||||||
int32_t vgId = TD_VID(pMeta->pVnode);
|
int32_t vgId = TD_VID(pMeta->pVnode);
|
||||||
|
@ -625,6 +627,7 @@ int32_t metaAddTableColumn(SMeta *pMeta, int64_t version, SVAlterTbReq *pReq, ST
|
||||||
int32_t rowSize = 0;
|
int32_t rowSize = 0;
|
||||||
SSchemaWrapper *pSchema = &pEntry->ntbEntry.schemaRow;
|
SSchemaWrapper *pSchema = &pEntry->ntbEntry.schemaRow;
|
||||||
SSchema *pColumn;
|
SSchema *pColumn;
|
||||||
|
SExtSchema extSchema = {0};
|
||||||
pEntry->version = version;
|
pEntry->version = version;
|
||||||
for (int32_t i = 0; i < pSchema->nCols; i++) {
|
for (int32_t i = 0; i < pSchema->nCols; i++) {
|
||||||
pColumn = &pSchema->pSchema[i];
|
pColumn = &pSchema->pSchema[i];
|
||||||
|
@ -659,6 +662,7 @@ int32_t metaAddTableColumn(SMeta *pMeta, int64_t version, SVAlterTbReq *pReq, ST
|
||||||
pColumn->type = pReq->type;
|
pColumn->type = pReq->type;
|
||||||
pColumn->flags = pReq->flags;
|
pColumn->flags = pReq->flags;
|
||||||
pColumn->colId = pEntry->ntbEntry.ncid++;
|
pColumn->colId = pEntry->ntbEntry.ncid++;
|
||||||
|
extSchema.typeMod = pReq->typeMod;
|
||||||
tstrncpy(pColumn->name, pReq->colName, TSDB_COL_NAME_LEN);
|
tstrncpy(pColumn->name, pReq->colName, TSDB_COL_NAME_LEN);
|
||||||
uint32_t compress;
|
uint32_t compress;
|
||||||
if (TSDB_ALTER_TABLE_ADD_COLUMN == pReq->action) {
|
if (TSDB_ALTER_TABLE_ADD_COLUMN == pReq->action) {
|
||||||
|
@ -673,6 +677,14 @@ int32_t metaAddTableColumn(SMeta *pMeta, int64_t version, SVAlterTbReq *pReq, ST
|
||||||
metaFetchEntryFree(&pEntry);
|
metaFetchEntryFree(&pEntry);
|
||||||
TAOS_RETURN(code);
|
TAOS_RETURN(code);
|
||||||
}
|
}
|
||||||
|
code = addTableExtSchema(pEntry, pColumn, pSchema->nCols, &extSchema);
|
||||||
|
// TODO wjm update extSchema, client set typeMod in add request.
|
||||||
|
if (code) {
|
||||||
|
metaError("vgId:%d, %s failed to add ext schema at %s:%d since %s, version:%" PRId64, TD_VID(pMeta->pVnode),
|
||||||
|
__func__, __FILE__, __LINE__, tstrerror(code), version);
|
||||||
|
metaFetchEntryFree(&pEntry);
|
||||||
|
TAOS_RETURN(code);
|
||||||
|
}
|
||||||
|
|
||||||
// do handle entry
|
// do handle entry
|
||||||
code = metaHandleEntry2(pMeta, pEntry);
|
code = metaHandleEntry2(pMeta, pEntry);
|
||||||
|
@ -783,6 +795,15 @@ int32_t metaDropTableColumn(SMeta *pMeta, int64_t version, SVAlterTbReq *pReq, S
|
||||||
TAOS_RETURN(TSDB_CODE_VND_INVALID_TABLE_ACTION);
|
TAOS_RETURN(TSDB_CODE_VND_INVALID_TABLE_ACTION);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// update column extschema
|
||||||
|
code = dropTableExtSchema(pEntry, iColumn, pSchema->nCols);
|
||||||
|
if (code) {
|
||||||
|
metaError("vgId:%d, %s failed to remove extschema at %s:%d since %s, version:%" PRId64, TD_VID(pMeta->pVnode),
|
||||||
|
__func__, __FILE__, __LINE__, tstrerror(code), version);
|
||||||
|
metaFetchEntryFree(&pEntry);
|
||||||
|
TAOS_RETURN(code);
|
||||||
|
}
|
||||||
|
|
||||||
// do handle entry
|
// do handle entry
|
||||||
code = metaHandleEntry2(pMeta, pEntry);
|
code = metaHandleEntry2(pMeta, pEntry);
|
||||||
if (code) {
|
if (code) {
|
||||||
|
|
|
@ -166,7 +166,15 @@ static int32_t setDescResultIntoDataBlock(bool sysInfoUser, SSDataBlock* pBlock,
|
||||||
STR_TO_VARSTR(buf, pMeta->schema[i].name);
|
STR_TO_VARSTR(buf, pMeta->schema[i].name);
|
||||||
COL_DATA_SET_VAL_AND_CHECK(pCol1, pBlock->info.rows, buf, false);
|
COL_DATA_SET_VAL_AND_CHECK(pCol1, pBlock->info.rows, buf, false);
|
||||||
|
|
||||||
STR_TO_VARSTR(buf, tDataTypes[pMeta->schema[i].type].name);
|
if (IS_DECIMAL_TYPE(pMeta->schema[i].type) && withExtSchema(pMeta->tableType)) {
|
||||||
|
uint8_t prec = 0, scale = 0;
|
||||||
|
decimalFromTypeMod(pMeta->schemaExt[i].typeMod, &prec, &scale);
|
||||||
|
size_t len = snprintf(buf + VARSTR_HEADER_SIZE, DESCRIBE_RESULT_FIELD_LEN - VARSTR_HEADER_SIZE, "%s(%hhu, %hhu)",
|
||||||
|
tDataTypes[pMeta->schema[i].type].name, prec, scale);
|
||||||
|
varDataSetLen(buf, len);
|
||||||
|
} else {
|
||||||
|
STR_TO_VARSTR(buf, tDataTypes[pMeta->schema[i].type].name);
|
||||||
|
}
|
||||||
COL_DATA_SET_VAL_AND_CHECK(pCol2, pBlock->info.rows, buf, false);
|
COL_DATA_SET_VAL_AND_CHECK(pCol2, pBlock->info.rows, buf, false);
|
||||||
int32_t bytes = getSchemaBytes(pMeta->schema + i);
|
int32_t bytes = getSchemaBytes(pMeta->schema + i);
|
||||||
COL_DATA_SET_VAL_AND_CHECK(pCol3, pBlock->info.rows, (const char*)&bytes, false);
|
COL_DATA_SET_VAL_AND_CHECK(pCol3, pBlock->info.rows, (const char*)&bytes, false);
|
||||||
|
|
|
@ -609,94 +609,6 @@ TEST(decimal128, divide) {
|
||||||
ASSERT_TRUE(1);
|
ASSERT_TRUE(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(decimal, api_taos_fetch_rows) {
|
|
||||||
const char* host = "127.0.0.1";
|
|
||||||
const char* user = "root";
|
|
||||||
const char* passwd = "taosdata";
|
|
||||||
const char* db = "test_api";
|
|
||||||
const char* create_tb = "create table if not exists test_api.nt(ts timestamp, c1 decimal(10, 2), c2 decimal(38, 10))";
|
|
||||||
const char* sql = "select c1, c2 from test_api.nt";
|
|
||||||
const char* sql_insert = "insert into test_api.nt values(now, 123456.123, 98472981092.1209111)";
|
|
||||||
|
|
||||||
TAOS* pTaos = taos_connect(host, user, passwd, NULL, 0);
|
|
||||||
if (!pTaos) {
|
|
||||||
cout << "taos connect failed: " << host << " " << taos_errstr(NULL);
|
|
||||||
FAIL();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto* res = taos_query(pTaos, (std::string("create database if not exists ") + db).c_str());
|
|
||||||
taos_free_result(res);
|
|
||||||
res = taos_query(pTaos, create_tb);
|
|
||||||
taos_free_result(res);
|
|
||||||
res = taos_query(pTaos, sql_insert);
|
|
||||||
taos_free_result(res);
|
|
||||||
|
|
||||||
res = taos_query(pTaos, sql);
|
|
||||||
int32_t code = taos_errno(res);
|
|
||||||
if (code != 0) {
|
|
||||||
cout << "taos_query with sql: " << sql << " failed: " << taos_errstr(res);
|
|
||||||
FAIL();
|
|
||||||
}
|
|
||||||
|
|
||||||
char buf[1024] = {0};
|
|
||||||
auto* fields = taos_fetch_fields(res);
|
|
||||||
auto fieldNum = taos_field_count(res);
|
|
||||||
while (auto row = taos_fetch_row(res)) {
|
|
||||||
taos_print_row(buf, row, fields, fieldNum);
|
|
||||||
cout << buf << endl;
|
|
||||||
}
|
|
||||||
taos_free_result(res);
|
|
||||||
|
|
||||||
res = taos_query(pTaos, sql);
|
|
||||||
code = taos_errno(res);
|
|
||||||
if (code != 0) {
|
|
||||||
cout << "taos_query with sql: " << sql << " failed: " << taos_errstr(res);
|
|
||||||
taos_free_result(res);
|
|
||||||
FAIL();
|
|
||||||
}
|
|
||||||
|
|
||||||
void* pData = NULL;
|
|
||||||
int32_t numOfRows = 0;
|
|
||||||
code = taos_fetch_raw_block(res, &numOfRows, &pData);
|
|
||||||
if (code != 0) {
|
|
||||||
cout << "taos_query with sql: " << sql << " failed: " << taos_errstr(res);
|
|
||||||
FAIL();
|
|
||||||
}
|
|
||||||
if (numOfRows > 0) {
|
|
||||||
int32_t version = *(int32_t*)pData;
|
|
||||||
ASSERT_EQ(version, BLOCK_VERSION_1);
|
|
||||||
int32_t rows = *(int32_t*)((char*)pData + 4 + 4);
|
|
||||||
int32_t colNum = *(int32_t*)((char*)pData + 4 + 4 + 4);
|
|
||||||
int32_t bytes_skip = 4 + 4 + 4 + 4 + 4 + 8;
|
|
||||||
char* p = (char*)pData + bytes_skip;
|
|
||||||
// col1
|
|
||||||
int8_t t = *(int8_t*)p;
|
|
||||||
int32_t type_mod = *(int32_t*)(p + 1);
|
|
||||||
|
|
||||||
ASSERT_EQ(t, TSDB_DATA_TYPE_DECIMAL64);
|
|
||||||
auto check_type_mod = [](char* pStart, uint8_t prec, uint8_t scale, int32_t bytes) {
|
|
||||||
ASSERT_EQ(*pStart, bytes);
|
|
||||||
ASSERT_EQ(*(pStart + 2), prec);
|
|
||||||
ASSERT_EQ(*(pStart + 3), scale);
|
|
||||||
};
|
|
||||||
check_type_mod(p + 1, 10, 2, 8);
|
|
||||||
|
|
||||||
// col2
|
|
||||||
p += 5;
|
|
||||||
t = *(int8_t*)p;
|
|
||||||
type_mod = *(int32_t*)(p + 1);
|
|
||||||
check_type_mod(p + 1, 38, 10, 16);
|
|
||||||
|
|
||||||
p = p + 5 + BitmapLen(numOfRows) + colNum * 4;
|
|
||||||
int64_t row1Val = *(int64_t*)p;
|
|
||||||
ASSERT_EQ(row1Val, 12345612);
|
|
||||||
}
|
|
||||||
taos_free_result(res);
|
|
||||||
|
|
||||||
taos_close(pTaos);
|
|
||||||
taos_cleanup();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(decimal, conversion) {
|
TEST(decimal, conversion) {
|
||||||
// convert uint8 to decimal
|
// convert uint8 to decimal
|
||||||
char buf[64] = {0};
|
char buf[64] = {0};
|
||||||
|
@ -1249,6 +1161,126 @@ TEST(decimal_all, ret_type_for_non_decimal_types) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class DecimalTest : public ::testing::Test {
|
||||||
|
TAOS* get_connection() {
|
||||||
|
auto conn = taos_connect(host, user, passwd, db, 0);
|
||||||
|
if (!conn) {
|
||||||
|
cout << "taos connect failed: " << host << " " << taos_errstr(NULL);
|
||||||
|
}
|
||||||
|
return conn;
|
||||||
|
}
|
||||||
|
TAOS* default_conn_ = NULL;
|
||||||
|
static constexpr const char* host = "127.0.0.1";
|
||||||
|
static constexpr const char* user = "root";
|
||||||
|
static constexpr const char* passwd = "taosdata";
|
||||||
|
static constexpr const char* db = "test_api";
|
||||||
|
|
||||||
|
public:
|
||||||
|
void SetUp() override {
|
||||||
|
default_conn_ = get_connection();
|
||||||
|
if (!default_conn_) {
|
||||||
|
FAIL();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void TearDown() override {
|
||||||
|
if (default_conn_) {
|
||||||
|
taos_close(default_conn_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(DecimalTest, insert) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(DecimalTest, api_taos_fetch_rows) {
|
||||||
|
const char* host = "127.0.0.1";
|
||||||
|
const char* user = "root";
|
||||||
|
const char* passwd = "taosdata";
|
||||||
|
const char* db = "test_api";
|
||||||
|
const char* create_tb = "create table if not exists test_api.nt(ts timestamp, c1 decimal(10, 2), c2 decimal(38, 10))";
|
||||||
|
const char* sql = "select c1, c2 from test_api.nt";
|
||||||
|
const char* sql_insert = "insert into test_api.nt values(now, 123456.123, 98472981092.1209111)";
|
||||||
|
|
||||||
|
TAOS* pTaos = taos_connect(host, user, passwd, NULL, 0);
|
||||||
|
if (!pTaos) {
|
||||||
|
cout << "taos connect failed: " << host << " " << taos_errstr(NULL);
|
||||||
|
FAIL();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* res = taos_query(pTaos, (std::string("create database if not exists ") + db).c_str());
|
||||||
|
taos_free_result(res);
|
||||||
|
res = taos_query(pTaos, create_tb);
|
||||||
|
taos_free_result(res);
|
||||||
|
res = taos_query(pTaos, sql_insert);
|
||||||
|
taos_free_result(res);
|
||||||
|
|
||||||
|
res = taos_query(pTaos, sql);
|
||||||
|
int32_t code = taos_errno(res);
|
||||||
|
if (code != 0) {
|
||||||
|
cout << "taos_query with sql: " << sql << " failed: " << taos_errstr(res);
|
||||||
|
FAIL();
|
||||||
|
}
|
||||||
|
|
||||||
|
char buf[1024] = {0};
|
||||||
|
auto* fields = taos_fetch_fields(res);
|
||||||
|
auto fieldNum = taos_field_count(res);
|
||||||
|
while (auto row = taos_fetch_row(res)) {
|
||||||
|
taos_print_row(buf, row, fields, fieldNum);
|
||||||
|
cout << buf << endl;
|
||||||
|
}
|
||||||
|
taos_free_result(res);
|
||||||
|
|
||||||
|
res = taos_query(pTaos, sql);
|
||||||
|
code = taos_errno(res);
|
||||||
|
if (code != 0) {
|
||||||
|
cout << "taos_query with sql: " << sql << " failed: " << taos_errstr(res);
|
||||||
|
taos_free_result(res);
|
||||||
|
FAIL();
|
||||||
|
}
|
||||||
|
|
||||||
|
void* pData = NULL;
|
||||||
|
int32_t numOfRows = 0;
|
||||||
|
code = taos_fetch_raw_block(res, &numOfRows, &pData);
|
||||||
|
if (code != 0) {
|
||||||
|
cout << "taos_query with sql: " << sql << " failed: " << taos_errstr(res);
|
||||||
|
FAIL();
|
||||||
|
}
|
||||||
|
if (numOfRows > 0) {
|
||||||
|
int32_t version = *(int32_t*)pData;
|
||||||
|
ASSERT_EQ(version, BLOCK_VERSION_1);
|
||||||
|
int32_t rows = *(int32_t*)((char*)pData + 4 + 4);
|
||||||
|
int32_t colNum = *(int32_t*)((char*)pData + 4 + 4 + 4);
|
||||||
|
int32_t bytes_skip = 4 + 4 + 4 + 4 + 4 + 8;
|
||||||
|
char* p = (char*)pData + bytes_skip;
|
||||||
|
// col1
|
||||||
|
int8_t t = *(int8_t*)p;
|
||||||
|
int32_t type_mod = *(int32_t*)(p + 1);
|
||||||
|
|
||||||
|
ASSERT_EQ(t, TSDB_DATA_TYPE_DECIMAL64);
|
||||||
|
auto check_type_mod = [](char* pStart, uint8_t prec, uint8_t scale, int32_t bytes) {
|
||||||
|
ASSERT_EQ(*pStart, bytes);
|
||||||
|
ASSERT_EQ(*(pStart + 2), prec);
|
||||||
|
ASSERT_EQ(*(pStart + 3), scale);
|
||||||
|
};
|
||||||
|
check_type_mod(p + 1, 10, 2, 8);
|
||||||
|
|
||||||
|
// col2
|
||||||
|
p += 5;
|
||||||
|
t = *(int8_t*)p;
|
||||||
|
type_mod = *(int32_t*)(p + 1);
|
||||||
|
check_type_mod(p + 1, 38, 10, 16);
|
||||||
|
|
||||||
|
p = p + 5 + BitmapLen(numOfRows) + colNum * 4;
|
||||||
|
int64_t row1Val = *(int64_t*)p;
|
||||||
|
ASSERT_EQ(row1Val, 12345612);
|
||||||
|
}
|
||||||
|
taos_free_result(res);
|
||||||
|
|
||||||
|
taos_close(pTaos);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
testing::InitGoogleTest(&argc, argv);
|
testing::InitGoogleTest(&argc, argv);
|
||||||
return RUN_ALL_TESTS();
|
return RUN_ALL_TESTS();
|
||||||
|
|
|
@ -9460,7 +9460,11 @@ static int32_t checkTableTagsSchema(STranslateContext* pCxt, SHashObj* pHash, SN
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// TODO wjm can't create tag with decimal type
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
|
if (IS_DECIMAL_TYPE(pTag->dataType.type)) {
|
||||||
|
code = generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_COLUMN, "Decimal type is not allowed for tag");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TSDB_CODE_SUCCESS == code && tagsSize > TSDB_MAX_TAGS_LEN) {
|
if (TSDB_CODE_SUCCESS == code && tagsSize > TSDB_MAX_TAGS_LEN) {
|
||||||
|
@ -16675,6 +16679,12 @@ static int32_t buildAddColReq(STranslateContext* pCxt, SAlterTableStmt* pStmt, S
|
||||||
int8_t code = setColCompressByOption(pReq->type, columnEncodeVal(pStmt->pColOptions->encode),
|
int8_t code = setColCompressByOption(pReq->type, columnEncodeVal(pStmt->pColOptions->encode),
|
||||||
columnCompressVal(pStmt->pColOptions->compress),
|
columnCompressVal(pStmt->pColOptions->compress),
|
||||||
columnLevelVal(pStmt->pColOptions->compressLevel), true, &pReq->compress);
|
columnLevelVal(pStmt->pColOptions->compressLevel), true, &pReq->compress);
|
||||||
|
if (code != TSDB_CODE_SUCCESS) return code;
|
||||||
|
}
|
||||||
|
pReq->typeMod = 0;
|
||||||
|
if (IS_DECIMAL_TYPE(pStmt->dataType.type)) {
|
||||||
|
pReq->typeMod = decimalCalcTypeMod(pStmt->dataType.precision, pStmt->dataType.scale);
|
||||||
|
pReq->flags |= COL_HAS_TYPE_MOD;
|
||||||
}
|
}
|
||||||
|
|
||||||
return TSDB_CODE_SUCCESS;
|
return TSDB_CODE_SUCCESS;
|
||||||
|
|
|
@ -2,6 +2,7 @@ from random import randrange
|
||||||
import time
|
import time
|
||||||
import threading
|
import threading
|
||||||
import secrets
|
import secrets
|
||||||
|
from tag_lite import column
|
||||||
from util.log import *
|
from util.log import *
|
||||||
from util.sql import *
|
from util.sql import *
|
||||||
from util.cases import *
|
from util.cases import *
|
||||||
|
@ -48,7 +49,12 @@ class DecimalType:
|
||||||
digits = '0'
|
digits = '0'
|
||||||
return digits
|
return digits
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def default_compression() -> str:
|
||||||
|
return "zstd"
|
||||||
|
@staticmethod
|
||||||
|
def default_encode() -> str:
|
||||||
|
return "disabled"
|
||||||
class TypeEnum:
|
class TypeEnum:
|
||||||
BOOL = 1
|
BOOL = 1
|
||||||
TINYINT = 2
|
TINYINT = 2
|
||||||
|
@ -244,13 +250,13 @@ class TableInserter:
|
||||||
sql += ", "
|
sql += ", "
|
||||||
local_flush_database = i % 5000 == 0;
|
local_flush_database = i % 5000 == 0;
|
||||||
if len(sql) > 1000:
|
if len(sql) > 1000:
|
||||||
tdLog.debug(f"insert into with sql{sql}")
|
#tdLog.debug(f"insert into with sql{sql}")
|
||||||
if flush_database and local_flush_database:
|
if flush_database and local_flush_database:
|
||||||
self.conn.execute(f"flush database {self.dbName}", queryTimes=1)
|
self.conn.execute(f"flush database {self.dbName}", queryTimes=1)
|
||||||
self.conn.execute(sql, queryTimes=1)
|
self.conn.execute(sql, queryTimes=1)
|
||||||
sql = pre_insert
|
sql = pre_insert
|
||||||
if len(sql) > len(pre_insert):
|
if len(sql) > len(pre_insert):
|
||||||
tdLog.debug(f"insert into with sql{sql}")
|
#tdLog.debug(f"insert into with sql{sql}")
|
||||||
if flush_database:
|
if flush_database:
|
||||||
self.conn.execute(f"flush database {self.dbName}", queryTimes=1)
|
self.conn.execute(f"flush database {self.dbName}", queryTimes=1)
|
||||||
self.conn.execute(sql, queryTimes=1)
|
self.conn.execute(sql, queryTimes=1)
|
||||||
|
@ -392,11 +398,13 @@ class TDTestCase:
|
||||||
results = tdSql.queryResult
|
results = tdSql.queryResult
|
||||||
for i, column_type in enumerate(column_types):
|
for i, column_type in enumerate(column_types):
|
||||||
if column_type.type == TypeEnum.DECIMAL:
|
if column_type.type == TypeEnum.DECIMAL:
|
||||||
if results[i+1][1] != "DECIMAL":
|
if results[i+1][1] != column_type.__str__():
|
||||||
tdLog.info(str(results))
|
tdLog.info(str(results))
|
||||||
tdLog.exit(f"check desc failed for table: {tbname} column {results[i+1][0]} type is {results[i+1][1]}, expect DECIMAL")
|
tdLog.exit(f"check desc failed for table: {tbname} column {results[i+1][0]} type is {results[i+1][1]}, expect DECIMAL")
|
||||||
## add decimal type bytes check
|
if results[i+1][4] != DecimalType.default_encode():
|
||||||
## add compression/encode check
|
tdLog.exit(f"check desc failed for table: {tbname} column {results[i+1][0]} encode is {results[i+1][5]}, expect {DecimalType.default_encode()}")
|
||||||
|
if results[i+1][5] != DecimalType.default_compression():
|
||||||
|
tdLog.exit(f"check desc failed for table: {tbname} column {results[i+1][0]} compression is {results[i+1][4]}, expect {DecimalType.default_compression()}")
|
||||||
|
|
||||||
def check_show_create_table(self, tbname: str, column_types: List[DataType], tag_types: List[DataType] = []):
|
def check_show_create_table(self, tbname: str, column_types: List[DataType], tag_types: List[DataType] = []):
|
||||||
sql = f"show create table {self.db_name}.{tbname}"
|
sql = f"show create table {self.db_name}.{tbname}"
|
||||||
|
@ -445,16 +453,34 @@ class TDTestCase:
|
||||||
DecimalColumnTableCreater(tdSql, self.db_name, self.stable_name, self.columns).create_child_table(self.c_table_prefix, self.c_table_num, self.tags, tag_values)
|
DecimalColumnTableCreater(tdSql, self.db_name, self.stable_name, self.columns).create_child_table(self.c_table_prefix, self.c_table_num, self.tags, tag_values)
|
||||||
self.check_desc("t1", self.columns, self.tags)
|
self.check_desc("t1", self.columns, self.tags)
|
||||||
|
|
||||||
return
|
|
||||||
## invalid precision/scale
|
## invalid precision/scale
|
||||||
invalid_precision_scale = ["decimal(-1, 2)", "decimal(39, 2)", "decimal(10, -1)", "decimal(10, 39)", "decimal(10, 2.5)", "decimal(10.5, 2)", "decimal(10.5, 2.5)", "decimal(0, 2)", "decimal(0)", "decimal", "decimal()"]
|
syntax_error = -2147473920
|
||||||
|
invalid_column = -2147473918
|
||||||
|
invalid_precision_scale = [("decimal(-1, 2)", syntax_error), ("decimal(39, 2)", invalid_column), ("decimal(10, -1)", syntax_error),
|
||||||
|
("decimal(10, 39)", invalid_column), ("decimal(10, 2.5)", syntax_error), ("decimal(10.5, 2)", syntax_error),
|
||||||
|
("decimal(10.5, 2.5)", syntax_error), ("decimal(0, 2)", invalid_column), ("decimal(0)", invalid_column),
|
||||||
|
("decimal", syntax_error), ("decimal()", syntax_error)]
|
||||||
for i in invalid_precision_scale:
|
for i in invalid_precision_scale:
|
||||||
sql = f"create table {self.db_name}.invalid_decimal_precision_scale (ts timestamp, c1 {i})"
|
sql = f"create table {self.db_name}.invalid_decimal_precision_scale (ts timestamp, c1 {i[0]})"
|
||||||
tdSql.error(sql, -1)
|
tdSql.error(sql, i[1])
|
||||||
|
|
||||||
## can't create decimal tag
|
## can't create decimal tag
|
||||||
|
sql = 'create stable %s.invalid_decimal_tag (ts timestamp) tags (t1 decimal(10, 2))' % (self.db_name)
|
||||||
|
tdSql.error(sql, invalid_column)
|
||||||
|
|
||||||
|
## alter table add column
|
||||||
|
sql = f'alter table {self.db_name}.{self.norm_table_name} add column c99 decimal(37, 19)'
|
||||||
|
self.columns.append(DataType(TypeEnum.DECIMAL, type_mod=DataType.get_decimal_type_mod(DecimalType(37, 19))))
|
||||||
|
tdSql.execute(sql, queryTimes=1)
|
||||||
|
self.check_desc(self.norm_table_name, self.columns)
|
||||||
|
## alter table add column with compression
|
||||||
|
|
||||||
|
## Test metaentry compatibility problem for decimal type:w
|
||||||
|
## How to test it?
|
||||||
|
## Create table with no decimal type, the metaentries should not have extschma, and add decimal column, the metaentries should have extschema for all columns.
|
||||||
|
## After drop this decimal column, the metaentries should not have extschema for all columns.
|
||||||
|
## Test for normal table and super table
|
||||||
|
|
||||||
## alter table
|
|
||||||
## drop index from stb
|
## drop index from stb
|
||||||
### These ops will override the previous stbobjs and meta entries, so test it
|
### These ops will override the previous stbobjs and meta entries, so test it
|
||||||
|
|
||||||
|
@ -466,7 +492,7 @@ class TDTestCase:
|
||||||
pass
|
pass
|
||||||
#TableInserter(tdSql, self.db_name, f"{self.c_table_prefix}{i}", self.columns, self.tags).insert(1, 1537146000000, 500)
|
#TableInserter(tdSql, self.db_name, f"{self.c_table_prefix}{i}", self.columns, self.tags).insert(1, 1537146000000, 500)
|
||||||
|
|
||||||
TableInserter(tdSql, self.db_name, self.norm_table_name, self.columns).insert(100000, 1537146000000, 500, flush_database=True)
|
TableInserter(tdSql, self.db_name, self.norm_table_name, self.columns).insert(10000, 1537146000000, 500, flush_database=True)
|
||||||
|
|
||||||
|
|
||||||
## insert null/None for decimal type
|
## insert null/None for decimal type
|
||||||
|
@ -483,7 +509,8 @@ class TDTestCase:
|
||||||
DataType(TypeEnum.VARCHAR, 255),
|
DataType(TypeEnum.VARCHAR, 255),
|
||||||
]
|
]
|
||||||
DecimalColumnTableCreater(tdSql, self.db_name, "tt", columns, []).create()
|
DecimalColumnTableCreater(tdSql, self.db_name, "tt", columns, []).create()
|
||||||
TableInserter(tdSql, self.db_name, 'tt', columns).insert(100000, 1537146000000, 500, flush_database=True)
|
TableInserter(tdSql, self.db_name, 'tt', columns).insert(10000, 1537146000000, 500, flush_database=True)
|
||||||
|
## TODO wjm test non support decimal version upgrade to decimal support version, and add decimal column
|
||||||
|
|
||||||
def test_decimal_ddl(self):
|
def test_decimal_ddl(self):
|
||||||
tdSql.execute("create database test", queryTimes=1)
|
tdSql.execute("create database test", queryTimes=1)
|
||||||
|
@ -493,7 +520,6 @@ class TDTestCase:
|
||||||
self.test_decimal_ddl()
|
self.test_decimal_ddl()
|
||||||
self.no_decimal_table_test()
|
self.no_decimal_table_test()
|
||||||
self.test_insert_decimal_values()
|
self.test_insert_decimal_values()
|
||||||
time.sleep(9999999)
|
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
tdSql.close()
|
tdSql.close()
|
||||||
|
|
Loading…
Reference in New Issue