|
|
|
@ -3097,213 +3097,6 @@ int32_t parseGroupbyClause(SQueryInfo* pQueryInfo, SArray* pList, SSqlCmd* pCmd)
|
|
|
|
|
return TSDB_CODE_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int32_t handleExprInHavingClause(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SColumnIndex* pIndex, tSQLExpr* pExpr, int32_t sqlOptr) {
|
|
|
|
|
STableMetaInfo* pTableMetaInfo = tscGetMetaInfo(pQueryInfo, pIndex->tableIndex);
|
|
|
|
|
|
|
|
|
|
STableMeta* pTableMeta = pTableMetaInfo->pTableMeta;
|
|
|
|
|
SSchema* pSchema = tscGetTableColumnSchema(pTableMeta, pIndex->columnIndex);
|
|
|
|
|
|
|
|
|
|
const char* msg1 = "non binary column not support like operator";
|
|
|
|
|
const char* msg2 = "binary column not support this operator";
|
|
|
|
|
const char* msg3 = "bool column not support this operator";
|
|
|
|
|
|
|
|
|
|
SColumn* pColumn = tscColumnListInsert(pQueryInfo->colList, pIndex);
|
|
|
|
|
SColumnFilterInfo* pColFilter = NULL;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* in case of TK_AND filter condition, we first find the corresponding column and build the query condition together
|
|
|
|
|
* the already existed condition.
|
|
|
|
|
*/
|
|
|
|
|
if (sqlOptr == TK_AND) {
|
|
|
|
|
// this is a new filter condition on this column
|
|
|
|
|
if (pColumn->numOfFilters == 0) {
|
|
|
|
|
pColFilter = addColumnFilterInfo(pColumn);
|
|
|
|
|
} else { // update the existed column filter information, find the filter info here
|
|
|
|
|
pColFilter = &pColumn->filterInfo[0];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pColFilter == NULL) {
|
|
|
|
|
return TSDB_CODE_TSC_OUT_OF_MEMORY;
|
|
|
|
|
}
|
|
|
|
|
} else if (sqlOptr == TK_OR) {
|
|
|
|
|
// TODO fixme: failed to invalid the filter expression: "col1 = 1 OR col2 = 2"
|
|
|
|
|
pColFilter = addColumnFilterInfo(pColumn);
|
|
|
|
|
if (pColFilter == NULL) {
|
|
|
|
|
return TSDB_CODE_TSC_OUT_OF_MEMORY;
|
|
|
|
|
}
|
|
|
|
|
} else { // error;
|
|
|
|
|
return TSDB_CODE_TSC_INVALID_SQL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pColFilter->filterstr =
|
|
|
|
|
((pSchema->type == TSDB_DATA_TYPE_BINARY || pSchema->type == TSDB_DATA_TYPE_NCHAR) ? 1 : 0);
|
|
|
|
|
|
|
|
|
|
if (pColFilter->filterstr) {
|
|
|
|
|
if (pExpr->nSQLOptr != TK_EQ
|
|
|
|
|
&& pExpr->nSQLOptr != TK_NE
|
|
|
|
|
&& pExpr->nSQLOptr != TK_ISNULL
|
|
|
|
|
&& pExpr->nSQLOptr != TK_NOTNULL
|
|
|
|
|
&& pExpr->nSQLOptr != TK_LIKE
|
|
|
|
|
) {
|
|
|
|
|
return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg2);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (pExpr->nSQLOptr == TK_LIKE) {
|
|
|
|
|
return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pSchema->type == TSDB_DATA_TYPE_BOOL) {
|
|
|
|
|
if (pExpr->nSQLOptr != TK_EQ && pExpr->nSQLOptr != TK_NE) {
|
|
|
|
|
return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg3);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pColumn->colIndex = *pIndex;
|
|
|
|
|
return doExtractColumnFilterInfo(pCmd, pQueryInfo, pColFilter, pIndex, pExpr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int32_t getHavingExpr(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, tSQLExpr** pExpr, int32_t parentOptr) {
|
|
|
|
|
if (pExpr == NULL || (*pExpr) == NULL) {
|
|
|
|
|
return TSDB_CODE_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char* msg1 = "invalid having clause";
|
|
|
|
|
|
|
|
|
|
tSQLExpr* pLeft = (*pExpr)->pLeft;
|
|
|
|
|
tSQLExpr* pRight = (*pExpr)->pRight;
|
|
|
|
|
|
|
|
|
|
if ((*pExpr)->nSQLOptr == TK_AND || (*pExpr)->nSQLOptr == TK_OR) {
|
|
|
|
|
int32_t ret = getHavingExpr(pCmd, pQueryInfo, &(*pExpr)->pLeft, (*pExpr)->nSQLOptr);
|
|
|
|
|
if (ret != TSDB_CODE_SUCCESS) {
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return getHavingExpr(pCmd, pQueryInfo, &(*pExpr)->pRight, (*pExpr)->nSQLOptr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((pLeft->nSQLOptr >= TK_COUNT && pLeft->nSQLOptr <= TK_AVG_IRATE) &&
|
|
|
|
|
(pRight->nSQLOptr >= TK_COUNT && pRight->nSQLOptr <= TK_AVG_IRATE)) {
|
|
|
|
|
return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pLeft->nSQLOptr >= TK_BOOL
|
|
|
|
|
&& pLeft->nSQLOptr <= TK_BINARY
|
|
|
|
|
&& pRight->nSQLOptr >= TK_BOOL
|
|
|
|
|
&& pRight->nSQLOptr <= TK_BINARY) {
|
|
|
|
|
return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
exchangeExpr(*pExpr);
|
|
|
|
|
|
|
|
|
|
pLeft = (*pExpr)->pLeft;
|
|
|
|
|
pRight = (*pExpr)->pRight;
|
|
|
|
|
|
|
|
|
|
if (!(pLeft->nSQLOptr >= TK_COUNT && pLeft->nSQLOptr <= TK_AVG_IRATE)) {
|
|
|
|
|
return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(pRight->nSQLOptr >= TK_BOOL && pRight->nSQLOptr <= TK_BINARY)) {
|
|
|
|
|
return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((*pExpr)->nSQLOptr >= TK_BITAND) {
|
|
|
|
|
return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pLeft->pParam == NULL || pLeft->pParam->nExpr < 1) {
|
|
|
|
|
return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int32_t i = 0; i < pLeft->pParam->nExpr; i++) {
|
|
|
|
|
tSqlExprItem* pParamElem = &(pLeft->pParam->a[i]);
|
|
|
|
|
if (pParamElem->pNode->nSQLOptr != TK_ALL && pParamElem->pNode->nSQLOptr != TK_ID) {
|
|
|
|
|
return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SColumnIndex index = COLUMN_INDEX_INITIALIZER;
|
|
|
|
|
if ((getColumnIndexByName(pCmd, &pParamElem->pNode->colInfo, pQueryInfo, &index) != TSDB_CODE_SUCCESS)) {
|
|
|
|
|
return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
STableMetaInfo* pTableMetaInfo = tscGetMetaInfo(pQueryInfo, index.tableIndex);
|
|
|
|
|
STableMeta* pTableMeta = pTableMetaInfo->pTableMeta;
|
|
|
|
|
|
|
|
|
|
if (index.columnIndex <= 0 ||
|
|
|
|
|
index.columnIndex >= tscGetNumOfColumns(pTableMeta)) {
|
|
|
|
|
return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tSqlExprItem item = {.pNode = pLeft, .aliasName = NULL, .distinct = false};
|
|
|
|
|
|
|
|
|
|
int32_t outputIndex = (int32_t)tscSqlExprNumOfExprs(pQueryInfo);
|
|
|
|
|
|
|
|
|
|
// ADD TRUE FOR TEST
|
|
|
|
|
if (addExprAndResultField(pCmd, pQueryInfo, outputIndex, &item, true) != TSDB_CODE_SUCCESS) {
|
|
|
|
|
return TSDB_CODE_TSC_INVALID_SQL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int32_t slot = tscNumOfFields(pQueryInfo) - 1;
|
|
|
|
|
SInternalField* pInfo = tscFieldInfoGetInternalField(&pQueryInfo->fieldsInfo, slot);
|
|
|
|
|
|
|
|
|
|
if (pInfo->pFieldFilters == NULL) {
|
|
|
|
|
SColumn* pFieldFilters = calloc(1, sizeof(SColumn));
|
|
|
|
|
if (pFieldFilters == NULL) {
|
|
|
|
|
return TSDB_CODE_TSC_OUT_OF_MEMORY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pInfo->pFieldFilters = pFieldFilters;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return handleExprInHavingClause(pCmd, pQueryInfo, pInfo->pFieldFilters, pExpr, parentOptr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int32_t parseHavingClause(SQueryInfo* pQueryInfo, tSQLExpr** pExpr, SSqlCmd* pCmd) {
|
|
|
|
|
const char* msg1 = "having only works with group by";
|
|
|
|
|
//const char* msg2 = "invalid column name in having clause";
|
|
|
|
|
//const char* msg3 = "columns from one table allowed as having columns";
|
|
|
|
|
//const char* msg4 = "no tag allowed in having clause";
|
|
|
|
|
const char* msg5 = "invalid expression in having clause";
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
const char* msg1 = "too many columns in group by clause";
|
|
|
|
|
const char* msg4 = "join query does not support group by";
|
|
|
|
|
const char* msg7 = "not support group by expression";
|
|
|
|
|
const char* msg8 = "not allowed column type for group by";
|
|
|
|
|
const char* msg9 = "tags not allowed for table query";
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
// todo : handle two tables situation
|
|
|
|
|
//STableMetaInfo* pTableMetaInfo = NULL;
|
|
|
|
|
|
|
|
|
|
if (pExpr == NULL || (*pExpr) == NULL) {
|
|
|
|
|
return TSDB_CODE_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pQueryInfo->groupbyExpr.numOfGroupCols <= 0) {
|
|
|
|
|
return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((*pExpr)->pLeft == NULL || (*pExpr)->pRight == NULL) {
|
|
|
|
|
return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg5);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pQueryInfo->colList == NULL) {
|
|
|
|
|
pQueryInfo->colList = taosArrayInit(4, POINTER_BYTES);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int32_t ret = 0;
|
|
|
|
|
|
|
|
|
|
if ((ret = getHavingExpr(pCmd, pQueryInfo, pExpr, TK_AND)) != TSDB_CODE_SUCCESS) {
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TSDB_CODE_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static SColumnFilterInfo* addColumnFilterInfo(SColumn* pColumn) {
|
|
|
|
|
if (pColumn == NULL) {
|
|
|
|
@ -3328,15 +3121,11 @@ static SColumnFilterInfo* addColumnFilterInfo(SColumn* pColumn) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int32_t doExtractColumnFilterInfo(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SColumnFilterInfo* pColumnFilter,
|
|
|
|
|
SColumnIndex* columnIndex, tSQLExpr* pExpr) {
|
|
|
|
|
int16_t colType, tSQLExpr* pExpr) {
|
|
|
|
|
const char* msg = "not supported filter condition";
|
|
|
|
|
|
|
|
|
|
tSQLExpr* pRight = pExpr->pRight;
|
|
|
|
|
STableMetaInfo* pTableMetaInfo = tscGetMetaInfo(pQueryInfo, columnIndex->tableIndex);
|
|
|
|
|
|
|
|
|
|
SSchema* pSchema = tscGetTableColumnSchema(pTableMetaInfo->pTableMeta, columnIndex->columnIndex);
|
|
|
|
|
|
|
|
|
|
int16_t colType = pSchema->type;
|
|
|
|
|
if (colType >= TSDB_DATA_TYPE_TINYINT && colType <= TSDB_DATA_TYPE_BIGINT) {
|
|
|
|
|
colType = TSDB_DATA_TYPE_BIGINT;
|
|
|
|
|
} else if (colType == TSDB_DATA_TYPE_FLOAT || colType == TSDB_DATA_TYPE_DOUBLE) {
|
|
|
|
@ -3649,7 +3438,10 @@ static int32_t extractColumnFilterInfo(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SC
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pColumn->colIndex = *pIndex;
|
|
|
|
|
return doExtractColumnFilterInfo(pCmd, pQueryInfo, pColFilter, pIndex, pExpr);
|
|
|
|
|
|
|
|
|
|
int16_t colType = pSchema->type;
|
|
|
|
|
|
|
|
|
|
return doExtractColumnFilterInfo(pCmd, pQueryInfo, pColFilter, colType, pExpr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void relToString(tSQLExpr* pExpr, char** str) {
|
|
|
|
@ -6901,6 +6693,259 @@ static int32_t checkQueryRangeForFill(SSqlCmd* pCmd, SQueryInfo* pQueryInfo) {
|
|
|
|
|
return TSDB_CODE_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int32_t tscInsertExprFields(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, tSQLExpr* pExpr, SInternalField** interField) {
|
|
|
|
|
tSqlExprItem item = {.pNode = pExpr, .aliasName = NULL, .distinct = false};
|
|
|
|
|
|
|
|
|
|
int32_t outputIndex = (int32_t)tscSqlExprNumOfExprs(pQueryInfo);
|
|
|
|
|
|
|
|
|
|
// ADD TRUE FOR TEST
|
|
|
|
|
if (addExprAndResultField(pCmd, pQueryInfo, outputIndex, &item, true) != TSDB_CODE_SUCCESS) {
|
|
|
|
|
return TSDB_CODE_TSC_INVALID_SQL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
++pQueryInfo->havingFieldNum;
|
|
|
|
|
|
|
|
|
|
int32_t slot = tscNumOfFields(pQueryInfo) - 1;
|
|
|
|
|
SInternalField* pInfo = tscFieldInfoGetInternalField(&pQueryInfo->fieldsInfo, slot);
|
|
|
|
|
pInfo->visible = false;
|
|
|
|
|
pInfo->pExpr = pExpr;
|
|
|
|
|
|
|
|
|
|
if (pInfo->pFieldFilters == NULL) {
|
|
|
|
|
SColumn* pFieldFilters = calloc(1, sizeof(SColumn));
|
|
|
|
|
if (pFieldFilters == NULL) {
|
|
|
|
|
return TSDB_CODE_TSC_OUT_OF_MEMORY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pInfo->pFieldFilters = pFieldFilters;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*interField = pInfo;
|
|
|
|
|
|
|
|
|
|
return TSDB_CODE_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int32_t tscGetExprFilters(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, tSQLExpr* pExpr, SInternalField** pField) {
|
|
|
|
|
SInternalField* pInfo = NULL;
|
|
|
|
|
|
|
|
|
|
for (int32_t i = pQueryInfo->havingFieldNum - 1; i >= 0; --i) {
|
|
|
|
|
pInfo = tscFieldInfoGetInternalField(&pQueryInfo->fieldsInfo, i);
|
|
|
|
|
|
|
|
|
|
if (0 == tSqlExprCompare(pInfo->pExpr, pExpr)) {
|
|
|
|
|
*pField = pInfo;
|
|
|
|
|
return TSDB_CODE_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int32_t ret = tscInsertExprFields(pCmd, pQueryInfo, pExpr, &pInfo);
|
|
|
|
|
if (ret) {
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*pField = pInfo;
|
|
|
|
|
|
|
|
|
|
return TSDB_CODE_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int32_t handleExprInHavingClause(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, tSQLExpr* pExpr, int32_t sqlOptr) {
|
|
|
|
|
const char* msg1 = "non binary column not support like operator";
|
|
|
|
|
const char* msg2 = "invalid operator for binary column in having clause";
|
|
|
|
|
const char* msg3 = "invalid operator for bool column in having clause";
|
|
|
|
|
|
|
|
|
|
SColumn* pColumn = NULL;
|
|
|
|
|
SColumnFilterInfo* pColFilter = NULL;
|
|
|
|
|
SInternalField* pInfo = NULL;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* in case of TK_AND filter condition, we first find the corresponding column and build the query condition together
|
|
|
|
|
* the already existed condition.
|
|
|
|
|
*/
|
|
|
|
|
if (sqlOptr == TK_AND) {
|
|
|
|
|
int32_t ret = tscGetExprFilters(pCmd, pQueryInfo, pExpr->pLeft, &pInfo);
|
|
|
|
|
if (ret) {
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pColumn = pInfo->pFieldFilters;
|
|
|
|
|
|
|
|
|
|
// this is a new filter condition on this column
|
|
|
|
|
if (pColumn->numOfFilters == 0) {
|
|
|
|
|
pColFilter = addColumnFilterInfo(pColumn);
|
|
|
|
|
} else { // update the existed column filter information, find the filter info here
|
|
|
|
|
pColFilter = &pColumn->filterInfo[0];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pColFilter == NULL) {
|
|
|
|
|
return TSDB_CODE_TSC_OUT_OF_MEMORY;
|
|
|
|
|
}
|
|
|
|
|
} else if (sqlOptr == TK_OR) {
|
|
|
|
|
int32_t ret = tscInsertExprFields(pCmd, pQueryInfo, pExpr->pLeft, &pInfo);
|
|
|
|
|
if (ret) {
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO fixme: failed to invalid the filter expression: "col1 = 1 OR col2 = 2"
|
|
|
|
|
pColFilter = addColumnFilterInfo(pColumn);
|
|
|
|
|
if (pColFilter == NULL) {
|
|
|
|
|
return TSDB_CODE_TSC_OUT_OF_MEMORY;
|
|
|
|
|
}
|
|
|
|
|
} else { // error;
|
|
|
|
|
return TSDB_CODE_TSC_INVALID_SQL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pColFilter->filterstr =
|
|
|
|
|
((pInfo->field.type == TSDB_DATA_TYPE_BINARY || pInfo->field.type == TSDB_DATA_TYPE_NCHAR) ? 1 : 0);
|
|
|
|
|
|
|
|
|
|
if (pColFilter->filterstr) {
|
|
|
|
|
if (pExpr->nSQLOptr != TK_EQ
|
|
|
|
|
&& pExpr->nSQLOptr != TK_NE
|
|
|
|
|
&& pExpr->nSQLOptr != TK_ISNULL
|
|
|
|
|
&& pExpr->nSQLOptr != TK_NOTNULL
|
|
|
|
|
&& pExpr->nSQLOptr != TK_LIKE
|
|
|
|
|
) {
|
|
|
|
|
return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg2);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (pExpr->nSQLOptr == TK_LIKE) {
|
|
|
|
|
return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pInfo->field.type == TSDB_DATA_TYPE_BOOL) {
|
|
|
|
|
if (pExpr->nSQLOptr != TK_EQ && pExpr->nSQLOptr != TK_NE) {
|
|
|
|
|
return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg3);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return doExtractColumnFilterInfo(pCmd, pQueryInfo, pColFilter, pInfo->field.type, pExpr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int32_t getHavingExpr(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, tSQLExpr* pExpr, int32_t parentOptr) {
|
|
|
|
|
if (pExpr == NULL) {
|
|
|
|
|
return TSDB_CODE_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char* msg1 = "invalid having clause";
|
|
|
|
|
|
|
|
|
|
tSQLExpr* pLeft = pExpr->pLeft;
|
|
|
|
|
tSQLExpr* pRight = pExpr->pRight;
|
|
|
|
|
|
|
|
|
|
if (pExpr->nSQLOptr == TK_AND || pExpr->nSQLOptr == TK_OR) {
|
|
|
|
|
int32_t ret = getHavingExpr(pCmd, pQueryInfo, pExpr->pLeft, pExpr->nSQLOptr);
|
|
|
|
|
if (ret != TSDB_CODE_SUCCESS) {
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return getHavingExpr(pCmd, pQueryInfo, pExpr->pRight, pExpr->nSQLOptr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((pLeft->nSQLOptr >= TK_COUNT && pLeft->nSQLOptr <= TK_AVG_IRATE) &&
|
|
|
|
|
(pRight->nSQLOptr >= TK_COUNT && pRight->nSQLOptr <= TK_AVG_IRATE)) {
|
|
|
|
|
return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pLeft->nSQLOptr >= TK_BOOL
|
|
|
|
|
&& pLeft->nSQLOptr <= TK_BINARY
|
|
|
|
|
&& pRight->nSQLOptr >= TK_BOOL
|
|
|
|
|
&& pRight->nSQLOptr <= TK_BINARY) {
|
|
|
|
|
return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
exchangeExpr(pExpr);
|
|
|
|
|
|
|
|
|
|
pLeft = pExpr->pLeft;
|
|
|
|
|
pRight = pExpr->pRight;
|
|
|
|
|
|
|
|
|
|
if (!(pLeft->nSQLOptr >= TK_COUNT && pLeft->nSQLOptr <= TK_AVG_IRATE)) {
|
|
|
|
|
return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(pRight->nSQLOptr >= TK_BOOL && pRight->nSQLOptr <= TK_BINARY)) {
|
|
|
|
|
return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pExpr->nSQLOptr >= TK_BITAND) {
|
|
|
|
|
return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pLeft->pParam == NULL || pLeft->pParam->nExpr < 1) {
|
|
|
|
|
return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int32_t i = 0; i < pLeft->pParam->nExpr; i++) {
|
|
|
|
|
tSqlExprItem* pParamElem = &(pLeft->pParam->a[i]);
|
|
|
|
|
if (pParamElem->pNode->nSQLOptr != TK_ALL && pParamElem->pNode->nSQLOptr != TK_ID) {
|
|
|
|
|
return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SColumnIndex index = COLUMN_INDEX_INITIALIZER;
|
|
|
|
|
if ((getColumnIndexByName(pCmd, &pParamElem->pNode->colInfo, pQueryInfo, &index) != TSDB_CODE_SUCCESS)) {
|
|
|
|
|
return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
STableMetaInfo* pTableMetaInfo = tscGetMetaInfo(pQueryInfo, index.tableIndex);
|
|
|
|
|
STableMeta* pTableMeta = pTableMetaInfo->pTableMeta;
|
|
|
|
|
|
|
|
|
|
if (index.columnIndex <= 0 ||
|
|
|
|
|
index.columnIndex >= tscGetNumOfColumns(pTableMeta)) {
|
|
|
|
|
return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return handleExprInHavingClause(pCmd, pQueryInfo, pExpr, parentOptr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int32_t parseHavingClause(SQueryInfo* pQueryInfo, tSQLExpr* pExpr, SSqlCmd* pCmd) {
|
|
|
|
|
const char* msg1 = "having only works with group by";
|
|
|
|
|
//const char* msg2 = "invalid column name in having clause";
|
|
|
|
|
//const char* msg3 = "columns from one table allowed as having columns";
|
|
|
|
|
//const char* msg4 = "no tag allowed in having clause";
|
|
|
|
|
const char* msg5 = "invalid expression in having clause";
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
const char* msg1 = "too many columns in group by clause";
|
|
|
|
|
const char* msg4 = "join query does not support group by";
|
|
|
|
|
const char* msg7 = "not support group by expression";
|
|
|
|
|
const char* msg8 = "not allowed column type for group by";
|
|
|
|
|
const char* msg9 = "tags not allowed for table query";
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
// todo : handle two tables situation
|
|
|
|
|
//STableMetaInfo* pTableMetaInfo = NULL;
|
|
|
|
|
|
|
|
|
|
if (pExpr == NULL) {
|
|
|
|
|
return TSDB_CODE_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pQueryInfo->groupbyExpr.numOfGroupCols <= 0) {
|
|
|
|
|
return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pExpr->pLeft == NULL || pExpr->pRight == NULL) {
|
|
|
|
|
return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg5);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pQueryInfo->colList == NULL) {
|
|
|
|
|
pQueryInfo->colList = taosArrayInit(4, POINTER_BYTES);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int32_t ret = 0;
|
|
|
|
|
|
|
|
|
|
if ((ret = getHavingExpr(pCmd, pQueryInfo, pExpr, TK_AND)) != TSDB_CODE_SUCCESS) {
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TSDB_CODE_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int32_t doCheckForQuery(SSqlObj* pSql, SQuerySQL* pQuerySql, int32_t index) {
|
|
|
|
|
assert(pQuerySql != NULL && (pQuerySql->from == NULL || taosArrayGetSize(pQuerySql->from) > 0));
|
|
|
|
|
|
|
|
|
@ -7028,7 +7073,7 @@ int32_t doCheckForQuery(SSqlObj* pSql, SQuerySQL* pQuerySql, int32_t index) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// parse the having clause in the first place
|
|
|
|
|
if (parseHavingClause(pQueryInfo, &pQuerySql->pHaving, pCmd) != TSDB_CODE_SUCCESS) {
|
|
|
|
|
if (parseHavingClause(pQueryInfo, pQuerySql->pHaving, pCmd) != TSDB_CODE_SUCCESS) {
|
|
|
|
|
return TSDB_CODE_TSC_INVALID_SQL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -7261,3 +7306,10 @@ bool hasNormalColumnFilter(SQueryInfo* pQueryInfo) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|