Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
taosdata
TDengine
提交
910b78f2
TDengine
项目概览
taosdata
/
TDengine
1 年多 前同步成功
通知
1185
Star
22016
Fork
4786
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
1
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
TDengine
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
1
Issue
1
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
未验证
提交
910b78f2
编写于
4月 08, 2021
作者:
H
haojun Liao
提交者:
GitHub
4月 08, 2021
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #5658 from taosdata/feature/TD-2577
[TD-2577]support having
上级
db481c59
855c5b0e
变更
15
展开全部
隐藏空白更改
内联
并排
Showing
15 changed file
with
5886 addition
and
995 deletion
+5886
-995
src/client/inc/tsclient.h
src/client/inc/tsclient.h
+28
-16
src/client/src/tscLocalMerge.c
src/client/src/tscLocalMerge.c
+87
-0
src/client/src/tscSQLParser.c
src/client/src/tscSQLParser.c
+341
-20
src/client/src/tscServer.c
src/client/src/tscServer.c
+36
-0
src/client/src/tscUtil.c
src/client/src/tscUtil.c
+24
-13
src/inc/taosmsg.h
src/inc/taosmsg.h
+28
-22
src/inc/ttokendef.h
src/inc/ttokendef.h
+5
-0
src/query/inc/qExecutor.h
src/query/inc/qExecutor.h
+8
-0
src/query/inc/qSqlparser.h
src/query/inc/qSqlparser.h
+7
-1
src/query/inc/sql.y
src/query/inc/sql.y
+3
-3
src/query/src/qExecutor.c
src/query/src/qExecutor.c
+276
-1
src/query/src/qSqlParser.c
src/query/src/qSqlParser.c
+76
-1
src/query/src/sql.c
src/query/src/sql.c
+1235
-918
tests/script/general/parser/having.sim
tests/script/general/parser/having.sim
+1841
-0
tests/script/general/parser/having_child.sim
tests/script/general/parser/having_child.sim
+1891
-0
未找到文件。
src/client/inc/tsclient.h
浏览文件 @
910b78f2
...
...
@@ -96,6 +96,25 @@ typedef struct STableMetaInfo {
SArray
*
tagColList
;
// SArray<SColumn*>, involved tag columns
}
STableMetaInfo
;
typedef
struct
SColumnIndex
{
int16_t
tableIndex
;
int16_t
columnIndex
;
}
SColumnIndex
;
typedef
struct
SFieldInfo
{
int16_t
numOfOutput
;
// number of column in result
TAOS_FIELD
*
final
;
SArray
*
internalField
;
// SArray<SInternalField>
}
SFieldInfo
;
typedef
struct
SColumn
{
SColumnIndex
colIndex
;
int32_t
numOfFilters
;
SColumnFilterInfo
*
filterInfo
;
}
SColumn
;
/* the structure for sql function in select clause */
typedef
struct
SSqlExpr
{
char
aliasName
[
TSDB_COL_NAME_LEN
];
// as aliasName
...
...
@@ -109,32 +128,24 @@ typedef struct SSqlExpr {
tVariant
param
[
3
];
// parameters are not more than 3
int32_t
offset
;
// sub result column value of arithmetic expression.
int16_t
resColId
;
// result column id
SColumn
*
pFilter
;
// expr filter
}
SSqlExpr
;
typedef
struct
SColumnIndex
{
int16_t
tableIndex
;
int16_t
columnIndex
;
}
SColumnIndex
;
typedef
struct
SExprFilter
{
tSqlExpr
*
pExpr
;
//used for having parse
SSqlExpr
*
pSqlExpr
;
SArray
*
fp
;
SColumn
*
pFilters
;
//having filter info
}
SExprFilter
;
typedef
struct
SInternalField
{
TAOS_FIELD
field
;
bool
visible
;
SExprInfo
*
pArithExprInfo
;
SSqlExpr
*
pSqlExpr
;
SExprFilter
*
pFieldFilters
;
}
SInternalField
;
typedef
struct
SFieldInfo
{
int16_t
numOfOutput
;
// number of column in result
TAOS_FIELD
*
final
;
SArray
*
internalField
;
// SArray<SInternalField>
}
SFieldInfo
;
typedef
struct
SColumn
{
SColumnIndex
colIndex
;
int32_t
numOfFilters
;
SColumnFilterInfo
*
filterInfo
;
}
SColumn
;
typedef
struct
SCond
{
uint64_t
uid
;
int32_t
len
;
// length of tag query condition data
...
...
@@ -243,6 +254,7 @@ typedef struct SQueryInfo {
int32_t
round
;
// 0/1/....
int32_t
bufLen
;
char
*
buf
;
int32_t
havingFieldNum
;
}
SQueryInfo
;
typedef
struct
{
...
...
src/client/src/tscLocalMerge.c
浏览文件 @
910b78f2
...
...
@@ -22,6 +22,7 @@
#include "tscUtil.h"
#include "tschemautil.h"
#include "tsclient.h"
#include "qUtil.h"
typedef
struct
SCompareParam
{
SLocalDataSource
**
pLocalData
;
...
...
@@ -1243,6 +1244,76 @@ static bool saveGroupResultInfo(SSqlObj *pSql) {
return
false
;
}
bool
doFilterFieldData
(
char
*
input
,
SExprFilter
*
pFieldFilters
,
int16_t
type
,
bool
*
notSkipped
)
{
bool
qualified
=
false
;
for
(
int32_t
k
=
0
;
k
<
pFieldFilters
->
pFilters
->
numOfFilters
;
++
k
)
{
__filter_func_t
fp
=
taosArrayGetP
(
pFieldFilters
->
fp
,
k
);
SColumnFilterElem
filterElem
=
{.
filterInfo
=
pFieldFilters
->
pFilters
->
filterInfo
[
k
]};
bool
isnull
=
isNull
(
input
,
type
);
if
(
isnull
)
{
if
(
fp
==
isNullOperator
)
{
qualified
=
true
;
break
;
}
else
{
continue
;
}
}
else
{
if
(
fp
==
notNullOperator
)
{
qualified
=
true
;
break
;
}
else
if
(
fp
==
isNullOperator
)
{
continue
;
}
}
if
(
fp
(
&
filterElem
,
input
,
input
,
type
))
{
qualified
=
true
;
break
;
}
}
*
notSkipped
=
qualified
;
return
TSDB_CODE_SUCCESS
;
}
int32_t
doHavingFilter
(
SQueryInfo
*
pQueryInfo
,
tFilePage
*
pOutput
,
bool
*
notSkipped
)
{
*
notSkipped
=
true
;
if
(
pQueryInfo
->
havingFieldNum
<=
0
)
{
return
TSDB_CODE_SUCCESS
;
}
//int32_t exprNum = (int32_t) tscSqlExprNumOfExprs(pQueryInfo);
size_t
numOfOutput
=
tscNumOfFields
(
pQueryInfo
);
for
(
int32_t
i
=
0
;
i
<
numOfOutput
;
++
i
)
{
SInternalField
*
pInterField
=
tscFieldInfoGetInternalField
(
&
pQueryInfo
->
fieldsInfo
,
i
);
SExprFilter
*
pFieldFilters
=
pInterField
->
pFieldFilters
;
if
(
pFieldFilters
==
NULL
)
{
continue
;
}
int32_t
type
=
pInterField
->
field
.
type
;
char
*
pInput
=
pOutput
->
data
+
pOutput
->
num
*
pFieldFilters
->
pSqlExpr
->
offset
;
doFilterFieldData
(
pInput
,
pFieldFilters
,
type
,
notSkipped
);
if
(
*
notSkipped
==
false
)
{
return
TSDB_CODE_SUCCESS
;
}
}
return
TSDB_CODE_SUCCESS
;
}
/**
*
* @param pSql
...
...
@@ -1283,6 +1354,22 @@ bool genFinalResults(SSqlObj *pSql, SLocalMerger *pLocalMerge, bool noMoreCurren
doArithmeticCalculate
(
pQueryInfo
,
pResBuf
,
pModel
->
rowSize
,
pLocalMerge
->
finalModel
->
rowSize
);
}
bool
notSkipped
=
true
;
doHavingFilter
(
pQueryInfo
,
pResBuf
,
&
notSkipped
);
if
(
!
notSkipped
)
{
pRes
->
numOfRows
=
0
;
pLocalMerge
->
discard
=
!
noMoreCurrentGroupRes
;
if
(
pLocalMerge
->
discard
)
{
SColumnModel
*
pInternModel
=
pLocalMerge
->
pDesc
->
pColumnModel
;
tColModelAppend
(
pInternModel
,
pLocalMerge
->
discardData
,
pLocalMerge
->
pTempBuffer
->
data
,
0
,
1
,
1
);
}
return
notSkipped
;
}
// no interval query, no fill operation
if
(
pQueryInfo
->
interval
.
interval
==
0
||
pQueryInfo
->
fillType
==
TSDB_FILL_NONE
)
{
genFinalResWithoutFill
(
pRes
,
pLocalMerge
,
pQueryInfo
);
...
...
src/client/src/tscSQLParser.c
浏览文件 @
910b78f2
...
...
@@ -34,6 +34,7 @@
#include "tstoken.h"
#include "tstrbuild.h"
#include "ttokendef.h"
#include "qUtil.h"
#define DEFAULT_PRIMARY_TIMESTAMP_COL_NAME "_c0"
...
...
@@ -1097,6 +1098,7 @@ static bool validateTableColumnInfo(SArray* pFieldList, SSqlCmd* pCmd) {
return
true
;
}
static
bool
validateTagParams
(
SArray
*
pTagsList
,
SArray
*
pFieldList
,
SSqlCmd
*
pCmd
)
{
assert
(
pTagsList
!=
NULL
);
...
...
@@ -1676,18 +1678,6 @@ int32_t parseSelectClause(SSqlCmd* pCmd, int32_t clauseIndex, SArray* pSelectLis
return
invalidSqlErrMsg
(
tscGetErrorMsgPayload
(
pCmd
),
msg2
);
}
/*
* transfer sql functions that need secondary merge into another format
* in dealing with super table queries such as: count/first/last
*/
if
(
isSTable
)
{
tscTansformFuncForSTableQuery
(
pQueryInfo
);
if
(
hasUnsupportFunctionsForSTableQuery
(
pCmd
,
pQueryInfo
))
{
return
TSDB_CODE_TSC_INVALID_SQL
;
}
}
return
TSDB_CODE_SUCCESS
;
}
...
...
@@ -3065,6 +3055,7 @@ int32_t parseGroupbyClause(SQueryInfo* pQueryInfo, SArray* pList, SSqlCmd* pCmd)
return
TSDB_CODE_SUCCESS
;
}
static
SColumnFilterInfo
*
addColumnFilterInfo
(
SColumn
*
pColumn
)
{
if
(
pColumn
==
NULL
)
{
return
NULL
;
...
...
@@ -3088,15 +3079,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
)
{
...
...
@@ -3301,7 +3288,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
int32_t
getTablenameCond
(
SSqlCmd
*
pCmd
,
SQueryInfo
*
pQueryInfo
,
tSqlExpr
*
pTableCond
,
SStringBuilder
*
sb
)
{
...
...
@@ -6030,7 +6020,7 @@ static int32_t doAddGroupbyColumnsOnDemand(SSqlCmd* pCmd, SQueryInfo* pQueryInfo
if
(
TSDB_COL_IS_TAG
(
pColIndex
->
flag
))
{
SColumnIndex
index
=
{.
tableIndex
=
pQueryInfo
->
groupbyExpr
.
tableIndex
,
.
columnIndex
=
colIndex
};
SSqlExpr
*
pExpr
=
tscSqlExpr
Append
(
pQueryInfo
,
TSDB_FUNC_TAG
,
&
index
,
type
,
bytes
,
getNewResColId
(
pQueryInfo
),
bytes
,
true
);
SSqlExpr
*
pExpr
=
tscSqlExpr
Insert
(
pQueryInfo
,
(
int32_t
)
size
-
pQueryInfo
->
havingFieldNum
,
TSDB_FUNC_TAG
,
&
index
,
type
,
bytes
,
getNewResColId
(
pQueryInfo
),
bytes
,
true
);
memset
(
pExpr
->
aliasName
,
0
,
sizeof
(
pExpr
->
aliasName
));
tstrncpy
(
pExpr
->
aliasName
,
name
,
sizeof
(
pExpr
->
aliasName
));
...
...
@@ -6039,7 +6029,7 @@ static int32_t doAddGroupbyColumnsOnDemand(SSqlCmd* pCmd, SQueryInfo* pQueryInfo
// NOTE: tag column does not add to source column list
SColumnList
ids
=
getColumnList
(
1
,
0
,
pColIndex
->
colIndex
);
insertResultField
(
pQueryInfo
,
(
int32_t
)
size
,
&
ids
,
bytes
,
(
int8_t
)
type
,
name
,
pExpr
);
insertResultField
(
pQueryInfo
,
(
int32_t
)
size
-
pQueryInfo
->
havingFieldNum
,
&
ids
,
bytes
,
(
int8_t
)
type
,
name
,
pExpr
);
}
else
{
// if this query is "group by" normal column, time window query is not allowed
if
(
isTimeWindowQuery
(
pQueryInfo
))
{
...
...
@@ -6769,6 +6759,313 @@ 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
;
size_t
n
=
tscSqlExprNumOfExprs
(
pQueryInfo
);
SSqlExpr
*
pSqlExpr
=
tscSqlExprGet
(
pQueryInfo
,
(
int32_t
)
n
-
1
);
int32_t
slot
=
tscNumOfFields
(
pQueryInfo
)
-
1
;
SInternalField
*
pInfo
=
tscFieldInfoGetInternalField
(
&
pQueryInfo
->
fieldsInfo
,
slot
);
pInfo
->
visible
=
false
;
if
(
pInfo
->
pFieldFilters
==
NULL
)
{
SExprFilter
*
pFieldFilters
=
calloc
(
1
,
sizeof
(
SExprFilter
));
if
(
pFieldFilters
==
NULL
)
{
return
TSDB_CODE_TSC_OUT_OF_MEMORY
;
}
SColumn
*
pFilters
=
calloc
(
1
,
sizeof
(
SColumn
));
if
(
pFilters
==
NULL
)
{
tfree
(
pFieldFilters
);
return
TSDB_CODE_TSC_OUT_OF_MEMORY
;
}
pFieldFilters
->
pFilters
=
pFilters
;
pFieldFilters
->
pSqlExpr
=
pSqlExpr
;
pSqlExpr
->
pFilter
=
pFilters
;
pInfo
->
pFieldFilters
=
pFieldFilters
;
}
pInfo
->
pFieldFilters
->
pExpr
=
pExpr
;
*
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
,
pQueryInfo
->
fieldsInfo
.
numOfOutput
-
1
-
i
);
if
(
pInfo
->
pFieldFilters
&&
0
==
tSqlExprCompare
(
pInfo
->
pFieldFilters
->
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
genExprFilter
(
SExprFilter
*
exprFilter
)
{
exprFilter
->
fp
=
taosArrayInit
(
4
,
sizeof
(
__filter_func_t
));
if
(
exprFilter
->
fp
==
NULL
)
{
return
TSDB_CODE_TSC_OUT_OF_MEMORY
;
}
for
(
int32_t
i
=
0
;
i
<
exprFilter
->
pFilters
->
numOfFilters
;
++
i
)
{
SColumnFilterInfo
*
filterInfo
=
&
exprFilter
->
pFilters
->
filterInfo
[
i
];
int32_t
lower
=
filterInfo
->
lowerRelOptr
;
int32_t
upper
=
filterInfo
->
upperRelOptr
;
if
(
lower
==
TSDB_RELATION_INVALID
&&
upper
==
TSDB_RELATION_INVALID
)
{
tscError
(
"invalid rel optr"
);
return
TSDB_CODE_TSC_APP_ERROR
;
}
__filter_func_t
ffp
=
getFilterOperator
(
lower
,
upper
);
if
(
ffp
==
NULL
)
{
tscError
(
"invalid filter info"
);
return
TSDB_CODE_TSC_APP_ERROR
;
}
taosArrayPush
(
exprFilter
->
fp
,
&
ffp
);
}
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
->
pFilters
;
// 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
=
tscGetExprFilters
(
pCmd
,
pQueryInfo
,
pExpr
->
pLeft
,
&
pInfo
);
if
(
ret
)
{
return
ret
;
}
pColumn
=
pInfo
->
pFieldFilters
->
pFilters
;
// 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
->
tokenId
!=
TK_EQ
&&
pExpr
->
tokenId
!=
TK_NE
&&
pExpr
->
tokenId
!=
TK_ISNULL
&&
pExpr
->
tokenId
!=
TK_NOTNULL
&&
pExpr
->
tokenId
!=
TK_LIKE
)
{
return
invalidSqlErrMsg
(
tscGetErrorMsgPayload
(
pCmd
),
msg2
);
}
}
else
{
if
(
pExpr
->
tokenId
==
TK_LIKE
)
{
return
invalidSqlErrMsg
(
tscGetErrorMsgPayload
(
pCmd
),
msg1
);
}
if
(
pInfo
->
field
.
type
==
TSDB_DATA_TYPE_BOOL
)
{
if
(
pExpr
->
tokenId
!=
TK_EQ
&&
pExpr
->
tokenId
!=
TK_NE
)
{
return
invalidSqlErrMsg
(
tscGetErrorMsgPayload
(
pCmd
),
msg3
);
}
}
}
int32_t
ret
=
doExtractColumnFilterInfo
(
pCmd
,
pQueryInfo
,
pColFilter
,
pInfo
->
field
.
type
,
pExpr
);
if
(
ret
)
{
return
ret
;
}
return
genExprFilter
(
pInfo
->
pFieldFilters
);
}
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
->
tokenId
==
TK_AND
||
pExpr
->
tokenId
==
TK_OR
)
{
int32_t
ret
=
getHavingExpr
(
pCmd
,
pQueryInfo
,
pExpr
->
pLeft
,
pExpr
->
tokenId
);
if
(
ret
!=
TSDB_CODE_SUCCESS
)
{
return
ret
;
}
return
getHavingExpr
(
pCmd
,
pQueryInfo
,
pExpr
->
pRight
,
pExpr
->
tokenId
);
}
if
(
pLeft
==
NULL
||
pRight
==
NULL
)
{
return
invalidSqlErrMsg
(
tscGetErrorMsgPayload
(
pCmd
),
msg1
);
}
if
(
pLeft
->
type
==
pRight
->
type
)
{
return
invalidSqlErrMsg
(
tscGetErrorMsgPayload
(
pCmd
),
msg1
);
}
exchangeExpr
(
pExpr
);
pLeft
=
pExpr
->
pLeft
;
pRight
=
pExpr
->
pRight
;
if
(
pLeft
->
type
!=
SQL_NODE_SQLFUNCTION
)
{
return
invalidSqlErrMsg
(
tscGetErrorMsgPayload
(
pCmd
),
msg1
);
}
if
(
pRight
->
type
!=
SQL_NODE_VALUE
)
{
return
invalidSqlErrMsg
(
tscGetErrorMsgPayload
(
pCmd
),
msg1
);
}
if
(
pExpr
->
tokenId
>=
TK_BITAND
)
{
return
invalidSqlErrMsg
(
tscGetErrorMsgPayload
(
pCmd
),
msg1
);
}
//if (pLeft->pParam == NULL || pLeft->pParam->nExpr < 1) {
// return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg1);
//}
if
(
pLeft
->
pParam
)
{
size_t
size
=
taosArrayGetSize
(
pLeft
->
pParam
);
for
(
int32_t
i
=
0
;
i
<
size
;
i
++
)
{
tSqlExprItem
*
pParamElem
=
taosArrayGet
(
pLeft
->
pParam
,
i
);
if
(
pParamElem
->
pNode
->
tokenId
!=
TK_ALL
&&
pParamElem
->
pNode
->
tokenId
!=
TK_ID
&&
pParamElem
->
pNode
->
tokenId
!=
TK_STRING
&&
pParamElem
->
pNode
->
tokenId
!=
TK_INTEGER
&&
pParamElem
->
pNode
->
tokenId
!=
TK_FLOAT
)
{
return
invalidSqlErrMsg
(
tscGetErrorMsgPayload
(
pCmd
),
msg1
);
}
if
(
pParamElem
->
pNode
->
tokenId
==
TK_ID
&&
(
pParamElem
->
pNode
->
colInfo
.
z
==
NULL
&&
pParamElem
->
pNode
->
colInfo
.
n
==
0
))
{
return
invalidSqlErrMsg
(
tscGetErrorMsgPayload
(
pCmd
),
msg1
);
}
if
(
pParamElem
->
pNode
->
tokenId
==
TK_ID
)
{
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
);
}
}
}
}
pLeft
->
functionId
=
isValidFunction
(
pLeft
->
operand
.
z
,
pLeft
->
operand
.
n
);
if
(
pLeft
->
functionId
<
0
)
{
return
invalidSqlErrMsg
(
tscGetErrorMsgPayload
(
pCmd
),
msg1
);
}
return
handleExprInHavingClause
(
pCmd
,
pQueryInfo
,
pExpr
,
parentOptr
);
}
int32_t
parseHavingClause
(
SQueryInfo
*
pQueryInfo
,
tSqlExpr
*
pExpr
,
SSqlCmd
*
pCmd
,
bool
isSTable
,
int32_t
joinQuery
,
int32_t
timeWindowQuery
)
{
const
char
*
msg1
=
"having only works with group by"
;
const
char
*
msg2
=
"functions or others can not be mixed up"
;
const
char
*
msg3
=
"invalid expression in having clause"
;
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
),
msg3
);
}
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
;
}
//REDO function check
if
(
!
functionCompatibleCheck
(
pQueryInfo
,
joinQuery
,
timeWindowQuery
))
{
return
invalidSqlErrMsg
(
tscGetErrorMsgPayload
(
pCmd
),
msg2
);
}
return
TSDB_CODE_SUCCESS
;
}
int32_t
doValidateSqlNode
(
SSqlObj
*
pSql
,
SQuerySqlNode
*
pQuerySqlNode
,
int32_t
index
)
{
assert
(
pQuerySqlNode
!=
NULL
&&
(
pQuerySqlNode
->
from
==
NULL
||
taosArrayGetSize
(
pQuerySqlNode
->
from
->
tableList
)
>
0
));
...
...
@@ -6934,6 +7231,23 @@ int32_t doValidateSqlNode(SSqlObj* pSql, SQuerySqlNode* pQuerySqlNode, int32_t i
}
}
// parse the having clause in the first place
if
(
parseHavingClause
(
pQueryInfo
,
pQuerySqlNode
->
pHaving
,
pCmd
,
isSTable
,
joinQuery
,
timeWindowQuery
)
!=
TSDB_CODE_SUCCESS
)
{
return
TSDB_CODE_TSC_INVALID_SQL
;
}
/*
* transfer sql functions that need secondary merge into another format
* in dealing with super table queries such as: count/first/last
*/
if
(
isSTable
)
{
tscTansformFuncForSTableQuery
(
pQueryInfo
);
if
(
hasUnsupportFunctionsForSTableQuery
(
pCmd
,
pQueryInfo
))
{
return
TSDB_CODE_TSC_INVALID_SQL
;
}
}
if
(
parseSessionClause
(
pCmd
,
pQueryInfo
,
pQuerySqlNode
)
!=
TSDB_CODE_SUCCESS
)
{
return
TSDB_CODE_TSC_INVALID_SQL
;
}
...
...
@@ -7125,3 +7439,10 @@ bool hasNormalColumnFilter(SQueryInfo* pQueryInfo) {
return
false
;
}
src/client/src/tscServer.c
浏览文件 @
910b78f2
...
...
@@ -862,8 +862,44 @@ int tscBuildQueryMsg(SSqlObj *pSql, SSqlInfo *pInfo) {
pSqlFuncExpr
->
functionId
=
htons
(
pExpr
->
functionId
);
pSqlFuncExpr
->
numOfParams
=
htons
(
pExpr
->
numOfParams
);
pSqlFuncExpr
->
resColId
=
htons
(
pExpr
->
resColId
);
if
(
pTableMeta
->
tableType
!=
TSDB_SUPER_TABLE
&&
pExpr
->
pFilter
&&
pExpr
->
pFilter
->
numOfFilters
>
0
)
{
pSqlFuncExpr
->
filterNum
=
htonl
(
pExpr
->
pFilter
->
numOfFilters
);
}
else
{
pSqlFuncExpr
->
filterNum
=
0
;
}
pMsg
+=
sizeof
(
SSqlFuncMsg
);
if
(
pSqlFuncExpr
->
filterNum
)
{
pMsg
+=
sizeof
(
SColumnFilterInfo
)
*
pExpr
->
pFilter
->
numOfFilters
;
// append the filter information after the basic column information
for
(
int32_t
f
=
0
;
f
<
pExpr
->
pFilter
->
numOfFilters
;
++
f
)
{
SColumnFilterInfo
*
pColFilter
=
&
pExpr
->
pFilter
->
filterInfo
[
f
];
SColumnFilterInfo
*
pFilterMsg
=
&
pSqlFuncExpr
->
filterInfo
[
f
];
pFilterMsg
->
filterstr
=
htons
(
pColFilter
->
filterstr
);
if
(
pColFilter
->
filterstr
)
{
pFilterMsg
->
len
=
htobe64
(
pColFilter
->
len
);
memcpy
(
pMsg
,
(
void
*
)
pColFilter
->
pz
,
(
size_t
)(
pColFilter
->
len
+
1
));
pMsg
+=
(
pColFilter
->
len
+
1
);
// append the additional filter binary info
}
else
{
pFilterMsg
->
lowerBndi
=
htobe64
(
pColFilter
->
lowerBndi
);
pFilterMsg
->
upperBndi
=
htobe64
(
pColFilter
->
upperBndi
);
}
pFilterMsg
->
lowerRelOptr
=
htons
(
pColFilter
->
lowerRelOptr
);
pFilterMsg
->
upperRelOptr
=
htons
(
pColFilter
->
upperRelOptr
);
if
(
pColFilter
->
lowerRelOptr
==
TSDB_RELATION_INVALID
&&
pColFilter
->
upperRelOptr
==
TSDB_RELATION_INVALID
)
{
tscError
(
"invalid filter info"
);
return
TSDB_CODE_TSC_INVALID_SQL
;
}
}
}
for
(
int32_t
j
=
0
;
j
<
pExpr
->
numOfParams
;
++
j
)
{
// todo add log
pSqlFuncExpr
->
arg
[
j
].
argType
=
htons
((
uint16_t
)
pExpr
->
param
[
j
].
nType
);
pSqlFuncExpr
->
arg
[
j
].
argBytes
=
htons
(
pExpr
->
param
[
j
].
nLen
);
...
...
src/client/src/tscUtil.c
浏览文件 @
910b78f2
...
...
@@ -1045,6 +1045,7 @@ SInternalField* tscFieldInfoAppend(SFieldInfo* pFieldInfo, TAOS_FIELD* pField) {
.
pSqlExpr
=
NULL
,
.
pArithExprInfo
=
NULL
,
.
visible
=
true
,
.
pFieldFilters
=
NULL
,
};
info
.
field
=
*
pField
;
...
...
@@ -1057,6 +1058,7 @@ SInternalField* tscFieldInfoInsert(SFieldInfo* pFieldInfo, int32_t index, TAOS_F
.
pSqlExpr
=
NULL
,
.
pArithExprInfo
=
NULL
,
.
visible
=
true
,
.
pFieldFilters
=
NULL
,
};
info
.
field
=
*
field
;
...
...
@@ -1130,6 +1132,22 @@ int32_t tscGetResRowLength(SArray* pExprList) {
return
size
;
}
static
void
destroyFilterInfo
(
SColumnFilterInfo
*
pFilterInfo
,
int32_t
numOfFilters
)
{
for
(
int32_t
i
=
0
;
i
<
numOfFilters
;
++
i
)
{
if
(
pFilterInfo
[
i
].
filterstr
)
{
tfree
(
pFilterInfo
[
i
].
pz
);
}
}
tfree
(
pFilterInfo
);
}
static
void
tscColumnDestroy
(
SColumn
*
pCol
)
{
destroyFilterInfo
(
pCol
->
filterInfo
,
pCol
->
numOfFilters
);
free
(
pCol
);
}
void
tscFieldInfoClear
(
SFieldInfo
*
pFieldInfo
)
{
if
(
pFieldInfo
==
NULL
)
{
return
;
...
...
@@ -1150,6 +1168,11 @@ void tscFieldInfoClear(SFieldInfo* pFieldInfo) {
tfree
(
pInfo
->
pArithExprInfo
);
}
if
(
pInfo
->
pFieldFilters
!=
NULL
)
{
tscColumnDestroy
(
pInfo
->
pFieldFilters
->
pFilters
);
tfree
(
pInfo
->
pFieldFilters
);
}
}
taosArrayDestroy
(
pFieldInfo
->
internalField
);
...
...
@@ -1411,15 +1434,7 @@ SColumn* tscColumnListInsert(SArray* pColumnList, SColumnIndex* pColIndex) {
return
taosArrayGetP
(
pColumnList
,
i
);
}
static
void
destroyFilterInfo
(
SColumnFilterInfo
*
pFilterInfo
,
int32_t
numOfFilters
)
{
for
(
int32_t
i
=
0
;
i
<
numOfFilters
;
++
i
)
{
if
(
pFilterInfo
[
i
].
filterstr
)
{
tfree
(
pFilterInfo
[
i
].
pz
);
}
}
tfree
(
pFilterInfo
);
}
SColumn
*
tscColumnClone
(
const
SColumn
*
src
)
{
assert
(
src
!=
NULL
);
...
...
@@ -1436,10 +1451,6 @@ SColumn* tscColumnClone(const SColumn* src) {
return
dst
;
}
static
void
tscColumnDestroy
(
SColumn
*
pCol
)
{
destroyFilterInfo
(
pCol
->
filterInfo
,
pCol
->
numOfFilters
);
free
(
pCol
);
}
void
tscColumnListCopy
(
SArray
*
dst
,
const
SArray
*
src
,
int16_t
tableIndex
)
{
assert
(
src
!=
NULL
&&
dst
!=
NULL
);
...
...
src/inc/taosmsg.h
浏览文件 @
910b78f2
...
...
@@ -399,6 +399,28 @@ typedef struct SColIndex {
char
name
[
TSDB_COL_NAME_LEN
];
// TODO remove it
}
SColIndex
;
typedef
struct
SColumnFilterInfo
{
int16_t
lowerRelOptr
;
int16_t
upperRelOptr
;
int16_t
filterstr
;
// denote if current column is char(binary/nchar)
union
{
struct
{
int64_t
lowerBndi
;
int64_t
upperBndi
;
};
struct
{
double
lowerBndd
;
double
upperBndd
;
};
struct
{
int64_t
pz
;
int64_t
len
;
};
};
}
SColumnFilterInfo
;
/* sql function msg, to describe the message to vnode about sql function
* operations in select clause */
typedef
struct
SSqlFuncMsg
{
...
...
@@ -419,38 +441,22 @@ typedef struct SSqlFuncMsg {
char
*
pz
;
}
argValue
;
}
arg
[
3
];
int32_t
filterNum
;
SColumnFilterInfo
filterInfo
[];
}
SSqlFuncMsg
;
typedef
struct
SExprInfo
{
S
SqlFuncMsg
base
;
S
ColumnFilterInfo
*
pFilter
;
struct
tExprNode
*
pExpr
;
int16_t
bytes
;
int16_t
type
;
int32_t
interBytes
;
int64_t
uid
;
SSqlFuncMsg
base
;
}
SExprInfo
;
typedef
struct
SColumnFilterInfo
{
int16_t
lowerRelOptr
;
int16_t
upperRelOptr
;
int16_t
filterstr
;
// denote if current column is char(binary/nchar)
union
{
struct
{
int64_t
lowerBndi
;
int64_t
upperBndi
;
};
struct
{
double
lowerBndd
;
double
upperBndd
;
};
struct
{
int64_t
pz
;
int64_t
len
;
};
};
}
SColumnFilterInfo
;
/*
* for client side struct, we only need the column id, type, bytes are not necessary
* But for data in vnode side, we need all the following information.
...
...
src/inc/ttokendef.h
浏览文件 @
910b78f2
...
...
@@ -205,6 +205,11 @@
#define TK_VALUES 186
#define TK_SPACE 300
#define TK_COMMENT 301
#define TK_ILLEGAL 302
...
...
src/query/inc/qExecutor.h
浏览文件 @
910b78f2
...
...
@@ -190,6 +190,8 @@ typedef struct SQuery {
bool
stabledev
;
// super table stddev query
int32_t
interBufSize
;
// intermediate buffer sizse
int32_t
havingNum
;
// having expr number
SOrderVal
order
;
int16_t
numOfCols
;
int16_t
numOfTags
;
...
...
@@ -285,6 +287,7 @@ enum OPERATOR_TYPE_E {
OP_Fill
=
13
,
OP_MultiTableAggregate
=
14
,
OP_MultiTableTimeInterval
=
15
,
OP_Having
=
16
,
};
typedef
struct
SOperatorInfo
{
...
...
@@ -402,6 +405,11 @@ typedef struct SOffsetOperatorInfo {
int64_t
offset
;
}
SOffsetOperatorInfo
;
typedef
struct
SHavingOperatorInfo
{
SArray
*
fp
;
}
SHavingOperatorInfo
;
typedef
struct
SFillOperatorInfo
{
SFillInfo
*
pFillInfo
;
SSDataBlock
*
pRes
;
...
...
src/query/inc/qSqlparser.h
浏览文件 @
910b78f2
...
...
@@ -98,6 +98,7 @@ typedef struct SQuerySqlNode {
SLimitVal
limit
;
// limit offset [optional]
SLimitVal
slimit
;
// group limit offset [optional]
SStrToken
sqlstr
;
// sql string in select clause
struct
tSqlExpr
*
pHaving
;
// having clause [optional]
}
SQuerySqlNode
;
typedef
struct
STableNamePair
{
...
...
@@ -253,6 +254,11 @@ SArray *tVariantListAppend(SArray *pList, tVariant *pVar, uint8_t sortOrder);
SArray
*
tVariantListInsert
(
SArray
*
pList
,
tVariant
*
pVar
,
uint8_t
sortOrder
,
int32_t
index
);
SArray
*
tVariantListAppendToken
(
SArray
*
pList
,
SStrToken
*
pAliasToken
,
uint8_t
sortOrder
);
tSqlExpr
*
tSqlExprCreate
(
tSqlExpr
*
pLeft
,
tSqlExpr
*
pRight
,
int32_t
optrType
);
int32_t
tSqlExprCompare
(
tSqlExpr
*
left
,
tSqlExpr
*
right
);
tSqlExpr
*
tSqlExprClone
(
tSqlExpr
*
pSrc
);
SFromInfo
*
setTableNameList
(
SFromInfo
*
pFromInfo
,
SStrToken
*
pName
,
SStrToken
*
pAlias
);
SFromInfo
*
setSubquery
(
SFromInfo
*
pFromInfo
,
SQuerySqlNode
*
pSqlNode
);
void
*
destroyFromInfo
(
SFromInfo
*
pFromInfo
);
...
...
@@ -272,7 +278,7 @@ void tSqlExprListDestroy(SArray *pList);
SQuerySqlNode
*
tSetQuerySqlNode
(
SStrToken
*
pSelectToken
,
SArray
*
pSelectList
,
SFromInfo
*
pFrom
,
tSqlExpr
*
pWhere
,
SArray
*
pGroupby
,
SArray
*
pSortOrder
,
SIntervalVal
*
pInterval
,
SSessionWindowVal
*
ps
,
SStrToken
*
pSliding
,
SArray
*
pFill
,
SLimitVal
*
pLimit
,
SLimitVal
*
pgLimit
);
SStrToken
*
pSliding
,
SArray
*
pFill
,
SLimitVal
*
pLimit
,
SLimitVal
*
pgLimit
,
tSqlExpr
*
pHaving
);
SCreateTableSql
*
tSetCreateTableInfo
(
SArray
*
pCols
,
SArray
*
pTags
,
SQuerySqlNode
*
pSelect
,
int32_t
type
);
...
...
src/query/inc/sql.y
浏览文件 @
910b78f2
...
...
@@ -453,7 +453,7 @@ tagitem(A) ::= PLUS(X) FLOAT(Y). {
%type select {SQuerySqlNode*}
%destructor select {destroyQuerySqlNode($$);}
select(A) ::= SELECT(T) selcollist(W) from(X) where_opt(Y) interval_opt(K) session_option(H) fill_opt(F) sliding_opt(S) groupby_opt(P) orderby_opt(Z) having_opt(N) slimit_opt(G) limit_opt(L). {
A = tSetQuerySqlNode(&T, W, X, Y, P, Z, &K, &H, &S, F, &L, &G);
A = tSetQuerySqlNode(&T, W, X, Y, P, Z, &K, &H, &S, F, &L, &G
, N
);
}
select(A) ::= LP select(B) RP. {A = B;}
...
...
@@ -471,7 +471,7 @@ cmd ::= union(X). { setSqlInfo(pInfo, X, NULL, TSDB_SQL_SELECT); }
// select client_version()
// select server_state()
select(A) ::= SELECT(T) selcollist(W). {
A = tSetQuerySqlNode(&T, W, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
A = tSetQuerySqlNode(&T, W, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
, NULL
);
}
// selcollist is a list of expressions that are to become the return
...
...
@@ -842,4 +842,4 @@ cmd ::= KILL QUERY INTEGER(X) COLON(Z) INTEGER(Y). {X.n += (Z.n + Y.n); s
%fallback ID ABORT AFTER ASC ATTACH BEFORE BEGIN CASCADE CLUSTER CONFLICT COPY DATABASE DEFERRED
DELIMITERS DESC DETACH EACH END EXPLAIN FAIL FOR GLOB IGNORE IMMEDIATE INITIALLY INSTEAD
LIKE MATCH KEY OF OFFSET RAISE REPLACE RESTRICT ROW STATEMENT TRIGGER VIEW ALL
NOW IPTOKEN SEMI NONE PREV LINEAR IMPORT TBNAME JOIN STABLE NULL INSERT INTO VALUES.
\ No newline at end of file
NOW IPTOKEN SEMI NONE PREV LINEAR IMPORT TBNAME JOIN STABLE NULL INSERT INTO VALUES.
src/query/src/qExecutor.c
浏览文件 @
910b78f2
...
...
@@ -181,6 +181,7 @@ static SOperatorInfo* createMultiTableAggOperatorInfo(SQueryRuntimeEnv* pRuntime
static
SOperatorInfo
*
createMultiTableTimeIntervalOperatorInfo
(
SQueryRuntimeEnv
*
pRuntimeEnv
,
SOperatorInfo
*
upstream
,
SExprInfo
*
pExpr
,
int32_t
numOfOutput
);
static
SOperatorInfo
*
createTagScanOperatorInfo
(
SQueryRuntimeEnv
*
pRuntimeEnv
,
SExprInfo
*
pExpr
,
int32_t
numOfOutput
);
static
SOperatorInfo
*
createTableBlockInfoScanOperator
(
void
*
pTsdbQueryHandle
,
SQueryRuntimeEnv
*
pRuntimeEnv
);
static
SOperatorInfo
*
createHavingOperatorInfo
(
SQueryRuntimeEnv
*
pRuntimeEnv
,
SOperatorInfo
*
upstream
,
SExprInfo
*
pExpr
,
int32_t
numOfOutput
);
static
void
destroyBasicOperatorInfo
(
void
*
param
,
int32_t
numOfOutput
);
static
void
destroySFillOperatorInfo
(
void
*
param
,
int32_t
numOfOutput
);
...
...
@@ -1819,6 +1820,10 @@ static int32_t setupQueryRuntimeEnv(SQueryRuntimeEnv *pRuntimeEnv, int32_t numOf
}
}
if
(
pQuery
->
havingNum
>
0
)
{
pRuntimeEnv
->
proot
=
createHavingOperatorInfo
(
pRuntimeEnv
,
pRuntimeEnv
->
proot
,
pQuery
->
pExpr1
,
pQuery
->
numOfOutput
);
}
if
(
pQuery
->
limit
.
offset
>
0
)
{
pRuntimeEnv
->
proot
=
createOffsetOperatorInfo
(
pRuntimeEnv
,
pRuntimeEnv
->
proot
);
}
...
...
@@ -4669,6 +4674,111 @@ static SSDataBlock* doOffset(void* param) {
}
}
bool
doFilterData
(
SColumnInfoData
*
p
,
int32_t
rid
,
SColumnFilterElem
*
filterElem
,
__filter_func_t
fp
)
{
char
*
input
=
p
->
pData
+
p
->
info
.
bytes
*
rid
;
bool
isnull
=
isNull
(
input
,
p
->
info
.
type
);
if
(
isnull
)
{
return
(
fp
==
isNullOperator
)
?
true
:
false
;
}
else
{
if
(
fp
==
notNullOperator
)
{
return
true
;
}
else
if
(
fp
==
isNullOperator
)
{
return
false
;
}
}
if
(
fp
(
filterElem
,
input
,
input
,
p
->
info
.
type
))
{
return
true
;
}
return
false
;
}
void
doHavingImpl
(
SOperatorInfo
*
pOperator
,
SSDataBlock
*
pBlock
)
{
SHavingOperatorInfo
*
pInfo
=
pOperator
->
info
;
int32_t
f
=
0
;
int32_t
allQualified
=
1
;
int32_t
exprQualified
=
0
;
for
(
int32_t
r
=
0
;
r
<
pBlock
->
info
.
rows
;
++
r
)
{
allQualified
=
1
;
for
(
int32_t
i
=
0
;
i
<
pOperator
->
numOfOutput
;
++
i
)
{
SExprInfo
*
pExprInfo
=
&
(
pOperator
->
pExpr
[
i
]);
if
(
pExprInfo
->
pFilter
==
NULL
)
{
continue
;
}
SArray
*
es
=
taosArrayGetP
(
pInfo
->
fp
,
i
);
assert
(
es
);
size_t
fpNum
=
taosArrayGetSize
(
es
);
exprQualified
=
0
;
for
(
int32_t
m
=
0
;
m
<
fpNum
;
++
m
)
{
__filter_func_t
fp
=
taosArrayGetP
(
es
,
m
);
assert
(
fp
);
//SColIndex* colIdx = &pExprInfo->base.colInfo;
SColumnInfoData
*
p
=
taosArrayGet
(
pBlock
->
pDataBlock
,
i
);
SColumnFilterElem
filterElem
=
{.
filterInfo
=
pExprInfo
->
pFilter
[
m
]};
if
(
doFilterData
(
p
,
r
,
&
filterElem
,
fp
))
{
exprQualified
=
1
;
break
;
}
}
if
(
exprQualified
==
0
)
{
allQualified
=
0
;
break
;
}
}
if
(
allQualified
==
0
)
{
continue
;
}
for
(
int32_t
i
=
0
;
i
<
pBlock
->
info
.
numOfCols
;
++
i
)
{
SColumnInfoData
*
pColInfoData
=
taosArrayGet
(
pBlock
->
pDataBlock
,
i
);
int16_t
bytes
=
pColInfoData
->
info
.
bytes
;
memmove
(
pColInfoData
->
pData
+
f
*
bytes
,
pColInfoData
->
pData
+
bytes
*
r
,
bytes
);
}
++
f
;
}
pBlock
->
info
.
rows
=
f
;
}
static
SSDataBlock
*
doHaving
(
void
*
param
)
{
SOperatorInfo
*
pOperator
=
(
SOperatorInfo
*
)
param
;
if
(
pOperator
->
status
==
OP_EXEC_DONE
)
{
return
NULL
;
}
SQueryRuntimeEnv
*
pRuntimeEnv
=
pOperator
->
pRuntimeEnv
;
while
(
1
)
{
SSDataBlock
*
pBlock
=
pOperator
->
upstream
->
exec
(
pOperator
->
upstream
);
if
(
pBlock
==
NULL
)
{
setQueryStatus
(
pRuntimeEnv
,
QUERY_COMPLETED
);
pOperator
->
status
=
OP_EXEC_DONE
;
return
NULL
;
}
doHavingImpl
(
pOperator
,
pBlock
);
return
pBlock
;
}
}
static
SSDataBlock
*
doIntervalAgg
(
void
*
param
)
{
SOperatorInfo
*
pOperator
=
(
SOperatorInfo
*
)
param
;
if
(
pOperator
->
status
==
OP_EXEC_DONE
)
{
...
...
@@ -5019,6 +5129,13 @@ static void destroyTagScanOperatorInfo(void* param, int32_t numOfOutput) {
pInfo
->
pRes
=
destroyOutputBuf
(
pInfo
->
pRes
);
}
static
void
destroyHavingOperatorInfo
(
void
*
param
,
int32_t
numOfOutput
)
{
SHavingOperatorInfo
*
pInfo
=
(
SHavingOperatorInfo
*
)
param
;
if
(
pInfo
->
fp
)
{
taosArrayDestroy
(
pInfo
->
fp
);
}
}
SOperatorInfo
*
createMultiTableAggOperatorInfo
(
SQueryRuntimeEnv
*
pRuntimeEnv
,
SOperatorInfo
*
upstream
,
SExprInfo
*
pExpr
,
int32_t
numOfOutput
)
{
SAggOperatorInfo
*
pInfo
=
calloc
(
1
,
sizeof
(
SAggOperatorInfo
));
...
...
@@ -5075,6 +5192,83 @@ SOperatorInfo* createArithOperatorInfo(SQueryRuntimeEnv* pRuntimeEnv, SOperatorI
return
pOperator
;
}
int32_t
initFilterFp
(
SExprInfo
*
pExpr
,
int32_t
numOfOutput
,
SArray
**
fps
)
{
__filter_func_t
fp
=
NULL
;
*
fps
=
taosArrayInit
(
numOfOutput
,
sizeof
(
SArray
*
));
if
(
*
fps
==
NULL
)
{
return
TSDB_CODE_TSC_OUT_OF_MEMORY
;
}
for
(
int32_t
i
=
0
;
i
<
numOfOutput
;
++
i
)
{
SExprInfo
*
pExprInfo
=
&
(
pExpr
[
i
]);
SColIndex
*
colIdx
=
&
pExprInfo
->
base
.
colInfo
;
if
(
pExprInfo
->
pFilter
==
NULL
||
!
TSDB_COL_IS_NORMAL_COL
(
colIdx
->
flag
))
{
taosArrayPush
(
*
fps
,
&
fp
);
continue
;
}
int32_t
filterNum
=
pExprInfo
->
base
.
filterNum
;
SColumnFilterInfo
*
filterInfo
=
pExprInfo
->
pFilter
;
SArray
*
es
=
taosArrayInit
(
filterNum
,
sizeof
(
__filter_func_t
));
for
(
int32_t
j
=
0
;
j
<
filterNum
;
++
j
)
{
int32_t
lower
=
filterInfo
->
lowerRelOptr
;
int32_t
upper
=
filterInfo
->
upperRelOptr
;
if
(
lower
==
TSDB_RELATION_INVALID
&&
upper
==
TSDB_RELATION_INVALID
)
{
qError
(
"invalid rel optr"
);
taosArrayDestroy
(
es
);
return
TSDB_CODE_QRY_APP_ERROR
;
}
__filter_func_t
ffp
=
getFilterOperator
(
lower
,
upper
);
if
(
ffp
==
NULL
)
{
qError
(
"invalid filter info"
);
taosArrayDestroy
(
es
);
return
TSDB_CODE_QRY_APP_ERROR
;
}
taosArrayPush
(
es
,
&
ffp
);
filterInfo
+=
1
;
}
taosArrayPush
(
*
fps
,
&
es
);
}
return
TSDB_CODE_SUCCESS
;
}
SOperatorInfo
*
createHavingOperatorInfo
(
SQueryRuntimeEnv
*
pRuntimeEnv
,
SOperatorInfo
*
upstream
,
SExprInfo
*
pExpr
,
int32_t
numOfOutput
)
{
SHavingOperatorInfo
*
pInfo
=
calloc
(
1
,
sizeof
(
SHavingOperatorInfo
));
initFilterFp
(
pExpr
,
numOfOutput
,
&
pInfo
->
fp
);
assert
(
pInfo
->
fp
);
SOperatorInfo
*
pOperator
=
calloc
(
1
,
sizeof
(
SOperatorInfo
));
pOperator
->
name
=
"HavingOperator"
;
pOperator
->
operatorType
=
OP_Having
;
pOperator
->
blockingOptr
=
false
;
pOperator
->
status
=
OP_IN_EXECUTING
;
pOperator
->
numOfOutput
=
numOfOutput
;
pOperator
->
pExpr
=
pExpr
;
pOperator
->
upstream
=
upstream
;
pOperator
->
exec
=
doHaving
;
pOperator
->
info
=
pInfo
;
pOperator
->
pRuntimeEnv
=
pRuntimeEnv
;
pOperator
->
cleanup
=
destroyHavingOperatorInfo
;
return
pOperator
;
}
SOperatorInfo
*
createLimitOperatorInfo
(
SQueryRuntimeEnv
*
pRuntimeEnv
,
SOperatorInfo
*
upstream
)
{
SLimitOperatorInfo
*
pInfo
=
calloc
(
1
,
sizeof
(
SLimitOperatorInfo
));
pInfo
->
limit
=
pRuntimeEnv
->
pQuery
->
limit
.
limit
;
...
...
@@ -5646,9 +5840,35 @@ int32_t convertQueryMsg(SQueryTableMsg *pQueryMsg, SQueryParam* param) {
pExprMsg
->
functionId
=
htons
(
pExprMsg
->
functionId
);
pExprMsg
->
numOfParams
=
htons
(
pExprMsg
->
numOfParams
);
pExprMsg
->
resColId
=
htons
(
pExprMsg
->
resColId
);
pExprMsg
->
filterNum
=
htonl
(
pExprMsg
->
filterNum
);
pMsg
+=
sizeof
(
SSqlFuncMsg
);
SColumnFilterInfo
*
pExprFilterInfo
=
pExprMsg
->
filterInfo
;
pMsg
+=
sizeof
(
SColumnFilterInfo
)
*
pExprMsg
->
filterNum
;
for
(
int32_t
f
=
0
;
f
<
pExprMsg
->
filterNum
;
++
f
)
{
SColumnFilterInfo
*
pFilterMsg
=
(
SColumnFilterInfo
*
)
pExprFilterInfo
;
pFilterMsg
->
filterstr
=
htons
(
pFilterMsg
->
filterstr
);
if
(
pFilterMsg
->
filterstr
)
{
pFilterMsg
->
len
=
htobe64
(
pFilterMsg
->
len
);
pFilterMsg
->
pz
=
(
int64_t
)
pMsg
;
pMsg
+=
(
pFilterMsg
->
len
+
1
);
}
else
{
pFilterMsg
->
lowerBndi
=
htobe64
(
pFilterMsg
->
lowerBndi
);
pFilterMsg
->
upperBndi
=
htobe64
(
pFilterMsg
->
upperBndi
);
}
pFilterMsg
->
lowerRelOptr
=
htons
(
pFilterMsg
->
lowerRelOptr
);
pFilterMsg
->
upperRelOptr
=
htons
(
pFilterMsg
->
upperRelOptr
);
pExprFilterInfo
++
;
}
for
(
int32_t
j
=
0
;
j
<
pExprMsg
->
numOfParams
;
++
j
)
{
pExprMsg
->
arg
[
j
].
argType
=
htons
(
pExprMsg
->
arg
[
j
].
argType
);
pExprMsg
->
arg
[
j
].
argBytes
=
htons
(
pExprMsg
->
arg
[
j
].
argBytes
);
...
...
@@ -5833,6 +6053,42 @@ _cleanup:
return
code
;
}
int32_t
cloneExprFilterInfo
(
SColumnFilterInfo
**
dst
,
SColumnFilterInfo
*
src
,
int32_t
filterNum
)
{
if
(
filterNum
<=
0
)
{
return
TSDB_CODE_SUCCESS
;
}
*
dst
=
calloc
(
filterNum
,
sizeof
(
*
src
));
if
(
*
dst
==
NULL
)
{
return
TSDB_CODE_QRY_OUT_OF_MEMORY
;
}
memcpy
(
*
dst
,
src
,
sizeof
(
*
src
)
*
filterNum
);
for
(
int32_t
i
=
0
;
i
<
filterNum
;
i
++
)
{
if
((
*
dst
)[
i
].
filterstr
&&
dst
[
i
]
->
len
>
0
)
{
void
*
pz
=
calloc
(
1
,
(
size_t
)(
*
dst
)[
i
].
len
+
1
);
if
(
pz
==
NULL
)
{
if
(
i
==
0
)
{
free
(
*
dst
);
}
else
{
freeColumnFilterInfo
(
*
dst
,
i
);
}
return
TSDB_CODE_QRY_OUT_OF_MEMORY
;
}
memcpy
(
pz
,
(
void
*
)
src
->
pz
,
(
size_t
)
src
->
len
+
1
);
(
*
dst
)[
i
].
pz
=
(
int64_t
)
pz
;
}
}
return
TSDB_CODE_SUCCESS
;
}
static
int32_t
buildArithmeticExprFromMsg
(
SExprInfo
*
pArithExprInfo
,
SQueryTableMsg
*
pQueryMsg
)
{
qDebug
(
"qmsg:%p create arithmetic expr from binary"
,
pQueryMsg
);
...
...
@@ -5946,6 +6202,13 @@ int32_t createQueryFuncExprFromMsg(SQueryTableMsg* pQueryMsg, int32_t numOfOutpu
type
=
s
->
type
;
bytes
=
s
->
bytes
;
}
if
(
pExprs
[
i
].
base
.
filterNum
>
0
)
{
int32_t
ret
=
cloneExprFilterInfo
(
&
pExprs
[
i
].
pFilter
,
pExprMsg
[
i
]
->
filterInfo
,
pExprMsg
[
i
]
->
filterNum
);
if
(
ret
)
{
return
ret
;
}
}
}
int32_t
param
=
(
int32_t
)
pExprs
[
i
].
base
.
arg
[
0
].
argValue
.
i64
;
...
...
@@ -6235,6 +6498,10 @@ SQInfo* createQInfoImpl(SQueryTableMsg* pQueryMsg, SSqlGroupbyExpr* pGroupbyExpr
if
(
TSDB_COL_IS_TAG
(
pExprs
[
col
].
base
.
colInfo
.
flag
))
{
pQuery
->
tagLen
+=
pExprs
[
col
].
bytes
;
}
if
(
pExprs
[
col
].
pFilter
)
{
++
pQuery
->
havingNum
;
}
}
doUpdateExprColumnIndex
(
pQuery
);
...
...
@@ -6338,6 +6605,10 @@ _cleanup_qinfo:
tExprTreeDestroy
(
pExprInfo
->
pExpr
,
NULL
);
pExprInfo
->
pExpr
=
NULL
;
}
if
(
pExprInfo
->
pFilter
)
{
freeColumnFilterInfo
(
pExprInfo
->
pFilter
,
pExprInfo
->
base
.
filterNum
);
}
}
tfree
(
pExprs
);
...
...
@@ -6422,7 +6693,7 @@ void freeColumnFilterInfo(SColumnFilterInfo* pFilter, int32_t numOfFilters) {
}
for
(
int32_t
i
=
0
;
i
<
numOfFilters
;
i
++
)
{
if
(
pFilter
[
i
].
filterstr
)
{
if
(
pFilter
[
i
].
filterstr
&&
pFilter
[
i
].
pz
)
{
free
((
void
*
)(
pFilter
[
i
].
pz
));
}
}
...
...
@@ -6464,6 +6735,10 @@ static void* destroyQueryFuncExpr(SExprInfo* pExprInfo, int32_t numOfExpr) {
if
(
pExprInfo
[
i
].
pExpr
!=
NULL
)
{
tExprTreeDestroy
(
pExprInfo
[
i
].
pExpr
,
NULL
);
}
if
(
pExprInfo
[
i
].
pFilter
)
{
freeColumnFilterInfo
(
pExprInfo
[
i
].
pFilter
,
pExprInfo
[
i
].
base
.
filterNum
);
}
}
tfree
(
pExprInfo
);
...
...
src/query/src/qSqlParser.c
浏览文件 @
910b78f2
...
...
@@ -310,6 +310,77 @@ tSqlExpr *tSqlExprCreate(tSqlExpr *pLeft, tSqlExpr *pRight, int32_t optrType) {
return
pExpr
;
}
static
FORCE_INLINE
int32_t
tStrTokenCompare
(
SStrToken
*
left
,
SStrToken
*
right
)
{
return
(
left
->
type
==
right
->
type
&&
left
->
n
==
right
->
n
&&
strncasecmp
(
left
->
z
,
right
->
z
,
left
->
n
)
==
0
)
?
0
:
1
;
}
int32_t
tSqlExprCompare
(
tSqlExpr
*
left
,
tSqlExpr
*
right
)
{
if
((
left
==
NULL
&&
right
)
||
(
left
&&
right
==
NULL
))
{
return
1
;
}
if
(
left
->
type
!=
right
->
type
)
{
return
1
;
}
if
(
left
->
tokenId
!=
right
->
tokenId
)
{
return
1
;
}
if
(
left
->
functionId
!=
right
->
functionId
)
{
return
1
;
}
if
((
left
->
pLeft
&&
right
->
pLeft
==
NULL
)
||
(
left
->
pLeft
==
NULL
&&
right
->
pLeft
)
||
(
left
->
pRight
&&
right
->
pRight
==
NULL
)
||
(
left
->
pRight
==
NULL
&&
right
->
pRight
)
||
(
left
->
pParam
&&
right
->
pParam
==
NULL
)
||
(
left
->
pParam
==
NULL
&&
right
->
pParam
))
{
return
1
;
}
if
(
tVariantCompare
(
&
left
->
value
,
&
right
->
value
))
{
return
1
;
}
if
(
tStrTokenCompare
(
&
left
->
colInfo
,
&
right
->
colInfo
))
{
return
1
;
}
if
(
right
->
pParam
&&
left
->
pParam
)
{
size_t
size
=
taosArrayGetSize
(
right
->
pParam
);
if
(
left
->
pParam
&&
taosArrayGetSize
(
left
->
pParam
)
!=
size
)
{
return
1
;
}
for
(
int32_t
i
=
0
;
i
<
size
;
i
++
)
{
tSqlExprItem
*
pLeftElem
=
taosArrayGet
(
left
->
pParam
,
i
);
tSqlExpr
*
pSubLeft
=
pLeftElem
->
pNode
;
tSqlExprItem
*
pRightElem
=
taosArrayGet
(
left
->
pParam
,
i
);
tSqlExpr
*
pSubRight
=
pRightElem
->
pNode
;
if
(
tSqlExprCompare
(
pSubLeft
,
pSubRight
))
{
return
1
;
}
}
}
if
(
left
->
pLeft
&&
tSqlExprCompare
(
left
->
pLeft
,
right
->
pLeft
))
{
return
1
;
}
if
(
left
->
pRight
&&
tSqlExprCompare
(
left
->
pRight
,
right
->
pRight
))
{
return
1
;
}
return
0
;
}
tSqlExpr
*
tSqlExprClone
(
tSqlExpr
*
pSrc
)
{
tSqlExpr
*
pExpr
=
calloc
(
1
,
sizeof
(
tSqlExpr
));
...
...
@@ -640,7 +711,7 @@ void tSetColumnType(TAOS_FIELD *pField, SStrToken *type) {
SQuerySqlNode
*
tSetQuerySqlNode
(
SStrToken
*
pSelectToken
,
SArray
*
pSelectList
,
SFromInfo
*
pFrom
,
tSqlExpr
*
pWhere
,
SArray
*
pGroupby
,
SArray
*
pSortOrder
,
SIntervalVal
*
pInterval
,
SSessionWindowVal
*
pSession
,
SStrToken
*
pSliding
,
SArray
*
pFill
,
SLimitVal
*
pLimit
,
SLimitVal
*
psLimit
)
{
SLimitVal
*
psLimit
,
tSqlExpr
*
pHaving
)
{
assert
(
pSelectList
!=
NULL
);
SQuerySqlNode
*
pSqlNode
=
calloc
(
1
,
sizeof
(
SQuerySqlNode
));
...
...
@@ -655,6 +726,7 @@ SQuerySqlNode *tSetQuerySqlNode(SStrToken *pSelectToken, SArray *pSelectList, SF
pSqlNode
->
pSortOrder
=
pSortOrder
;
pSqlNode
->
pWhere
=
pWhere
;
pSqlNode
->
fillType
=
pFill
;
pSqlNode
->
pHaving
=
pHaving
;
if
(
pLimit
!=
NULL
)
{
pSqlNode
->
limit
=
*
pLimit
;
...
...
@@ -717,6 +789,9 @@ void destroyQuerySqlNode(SQuerySqlNode *pQuerySql) {
tSqlExprDestroy
(
pQuerySql
->
pWhere
);
pQuerySql
->
pWhere
=
NULL
;
tSqlExprDestroy
(
pQuerySql
->
pHaving
);
pQuerySql
->
pHaving
=
NULL
;
taosArrayDestroyEx
(
pQuerySql
->
pSortOrder
,
freeVariant
);
pQuerySql
->
pSortOrder
=
NULL
;
...
...
src/query/src/sql.c
浏览文件 @
910b78f2
此差异已折叠。
点击以展开。
tests/script/general/parser/having.sim
0 → 100644
浏览文件 @
910b78f2
此差异已折叠。
点击以展开。
tests/script/general/parser/having_child.sim
0 → 100644
浏览文件 @
910b78f2
此差异已折叠。
点击以展开。
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录