diff --git a/src/client/src/tscSQLParser.c b/src/client/src/tscSQLParser.c index 2764ff4148012a57ed77d2a57ee770fdcbba8b23..586e4ddfb7c2d1903ee5fb0c48ba3599fca2c8e5 100644 --- a/src/client/src/tscSQLParser.c +++ b/src/client/src/tscSQLParser.c @@ -6099,6 +6099,8 @@ int32_t validateOrderbyNode(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SSqlNode* pSq const char* msg10 = "not support distinct mixed with order by"; const char* msg11 = "not support order with udf"; const char* msg12 = "order by tags not supported with diff/derivative/csum/mavg"; + const char* msg13 = "order by json tag, key is too long"; + const char* msg14 = "order by json tag, must be json->'key'"; setDefaultOrderInfo(pQueryInfo); STableMetaInfo* pTableMetaInfo = tscGetMetaInfo(pQueryInfo, 0); @@ -6186,7 +6188,21 @@ int32_t validateOrderbyNode(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SSqlNode* pSq } SColIndex* pColIndex = taosArrayGet(pQueryInfo->groupbyExpr.columnInfo, 0); if (relTagIndex == pColIndex->colIndex) { - orderByTags = true; + if (tscGetColumnSchemaById(pTableMetaInfo->pTableMeta, pColIndex->colId)->type == TSDB_DATA_TYPE_JSON){ + if(!pItem->isJsonExp){ + return invalidOperationMsg(pMsgBuf, msg14); + } + if(pItem->jsonExp->exprToken.n >= sizeof(pColIndex->name)){ + return invalidOperationMsg(pMsgBuf, msg13); + } + if(strncmp(pColIndex->name, pItem->jsonExp->exprToken.z, pItem->jsonExp->exprToken.n) == 0){ + orderByTags = true; + }else{ + orderByTags = false; + } + }else{ + orderByTags = true; + } } } else if (index.columnIndex == TSDB_TBNAME_COLUMN_INDEX) { // order by tbname // it is a tag column diff --git a/src/client/src/tscUtil.c b/src/client/src/tscUtil.c index 92debee6a4299e489c54f1b71fb8a349323524e1..491857a9790e1673e031926be18cfccf04e15492 100644 --- a/src/client/src/tscUtil.c +++ b/src/client/src/tscUtil.c @@ -5472,7 +5472,7 @@ int parseJsontoTagData(char* json, SKVRowBuilder* kvRowBuilder, char* errMsg, in retCode = tscSQLSyntaxErrMsg(errMsg, "json key too long, more than 256", NULL); goto end; } - if(taosHashGet(keyHash, jsonKey, strlen(jsonKey)) != NULL){ + if(strlen(jsonKey) == 0 || taosHashGet(keyHash, jsonKey, strlen(jsonKey)) != NULL){ continue; } diff --git a/src/util/src/tutil.c b/src/util/src/tutil.c index 4dac2026a736bd5b6189e376a9f071184e40380e..c15197b7537601c0f0ca72420a6711547d1ed0ed 100644 --- a/src/util/src/tutil.c +++ b/src/util/src/tutil.c @@ -526,9 +526,7 @@ void jsonKeyMd5(void *pMsg, int msgLen, void *pKey) { bool isValidateTag(char *input) { if (!input) return false; - size_t len = strlen(input); - if (len == 0) return false; - for (size_t i = 0; i < len; ++i) { + for (size_t i = 0; i < strlen(input); ++i) { if (isprint(input[i]) == 0) return false; } return true; diff --git a/tests/pytest/stable/json_tag.py b/tests/develop-test/0-management/3-tag/json_tag.py similarity index 88% rename from tests/pytest/stable/json_tag.py rename to tests/develop-test/0-management/3-tag/json_tag.py index cc59221b3bb6aab36020d8fafb98610f69f6833b..2c6861c40a9612a5126a6d65b12705ec0bb16b6d 100644 --- a/tests/pytest/stable/json_tag.py +++ b/tests/develop-test/0-management/3-tag/json_tag.py @@ -19,6 +19,13 @@ from util.sql import tdSql class TDTestCase: + def caseDescription(self): + ''' + Json tag test case, include create table with json tag, + select json tag and query with json tag in where condition, + besides, include json tag in group by/order by/join/subquery. + ''' + return def init(self, conn, logSql): tdLog.debug("start to execute %s" % __file__) @@ -38,7 +45,7 @@ class TDTestCase: tdSql.execute("insert into jsons1_7 using jsons1 tags('{\"tag1\":\"收到货\",\"tag2\":\"\",\"tag3\":null}') values(1591062628000, 2, NULL, '你就会', 'dws')") # test duplicate key using the first one. elimate empty key - tdSql.execute("CREATE TABLE if not exists jsons1_8 using jsons1 tags('{\"tag1\":null, \"tag1\":true, \"tag1\":45, \"1tag$\":2, \" \":90}')") + tdSql.execute("CREATE TABLE if not exists jsons1_8 using jsons1 tags('{\"tag1\":null, \"tag1\":true, \"tag1\":45, \"1tag$\":2, \" \":90, \"\":32}')") # test empty json string, save as jtag is NULL tdSql.execute("insert into jsons1_9 using jsons1 tags('\t') values (1591062328000, 24, NULL, '你就会', '2sdw')") @@ -60,10 +67,20 @@ class TDTestCase: tdSql.error("CREATE TABLE if not exists jsons1_14 using jsons1 tags('{\"tag1\":[1,true]}')") tdSql.error("CREATE TABLE if not exists jsons1_14 using jsons1 tags('{\"tag1\":{}}')") tdSql.error("CREATE TABLE if not exists jsons1_14 using jsons1 tags('{\"。loc\":\"fff\"}')") - tdSql.error("CREATE TABLE if not exists jsons1_14 using jsons1 tags('{\"\":\"fff\"}')") tdSql.error("CREATE TABLE if not exists jsons1_14 using jsons1 tags('{\"\t\":\"fff\"}')") tdSql.error("CREATE TABLE if not exists jsons1_14 using jsons1 tags('{\"试试\":\"fff\"}')") + #test length limit + char1= ''.join(['abcd']*64) + char3= ''.join(['abcd']*1022) + print(len(char3)) # 4088 + tdSql.error("CREATE TABLE if not exists jsons1_15 using jsons1 tags('{\"%s1\":5}')" % char1) # len(key)=257 + tdSql.execute("CREATE TABLE if not exists jsons1_15 using jsons1 tags('{\"%s\":5}')" % char1) # len(key)=256 + tdSql.error("CREATE TABLE if not exists jsons1_16 using jsons1 tags('{\"TS\":\"%s\"}')" % char3) # len(object)=4097 + tdSql.execute("CREATE TABLE if not exists jsons1_16 using jsons1 tags('{\"T\":\"%s\"}')" % char3) # len(object)=4096 + tdSql.execute("drop table if exists jsons1_15") + tdSql.execute("drop table if exists jsons1_16") + print("============== STEP 2 ===== alter table json tag") tdSql.error("ALTER STABLE jsons1 add tag tag2 nchar(20)") tdSql.error("ALTER STABLE jsons1 drop tag jtag") @@ -86,6 +103,14 @@ class TDTestCase: tdSql.error("select * from jsons1 where jtag contains''") tdSql.error("select * from jsons1 where jtag contains 'location'='beijing'") + # test function error + tdSql.error("select avg(jtag->'tag1') from jsons1") + tdSql.error("select avg(jtag) from jsons1") + tdSql.error("select min(jtag->'tag1') from jsons1") + tdSql.error("select min(jtag) from jsons1") + tdSql.error("select ceil(jtag->'tag1') from jsons1") + tdSql.error("select ceil(jtag) from jsons1") + # test select normal column tdSql.query("select dataint from jsons1") tdSql.checkRows(9) @@ -271,6 +296,13 @@ class TDTestCase: tdSql.query("select * from jsons1 where jtag->'tag1'='femail' and jtag contains 'tag3'") tdSql.checkRows(2) + + # test with between and + tdSql.query("select * from jsons1 where jtag->'tag1' between 1 and 30") + tdSql.checkRows(3) + tdSql.query("select * from jsons1 where jtag->'tag1' between 'femail' and 'beijing'") + tdSql.checkRows(2) + # test with tbname/normal column tdSql.query("select * from jsons1 where tbname = 'jsons1_1'") tdSql.checkRows(2) @@ -291,7 +323,7 @@ class TDTestCase: # test where condition in no support in tdSql.error("select * from jsons1 where jtag->'tag1' in ('beijing')") - # test where condition match + # test where condition match/nmath tdSql.query("select * from jsons1 where jtag->'tag1' match 'ma'") tdSql.checkRows(2) tdSql.query("select * from jsons1 where jtag->'tag1' match 'ma$'") @@ -300,6 +332,8 @@ class TDTestCase: tdSql.checkRows(2) tdSql.query("select * from jsons1 where jtag->'tag1' match '收到'") tdSql.checkRows(1) + tdSql.query("select * from jsons1 where jtag->'tag1' nmatch 'ma'") + tdSql.checkRows(2) # test distinct tdSql.execute("insert into jsons1_14 using jsons1 tags('{\"tag1\":\"收到货\",\"tag2\":\"\",\"tag3\":null}') values(1591062628000, 2, NULL, '你就会', 'dws')") @@ -335,6 +369,8 @@ class TDTestCase: tdSql.checkColNameList(res, cname_list) # test group by & order by json tag + tdSql.error("select count(*) from jsons1 group by jtag->'tag1' order by jtag->'tag2'") + tdSql.error("select count(*) from jsons1 group by jtag->'tag1' order by jtag") tdSql.query("select count(*) from jsons1 group by jtag->'tag1' order by jtag->'tag1' desc") tdSql.checkRows(8) tdSql.checkData(0, 0, 2) @@ -368,6 +404,10 @@ class TDTestCase: tdSql.checkData(7, 0, 11) tdSql.checkData(7, 1, '"femail"') + # test having + tdSql.query("select stddev(dataint) from jsons1 group by jtag->'tag1' having stddev(dataint) > 0") + tdSql.checkRows(2) + res = tdSql.getColNameList("select stddev(dataint) from jsons1 group by jsons1.jtag->'tag1'") cname_list = [] cname_list.append("stddev(dataint)") @@ -405,6 +445,16 @@ class TDTestCase: tdSql.checkData(1, 1, "jsons1_1") tdSql.checkData(1, 2, '"femail"') + # union all + tdSql.error("select jtag->'tag1' from jsons1 union all select jtag->'tag2' from jsons2") + tdSql.error("select jtag->'tag1' from jsons1_1 union all select jtag->'tag2' from jsons2_1") + + tdSql.query("select jtag->'tag1' from jsons1_1 union all select jtag->'tag1' from jsons2_1") + tdSql.checkRows(2) + tdSql.query("select dataint,jtag->'tag1',tbname from jsons1 union all select dataint,jtag->'tag1',tbname from jsons2") + tdSql.checkRows(13) + + def stop(self): tdSql.close() tdLog.success("%s successfully executed" % __file__) diff --git a/tests/develop-test/fulltest.sh b/tests/develop-test/fulltest.sh index e71a25659b1e5a2eed92e615f63eb18ace64de92..5c3b225f3fa1e24a098bcfafb19981c58115c337 100755 --- a/tests/develop-test/fulltest.sh +++ b/tests/develop-test/fulltest.sh @@ -1 +1,2 @@ -python3 test.py -f 1-insert/0-sql/basic.py \ No newline at end of file +python3 test.py -f 0-management/3-tag/json_tag.py +python3 test.py -f 1-insert/0-sql/basic.py