diff --git a/include/common/tmsg.h b/include/common/tmsg.h index 7f75653836..ae6aa6c254 100644 --- a/include/common/tmsg.h +++ b/include/common/tmsg.h @@ -3440,6 +3440,8 @@ typedef struct { int8_t source; // TD_REQ_FROM_TAOX-taosX or TD_REQ_FROM_APP-taosClient uint32_t compress; // TSDB_ALTER_TABLE_UPDATE_COLUMN_COMPRESS SArray* pMultiTag; // TSDB_ALTER_TABLE_ADD_MULTI_TAGS + // for Add column + STypeMod typeMod; } SVAlterTbReq; int32_t tEncodeSVAlterTbReq(SEncoder* pEncoder, const SVAlterTbReq* pReq); diff --git a/source/common/src/msg/tmsg.c b/source/common/src/msg/tmsg.c index d2ae2d213b..01912dc369 100644 --- a/source/common/src/msg/tmsg.c +++ b/source/common/src/msg/tmsg.c @@ -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->flags)); TAOS_CHECK_EXIT(tEncodeI32v(pEncoder, pReq->bytes)); + TAOS_CHECK_EXIT(tEncodeI32(pEncoder, pReq->typeMod)); break; case TSDB_ALTER_TABLE_DROP_COLUMN: 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(tEncodeI32v(pEncoder, pReq->bytes)); TAOS_CHECK_EXIT(tEncodeU32(pEncoder, pReq->compress)); + TAOS_CHECK_EXIT(tEncodeI32(pEncoder, pReq->typeMod)); break; default: 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->flags)); TAOS_CHECK_EXIT(tDecodeI32v(pDecoder, &pReq->bytes)); + if (!tDecodeIsEnd(pDecoder)) { + TAOS_CHECK_EXIT(tDecodeI32(pDecoder, &pReq->typeMod)); + } break; case TSDB_ALTER_TABLE_DROP_COLUMN: 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(tDecodeI32v(pDecoder, &pReq->bytes)); TAOS_CHECK_EXIT(tDecodeU32(pDecoder, &pReq->compress)); + if (!tDecodeIsEnd(pDecoder)) { + TAOS_CHECK_EXIT(tDecodeI32(pDecoder, &pReq->typeMod)); + } default: break; } diff --git a/source/dnode/vnode/src/meta/metaEntry.c b/source/dnode/vnode/src/meta/metaEntry.c index 6b5a06d155..d2b61649ca 100644 --- a/source/dnode/vnode/src/meta/metaEntry.c +++ b/source/dnode/vnode/src/meta/metaEntry.c @@ -428,6 +428,15 @@ int32_t metaCloneEntry(const SMetaEntry *pEntry, SMetaEntry **ppEntry) { metaCloneEntryFree(ppEntry); 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; } diff --git a/source/dnode/vnode/src/meta/metaTable.c b/source/dnode/vnode/src/meta/metaTable.c index 2a706e671e..fd0608d46d 100644 --- a/source/dnode/vnode/src/meta/metaTable.c +++ b/source/dnode/vnode/src/meta/metaTable.c @@ -69,6 +69,36 @@ int32_t updataTableColCmpr(SColCmprWrapper *pWp, SSchema *pSchema, int8_t add, u 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) { pMetaRsp->pSchemas = taosMemoryMalloc(pSchema->nCols * sizeof(SSchema)); if (NULL == pMetaRsp->pSchemas) { diff --git a/source/dnode/vnode/src/meta/metaTable2.c b/source/dnode/vnode/src/meta/metaTable2.c index a4701ec2a8..603dfaf9fa 100644 --- a/source/dnode/vnode/src/meta/metaTable2.c +++ b/source/dnode/vnode/src/meta/metaTable2.c @@ -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 void metaFetchEntryFree(SMetaEntry **ppEntry); 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) { 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; SSchemaWrapper *pSchema = &pEntry->ntbEntry.schemaRow; SSchema *pColumn; + SExtSchema extSchema = {0}; pEntry->version = version; for (int32_t i = 0; i < pSchema->nCols; 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->flags = pReq->flags; pColumn->colId = pEntry->ntbEntry.ncid++; + extSchema.typeMod = pReq->typeMod; tstrncpy(pColumn->name, pReq->colName, TSDB_COL_NAME_LEN); uint32_t compress; 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); 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 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); } + // 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 code = metaHandleEntry2(pMeta, pEntry); if (code) { diff --git a/source/libs/command/src/command.c b/source/libs/command/src/command.c index 1a40c8b4f5..e63457c150 100644 --- a/source/libs/command/src/command.c +++ b/source/libs/command/src/command.c @@ -166,7 +166,15 @@ static int32_t setDescResultIntoDataBlock(bool sysInfoUser, SSDataBlock* pBlock, STR_TO_VARSTR(buf, pMeta->schema[i].name); 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); int32_t bytes = getSchemaBytes(pMeta->schema + i); COL_DATA_SET_VAL_AND_CHECK(pCol3, pBlock->info.rows, (const char*)&bytes, false); diff --git a/source/libs/decimal/test/decimalTest.cpp b/source/libs/decimal/test/decimalTest.cpp index 61fef52630..11f1dae816 100644 --- a/source/libs/decimal/test/decimalTest.cpp +++ b/source/libs/decimal/test/decimalTest.cpp @@ -609,94 +609,6 @@ TEST(decimal128, divide) { 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) { // convert uint8 to decimal 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) { testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); diff --git a/source/libs/parser/src/parTranslater.c b/source/libs/parser/src/parTranslater.c index 88f899ae34..667956d546 100755 --- a/source/libs/parser/src/parTranslater.c +++ b/source/libs/parser/src/parTranslater.c @@ -9460,7 +9460,11 @@ static int32_t checkTableTagsSchema(STranslateContext* pCxt, SHashObj* pHash, SN } else { 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) { @@ -16675,6 +16679,12 @@ static int32_t buildAddColReq(STranslateContext* pCxt, SAlterTableStmt* pStmt, S int8_t code = setColCompressByOption(pReq->type, columnEncodeVal(pStmt->pColOptions->encode), columnCompressVal(pStmt->pColOptions->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; diff --git a/tests/system-test/2-query/decimal.py b/tests/system-test/2-query/decimal.py index a75cd6974e..b697bb0450 100644 --- a/tests/system-test/2-query/decimal.py +++ b/tests/system-test/2-query/decimal.py @@ -2,6 +2,7 @@ from random import randrange import time import threading import secrets +from tag_lite import column from util.log import * from util.sql import * from util.cases import * @@ -47,8 +48,13 @@ class DecimalType: if digits == '': digits = '0' return digits - - + + @staticmethod + def default_compression() -> str: + return "zstd" + @staticmethod + def default_encode() -> str: + return "disabled" class TypeEnum: BOOL = 1 TINYINT = 2 @@ -244,13 +250,13 @@ class TableInserter: sql += ", " local_flush_database = i % 5000 == 0; 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: self.conn.execute(f"flush database {self.dbName}", queryTimes=1) self.conn.execute(sql, queryTimes=1) sql = 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: self.conn.execute(f"flush database {self.dbName}", queryTimes=1) self.conn.execute(sql, queryTimes=1) @@ -392,11 +398,13 @@ class TDTestCase: results = tdSql.queryResult for i, column_type in enumerate(column_types): 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.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 - ## add compression/encode check + if results[i+1][4] != DecimalType.default_encode(): + 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] = []): 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) self.check_desc("t1", self.columns, self.tags) - return ## 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: - sql = f"create table {self.db_name}.invalid_decimal_precision_scale (ts timestamp, c1 {i})" - tdSql.error(sql, -1) + sql = f"create table {self.db_name}.invalid_decimal_precision_scale (ts timestamp, c1 {i[0]})" + tdSql.error(sql, i[1]) ## 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 ### These ops will override the previous stbobjs and meta entries, so test it @@ -466,7 +492,7 @@ class TDTestCase: 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, 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 @@ -483,7 +509,8 @@ class TDTestCase: DataType(TypeEnum.VARCHAR, 255), ] 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): tdSql.execute("create database test", queryTimes=1) @@ -493,7 +520,6 @@ class TDTestCase: self.test_decimal_ddl() self.no_decimal_table_test() self.test_insert_decimal_values() - time.sleep(9999999) def stop(self): tdSql.close()