fix: cols funcs, sub query

This commit is contained in:
factosea 2025-02-05 15:26:03 +08:00
parent 7e553f7bc9
commit fbe345a82e
10 changed files with 144 additions and 85 deletions

View File

@ -699,6 +699,8 @@ char* getJoinSTypeString(EJoinSubType type);
char* getFullJoinTypeString(EJoinType type, EJoinSubType stype);
int32_t mergeJoinConds(SNode** ppDst, SNode** ppSrc);
int32_t rewriteExprAliasName(SExprNode* pNode, int64_t num);
#ifdef __cplusplus
}
#endif

View File

@ -41,7 +41,7 @@ int32_t sendSyncReq(const SEpSet *pEpSet, SRpcMsg *pMsg) {
}
char *i642str(int64_t val) {
static char str[24] = {0};
static threadlocal char str[24] = {0};
(void)snprintf(str, sizeof(str), "%" PRId64, val);
return str;
}

View File

@ -1702,7 +1702,7 @@ static int32_t translateOutVarchar(SFunctionNode* pFunc, char* pErrBuf, int32_t
return TSDB_CODE_SUCCESS;
}
static int32_t translateColsFunction(SFunctionNode* pFunc, char* pErrBuf, int32_t len) {
static int32_t invalidColsFunction(SFunctionNode* pFunc, char* pErrBuf, int32_t len) {
return TSDB_CODE_PAR_INVALID_COLS_FUNCTION;
}
@ -5654,7 +5654,7 @@ const SBuiltinFuncDefinition funcMgtBuiltins[] = {
},
{
.name = "cols",
.translateFunc = translateColsFunction,
.translateFunc = invalidColsFunction,
},
};
// clang-format on

View File

@ -3237,3 +3237,7 @@ int32_t nodesListDeduplicate(SNodeList** ppList) {
}
return code;
}
int32_t rewriteExprAliasName(SExprNode* pNode, int64_t num) {
return tsnprintf(pNode->aliasName, TSDB_COL_NAME_LEN, "expr_%d", num);
}

View File

@ -1574,24 +1574,30 @@ static int32_t findAndSetColumn(STranslateContext* pCxt, SColumnNode** pColRef,
STempTableNode* pTempTable = (STempTableNode*)pTable;
SNodeList* pProjectList = getProjectList(pTempTable->pSubquery);
SNode* pNode;
SExprNode* pFoundExpr = NULL;
FOREACH(pNode, pProjectList) {
SExprNode* pExpr = (SExprNode*)pNode;
if (0 == strcmp(pCol->colName, pExpr->aliasName)) {
if (0 == strcmp(pCol->colName, pExpr->aliasName) || 0 == strcmp(pCol->colName, pExpr->userAlias)) {
if (*pFound) {
return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_AMBIGUOUS_COLUMN, pCol->colName);
}
code = setColumnInfoByExpr(pTempTable, pExpr, pColRef);
if (TSDB_CODE_SUCCESS != code) {
break;
}
pFoundExpr = pExpr;
*pFound = true;
} else if (isPrimaryKeyImpl(pNode) && isInternalPrimaryKey(pCol)) {
code = setColumnInfoByExpr(pTempTable, pExpr, pColRef);
if (TSDB_CODE_SUCCESS != code) break;
if (*pFound) {
return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_AMBIGUOUS_COLUMN, pCol->colName);
}
pFoundExpr = pExpr;
pCol->isPrimTs = true;
*pFound = true;
}
}
if (pFoundExpr) {
code = setColumnInfoByExpr(pTempTable, pFoundExpr, pColRef);
if (TSDB_CODE_SUCCESS != code) {
return code;
}
}
}
return code;
}
@ -5561,7 +5567,7 @@ static int32_t rewriteProjectAlias(SNodeList* pProjectionList) {
if ('\0' == pExpr->userAlias[0]) {
tstrncpy(pExpr->userAlias, pExpr->aliasName, TSDB_COL_NAME_LEN);
}
snprintf(pExpr->aliasName, TSDB_COL_NAME_LEN,"#expr_%d", no++);
rewriteExprAliasName(pExpr, no++);
}
return TSDB_CODE_SUCCESS;
}
@ -7622,6 +7628,16 @@ static int32_t rewriteColsFunction(STranslateContext* pCxt, SNodeList** nodeList
}
static int32_t translateColsFunction(STranslateContext* pCxt, SSelectStmt* pSelect) {
if (QUERY_NODE_TEMP_TABLE == nodeType(pSelect->pFromTable)) {
SNode* pSubquery = ((STempTableNode*)pSelect->pFromTable)->pSubquery;
if (QUERY_NODE_SELECT_STMT == nodeType(pSubquery)) {
SSelectStmt* pSubSelect = (SSelectStmt*)pSubquery;
int32_t code = translateColsFunction(pCxt, pSubSelect);
if (TSDB_CODE_SUCCESS != code) {
return code;
}
}
}
SNodeList* selectFuncList = NULL;
int32_t code = rewriteColsFunction(pCxt, &pSelect->pProjectionList, &selectFuncList);
if (code == TSDB_CODE_SUCCESS) {
@ -7647,9 +7663,9 @@ _end:
static int32_t translateSelectFrom(STranslateContext* pCxt, SSelectStmt* pSelect) {
pCxt->pCurrStmt = (SNode*)pSelect;
pCxt->dual = false;
int32_t code = translateFrom(pCxt, &pSelect->pFromTable);
int32_t code = translateColsFunction(pCxt, pSelect);
if (TSDB_CODE_SUCCESS == code) {
code = translateColsFunction(pCxt, pSelect);
code = translateFrom(pCxt, &pSelect->pFromTable);
}
if (TSDB_CODE_SUCCESS == code) {
pSelect->precision = ((STableNode*)pSelect->pFromTable)->precision;

View File

@ -152,7 +152,7 @@ static EDealRes doNameExpr(SNode* pNode, void* pContext) {
case QUERY_NODE_LOGIC_CONDITION:
case QUERY_NODE_FUNCTION: {
if ('\0' == ((SExprNode*)pNode)->aliasName[0]) {
snprintf(((SExprNode*)pNode)->aliasName, TSDB_COL_NAME_LEN, "#expr_%p", pNode);
rewriteExprAliasName((SExprNode*)pNode, (int64_t)pNode);
}
return DEAL_RES_IGNORE_CHILD;
}

View File

@ -3035,7 +3035,7 @@ static int32_t smaIndexOptCreateSmaCols(SNodeList* pFuncs, uint64_t tableId, SNo
}
SExprNode exprNode;
exprNode.resType = ((SExprNode*)pWsNode)->resType;
snprintf(exprNode.aliasName, TSDB_COL_NAME_LEN, "#expr_%d", index + 1);
rewriteExprAliasName(&exprNode, index + 1);
SColumnNode* pkNode = NULL;
code = smaIndexOptCreateSmaCol((SNode*)&exprNode, tableId, PRIMARYKEY_TIMESTAMP_COL_ID, &pkNode);
if (TSDB_CODE_SUCCESS != code) {

View File

@ -13,6 +13,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "nodes.h"
#include "planInt.h"
#include "catalog.h"
@ -30,98 +31,106 @@ typedef struct SSlotIndex {
SArray* pSlotIdsInfo; // duplicate name slot
} SSlotIndex;
static int64_t getExprBindIndexStr(SNode* pNode, char* bindInfo) {
if (nodeType(pNode) == QUERY_NODE_COLUMN) {
SColumnNode* pCol = (SColumnNode*)pNode;
if (pCol->dataBlockId == 0) {
return 0;
}
}
if (nodesIsExprNode(pNode)) {
SExprNode* pExpr = (SExprNode*)pNode;
if (pExpr->bindTupleFuncIdx > 0 && pExpr->bindTupleFuncIdx <= 9) {
bindInfo[0] = '0' + pExpr->bindTupleFuncIdx;
return 1;
} else if (pExpr->bindTupleFuncIdx != 0) {
return tsnprintf(bindInfo, sizeof(bindInfo), "%d", pExpr->bindTupleFuncIdx);
}
}
return 0;
}
enum {
SLOT_KEY_TYPE_ALL = 1,
SLOT_KEY_TYPE_COLNAME = 2,
};
static int32_t getSlotKeyHelper(SNode* pNode, const char* pPreName, const char* name, char** ppKey, int32_t callocLen,
int32_t* pLen, uint16_t extraBufLen, int8_t slotKeyType) {
int32_t code = 0;
char bindInfo[16] = {0};
//int exBindInfoLen = getExprBindIndexStr(pNode, bindInfo);
*ppKey = taosMemoryCalloc(1, callocLen);
if (!*ppKey) {
return terrno;
}
if (slotKeyType == SLOT_KEY_TYPE_ALL) {
TAOS_STRNCAT(*ppKey, pPreName, TSDB_TABLE_NAME_LEN);
TAOS_STRNCAT(*ppKey, ".", 2);
TAOS_STRNCAT(*ppKey, name, TSDB_COL_NAME_LEN);
// if (exBindInfoLen > 0) {
// TAOS_STRNCAT(*ppKey, bindInfo, exBindInfoLen);
// }
*pLen = taosHashBinary(*ppKey, strlen(*ppKey));
} else {
TAOS_STRNCAT(*ppKey, name, TSDB_COL_NAME_LEN);
*pLen = strlen(*ppKey);
}
return code;
}
static int32_t getSlotKey(SNode* pNode, const char* pStmtName, char** ppKey, int32_t* pLen, uint16_t extraBufLen) {
int32_t code = 0;
int32_t callocLen = 0;
if (QUERY_NODE_COLUMN == nodeType(pNode)) {
SColumnNode* pCol = (SColumnNode*)pNode;
if (NULL != pStmtName) {
if ('\0' != pStmtName[0]) {
*ppKey = taosMemoryCalloc(1, TSDB_TABLE_NAME_LEN + 1 + TSDB_COL_NAME_LEN + 1 + extraBufLen);
if (!*ppKey) {
return terrno;
}
TAOS_STRNCAT(*ppKey, pStmtName, TSDB_TABLE_NAME_LEN);
TAOS_STRNCAT(*ppKey, ".", 2);
TAOS_STRNCAT(*ppKey, pCol->node.aliasName, TSDB_COL_NAME_LEN);
*pLen = taosHashBinary(*ppKey, strlen(*ppKey));
return code;
callocLen = TSDB_TABLE_NAME_LEN + 1 + TSDB_COL_NAME_LEN + 1 + extraBufLen;
return getSlotKeyHelper(pNode, pStmtName, pCol->node.aliasName, ppKey, callocLen, pLen, extraBufLen,
SLOT_KEY_TYPE_ALL);
} else {
*ppKey = taosMemoryCalloc(1, TSDB_COL_NAME_LEN + 1 + extraBufLen);
if (!*ppKey) {
return terrno;
}
TAOS_STRNCAT(*ppKey, pCol->node.aliasName, TSDB_COL_NAME_LEN);
*pLen = strlen(*ppKey);
return code;
callocLen = TSDB_COL_NAME_LEN + 1 + extraBufLen;
return getSlotKeyHelper(pNode, pStmtName, pCol->node.aliasName, ppKey, callocLen, pLen, extraBufLen,
SLOT_KEY_TYPE_COLNAME);
}
}
if ('\0' == pCol->tableAlias[0]) {
*ppKey = taosMemoryCalloc(1, TSDB_COL_NAME_LEN + 1 + extraBufLen);
if (!*ppKey) {
return terrno;
}
TAOS_STRNCAT(*ppKey, pCol->colName, TSDB_COL_NAME_LEN);
*pLen = strlen(*ppKey);
return code;
callocLen = TSDB_COL_NAME_LEN + 1 + extraBufLen;
return getSlotKeyHelper(pNode, pStmtName, pCol->colName, ppKey, callocLen, pLen, extraBufLen,
SLOT_KEY_TYPE_COLNAME);
}
*ppKey = taosMemoryCalloc(1, TSDB_TABLE_NAME_LEN + 1 + TSDB_COL_NAME_LEN + 1 + extraBufLen);
if (!*ppKey) {
return terrno;
}
TAOS_STRNCAT(*ppKey, pCol->tableAlias, TSDB_TABLE_NAME_LEN);
TAOS_STRNCAT(*ppKey, ".", 2);
TAOS_STRNCAT(*ppKey, pCol->colName, TSDB_COL_NAME_LEN);
*pLen = taosHashBinary(*ppKey, strlen(*ppKey));
return code;
callocLen = TSDB_TABLE_NAME_LEN + 1 + TSDB_COL_NAME_LEN + 1 + extraBufLen;
return getSlotKeyHelper(pNode, pCol->tableAlias, pCol->colName, ppKey, callocLen, pLen, extraBufLen,
SLOT_KEY_TYPE_ALL);
} else if (QUERY_NODE_FUNCTION == nodeType(pNode)) {
SFunctionNode* pFunc = (SFunctionNode*)pNode;
if (FUNCTION_TYPE_TBNAME == pFunc->funcType) {
SValueNode* pVal = (SValueNode*)nodesListGetNode(pFunc->pParameterList, 0);
if (pVal) {
if (NULL != pStmtName && '\0' != pStmtName[0]) {
*ppKey = taosMemoryCalloc(1, TSDB_TABLE_NAME_LEN + 1 + TSDB_COL_NAME_LEN + 1 + extraBufLen);
if (!*ppKey) {
return terrno;
}
TAOS_STRNCAT(*ppKey, pStmtName, TSDB_TABLE_NAME_LEN);
TAOS_STRNCAT(*ppKey, ".", 2);
TAOS_STRNCAT(*ppKey, ((SExprNode*)pNode)->aliasName, TSDB_COL_NAME_LEN);
*pLen = taosHashBinary(*ppKey, strlen(*ppKey));
return code;
callocLen = TSDB_TABLE_NAME_LEN + 1 + TSDB_COL_NAME_LEN + 1 + extraBufLen;
return getSlotKeyHelper(pNode, pStmtName, ((SExprNode*)pNode)->aliasName, ppKey, callocLen, pLen, extraBufLen,
SLOT_KEY_TYPE_ALL);
}
int32_t literalLen = strlen(pVal->literal);
*ppKey = taosMemoryCalloc(1, literalLen + 1 + TSDB_COL_NAME_LEN + 1 + extraBufLen);
if (!*ppKey) {
return terrno;
}
TAOS_STRNCAT(*ppKey, pVal->literal, literalLen);
TAOS_STRNCAT(*ppKey, ".", 2);
TAOS_STRNCAT(*ppKey, ((SExprNode*)pNode)->aliasName, TSDB_COL_NAME_LEN);
*pLen = taosHashBinary(*ppKey, strlen(*ppKey));
return code;
callocLen = literalLen + 1 + TSDB_COL_NAME_LEN + 1 + extraBufLen;
return getSlotKeyHelper(pNode, pVal->literal, ((SExprNode*)pNode)->aliasName, ppKey, callocLen, pLen,
extraBufLen, SLOT_KEY_TYPE_ALL);
}
}
}
if (NULL != pStmtName && '\0' != pStmtName[0]) {
*ppKey = taosMemoryCalloc(1, TSDB_TABLE_NAME_LEN + 1 + TSDB_COL_NAME_LEN + 1 + extraBufLen);
if (!*ppKey) {
return terrno;
}
TAOS_STRNCAT(*ppKey, pStmtName, TSDB_TABLE_NAME_LEN);
TAOS_STRNCAT(*ppKey, ".", 2);
TAOS_STRNCAT(*ppKey, ((SExprNode*)pNode)->aliasName, TSDB_COL_NAME_LEN);
*pLen = taosHashBinary(*ppKey, strlen(*ppKey));
return code;
callocLen = TSDB_TABLE_NAME_LEN + 1 + TSDB_COL_NAME_LEN + 1 + extraBufLen;
return getSlotKeyHelper(pNode, pStmtName, ((SExprNode*)pNode)->aliasName, ppKey, callocLen, pLen, extraBufLen,
SLOT_KEY_TYPE_ALL);
}
*ppKey = taosMemoryCalloc(1, TSDB_COL_NAME_LEN + 1 + extraBufLen);
if (!*ppKey) {
return terrno;
}
TAOS_STRNCAT(*ppKey, ((SExprNode*)pNode)->aliasName, TSDB_COL_NAME_LEN);
*pLen = strlen(*ppKey);
callocLen = TSDB_COL_NAME_LEN + 1 + extraBufLen;
return getSlotKeyHelper(pNode, pStmtName, ((SExprNode*)pNode)->aliasName, ppKey, callocLen, pLen, extraBufLen,
SLOT_KEY_TYPE_COLNAME);
return code;
}

View File

@ -79,6 +79,8 @@ static EDealRes doCreateColumn(SNode* pNode, void* pContext) {
}
}
}
pCol->node.bindTupleFuncIdx = pExpr->bindTupleFuncIdx;
pCol->node.tupleFuncIdx = pExpr->tupleFuncIdx;
return (TSDB_CODE_SUCCESS == nodesListStrictAppend(pCxt->pList, (SNode*)pCol) ? DEAL_RES_IGNORE_CHILD
: DEAL_RES_ERROR);
}

View File

@ -506,9 +506,35 @@ class TDTestCase:
tdSql.checkData(1, 5, 1734574929003)
tdSql.checkData(1, 6, 3)
# todo 2, sub query has cols func
# select * from (select cols(last_row(c0), ts as t1, c1 as c11), cols(first(c0), ts as t2, c1 c21), first(c0) from test.meters where c0 < 4);
# todo 3, cols on system table
# sub query has cols func
tdSql.query(f'select c11 from (select cols(last_row(c0), ts as t1, c1 as c11), cols(first(c0), ts as t2, c1 c21), first(c0) from test.meters where c0 < 4)')
tdSql.checkRows(1)
tdSql.checkCols(1)
tdSql.checkData(0, 0, 3)
tdSql.query(f'select c11, c21 from (select cols(last_row(c0), ts as t1, c1 as c11), cols(first(c0), ts as t2, c1 c21), first(c0) from test.meters where c0 < 4)')
tdSql.checkRows(1)
tdSql.checkCols(2)
tdSql.checkData(0, 0, 3)
tdSql.checkData(0, 1, 1)
tdSql.query(f'select c1, c21 from (select cols(last_row(c0), ts as t1, c1), cols(first(c0), ts as t2, c1 c21), first(c0) from test.meters where c0 < 4)')
tdSql.checkRows(1)
tdSql.checkCols(2)
tdSql.checkData(0, 0, 3)
tdSql.checkData(0, 1, 1)
tdSql.error(f'select c1 from (select cols(last_row(c0), ts as t1, c1), cols(first(c0), ts as t2, c1), first(c0) from test.meters where c0 < 4)')
# cols on system table
tdSql.query(f'select cols(max(vgroup_id), uid) from information_schema.ins_tables')
tdSql.checkRows(1)
tdSql.checkCols(1)
tdSql.query(f'select cols(max(vgroup_id), uid, `ttl`, create_time) from information_schema.ins_tables')
tdSql.checkRows(1)
tdSql.checkCols(3)
tdSql.query(f'select cols(max(vgroup_id), uid as uidname) from information_schema.ins_tables')
tdSql.checkRows(1)
tdSql.checkCols(1)
tdSql.error(f'select cols(last(vgroup_id), uid, `ttl`, create_time) from information_schema.ins_tables')
tdSql.error(f'select cols(first(vgroup_id), uid, `ttl`, create_time) from information_schema.ins_tables')
def funcSupperTableTest(self):
tdSql.execute('create database if not exists db;')
@ -534,7 +560,7 @@ class TDTestCase:
tdSql.checkData(0, 6, 'c2')
tdSql.checkData(0, 7, True)
#tdSql.execute(f'drop table if exists db.st')
tdSql.execute(f'drop table if exists db.st')
def funcNestTest(self):