/src/tdengine/source/libs/planner/src/planPhysiCreater.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com> |
3 | | * |
4 | | * SPDX-License-Identifier: AGPL-3.0-or-later |
5 | | * |
6 | | * This program is free software: you can use, redistribute, and/or modify |
7 | | * it under the terms of the GNU Affero General Public License, version 3 |
8 | | * or later ("AGPL"), as published by the Free Software Foundation. |
9 | | * |
10 | | * This program is distributed in the hope that it will be useful, but WITHOUT |
11 | | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
12 | | * FITNESS FOR A PARTICULAR PURPOSE. |
13 | | * |
14 | | * You should have received a copy of the GNU Affero General Public License |
15 | | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | | */ |
17 | | |
18 | | #include <stdio.h> |
19 | | #include <stdlib.h> |
20 | | |
21 | | #include "extConnector.h" |
22 | | #include "nodes.h" |
23 | | #include "planInt.h" |
24 | | |
25 | | #include "catalog.h" |
26 | | #include "functionMgt.h" |
27 | | #include "planner.h" |
28 | | #include "scalar.h" |
29 | | #include "plannodes.h" |
30 | | #include "systable.h" |
31 | | #include "tglobal.h" |
32 | | #include "ttypes.h" |
33 | | |
34 | | typedef struct SSlotIdInfo { |
35 | | int16_t slotId; |
36 | | bool set; |
37 | | } SSlotIdInfo; |
38 | | |
39 | 0 | static bool fqDiagEnabled(void) { |
40 | 0 | return NULL != getenv("FQ_DIAG"); |
41 | 0 | } |
42 | | |
43 | 0 | static void fqDiagDumpExprList(const char* pTag, const SNodeList* pExprs) { |
44 | 0 | if (!fqDiagEnabled()) { |
45 | 0 | return; |
46 | 0 | } |
47 | | |
48 | 0 | fprintf(stderr, "[FQ-DIAG] %s count=%d\n", pTag ? pTag : "(null)", |
49 | 0 | pExprs ? LIST_LENGTH((SNodeList*)pExprs) : 0); |
50 | 0 | if (NULL == pExprs) { |
51 | 0 | return; |
52 | 0 | } |
53 | | |
54 | 0 | int32_t idx = 0; |
55 | 0 | SNode* pExpr = NULL; |
56 | 0 | FOREACH(pExpr, pExprs) { |
57 | 0 | const SNode* pInner = pExpr; |
58 | 0 | if (QUERY_NODE_TARGET == nodeType((SNode*)pInner)) { |
59 | 0 | pInner = ((const STargetNode*)pInner)->pExpr; |
60 | 0 | } |
61 | |
|
62 | 0 | const char* pAlias = nodesIsExprNode((SNode*)pInner) ? ((const SExprNode*)pInner)->aliasName : ""; |
63 | 0 | const char* pUserAlias = nodesIsExprNode((SNode*)pInner) ? ((const SExprNode*)pInner)->userAlias : ""; |
64 | 0 | const char* pColName = (NULL != pInner && QUERY_NODE_COLUMN == nodeType((SNode*)pInner)) |
65 | 0 | ? ((const SColumnNode*)pInner)->colName |
66 | 0 | : ""; |
67 | 0 | const char* pFuncName = (NULL != pInner && QUERY_NODE_FUNCTION == nodeType((SNode*)pInner)) |
68 | 0 | ? ((const SFunctionNode*)pInner)->functionName |
69 | 0 | : ""; |
70 | 0 | fprintf(stderr, |
71 | 0 | "[FQ-DIAG] [%d] rawType=%d innerType=%d alias=%s userAlias=%s col=%s func=%s\n", |
72 | 0 | idx, pExpr ? (int)nodeType(pExpr) : -1, pInner ? (int)nodeType((SNode*)pInner) : -1, |
73 | 0 | pAlias, pUserAlias, pColName, pFuncName); |
74 | 0 | ++idx; |
75 | 0 | } |
76 | 0 | } |
77 | | |
78 | | typedef struct SSlotIndex { |
79 | | int64_t dataBlockId; |
80 | | SArray* pSlotIdsInfo; // duplicate name slot |
81 | | } SSlotIndex; |
82 | | |
83 | | enum { |
84 | | SLOT_KEY_TYPE_ALL = 1, |
85 | | SLOT_KEY_TYPE_COLNAME = 2, |
86 | | SLOT_KEY_TYPE_REF = 3, |
87 | | }; |
88 | | |
89 | 0 | static bool fqRemotePlanHasRepeatScanAgg(const SLogicNode* pNode) { |
90 | 0 | if (NULL == pNode) { |
91 | 0 | return false; |
92 | 0 | } |
93 | | |
94 | 0 | if (QUERY_NODE_LOGIC_PLAN_AGG == nodeType(pNode)) { |
95 | 0 | const SAggLogicNode* pAgg = (const SAggLogicNode*)pNode; |
96 | 0 | const SNode* pFunc = NULL; |
97 | 0 | FOREACH(pFunc, pAgg->pAggFuncs) { |
98 | 0 | if (QUERY_NODE_FUNCTION == nodeType(pFunc) && |
99 | 0 | fmIsRepeatScanFunc(((const SFunctionNode*)pFunc)->funcId)) { |
100 | 0 | return true; |
101 | 0 | } |
102 | 0 | } |
103 | 0 | } |
104 | | |
105 | 0 | if (NULL == pNode->pChildren) { |
106 | 0 | return false; |
107 | 0 | } |
108 | | |
109 | 0 | const SNode* pChild = NULL; |
110 | 0 | FOREACH(pChild, pNode->pChildren) { |
111 | 0 | if (fqRemotePlanHasRepeatScanAgg((const SLogicNode*)pChild)) { |
112 | 0 | return true; |
113 | 0 | } |
114 | 0 | } |
115 | | |
116 | 0 | return false; |
117 | 0 | } |
118 | | |
119 | 0 | static bool fqExprHasAnalyzeInfluxScalarAgg(const SNode* pNode, bool underAgg) { |
120 | 0 | if (NULL == pNode) { |
121 | 0 | return false; |
122 | 0 | } |
123 | | |
124 | 0 | switch (nodeType(pNode)) { |
125 | 0 | case QUERY_NODE_TARGET: |
126 | 0 | return fqExprHasAnalyzeInfluxScalarAgg((const SNode*)((const STargetNode*)pNode)->pExpr, underAgg); |
127 | 0 | case QUERY_NODE_REMOTE_VALUE: |
128 | 0 | return underAgg; |
129 | 0 | case QUERY_NODE_OPERATOR: { |
130 | 0 | const SOperatorNode* pOp = (const SOperatorNode*)pNode; |
131 | 0 | return fqExprHasAnalyzeInfluxScalarAgg(pOp->pLeft, underAgg) || |
132 | 0 | fqExprHasAnalyzeInfluxScalarAgg(pOp->pRight, underAgg); |
133 | 0 | } |
134 | 0 | case QUERY_NODE_LOGIC_CONDITION: { |
135 | 0 | const SLogicConditionNode* pCond = (const SLogicConditionNode*)pNode; |
136 | 0 | const SNode* pChild = NULL; |
137 | 0 | FOREACH(pChild, pCond->pParameterList) { |
138 | 0 | if (fqExprHasAnalyzeInfluxScalarAgg(pChild, underAgg)) { |
139 | 0 | return true; |
140 | 0 | } |
141 | 0 | } |
142 | 0 | return false; |
143 | 0 | } |
144 | 0 | case QUERY_NODE_CASE_WHEN: { |
145 | 0 | const SCaseWhenNode* pCase = (const SCaseWhenNode*)pNode; |
146 | 0 | if (fqExprHasAnalyzeInfluxScalarAgg(pCase->pCase, underAgg) || |
147 | 0 | fqExprHasAnalyzeInfluxScalarAgg(pCase->pElse, underAgg)) { |
148 | 0 | return true; |
149 | 0 | } |
150 | | |
151 | 0 | const SNode* pWhenThen = NULL; |
152 | 0 | FOREACH(pWhenThen, pCase->pWhenThenList) { |
153 | 0 | const SWhenThenNode* pItem = (const SWhenThenNode*)pWhenThen; |
154 | 0 | if (fqExprHasAnalyzeInfluxScalarAgg(pItem->pWhen, underAgg) || |
155 | 0 | fqExprHasAnalyzeInfluxScalarAgg(pItem->pThen, underAgg)) { |
156 | 0 | return true; |
157 | 0 | } |
158 | 0 | } |
159 | 0 | return false; |
160 | 0 | } |
161 | 0 | case QUERY_NODE_FUNCTION: { |
162 | 0 | const SFunctionNode* pFunc = (const SFunctionNode*)pNode; |
163 | 0 | bool nextUnderAgg = underAgg || fmIsAggFunc(pFunc->funcId); |
164 | 0 | const SNode* pArg = NULL; |
165 | 0 | FOREACH(pArg, pFunc->pParameterList) { |
166 | 0 | if (fqExprHasAnalyzeInfluxScalarAgg(pArg, nextUnderAgg)) { |
167 | 0 | return true; |
168 | 0 | } |
169 | 0 | } |
170 | 0 | return false; |
171 | 0 | } |
172 | 0 | case QUERY_NODE_NODE_LIST: { |
173 | 0 | const SNodeListNode* pList = (const SNodeListNode*)pNode; |
174 | 0 | const SNode* pItem = NULL; |
175 | 0 | FOREACH(pItem, pList->pNodeList) { |
176 | 0 | if (fqExprHasAnalyzeInfluxScalarAgg(pItem, underAgg)) { |
177 | 0 | return true; |
178 | 0 | } |
179 | 0 | } |
180 | 0 | return false; |
181 | 0 | } |
182 | 0 | default: |
183 | 0 | return false; |
184 | 0 | } |
185 | 0 | } |
186 | | |
187 | 0 | static bool fqRemoteLogicNeedsAnalyzeInfluxScalarAggFallback(const SLogicNode* pNode) { |
188 | 0 | if (NULL == pNode) { |
189 | 0 | return false; |
190 | 0 | } |
191 | | |
192 | 0 | if (fqExprHasAnalyzeInfluxScalarAgg((const SNode*)pNode->pConditions, false)) { |
193 | 0 | return true; |
194 | 0 | } |
195 | | |
196 | 0 | const SNode* pTarget = NULL; |
197 | 0 | FOREACH(pTarget, pNode->pTargets) { |
198 | 0 | if (fqExprHasAnalyzeInfluxScalarAgg(pTarget, false)) { |
199 | 0 | return true; |
200 | 0 | } |
201 | 0 | } |
202 | | |
203 | 0 | switch (nodeType((const SNode*)pNode)) { |
204 | 0 | case QUERY_NODE_LOGIC_PLAN_AGG: { |
205 | 0 | const SAggLogicNode* pAgg = (const SAggLogicNode*)pNode; |
206 | 0 | const SNode* pExpr = NULL; |
207 | 0 | FOREACH(pExpr, pAgg->pAggFuncs) { |
208 | 0 | if (fqExprHasAnalyzeInfluxScalarAgg(pExpr, false)) { |
209 | 0 | return true; |
210 | 0 | } |
211 | 0 | } |
212 | 0 | FOREACH(pExpr, pAgg->pGroupKeys) { |
213 | 0 | if (fqExprHasAnalyzeInfluxScalarAgg(pExpr, false)) { |
214 | 0 | return true; |
215 | 0 | } |
216 | 0 | } |
217 | 0 | break; |
218 | 0 | } |
219 | 0 | case QUERY_NODE_LOGIC_PLAN_PROJECT: { |
220 | 0 | const SProjectLogicNode* pProj = (const SProjectLogicNode*)pNode; |
221 | 0 | const SNode* pExpr = NULL; |
222 | 0 | FOREACH(pExpr, pProj->pProjections) { |
223 | 0 | if (fqExprHasAnalyzeInfluxScalarAgg(pExpr, false)) { |
224 | 0 | return true; |
225 | 0 | } |
226 | 0 | } |
227 | 0 | break; |
228 | 0 | } |
229 | 0 | default: |
230 | 0 | break; |
231 | 0 | } |
232 | | |
233 | 0 | const SNode* pChild = NULL; |
234 | 0 | FOREACH(pChild, pNode->pChildren) { |
235 | 0 | if (fqRemoteLogicNeedsAnalyzeInfluxScalarAggFallback((const SLogicNode*)pChild)) { |
236 | 0 | return true; |
237 | 0 | } |
238 | 0 | } |
239 | | |
240 | 0 | return false; |
241 | 0 | } |
242 | | |
243 | | static bool fqShouldUseAnalyzeInfluxScalarAggFallback(const SPhysiPlanContext* pCxt, |
244 | 0 | const SScanLogicNode* pScanLogicNode) { |
245 | 0 | if (NULL == pCxt || NULL == pCxt->pPlanCxt || NULL == pScanLogicNode || |
246 | 0 | NULL == pScanLogicNode->pExtTableNode || NULL == pScanLogicNode->pRemoteLogicPlan) { |
247 | 0 | return false; |
248 | 0 | } |
249 | | |
250 | 0 | if (((const SExtTableNode*)pScanLogicNode->pExtTableNode)->sourceType != EXT_SOURCE_INFLUXDB) { |
251 | 0 | return false; |
252 | 0 | } |
253 | | |
254 | 0 | if (QUERY_NODE_EXPLAIN_STMT != nodeType(pCxt->pPlanCxt->pAstRoot)) { |
255 | 0 | return false; |
256 | 0 | } |
257 | | |
258 | 0 | if (!((const SExplainStmt*)pCxt->pPlanCxt->pAstRoot)->analyze) { |
259 | 0 | return false; |
260 | 0 | } |
261 | | |
262 | 0 | return fqRemoteLogicNeedsAnalyzeInfluxScalarAggFallback((const SLogicNode*)pScanLogicNode->pRemoteLogicPlan); |
263 | 0 | } |
264 | | |
265 | | static int32_t addDataBlockSlotsImpl(SPhysiPlanContext* pCxt, SNodeList* pList, SDataBlockDescNode* pDataBlockDesc, |
266 | | const char* pStmtName, bool output, bool reserve); |
267 | | |
268 | | static int32_t getSlotKeyHelper(SNode* pNode, const char* pPreName, const char* name, char** ppKey, int32_t callocLen, |
269 | 0 | int32_t* pLen, uint16_t extraBufLen, int8_t slotKeyType) { |
270 | 0 | int32_t code = 0; |
271 | 0 | *ppKey = taosMemoryCalloc(1, callocLen); |
272 | 0 | if (!*ppKey) { |
273 | 0 | return terrno; |
274 | 0 | } |
275 | 0 | if (slotKeyType == SLOT_KEY_TYPE_ALL) { |
276 | 0 | TAOS_STRNCAT(*ppKey, pPreName, TSDB_TABLE_NAME_LEN); |
277 | 0 | TAOS_STRNCAT(*ppKey, ".", 2); |
278 | 0 | TAOS_STRNCAT(*ppKey, name, TSDB_COL_NAME_LEN); |
279 | 0 | *pLen = taosHashBinary(*ppKey, strlen(*ppKey), callocLen); |
280 | 0 | } else { |
281 | 0 | TAOS_STRNCAT(*ppKey, name, TSDB_COL_NAME_LEN); |
282 | 0 | *pLen = strlen(*ppKey); |
283 | 0 | } |
284 | 0 | return code; |
285 | 0 | } |
286 | | |
287 | | static int32_t getSlotKey(SNode* pNode, const char* pStmtName, char** ppKey, int32_t* pLen, uint16_t extraBufLen, |
288 | 0 | int32_t* cap) { |
289 | 0 | int32_t code = 0; |
290 | 0 | int32_t callocLen = 0; |
291 | 0 | if (QUERY_NODE_COLUMN == nodeType(pNode)) { |
292 | 0 | SColumnNode* pCol = (SColumnNode*)pNode; |
293 | 0 | if (NULL != pStmtName) { |
294 | 0 | if ('\0' != pStmtName[0]) { |
295 | 0 | callocLen = TSDB_TABLE_NAME_LEN + 1 + TSDB_COL_NAME_LEN + 1 + extraBufLen; |
296 | 0 | *cap = callocLen; |
297 | 0 | return getSlotKeyHelper(pNode, pStmtName, pCol->node.aliasName, ppKey, callocLen, pLen, extraBufLen, |
298 | 0 | SLOT_KEY_TYPE_ALL); |
299 | 0 | } else { |
300 | 0 | callocLen = TSDB_COL_NAME_LEN + 1 + extraBufLen; |
301 | 0 | *cap = callocLen; |
302 | 0 | return getSlotKeyHelper(pNode, pStmtName, pCol->node.aliasName, ppKey, callocLen, pLen, extraBufLen, |
303 | 0 | SLOT_KEY_TYPE_COLNAME); |
304 | 0 | } |
305 | 0 | } |
306 | 0 | if ('\0' == pCol->tableAlias[0]) { |
307 | 0 | callocLen = TSDB_COL_NAME_LEN + 1 + extraBufLen; |
308 | 0 | *cap = callocLen; |
309 | 0 | return getSlotKeyHelper(pNode, pStmtName, pCol->colName, ppKey, callocLen, pLen, extraBufLen, |
310 | 0 | SLOT_KEY_TYPE_COLNAME); |
311 | 0 | } |
312 | 0 | if (pCol->hasRef) { |
313 | 0 | int32_t allocLen = TSDB_EXT_SOURCE_NAME_LEN + TSDB_TABLE_FNAME_LEN + TSDB_COL_NAME_LEN * 2 + 5 + extraBufLen; |
314 | 0 | *ppKey = taosMemoryCalloc(1, allocLen); |
315 | 0 | if (!*ppKey) { |
316 | 0 | return terrno; |
317 | 0 | } |
318 | | // For tag columns, include colName to prevent slot collisions when STB-level |
319 | | // metadata non-deterministically reports the same ref source for different tags |
320 | 0 | if (pCol->colType == COLUMN_TYPE_TAG) { |
321 | 0 | TAOS_STRNCAT(*ppKey, pCol->colName, TSDB_COL_NAME_LEN); |
322 | 0 | TAOS_STRNCAT(*ppKey, ":", 2); |
323 | 0 | } |
324 | 0 | if ('\0' != pCol->refSourceName[0]) { |
325 | 0 | TAOS_STRNCAT(*ppKey, pCol->refSourceName, TSDB_EXT_SOURCE_NAME_LEN); |
326 | 0 | TAOS_STRNCAT(*ppKey, ".", 2); |
327 | 0 | } |
328 | 0 | TAOS_STRNCAT(*ppKey, pCol->refDbName, TSDB_DB_NAME_LEN); |
329 | 0 | TAOS_STRNCAT(*ppKey, ".", 2); |
330 | 0 | TAOS_STRNCAT(*ppKey, pCol->refTableName, TSDB_TABLE_NAME_LEN); |
331 | 0 | TAOS_STRNCAT(*ppKey, ".", 2); |
332 | 0 | TAOS_STRNCAT(*ppKey, pCol->refColName, TSDB_COL_NAME_LEN); |
333 | 0 | *pLen = taosHashBinary(*ppKey, strlen(*ppKey), allocLen); |
334 | 0 | *cap = allocLen; |
335 | 0 | return code; |
336 | 0 | } |
337 | 0 | if (pCol->hasDep) { |
338 | 0 | int32_t allocLen = TSDB_EXT_SOURCE_NAME_LEN + TSDB_TABLE_FNAME_LEN + TSDB_COL_NAME_LEN + 4 + extraBufLen; |
339 | 0 | *ppKey = taosMemoryCalloc(1, allocLen); |
340 | 0 | if (!*ppKey) { |
341 | 0 | return terrno; |
342 | 0 | } |
343 | 0 | if ('\0' != pCol->refSourceName[0]) { |
344 | 0 | TAOS_STRNCAT(*ppKey, pCol->refSourceName, TSDB_EXT_SOURCE_NAME_LEN); |
345 | 0 | TAOS_STRNCAT(*ppKey, ".", 2); |
346 | 0 | } |
347 | 0 | TAOS_STRNCAT(*ppKey, pCol->dbName, TSDB_DB_NAME_LEN); |
348 | 0 | TAOS_STRNCAT(*ppKey, ".", 2); |
349 | 0 | TAOS_STRNCAT(*ppKey, pCol->tableAlias, TSDB_TABLE_NAME_LEN); |
350 | 0 | TAOS_STRNCAT(*ppKey, ".", 2); |
351 | 0 | TAOS_STRNCAT(*ppKey, pCol->colName, TSDB_COL_NAME_LEN); |
352 | 0 | planDebug("getSlotKey hasDep: '%s' (len=%d)", *ppKey, (int)strlen(*ppKey)); |
353 | 0 | *cap = allocLen; |
354 | 0 | *pLen = taosHashBinary(*ppKey, strlen(*ppKey), allocLen); |
355 | 0 | return code; |
356 | 0 | } |
357 | 0 | callocLen = TSDB_TABLE_NAME_LEN + 1 + TSDB_COL_NAME_LEN + 1 + extraBufLen; |
358 | 0 | *cap = callocLen; |
359 | 0 | planDebug("getSlotKey default: tableAlias='%s' colName='%s' hasRef=%d hasDep=%d", pCol->tableAlias, pCol->colName, pCol->hasRef, pCol->hasDep); |
360 | 0 | return getSlotKeyHelper(pNode, pCol->tableAlias, pCol->colName, ppKey, callocLen, pLen, extraBufLen, |
361 | 0 | SLOT_KEY_TYPE_ALL); |
362 | 0 | } else if (QUERY_NODE_FUNCTION == nodeType(pNode)) { |
363 | 0 | SFunctionNode* pFunc = (SFunctionNode*)pNode; |
364 | 0 | if (FUNCTION_TYPE_TBNAME == pFunc->funcType) { |
365 | 0 | SValueNode* pVal = (SValueNode*)nodesListGetNode(pFunc->pParameterList, 0); |
366 | 0 | if (pVal) { |
367 | 0 | if (NULL != pStmtName && '\0' != pStmtName[0]) { |
368 | 0 | callocLen = TSDB_TABLE_NAME_LEN + 1 + TSDB_COL_NAME_LEN + 1 + extraBufLen; |
369 | 0 | return getSlotKeyHelper(pNode, pStmtName, ((SExprNode*)pNode)->aliasName, ppKey, callocLen, pLen, extraBufLen, |
370 | 0 | SLOT_KEY_TYPE_ALL); |
371 | 0 | } |
372 | 0 | int32_t literalLen = strlen(pVal->literal); |
373 | 0 | callocLen = literalLen + 1 + TSDB_COL_NAME_LEN + 1 + extraBufLen; |
374 | 0 | *cap = callocLen; |
375 | 0 | return getSlotKeyHelper(pNode, pVal->literal, ((SExprNode*)pNode)->aliasName, ppKey, callocLen, pLen, |
376 | 0 | extraBufLen, SLOT_KEY_TYPE_ALL); |
377 | 0 | } |
378 | 0 | } |
379 | 0 | } |
380 | | |
381 | 0 | if (NULL != pStmtName && '\0' != pStmtName[0]) { |
382 | 0 | callocLen = TSDB_TABLE_NAME_LEN + 1 + TSDB_COL_NAME_LEN + 1 + extraBufLen; |
383 | 0 | *cap = callocLen; |
384 | 0 | return getSlotKeyHelper(pNode, pStmtName, ((SExprNode*)pNode)->aliasName, ppKey, callocLen, pLen, extraBufLen, |
385 | 0 | SLOT_KEY_TYPE_ALL); |
386 | 0 | } |
387 | | |
388 | 0 | callocLen = TSDB_COL_NAME_LEN + 1 + extraBufLen; |
389 | 0 | *cap = callocLen; |
390 | 0 | code = getSlotKeyHelper(pNode, pStmtName, ((SExprNode*)pNode)->aliasName, ppKey, callocLen, pLen, extraBufLen, |
391 | 0 | SLOT_KEY_TYPE_COLNAME); |
392 | 0 | if (TSDB_CODE_SUCCESS == code) { |
393 | 0 | qDebug("FQ-Slots: getSlotKey exprType=%d stmtName=%s aliasName=%s key=%s len=%d cap=%d", |
394 | 0 | (int)nodeType(pNode), (NULL != pStmtName ? pStmtName : "(null)"), |
395 | 0 | ((SExprNode*)pNode)->aliasName, (NULL != *ppKey ? *ppKey : "(null)"), *pLen, *cap); |
396 | 0 | } else { |
397 | 0 | planError("FQ-Slots: getSlotKey failed exprType=%d stmtName=%s aliasName=%s code=0x%x", |
398 | 0 | (int)nodeType(pNode), (NULL != pStmtName ? pStmtName : "(null)"), |
399 | 0 | ((SExprNode*)pNode)->aliasName, code); |
400 | 0 | } |
401 | 0 | return code; |
402 | 0 | return code; |
403 | 0 | } |
404 | | |
405 | | static SNode* createSlotDesc(SPhysiPlanContext* pCxt, const char* pName, const SNode* pNode, int16_t slotId, |
406 | 0 | bool output, bool reserve) { |
407 | 0 | SSlotDescNode* pSlot = NULL; |
408 | 0 | int32_t code = nodesMakeNode(QUERY_NODE_SLOT_DESC, (SNode**)&pSlot); |
409 | 0 | if (NULL == pSlot) { |
410 | 0 | terrno = code; |
411 | 0 | return NULL; |
412 | 0 | } |
413 | 0 | snprintf(pSlot->name, sizeof(pSlot->name), "%s", pName); |
414 | 0 | pSlot->slotId = slotId; |
415 | 0 | pSlot->dataType = ((SExprNode*)pNode)->resType; |
416 | 0 | pSlot->reserve = reserve; |
417 | 0 | pSlot->output = output; |
418 | 0 | return (SNode*)pSlot; |
419 | 0 | } |
420 | | |
421 | 0 | static int32_t createTarget(SNode* pNode, int64_t dataBlockId, int16_t slotId, SNode** pOutput) { |
422 | 0 | STargetNode* pTarget = NULL; |
423 | 0 | int32_t code = nodesMakeNode(QUERY_NODE_TARGET, (SNode**)&pTarget); |
424 | 0 | if (NULL == pTarget) { |
425 | 0 | return code; |
426 | 0 | } |
427 | | |
428 | 0 | pTarget->dataBlockId = dataBlockId; |
429 | 0 | pTarget->slotId = slotId; |
430 | 0 | pTarget->pExpr = pNode; |
431 | |
|
432 | 0 | *pOutput = (SNode*)pTarget; |
433 | 0 | return TSDB_CODE_SUCCESS; |
434 | 0 | } |
435 | | |
436 | 0 | static int32_t putSlotToHashImpl(int64_t dataBlockId, int16_t slotId, const char* pName, int32_t len, SHashObj* pHash) { |
437 | 0 | SSlotIndex* pIndex = taosHashGet(pHash, pName, len); |
438 | 0 | if (NULL != pIndex) { |
439 | 0 | SSlotIdInfo info = {.slotId = slotId, .set = false}; |
440 | 0 | if (NULL == taosArrayPush(pIndex->pSlotIdsInfo, &info)) { |
441 | 0 | return terrno; |
442 | 0 | } |
443 | 0 | return TSDB_CODE_SUCCESS; |
444 | 0 | } |
445 | | |
446 | 0 | SSlotIndex index = {.dataBlockId = dataBlockId, .pSlotIdsInfo = taosArrayInit(TARRAY_MIN_SIZE, sizeof(SSlotIdInfo))}; |
447 | 0 | if (NULL == index.pSlotIdsInfo) { |
448 | 0 | return terrno; |
449 | 0 | } |
450 | 0 | SSlotIdInfo info = {.slotId = slotId, .set = false}; |
451 | 0 | if (NULL == taosArrayPush(index.pSlotIdsInfo, &info)) { |
452 | 0 | taosArrayDestroy(index.pSlotIdsInfo); |
453 | 0 | return terrno; |
454 | 0 | } |
455 | 0 | int32_t code = taosHashPut(pHash, pName, len, &index, sizeof(SSlotIndex)); |
456 | 0 | if (TSDB_CODE_SUCCESS != code) { |
457 | 0 | taosArrayDestroy(index.pSlotIdsInfo); |
458 | 0 | } |
459 | 0 | return code; |
460 | 0 | } |
461 | | |
462 | | static int32_t putSlotToHash(const char* pName, int32_t len, int64_t dataBlockId, int16_t slotId, SNode* pNode, |
463 | 0 | SHashObj* pHash) { |
464 | 0 | return putSlotToHashImpl(dataBlockId, slotId, pName, len, pHash); |
465 | 0 | } |
466 | | |
467 | | static int32_t createDataBlockDescHash(SPhysiPlanContext* pCxt, int32_t capacity, int64_t dataBlockId, |
468 | 0 | SHashObj** pDescHash, SHashObj** ppProjIdxDescHash) { |
469 | 0 | SHashObj* pHash = taosHashInit(capacity, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), false, HASH_NO_LOCK); |
470 | 0 | if (NULL == pHash) { |
471 | 0 | return terrno; |
472 | 0 | } |
473 | 0 | SHashObj* pProjIdxHash = taosHashInit(capacity, taosGetDefaultHashFunction(TSDB_DATA_TYPE_INT), false, HASH_NO_LOCK); |
474 | 0 | if (!pProjIdxHash) { |
475 | 0 | taosHashCleanup(pHash); |
476 | 0 | return terrno; |
477 | 0 | } |
478 | 0 | if (NULL == taosArrayInsert(pCxt->pLocationHelper, (size_t)dataBlockId, &pHash)) { |
479 | 0 | taosHashCleanup(pHash); |
480 | 0 | taosHashCleanup(pProjIdxHash); |
481 | 0 | return terrno; |
482 | 0 | } |
483 | 0 | if (NULL == taosArrayInsert(pCxt->pProjIdxLocHelper, (size_t)dataBlockId, &pProjIdxHash)) { |
484 | 0 | taosHashCleanup(pHash); |
485 | 0 | taosHashCleanup(pProjIdxHash); |
486 | 0 | return terrno; |
487 | 0 | } |
488 | | |
489 | 0 | *pDescHash = pHash; |
490 | 0 | *ppProjIdxDescHash = pProjIdxHash; |
491 | 0 | return TSDB_CODE_SUCCESS; |
492 | 0 | } |
493 | | |
494 | 0 | static void fqResetLocationHashSlotSet(SHashObj* pHash) { |
495 | 0 | if (NULL == pHash) { |
496 | 0 | return; |
497 | 0 | } |
498 | 0 |
|
499 | 0 | SSlotIndex* pIndex = taosHashIterate(pHash, NULL); |
500 | 0 | while (NULL != pIndex) { |
501 | 0 | if (NULL != pIndex->pSlotIdsInfo) { |
502 | 0 | int32_t size = taosArrayGetSize(pIndex->pSlotIdsInfo); |
503 | 0 | for (int32_t i = 0; i < size; ++i) { |
504 | 0 | SSlotIdInfo* pInfo = taosArrayGet(pIndex->pSlotIdsInfo, i); |
505 | 0 | if (NULL != pInfo) { |
506 | 0 | pInfo->set = false; |
507 | 0 | } |
508 | 0 | } |
509 | 0 | } |
510 | 0 | pIndex = taosHashIterate(pHash, pIndex); |
511 | 0 | } |
512 | 0 | } |
513 | | |
514 | | static int32_t buildDataBlockSlots(SPhysiPlanContext* pCxt, SNodeList* pList, SDataBlockDescNode* pDataBlockDesc, |
515 | 0 | SHashObj* pHash, SHashObj* pProjIdxDescHash) { |
516 | 0 | pDataBlockDesc->pSlots = NULL; |
517 | 0 | int32_t code = nodesMakeList(&pDataBlockDesc->pSlots); |
518 | 0 | if (NULL == pDataBlockDesc->pSlots) { |
519 | 0 | return code; |
520 | 0 | } |
521 | | |
522 | 0 | int16_t slotId = 0; |
523 | 0 | SNode* pNode = NULL; |
524 | 0 | FOREACH(pNode, pList) { |
525 | 0 | char* name = NULL; |
526 | 0 | int32_t len = 0; |
527 | 0 | int32_t cap = 0; |
528 | 0 | code = getSlotKey(pNode, NULL, &name, &len, 16, &cap); |
529 | 0 | planDebug("FQ-Slots: buildDataBlockSlots dataBlockId=%" PRId64 " slotId=%d exprNodeType=%d key=%s len=%d code=0x%x", |
530 | 0 | pDataBlockDesc->dataBlockId, slotId, (int)nodeType(pNode), |
531 | 0 | (NULL != name ? name : "(null)"), len, code); |
532 | 0 | if (TSDB_CODE_SUCCESS == code) { |
533 | 0 | code = nodesListStrictAppend(pDataBlockDesc->pSlots, createSlotDesc(pCxt, name, pNode, slotId, true, false)); |
534 | 0 | } |
535 | 0 | code = putSlotToHash(name, len, pDataBlockDesc->dataBlockId, slotId, pNode, pHash); |
536 | 0 | if (TSDB_CODE_SUCCESS == code) { |
537 | 0 | if (nodeType(pNode) == QUERY_NODE_COLUMN && ((SColumnNode*)pNode)->resIdx > 0) { |
538 | 0 | snprintf(name + strlen(name), cap, "_%d", ((SColumnNode*)pNode)->resIdx); |
539 | 0 | code = putSlotToHash(name, strlen(name), pDataBlockDesc->dataBlockId, slotId, pNode, pProjIdxDescHash); |
540 | 0 | } |
541 | 0 | } |
542 | 0 | taosMemoryFree(name); |
543 | 0 | if (TSDB_CODE_SUCCESS == code) { |
544 | 0 | pDataBlockDesc->totalRowSize += ((SExprNode*)pNode)->resType.bytes; |
545 | 0 | pDataBlockDesc->outputRowSize += ((SExprNode*)pNode)->resType.bytes; |
546 | 0 | ++slotId; |
547 | 0 | } else { |
548 | 0 | break; |
549 | 0 | } |
550 | 0 | } |
551 | 0 | return code; |
552 | 0 | } |
553 | | |
554 | 0 | static int32_t createDataBlockDesc(SPhysiPlanContext* pCxt, SNodeList* pList, SDataBlockDescNode** pDataBlockDesc) { |
555 | 0 | SDataBlockDescNode* pDesc = NULL; |
556 | 0 | int32_t code = nodesMakeNode(QUERY_NODE_DATABLOCK_DESC, (SNode**)&pDesc); |
557 | 0 | if (NULL == pDesc) { |
558 | 0 | return code; |
559 | 0 | } |
560 | 0 | pDesc->dataBlockId = pCxt->nextDataBlockId++; |
561 | 0 | planDebug("FQ-Slots: createDataBlockDesc start dataBlockId=%" PRId64 " targets=%d", |
562 | 0 | pDesc->dataBlockId, pList ? LIST_LENGTH(pList) : 0); |
563 | |
|
564 | 0 | SHashObj* pHash = NULL; |
565 | 0 | SHashObj* pProjIdxHash = NULL; |
566 | 0 | code = createDataBlockDescHash(pCxt, LIST_LENGTH(pList), pDesc->dataBlockId, &pHash, &pProjIdxHash); |
567 | 0 | if (TSDB_CODE_SUCCESS == code) { |
568 | 0 | code = buildDataBlockSlots(pCxt, pList, pDesc, pHash, pProjIdxHash); |
569 | 0 | } |
570 | |
|
571 | 0 | if (TSDB_CODE_SUCCESS == code) { |
572 | 0 | *pDataBlockDesc = pDesc; |
573 | 0 | planDebug("FQ-Slots: createDataBlockDesc done dataBlockId=%" PRId64 " slots=%d totalRowSize=%d outputRowSize=%d", |
574 | 0 | pDesc->dataBlockId, pDesc->pSlots ? LIST_LENGTH(pDesc->pSlots) : 0, |
575 | 0 | pDesc->totalRowSize, pDesc->outputRowSize); |
576 | 0 | } else { |
577 | 0 | planError("FQ-Slots: createDataBlockDesc failed dataBlockId=%" PRId64 " targets=%d code=0x%x", |
578 | 0 | pDesc->dataBlockId, pList ? LIST_LENGTH(pList) : 0, code); |
579 | 0 | nodesDestroyNode((SNode*)pDesc); |
580 | 0 | } |
581 | |
|
582 | 0 | return code; |
583 | 0 | } |
584 | | |
585 | 0 | static void destroySlotIndexHash(SHashObj* pHash) { |
586 | 0 | if (NULL == pHash) { |
587 | 0 | return; |
588 | 0 | } |
589 | | |
590 | 0 | SSlotIndex* pIndex = taosHashIterate(pHash, NULL); |
591 | 0 | while (NULL != pIndex) { |
592 | 0 | taosArrayDestroy(pIndex->pSlotIdsInfo); |
593 | 0 | pIndex = taosHashIterate(pHash, pIndex); |
594 | 0 | } |
595 | 0 | taosHashCleanup(pHash); |
596 | 0 | } |
597 | | |
598 | 0 | static void fqClearDataBlockDescHashes(SPhysiPlanContext* pCxt, int64_t dataBlockId) { |
599 | 0 | if (NULL == pCxt) { |
600 | 0 | return; |
601 | 0 | } |
602 | | |
603 | 0 | if (NULL != pCxt->pLocationHelper && dataBlockId < taosArrayGetSize(pCxt->pLocationHelper)) { |
604 | 0 | SHashObj* pHash = taosArrayGetP(pCxt->pLocationHelper, (size_t)dataBlockId); |
605 | 0 | if (NULL != pHash) { |
606 | 0 | SHashObj* pNull = NULL; |
607 | 0 | destroySlotIndexHash(pHash); |
608 | 0 | taosArraySet(pCxt->pLocationHelper, (size_t)dataBlockId, &pNull); |
609 | 0 | } |
610 | 0 | } |
611 | |
|
612 | 0 | if (NULL != pCxt->pProjIdxLocHelper && dataBlockId < taosArrayGetSize(pCxt->pProjIdxLocHelper)) { |
613 | 0 | SHashObj* pHash = taosArrayGetP(pCxt->pProjIdxLocHelper, (size_t)dataBlockId); |
614 | 0 | if (NULL != pHash) { |
615 | 0 | SHashObj* pNull = NULL; |
616 | 0 | destroySlotIndexHash(pHash); |
617 | 0 | taosArraySet(pCxt->pProjIdxLocHelper, (size_t)dataBlockId, &pNull); |
618 | 0 | } |
619 | 0 | } |
620 | 0 | } |
621 | | |
622 | | static int32_t fqRebuildDataBlockDesc(SPhysiPlanContext* pCxt, SDataBlockDescNode* pDesc, SNodeList* pOutputCols, |
623 | 0 | SNodeList* pReserveCols) { |
624 | 0 | if (NULL == pCxt || NULL == pDesc) { |
625 | 0 | return TSDB_CODE_INVALID_PARA; |
626 | 0 | } |
627 | | |
628 | 0 | int64_t dataBlockId = pDesc->dataBlockId; |
629 | 0 | planDebug("FQ-Slots: fqRebuildDataBlockDesc start dataBlockId=%" PRId64 " outputCols=%d reserveCols=%d", |
630 | 0 | dataBlockId, pOutputCols ? LIST_LENGTH(pOutputCols) : 0, |
631 | 0 | pReserveCols ? LIST_LENGTH(pReserveCols) : 0); |
632 | 0 | int32_t cap = 0; |
633 | 0 | if (pOutputCols != NULL) { |
634 | 0 | cap += LIST_LENGTH(pOutputCols); |
635 | 0 | } |
636 | 0 | if (pReserveCols != NULL) { |
637 | 0 | cap += LIST_LENGTH(pReserveCols); |
638 | 0 | } |
639 | 0 | if (cap <= 0) { |
640 | 0 | cap = 1; |
641 | 0 | } |
642 | |
|
643 | 0 | nodesDestroyList(pDesc->pSlots); |
644 | 0 | pDesc->pSlots = NULL; |
645 | 0 | pDesc->totalRowSize = 0; |
646 | 0 | pDesc->outputRowSize = 0; |
647 | |
|
648 | 0 | fqClearDataBlockDescHashes(pCxt, dataBlockId); |
649 | |
|
650 | 0 | SHashObj* pHash = NULL; |
651 | 0 | SHashObj* pProjIdxHash = NULL; |
652 | 0 | int32_t code = createDataBlockDescHash(pCxt, cap, dataBlockId, &pHash, &pProjIdxHash); |
653 | 0 | if (TSDB_CODE_SUCCESS != code) { |
654 | 0 | return code; |
655 | 0 | } |
656 | | |
657 | 0 | code = nodesMakeList(&pDesc->pSlots); |
658 | 0 | if (TSDB_CODE_SUCCESS != code) { |
659 | 0 | fqClearDataBlockDescHashes(pCxt, dataBlockId); |
660 | 0 | return code; |
661 | 0 | } |
662 | | |
663 | 0 | if (pOutputCols != NULL) { |
664 | 0 | code = addDataBlockSlotsImpl(pCxt, pOutputCols, pDesc, NULL, true, false); |
665 | 0 | if (TSDB_CODE_SUCCESS != code) { |
666 | 0 | return code; |
667 | 0 | } |
668 | 0 | } |
669 | | |
670 | 0 | if (pReserveCols != NULL) { |
671 | 0 | code = addDataBlockSlotsImpl(pCxt, pReserveCols, pDesc, NULL, false, true); |
672 | 0 | if (TSDB_CODE_SUCCESS != code) { |
673 | 0 | return code; |
674 | 0 | } |
675 | 0 | } |
676 | | |
677 | 0 | planDebug("FQ-Slots: rebuilt dataBlockDesc=%" PRId64 " outputCols=%d reserveCols=%d totalSlots=%d totalRowSize=%d outputRowSize=%d", |
678 | 0 | dataBlockId, |
679 | 0 | pOutputCols ? LIST_LENGTH(pOutputCols) : 0, |
680 | 0 | pReserveCols ? LIST_LENGTH(pReserveCols) : 0, |
681 | 0 | pDesc->pSlots ? LIST_LENGTH(pDesc->pSlots) : 0, |
682 | 0 | pDesc->totalRowSize, pDesc->outputRowSize); |
683 | 0 | return TSDB_CODE_SUCCESS; |
684 | 0 | } |
685 | | |
686 | 0 | static int16_t getUnsetSlotId(const SArray* pSlotIdsInfo) { |
687 | 0 | int32_t size = taosArrayGetSize(pSlotIdsInfo); |
688 | 0 | for (int32_t i = 0; i < size; ++i) { |
689 | 0 | SSlotIdInfo* pInfo = taosArrayGet(pSlotIdsInfo, i); |
690 | 0 | if (!pInfo->set) { |
691 | 0 | pInfo->set = true; |
692 | 0 | return pInfo->slotId; |
693 | 0 | } |
694 | 0 | } |
695 | 0 | return ((SSlotIdInfo*)taosArrayGet(pSlotIdsInfo, 0))->slotId; |
696 | 0 | } |
697 | | |
698 | | static int32_t addDataBlockSlotsImpl(SPhysiPlanContext* pCxt, SNodeList* pList, SDataBlockDescNode* pDataBlockDesc, |
699 | 0 | const char* pStmtName, bool output, bool reserve) { |
700 | 0 | if (NULL == pList) { |
701 | 0 | return TSDB_CODE_SUCCESS; |
702 | 0 | } |
703 | | |
704 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
705 | 0 | SHashObj* pHash = taosArrayGetP(pCxt->pLocationHelper, pDataBlockDesc->dataBlockId); |
706 | 0 | int16_t nextSlotId = LIST_LENGTH(pDataBlockDesc->pSlots), slotId = 0; |
707 | 0 | SNode* pNode = NULL; |
708 | 0 | FOREACH(pNode, pList) { |
709 | 0 | SNode* pExpr = QUERY_NODE_ORDER_BY_EXPR == nodeType(pNode) ? ((SOrderByExprNode*)pNode)->pExpr : pNode; |
710 | 0 | char* name = NULL; |
711 | 0 | int32_t len = 0; |
712 | 0 | int32_t cap = 0; |
713 | 0 | code = getSlotKey(pExpr, pStmtName, &name, &len, 0, &cap); |
714 | 0 | planDebug("FQ-Slots: addDataBlockSlots dataBlockId=%" PRId64 " nextSlotId=%d output=%d reserve=%d exprNodeType=%d exprAlias=%s key=%s len=%d code=0x%x", |
715 | 0 | pDataBlockDesc->dataBlockId, nextSlotId, (int)output, (int)reserve, |
716 | 0 | (int)nodeType(pExpr), ((SExprNode*)pExpr)->aliasName, |
717 | 0 | (NULL != name ? name : "(null)"), len, code); |
718 | 0 | if (TSDB_CODE_SUCCESS == code) { |
719 | 0 | SSlotIndex* pIndex = taosHashGet(pHash, name, len); |
720 | 0 | if (NULL == pIndex) { |
721 | 0 | code = nodesListStrictAppend(pDataBlockDesc->pSlots, |
722 | 0 | createSlotDesc(pCxt, name, pExpr, nextSlotId, output, reserve)); |
723 | 0 | if (TSDB_CODE_SUCCESS == code) { |
724 | 0 | code = putSlotToHashImpl(pDataBlockDesc->dataBlockId, nextSlotId, name, len, pHash); |
725 | 0 | } |
726 | 0 | pDataBlockDesc->totalRowSize += ((SExprNode*)pExpr)->resType.bytes; |
727 | 0 | if (output) { |
728 | 0 | pDataBlockDesc->outputRowSize += ((SExprNode*)pExpr)->resType.bytes; |
729 | 0 | } |
730 | 0 | slotId = nextSlotId; |
731 | 0 | ++nextSlotId; |
732 | 0 | } else { |
733 | 0 | slotId = getUnsetSlotId(pIndex->pSlotIdsInfo); |
734 | 0 | } |
735 | 0 | } |
736 | |
|
737 | 0 | taosMemoryFree(name); |
738 | 0 | if (TSDB_CODE_SUCCESS == code) { |
739 | 0 | SNode* pTarget = NULL; |
740 | 0 | code = createTarget(pNode, pDataBlockDesc->dataBlockId, slotId, &pTarget); |
741 | 0 | if (TSDB_CODE_SUCCESS == code) { |
742 | 0 | REPLACE_NODE(pTarget); |
743 | 0 | } |
744 | 0 | } |
745 | |
|
746 | 0 | if (TSDB_CODE_SUCCESS != code) { |
747 | 0 | break; |
748 | 0 | } |
749 | 0 | } |
750 | 0 | return code; |
751 | 0 | } |
752 | | |
753 | 0 | static int32_t addDataBlockSlots(SPhysiPlanContext* pCxt, SNodeList* pList, SDataBlockDescNode* pDataBlockDesc) { |
754 | 0 | return addDataBlockSlotsImpl(pCxt, pList, pDataBlockDesc, NULL, false, true); |
755 | 0 | } |
756 | | |
757 | 0 | static int32_t addDataBlockSlot(SPhysiPlanContext* pCxt, SNode** pNode, SDataBlockDescNode* pDataBlockDesc) { |
758 | 0 | if (NULL == pNode || NULL == *pNode) { |
759 | 0 | return TSDB_CODE_SUCCESS; |
760 | 0 | } |
761 | | |
762 | 0 | SNodeList* pList = NULL; |
763 | 0 | int32_t code = nodesListMakeAppend(&pList, *pNode); |
764 | 0 | if (TSDB_CODE_SUCCESS == code) { |
765 | 0 | code = addDataBlockSlots(pCxt, pList, pDataBlockDesc); |
766 | 0 | } |
767 | 0 | if (TSDB_CODE_SUCCESS == code) { |
768 | 0 | *pNode = nodesListGetNode(pList, 0); |
769 | 0 | } |
770 | 0 | nodesClearList(pList); |
771 | 0 | return code; |
772 | 0 | } |
773 | | |
774 | | static int32_t addDataBlockSlotsForProject(SPhysiPlanContext* pCxt, const char* pStmtName, SNodeList* pList, |
775 | 0 | SDataBlockDescNode* pDataBlockDesc) { |
776 | 0 | return addDataBlockSlotsImpl(pCxt, pList, pDataBlockDesc, pStmtName, false, true); |
777 | 0 | } |
778 | | |
779 | 0 | static int32_t pushdownDataBlockSlots(SPhysiPlanContext* pCxt, SNodeList* pList, SDataBlockDescNode* pDataBlockDesc) { |
780 | 0 | return addDataBlockSlotsImpl(pCxt, pList, pDataBlockDesc, NULL, true, true); |
781 | 0 | } |
782 | | |
783 | | typedef struct SSetSlotIdCxt { |
784 | | int32_t errCode; |
785 | | SHashObj* pLeftHash; |
786 | | SHashObj* pLeftProjIdxHash; |
787 | | SHashObj* pRightHash; |
788 | | SHashObj* pRightProdIdxHash; |
789 | | const char* pLeftTableAlias; |
790 | | const char* pRightTableAlias; |
791 | | const char* pLeftAlias; |
792 | | const char* pRightAlias; |
793 | | } SSetSlotIdCxt; |
794 | | |
795 | | typedef struct SMultiTableSetSlotIdCxt { |
796 | | int32_t errCode; |
797 | | SArray* hashArray; |
798 | | SArray* projIdxHashArray; |
799 | | SHashObj* mergedHash; |
800 | | SHashObj* mergedProjIdxHash; |
801 | | SNodeList* pChild; |
802 | | bool isVtb; |
803 | | } SMultiTableSetSlotIdCxt; |
804 | | |
805 | | static int32_t fqBuildUnqualifiedSlotKey(const char* pName, uint16_t extraBufLen, char** ppKey, |
806 | 0 | int32_t* pLen, int32_t* pCap) { |
807 | 0 | if (NULL == pName || '\0' == pName[0] || NULL == ppKey || NULL == pLen || NULL == pCap) { |
808 | 0 | return TSDB_CODE_INVALID_PARA; |
809 | 0 | } |
810 | | |
811 | 0 | *ppKey = NULL; |
812 | 0 | *pLen = 0; |
813 | 0 | *pCap = TSDB_COL_NAME_LEN + 1 + extraBufLen; |
814 | 0 | return getSlotKeyHelper(NULL, "", pName, ppKey, *pCap, pLen, extraBufLen, SLOT_KEY_TYPE_COLNAME); |
815 | 0 | } |
816 | | |
817 | | static int32_t fqBuildQualifiedSlotKey(const char* pTableName, const char* pColName, uint16_t extraBufLen, |
818 | 0 | char** ppKey, int32_t* pLen, int32_t* pCap) { |
819 | 0 | if (NULL == pTableName || '\0' == pTableName[0] || NULL == pColName || '\0' == pColName[0] || |
820 | 0 | NULL == ppKey || NULL == pLen || NULL == pCap) { |
821 | 0 | return TSDB_CODE_INVALID_PARA; |
822 | 0 | } |
823 | | |
824 | 0 | *ppKey = NULL; |
825 | 0 | *pLen = 0; |
826 | 0 | *pCap = TSDB_TABLE_NAME_LEN + 1 + TSDB_COL_NAME_LEN + 1 + extraBufLen; |
827 | 0 | return getSlotKeyHelper(NULL, pTableName, pColName, ppKey, *pCap, pLen, extraBufLen, SLOT_KEY_TYPE_ALL); |
828 | 0 | } |
829 | | |
830 | | static int32_t fqBuildRefSlotKey(const SColumnNode* pCol, uint16_t extraBufLen, char** ppKey, int32_t* pLen, |
831 | 0 | int32_t* pCap) { |
832 | 0 | if (NULL == pCol || NULL == ppKey || NULL == pLen || NULL == pCap || !pCol->hasRef || |
833 | 0 | '\0' == pCol->refDbName[0] || '\0' == pCol->refTableName[0] || '\0' == pCol->refColName[0]) { |
834 | 0 | return TSDB_CODE_INVALID_PARA; |
835 | 0 | } |
836 | | |
837 | 0 | int32_t allocLen = TSDB_EXT_SOURCE_NAME_LEN + TSDB_TABLE_FNAME_LEN + TSDB_COL_NAME_LEN * 2 + 5 + extraBufLen; |
838 | 0 | *ppKey = taosMemoryCalloc(1, allocLen); |
839 | 0 | if (NULL == *ppKey) { |
840 | 0 | return terrno; |
841 | 0 | } |
842 | | |
843 | 0 | if (COLUMN_TYPE_TAG == pCol->colType) { |
844 | 0 | TAOS_STRNCAT(*ppKey, pCol->colName, TSDB_COL_NAME_LEN); |
845 | 0 | TAOS_STRNCAT(*ppKey, ":", 2); |
846 | 0 | } |
847 | 0 | if ('\0' != pCol->refSourceName[0]) { |
848 | 0 | TAOS_STRNCAT(*ppKey, pCol->refSourceName, TSDB_EXT_SOURCE_NAME_LEN); |
849 | 0 | TAOS_STRNCAT(*ppKey, ".", 2); |
850 | 0 | } |
851 | 0 | TAOS_STRNCAT(*ppKey, pCol->refDbName, TSDB_DB_NAME_LEN); |
852 | 0 | TAOS_STRNCAT(*ppKey, ".", 2); |
853 | 0 | TAOS_STRNCAT(*ppKey, pCol->refTableName, TSDB_TABLE_NAME_LEN); |
854 | 0 | TAOS_STRNCAT(*ppKey, ".", 2); |
855 | 0 | TAOS_STRNCAT(*ppKey, pCol->refColName, TSDB_COL_NAME_LEN); |
856 | 0 | *pLen = taosHashBinary(*ppKey, strlen(*ppKey), allocLen); |
857 | 0 | *pCap = allocLen; |
858 | 0 | return TSDB_CODE_SUCCESS; |
859 | 0 | } |
860 | | |
861 | 0 | static bool fqSlotLookupHasHit(SHashObj* pHash, const char* pKey, int32_t keyLen) { |
862 | 0 | return (NULL != pHash && NULL != pKey && keyLen > 0 && NULL != taosHashGet(pHash, pKey, keyLen)); |
863 | 0 | } |
864 | | |
865 | 0 | static void fqAppendSlotDiagItem(char* pBuf, int32_t bufLen, int32_t* pPos, const char* pItem) { |
866 | 0 | if (NULL == pBuf || bufLen <= 0 || NULL == pPos || NULL == pItem || *pPos >= bufLen - 1) { |
867 | 0 | return; |
868 | 0 | } |
869 | | |
870 | 0 | int32_t remain = bufLen - *pPos; |
871 | 0 | int32_t written = snprintf(pBuf + *pPos, remain, "%s%s", (*pPos > 0 ? "; " : ""), pItem); |
872 | 0 | if (written < 0) { |
873 | 0 | return; |
874 | 0 | } |
875 | | |
876 | 0 | if (written >= remain) { |
877 | 0 | *pPos = bufLen - 1; |
878 | 0 | pBuf[bufLen - 1] = '\0'; |
879 | 0 | return; |
880 | 0 | } |
881 | | |
882 | 0 | *pPos += written; |
883 | 0 | } |
884 | | |
885 | | static void fqAppendSlotKeyAttempt(char* pBuf, int32_t bufLen, int32_t* pPos, const char* pLabel, const char* pKey, |
886 | 0 | bool hit1, bool hit2, const char* pHash1Label, const char* pHash2Label) { |
887 | 0 | if (NULL == pLabel || NULL == pKey || '\0' == pKey[0]) { |
888 | 0 | return; |
889 | 0 | } |
890 | | |
891 | 0 | char item[256] = {0}; |
892 | 0 | if (NULL != pHash2Label) { |
893 | 0 | (void)snprintf(item, sizeof(item), "%s=%s[%s=%d,%s=%d]", pLabel, pKey, pHash1Label, (int)hit1, pHash2Label, |
894 | 0 | (int)hit2); |
895 | 0 | } else { |
896 | 0 | (void)snprintf(item, sizeof(item), "%s=%s[%s=%d]", pLabel, pKey, pHash1Label, (int)hit1); |
897 | 0 | } |
898 | 0 | fqAppendSlotDiagItem(pBuf, bufLen, pPos, item); |
899 | 0 | } |
900 | | |
901 | 0 | static bool fqSlotKeyMatchesFocus(const char* pKey, const char* pFocus) { |
902 | 0 | return (NULL != pKey && NULL != pFocus && '\0' != pFocus[0] && NULL != strstr(pKey, pFocus)); |
903 | 0 | } |
904 | | |
905 | | static void fqBuildSlotHashSummary(SHashObj* pHash, const char* pFocus1, const char* pFocus2, const char* pFocus3, |
906 | 0 | char* pBuf, int32_t bufLen) { |
907 | 0 | if (NULL == pBuf || bufLen <= 0) { |
908 | 0 | return; |
909 | 0 | } |
910 | | |
911 | 0 | pBuf[0] = '\0'; |
912 | 0 | if (NULL == pHash) { |
913 | 0 | (void)snprintf(pBuf, bufLen, "size=0 hash=(nil)"); |
914 | 0 | return; |
915 | 0 | } |
916 | | |
917 | 0 | char focusBuf[512] = {0}; |
918 | 0 | char sampleBuf[512] = {0}; |
919 | 0 | int32_t focusPos = 0; |
920 | 0 | int32_t samplePos = 0; |
921 | 0 | int32_t focusCnt = 0; |
922 | 0 | int32_t sampleCnt = 0; |
923 | 0 | int32_t iterCnt = 0; |
924 | 0 | void* pIter = taosHashIterate(pHash, NULL); |
925 | 0 | while (NULL != pIter && iterCnt < 64) { |
926 | 0 | size_t keyLen = 0; |
927 | 0 | const char* pKey = taosHashGetKey(pIter, &keyLen); |
928 | 0 | if (NULL != pKey && '\0' != pKey[0]) { |
929 | 0 | if (sampleCnt < 8) { |
930 | 0 | fqAppendSlotDiagItem(sampleBuf, sizeof(sampleBuf), &samplePos, pKey); |
931 | 0 | ++sampleCnt; |
932 | 0 | } |
933 | 0 | if (focusCnt < 6 && |
934 | 0 | (fqSlotKeyMatchesFocus(pKey, pFocus1) || fqSlotKeyMatchesFocus(pKey, pFocus2) || |
935 | 0 | fqSlotKeyMatchesFocus(pKey, pFocus3))) { |
936 | 0 | fqAppendSlotDiagItem(focusBuf, sizeof(focusBuf), &focusPos, pKey); |
937 | 0 | ++focusCnt; |
938 | 0 | } |
939 | 0 | } |
940 | 0 | ++iterCnt; |
941 | 0 | pIter = taosHashIterate(pHash, pIter); |
942 | 0 | } |
943 | |
|
944 | 0 | (void)snprintf(pBuf, bufLen, "size=%d iter=%d focus=[%s] sample=[%s]", (int32_t)taosHashGetSize(pHash), iterCnt, |
945 | 0 | ('\0' != focusBuf[0] ? focusBuf : "-"), ('\0' != sampleBuf[0] ? sampleBuf : "-")); |
946 | 0 | } |
947 | | |
948 | | static void fqLogSlotLookupMiss(const char* pTag, const SColumnNode* pCol, const char* pRawKey, const char* pProjKey, |
949 | | SHashObj* pHash1, const char* pHash1Label, SHashObj* pHash2, |
950 | | const char* pHash2Label, SHashObj* pProjHash1, const char* pProjHash1Label, |
951 | 0 | SHashObj* pProjHash2, const char* pProjHash2Label) { |
952 | 0 | if (NULL == pTag || NULL == pCol) { |
953 | 0 | return; |
954 | 0 | } |
955 | | |
956 | 0 | char attempts[1024] = {0}; |
957 | 0 | int32_t attemptsPos = 0; |
958 | |
|
959 | 0 | fqAppendSlotKeyAttempt(attempts, sizeof(attempts), &attemptsPos, "raw", pRawKey, |
960 | 0 | fqSlotLookupHasHit(pHash1, pRawKey, strlen(pRawKey)), |
961 | 0 | fqSlotLookupHasHit(pHash2, pRawKey, strlen(pRawKey)), pHash1Label, pHash2Label); |
962 | |
|
963 | 0 | if (NULL != pProjKey && '\0' != pProjKey[0]) { |
964 | 0 | fqAppendSlotKeyAttempt(attempts, sizeof(attempts), &attemptsPos, "projRef", pProjKey, |
965 | 0 | fqSlotLookupHasHit(pProjHash1, pProjKey, strlen(pProjKey)), |
966 | 0 | fqSlotLookupHasHit(pProjHash2, pProjKey, strlen(pProjKey)), pProjHash1Label, |
967 | 0 | pProjHash2Label); |
968 | 0 | } |
969 | |
|
970 | 0 | char* pKey = NULL; |
971 | 0 | int32_t keyLen = 0; |
972 | 0 | int32_t keyCap = 0; |
973 | 0 | int32_t code = fqBuildUnqualifiedSlotKey(pCol->colName, 64, &pKey, &keyLen, &keyCap); |
974 | 0 | if (TSDB_CODE_SUCCESS == code) { |
975 | 0 | fqAppendSlotKeyAttempt(attempts, sizeof(attempts), &attemptsPos, "plainCol", pKey, |
976 | 0 | fqSlotLookupHasHit(pHash1, pKey, keyLen), fqSlotLookupHasHit(pHash2, pKey, keyLen), |
977 | 0 | pHash1Label, pHash2Label); |
978 | 0 | } |
979 | 0 | taosMemoryFree(pKey); |
980 | |
|
981 | 0 | pKey = NULL; |
982 | 0 | keyLen = 0; |
983 | 0 | keyCap = 0; |
984 | 0 | if ('\0' != pCol->node.aliasName[0]) { |
985 | 0 | code = fqBuildUnqualifiedSlotKey(pCol->node.aliasName, 64, &pKey, &keyLen, &keyCap); |
986 | 0 | if (TSDB_CODE_SUCCESS == code) { |
987 | 0 | fqAppendSlotKeyAttempt(attempts, sizeof(attempts), &attemptsPos, "alias", pKey, |
988 | 0 | fqSlotLookupHasHit(pHash1, pKey, keyLen), fqSlotLookupHasHit(pHash2, pKey, keyLen), |
989 | 0 | pHash1Label, pHash2Label); |
990 | 0 | } |
991 | 0 | taosMemoryFree(pKey); |
992 | 0 | } |
993 | |
|
994 | 0 | pKey = NULL; |
995 | 0 | keyLen = 0; |
996 | 0 | keyCap = 0; |
997 | 0 | if ('\0' != pCol->node.userAlias[0]) { |
998 | 0 | code = fqBuildUnqualifiedSlotKey(pCol->node.userAlias, 64, &pKey, &keyLen, &keyCap); |
999 | 0 | if (TSDB_CODE_SUCCESS == code) { |
1000 | 0 | fqAppendSlotKeyAttempt(attempts, sizeof(attempts), &attemptsPos, "userAlias", pKey, |
1001 | 0 | fqSlotLookupHasHit(pHash1, pKey, keyLen), fqSlotLookupHasHit(pHash2, pKey, keyLen), |
1002 | 0 | pHash1Label, pHash2Label); |
1003 | 0 | } |
1004 | 0 | taosMemoryFree(pKey); |
1005 | 0 | } |
1006 | |
|
1007 | 0 | pKey = NULL; |
1008 | 0 | keyLen = 0; |
1009 | 0 | keyCap = 0; |
1010 | 0 | if ('\0' != pCol->tableAlias[0]) { |
1011 | 0 | code = fqBuildQualifiedSlotKey(pCol->tableAlias, pCol->colName, 64, &pKey, &keyLen, &keyCap); |
1012 | 0 | if (TSDB_CODE_SUCCESS == code) { |
1013 | 0 | fqAppendSlotKeyAttempt(attempts, sizeof(attempts), &attemptsPos, "tableAlias.col", pKey, |
1014 | 0 | fqSlotLookupHasHit(pHash1, pKey, keyLen), fqSlotLookupHasHit(pHash2, pKey, keyLen), |
1015 | 0 | pHash1Label, pHash2Label); |
1016 | 0 | } |
1017 | 0 | taosMemoryFree(pKey); |
1018 | 0 | } |
1019 | |
|
1020 | 0 | pKey = NULL; |
1021 | 0 | keyLen = 0; |
1022 | 0 | keyCap = 0; |
1023 | 0 | if (pCol->hasRef) { |
1024 | 0 | code = fqBuildRefSlotKey(pCol, 64, &pKey, &keyLen, &keyCap); |
1025 | 0 | if (TSDB_CODE_SUCCESS == code) { |
1026 | 0 | fqAppendSlotKeyAttempt(attempts, sizeof(attempts), &attemptsPos, "refKey", pKey, |
1027 | 0 | fqSlotLookupHasHit(pHash1, pKey, keyLen), fqSlotLookupHasHit(pHash2, pKey, keyLen), |
1028 | 0 | pHash1Label, pHash2Label); |
1029 | 0 | } |
1030 | 0 | taosMemoryFree(pKey); |
1031 | 0 | } |
1032 | |
|
1033 | 0 | char hash1Summary[640] = {0}; |
1034 | 0 | char hash2Summary[640] = {0}; |
1035 | 0 | char projHash1Summary[640] = {0}; |
1036 | 0 | char projHash2Summary[640] = {0}; |
1037 | 0 | fqBuildSlotHashSummary(pHash1, pCol->colName, pCol->node.aliasName, pCol->node.userAlias, hash1Summary, |
1038 | 0 | sizeof(hash1Summary)); |
1039 | 0 | fqBuildSlotHashSummary(pHash2, pCol->colName, pCol->node.aliasName, pCol->node.userAlias, hash2Summary, |
1040 | 0 | sizeof(hash2Summary)); |
1041 | 0 | fqBuildSlotHashSummary(pProjHash1, pCol->colName, pCol->node.aliasName, pCol->node.userAlias, projHash1Summary, |
1042 | 0 | sizeof(projHash1Summary)); |
1043 | 0 | fqBuildSlotHashSummary(pProjHash2, pCol->colName, pCol->node.aliasName, pCol->node.userAlias, projHash2Summary, |
1044 | 0 | sizeof(projHash2Summary)); |
1045 | |
|
1046 | 0 | planDebug("%s: attempts=%s", pTag, attempts); |
1047 | 0 | planDebug("%s: normalHash %s={%s} %s={%s}", pTag, pHash1Label, hash1Summary, |
1048 | 0 | (NULL != pHash2Label ? pHash2Label : "hash2"), hash2Summary); |
1049 | 0 | planDebug("%s: projHash %s={%s} %s={%s}", pTag, pProjHash1Label, projHash1Summary, |
1050 | 0 | (NULL != pProjHash2Label ? pProjHash2Label : "projHash2"), projHash2Summary); |
1051 | 0 | } |
1052 | | |
1053 | 0 | static EDealRes doSetSlotId(SNode* pNode, void* pContext) { |
1054 | 0 | if (QUERY_NODE_COLUMN == nodeType(pNode) && 0 != strcmp(((SColumnNode*)pNode)->colName, "*")) { |
1055 | 0 | SSetSlotIdCxt* pCxt = (SSetSlotIdCxt*)pContext; |
1056 | 0 | SColumnNode* pCol = (SColumnNode*)pNode; |
1057 | 0 | bool preferLeft = NULL != pCxt->pLeftTableAlias && '\0' != pCxt->pLeftTableAlias[0] && |
1058 | 0 | 0 == strcmp(pCol->tableAlias, pCxt->pLeftTableAlias); |
1059 | 0 | bool preferRight = !preferLeft && NULL != pCxt->pRightTableAlias && '\0' != pCxt->pRightTableAlias[0] && |
1060 | 0 | 0 == strcmp(pCol->tableAlias, pCxt->pRightTableAlias); |
1061 | 0 | SHashObj* pFirstHash = preferRight ? pCxt->pRightHash : pCxt->pLeftHash; |
1062 | 0 | SHashObj* pSecondHash = preferRight ? pCxt->pLeftHash : pCxt->pRightHash; |
1063 | 0 | SHashObj* pFirstProjIdxHash = preferRight ? pCxt->pRightProdIdxHash : pCxt->pLeftProjIdxHash; |
1064 | 0 | SHashObj* pSecondProjIdxHash = preferRight ? pCxt->pLeftProjIdxHash : pCxt->pRightProdIdxHash; |
1065 | 0 | char* name = NULL; |
1066 | 0 | char rawLookupKey[TSDB_TABLE_FNAME_LEN + TSDB_COL_NAME_LEN + 96] = {0}; |
1067 | 0 | char projLookupKey[TSDB_TABLE_FNAME_LEN + TSDB_COL_NAME_LEN + 96] = {0}; |
1068 | 0 | int32_t len = 0; |
1069 | 0 | int32_t cap = 0; |
1070 | 0 | pCxt->errCode = getSlotKey(pNode, NULL, &name, &len, 64, &cap); |
1071 | 0 | if (TSDB_CODE_SUCCESS != pCxt->errCode) { |
1072 | 0 | return DEAL_RES_ERROR; |
1073 | 0 | } |
1074 | 0 | if (NULL != name) { |
1075 | 0 | tstrncpy(rawLookupKey, name, sizeof(rawLookupKey)); |
1076 | 0 | } |
1077 | 0 | SSlotIndex* pIndex = NULL; |
1078 | 0 | if (((SColumnNode*)pNode)->projRefIdx > 0) { |
1079 | 0 | snprintf(name + strlen(name), cap, "_%d", ((SColumnNode*)pNode)->projRefIdx); |
1080 | 0 | tstrncpy(projLookupKey, name, sizeof(projLookupKey)); |
1081 | 0 | pIndex = taosHashGet(pFirstProjIdxHash, name, strlen(name)); |
1082 | 0 | if (!pIndex) { |
1083 | 0 | pIndex = taosHashGet(pSecondProjIdxHash, name, strlen(name)); |
1084 | 0 | } |
1085 | 0 | } |
1086 | 0 | if (NULL == pIndex) { |
1087 | 0 | SSlotIndex* pFullIdx = taosHashGet(pFirstHash, name, len); |
1088 | 0 | if (NULL == pFullIdx) { |
1089 | 0 | pFullIdx = taosHashGet(pSecondHash, name, len); |
1090 | 0 | } |
1091 | 0 | if (NULL != pFullIdx) { |
1092 | 0 | pIndex = pFullIdx; |
1093 | 0 | } |
1094 | 0 | if (NULL == pIndex && false == pCol->hasRef && false == pCol->hasDep) { |
1095 | 0 | int32_t colLen = (int32_t)strlen(pCol->colName); |
1096 | 0 | if (colLen > 0) { |
1097 | 0 | pIndex = taosHashGet(pFirstHash, pCol->colName, colLen); |
1098 | 0 | if (NULL == pIndex) { |
1099 | 0 | pIndex = taosHashGet(pSecondHash, pCol->colName, colLen); |
1100 | 0 | } |
1101 | 0 | } |
1102 | |
|
1103 | 0 | if (NULL == pIndex && ((SExprNode*)pCol)->aliasName[0] != '\0') { |
1104 | 0 | int32_t aliasLen = (int32_t)strlen(((SExprNode*)pCol)->aliasName); |
1105 | 0 | pIndex = taosHashGet(pFirstHash, ((SExprNode*)pCol)->aliasName, aliasLen); |
1106 | 0 | if (NULL == pIndex) { |
1107 | 0 | pIndex = taosHashGet(pSecondHash, ((SExprNode*)pCol)->aliasName, aliasLen); |
1108 | 0 | } |
1109 | 0 | } |
1110 | 0 | } |
1111 | 0 | } |
1112 | 0 | if (NULL == pIndex) { |
1113 | 0 | name[len] = 0; |
1114 | 0 | pIndex = taosHashGet(pFirstHash, name, len); |
1115 | 0 | if (NULL == pIndex) { |
1116 | 0 | pIndex = taosHashGet(pSecondHash, name, len); |
1117 | 0 | } |
1118 | 0 | } |
1119 | | // pIndex is definitely not NULL, otherwise it is a bug |
1120 | 0 | if (NULL == pIndex) { |
1121 | 0 | planError("doSetSlotId failed, invalid slot name %s (colId=%d, tableAlias=%s, tableName=%s)", |
1122 | 0 | name, |
1123 | 0 | (QUERY_NODE_COLUMN == nodeType(pNode)) ? ((SColumnNode*)pNode)->colId : -1, |
1124 | 0 | (QUERY_NODE_COLUMN == nodeType(pNode)) ? ((SColumnNode*)pNode)->tableAlias : "?", |
1125 | 0 | (QUERY_NODE_COLUMN == nodeType(pNode)) ? ((SColumnNode*)pNode)->tableName : "?"); |
1126 | 0 | if (QUERY_NODE_COLUMN == nodeType(pNode)) { |
1127 | 0 | SColumnNode* pDbgCol = (SColumnNode*)pNode; |
1128 | 0 | planError("FQ-slotMiss: colName=%s aliasName=%s userAlias=%s hasRef=%d hasDep=%d projRefIdx=%d projIdx=%d relatedTo=%d leftHash=%p rightHash=%p", |
1129 | 0 | pDbgCol->colName, pDbgCol->node.aliasName, pDbgCol->node.userAlias, (int)pDbgCol->hasRef, |
1130 | 0 | (int)pDbgCol->hasDep, (int)pDbgCol->projRefIdx, (int)pDbgCol->projIdx, |
1131 | 0 | (int)pDbgCol->node.relatedTo, pCxt->pLeftHash, pCxt->pRightHash); |
1132 | 0 | fqLogSlotLookupMiss("FQ-slotMissDiag", pDbgCol, rawLookupKey, projLookupKey, pCxt->pLeftHash, "leftHash", |
1133 | 0 | pCxt->pRightHash, "rightHash", pCxt->pLeftProjIdxHash, "leftProjIdxHash", |
1134 | 0 | pCxt->pRightProdIdxHash, "rightProjIdxHash"); |
1135 | 0 | } |
1136 | 0 | pCxt->errCode = TSDB_CODE_PLAN_SLOT_NOT_FOUND; |
1137 | 0 | taosMemoryFree(name); |
1138 | 0 | return DEAL_RES_ERROR; |
1139 | 0 | } |
1140 | 0 | ((SColumnNode*)pNode)->dataBlockId = pIndex->dataBlockId; |
1141 | 0 | int16_t assignedSlot = ((SSlotIdInfo*)taosArrayGet(pIndex->pSlotIdsInfo, 0))->slotId; |
1142 | 0 | qDebug("doSetSlotId: colName='%s' aliasName='%s' tableAlias='%s' numSlots=%d assignedSlotId=%d", |
1143 | 0 | ((SColumnNode*)pNode)->colName, |
1144 | 0 | ((SExprNode*)pNode)->aliasName, |
1145 | 0 | ((SColumnNode*)pNode)->tableAlias, |
1146 | 0 | (int32_t)taosArrayGetSize(pIndex->pSlotIdsInfo), |
1147 | 0 | (int32_t)assignedSlot); |
1148 | 0 | ((SColumnNode*)pNode)->slotId = assignedSlot; |
1149 | 0 | taosMemoryFree(name); |
1150 | 0 | return DEAL_RES_IGNORE_CHILD; |
1151 | 0 | } |
1152 | 0 | return DEAL_RES_CONTINUE; |
1153 | 0 | } |
1154 | | |
1155 | 0 | static EDealRes doSetMultiTableSlotId(SNode* pNode, void* pContext) { |
1156 | 0 | if (QUERY_NODE_COLUMN == nodeType(pNode) && 0 != strcmp(((SColumnNode*)pNode)->colName, "*")) { |
1157 | 0 | SMultiTableSetSlotIdCxt* pCxt = (SMultiTableSetSlotIdCxt*)pContext; |
1158 | 0 | char* name = NULL; |
1159 | 0 | char rawLookupKey[TSDB_TABLE_FNAME_LEN + TSDB_COL_NAME_LEN + 96] = {0}; |
1160 | 0 | char projLookupKey[TSDB_TABLE_FNAME_LEN + TSDB_COL_NAME_LEN + 96] = {0}; |
1161 | 0 | int32_t len = 0; |
1162 | 0 | int32_t cap = 0; |
1163 | 0 | SColumnNode* pCol = (SColumnNode*)pNode; |
1164 | 0 | if (pCxt->isVtb && ((!pCol->hasRef && pCol->colType != COLUMN_TYPE_TAG && '\0' != pCol->tableAlias[0]) || (pCol->colId == PRIMARYKEY_TIMESTAMP_COL_ID))) { |
1165 | | // set slot id for : |
1166 | | // 1. column with ref |
1167 | | // 2. tag column |
1168 | | // 3. pseudo column function |
1169 | | |
1170 | | // even if ts column has ref, still skip it (VTB only). |
1171 | 0 | return DEAL_RES_CONTINUE; |
1172 | 0 | } |
1173 | | |
1174 | 0 | pCxt->errCode = getSlotKey(pNode, NULL, &name, &len, 16, &cap); |
1175 | 0 | if (TSDB_CODE_SUCCESS != pCxt->errCode) { |
1176 | 0 | return DEAL_RES_ERROR; |
1177 | 0 | } |
1178 | 0 | if (NULL != name) { |
1179 | 0 | tstrncpy(rawLookupKey, name, sizeof(rawLookupKey)); |
1180 | 0 | } |
1181 | 0 | SSlotIndex* pIndex = NULL; |
1182 | 0 | if (pCol->projRefIdx > 0) { |
1183 | 0 | snprintf(name + strlen(name), cap - strlen(name), "_%d", pCol->projRefIdx); |
1184 | 0 | tstrncpy(projLookupKey, name, sizeof(projLookupKey)); |
1185 | 0 | SSlotIndex** ppIndex = (SSlotIndex**)taosHashGet(pCxt->mergedProjIdxHash, name, strlen(name)); |
1186 | 0 | if (ppIndex) { |
1187 | 0 | pIndex = *ppIndex; |
1188 | 0 | } |
1189 | 0 | } else { |
1190 | 0 | SSlotIndex** ppIndex = (SSlotIndex**)taosHashGet(pCxt->mergedHash, name, len); |
1191 | 0 | if (ppIndex) { |
1192 | 0 | pIndex = *ppIndex; |
1193 | 0 | } |
1194 | 0 | } |
1195 | | // pIndex is definitely not NULL, otherwise it is a bug |
1196 | 0 | if (NULL == pIndex) { |
1197 | 0 | planError("doSetMultiTableSlotId failed, invalid slot name %s (col=%s, db=%s, tbl=%s, alias=%s, hasRef=%d, refDb=%s, refTbl=%s, refCol=%s, colType=%d, len=%d)", |
1198 | 0 | name, pCol->colName, pCol->dbName, pCol->tableName, pCol->tableAlias, |
1199 | 0 | pCol->hasRef, pCol->refDbName, pCol->refTableName, pCol->refColName, |
1200 | 0 | pCol->colType, len); |
1201 | 0 | fqLogSlotLookupMiss("FQ-multiSlotMissDiag", pCol, rawLookupKey, projLookupKey, pCxt->mergedHash, "mergedHash", |
1202 | 0 | NULL, NULL, pCxt->mergedProjIdxHash, "mergedProjIdxHash", NULL, NULL); |
1203 | 0 | pCxt->errCode = TSDB_CODE_PLAN_SLOT_NOT_FOUND; |
1204 | 0 | taosMemoryFree(name); |
1205 | 0 | return DEAL_RES_ERROR; |
1206 | 0 | } |
1207 | 0 | pCol->dataBlockId = pIndex->dataBlockId; |
1208 | 0 | pCol->slotId = ((SSlotIdInfo*)taosArrayGet(pIndex->pSlotIdsInfo, 0))->slotId; |
1209 | 0 | taosMemoryFree(name); |
1210 | 0 | return DEAL_RES_IGNORE_CHILD; |
1211 | 0 | } |
1212 | 0 | return DEAL_RES_CONTINUE; |
1213 | 0 | } |
1214 | | |
1215 | | static int32_t setNodeSlotIdImpl(SPhysiPlanContext* pCxt, int64_t leftDataBlockId, int64_t rightDataBlockId, |
1216 | | const char* pLeftTableAlias, const char* pRightTableAlias, SNode* pNode, |
1217 | 0 | SNode** pOutput) { |
1218 | 0 | if (NULL == pNode) { |
1219 | 0 | return TSDB_CODE_SUCCESS; |
1220 | 0 | } |
1221 | | |
1222 | 0 | SNode* pRes = NULL; |
1223 | 0 | int32_t code = nodesCloneNode(pNode, &pRes); |
1224 | 0 | if (NULL == pRes) { |
1225 | 0 | return code; |
1226 | 0 | } |
1227 | | |
1228 | 0 | SSetSlotIdCxt cxt = { |
1229 | 0 | .errCode = TSDB_CODE_SUCCESS, |
1230 | 0 | .pLeftHash = taosArrayGetP(pCxt->pLocationHelper, leftDataBlockId), |
1231 | 0 | .pLeftProjIdxHash = taosArrayGetP(pCxt->pProjIdxLocHelper, leftDataBlockId), |
1232 | 0 | .pRightHash = (rightDataBlockId < 0 ? NULL : taosArrayGetP(pCxt->pLocationHelper, rightDataBlockId)), |
1233 | 0 | .pRightProdIdxHash = (rightDataBlockId < 0 ? NULL : taosArrayGetP(pCxt->pProjIdxLocHelper, rightDataBlockId)), |
1234 | 0 | .pLeftTableAlias = pLeftTableAlias, |
1235 | 0 | .pRightTableAlias = pRightTableAlias}; |
1236 | 0 | nodesWalkExpr(pRes, doSetSlotId, &cxt); |
1237 | 0 | if (TSDB_CODE_SUCCESS != cxt.errCode) { |
1238 | 0 | nodesDestroyNode(pRes); |
1239 | 0 | return cxt.errCode; |
1240 | 0 | } |
1241 | 0 | *pOutput = pRes; |
1242 | 0 | return TSDB_CODE_SUCCESS; |
1243 | 0 | } |
1244 | | |
1245 | | static int32_t setNodeSlotIdWithAliases(SPhysiPlanContext* pCxt, int64_t leftDataBlockId, int64_t rightDataBlockId, |
1246 | | const char* pLeftAlias, const char* pRightAlias, SNode* pNode, |
1247 | 0 | SNode** pOutput) { |
1248 | 0 | return setNodeSlotIdImpl(pCxt, leftDataBlockId, rightDataBlockId, pLeftAlias, pRightAlias, pNode, pOutput); |
1249 | 0 | } |
1250 | | |
1251 | | static int32_t setNodeSlotId(SPhysiPlanContext* pCxt, int64_t leftDataBlockId, int64_t rightDataBlockId, SNode* pNode, |
1252 | 0 | SNode** pOutput) { |
1253 | 0 | return setNodeSlotIdWithAliases(pCxt, leftDataBlockId, rightDataBlockId, NULL, NULL, pNode, pOutput); |
1254 | 0 | } |
1255 | | |
1256 | | static int32_t setListSlotId(SPhysiPlanContext* pCxt, int64_t leftDataBlockId, int64_t rightDataBlockId, |
1257 | 0 | const SNodeList* pList, SNodeList** pOutput) { |
1258 | 0 | if (NULL == pList) { |
1259 | 0 | return TSDB_CODE_SUCCESS; |
1260 | 0 | } |
1261 | | |
1262 | 0 | SNodeList* pRes = NULL; |
1263 | 0 | int32_t code = nodesCloneList(pList, &pRes); |
1264 | 0 | if (NULL == pRes) { |
1265 | 0 | return code; |
1266 | 0 | } |
1267 | | |
1268 | 0 | SSetSlotIdCxt cxt = { |
1269 | 0 | .errCode = TSDB_CODE_SUCCESS, |
1270 | 0 | .pLeftHash = taosArrayGetP(pCxt->pLocationHelper, leftDataBlockId), |
1271 | 0 | .pLeftProjIdxHash = taosArrayGetP(pCxt->pProjIdxLocHelper, leftDataBlockId), |
1272 | 0 | .pRightHash = (rightDataBlockId < 0 ? NULL : taosArrayGetP(pCxt->pLocationHelper, rightDataBlockId)), |
1273 | 0 | .pRightProdIdxHash = (rightDataBlockId < 0 ? NULL : taosArrayGetP(pCxt->pProjIdxLocHelper, rightDataBlockId))}; |
1274 | 0 | nodesWalkExprs(pRes, doSetSlotId, &cxt); |
1275 | 0 | if (TSDB_CODE_SUCCESS != cxt.errCode) { |
1276 | 0 | nodesDestroyList(pRes); |
1277 | 0 | return cxt.errCode; |
1278 | 0 | } |
1279 | 0 | *pOutput = pRes; |
1280 | 0 | return TSDB_CODE_SUCCESS; |
1281 | 0 | } |
1282 | | |
1283 | 0 | static int32_t mergeSlotHashForChildren(SNodeList* pChild, SArray* hashArray, SHashObj** ppMerged) { |
1284 | 0 | int32_t capacity = 0; |
1285 | 0 | SNode* node = NULL; |
1286 | 0 | FOREACH(node, pChild) { |
1287 | 0 | SPhysiNode* pChildNode = (SPhysiNode*)node; |
1288 | 0 | if (pChildNode->pOutputDataBlockDesc && pChildNode->pOutputDataBlockDesc->pSlots) { |
1289 | 0 | capacity += LIST_LENGTH(pChildNode->pOutputDataBlockDesc->pSlots); |
1290 | 0 | } |
1291 | 0 | } |
1292 | 0 | if (capacity <= 0) { |
1293 | 0 | capacity = 1; |
1294 | 0 | } |
1295 | |
|
1296 | 0 | SHashObj* pMerged = |
1297 | 0 | taosHashInit(capacity, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), false, HASH_NO_LOCK); |
1298 | 0 | if (NULL == pMerged) { |
1299 | 0 | return terrno; |
1300 | 0 | } |
1301 | | |
1302 | 0 | FOREACH(node, pChild) { |
1303 | 0 | SPhysiNode* pChildNode = (SPhysiNode*)node; |
1304 | 0 | if (NULL == pChildNode->pOutputDataBlockDesc) { |
1305 | 0 | continue; |
1306 | 0 | } |
1307 | 0 | SHashObj* pSrc = taosArrayGetP(hashArray, (size_t)pChildNode->pOutputDataBlockDesc->dataBlockId); |
1308 | 0 | if (NULL == pSrc) { |
1309 | 0 | continue; |
1310 | 0 | } |
1311 | 0 | void* pIt = taosHashIterate(pSrc, NULL); |
1312 | 0 | while (pIt) { |
1313 | 0 | size_t keyLen = 0; |
1314 | 0 | char* pKey = taosHashGetKey(pIt, &keyLen); |
1315 | 0 | if (NULL == taosHashGet(pMerged, pKey, keyLen)) { |
1316 | 0 | SSlotIndex* pIndex = (SSlotIndex*)pIt; |
1317 | 0 | int32_t code = taosHashPut(pMerged, pKey, keyLen, &pIndex, POINTER_BYTES); |
1318 | 0 | if (TSDB_CODE_SUCCESS != code) { |
1319 | 0 | taosHashCleanup(pMerged); |
1320 | 0 | return code; |
1321 | 0 | } |
1322 | 0 | } |
1323 | 0 | pIt = taosHashIterate(pSrc, pIt); |
1324 | 0 | } |
1325 | 0 | } |
1326 | | |
1327 | 0 | *ppMerged = pMerged; |
1328 | 0 | return TSDB_CODE_SUCCESS; |
1329 | 0 | } |
1330 | | |
1331 | | static int32_t setMultiBlockSlotId(SPhysiPlanContext* pCxt, SNodeList* pChild, bool isVtb, const SNodeList* pList, |
1332 | 0 | SNodeList** pOutput) { |
1333 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
1334 | 0 | if (NULL == pList) { |
1335 | 0 | PLAN_RET(code); |
1336 | 0 | } |
1337 | | |
1338 | 0 | SNodeList* pRes = NULL; |
1339 | 0 | SHashObj* mergedHash = NULL; |
1340 | 0 | SHashObj* mergedProjIdxHash = NULL; |
1341 | |
|
1342 | 0 | PLAN_ERR_JRET(nodesCloneList(pList, &pRes)); |
1343 | | |
1344 | 0 | PLAN_ERR_JRET(mergeSlotHashForChildren(pChild, pCxt->pLocationHelper, &mergedHash)); |
1345 | 0 | PLAN_ERR_JRET(mergeSlotHashForChildren(pChild, pCxt->pProjIdxLocHelper, &mergedProjIdxHash)); |
1346 | | |
1347 | 0 | SMultiTableSetSlotIdCxt cxt = { |
1348 | 0 | .errCode = TSDB_CODE_SUCCESS, |
1349 | 0 | .hashArray = pCxt->pLocationHelper, |
1350 | 0 | .projIdxHashArray = pCxt->pProjIdxLocHelper, |
1351 | 0 | .mergedHash = mergedHash, |
1352 | 0 | .mergedProjIdxHash = mergedProjIdxHash, |
1353 | 0 | .pChild = pChild, |
1354 | 0 | .isVtb = isVtb |
1355 | 0 | }; |
1356 | |
|
1357 | 0 | nodesWalkExprs(pRes, doSetMultiTableSlotId, &cxt); |
1358 | 0 | PLAN_ERR_JRET(cxt.errCode); |
1359 | | |
1360 | 0 | *pOutput = pRes; |
1361 | 0 | taosHashCleanup(mergedHash); |
1362 | 0 | taosHashCleanup(mergedProjIdxHash); |
1363 | 0 | return code; |
1364 | 0 | _return: |
1365 | 0 | if (mergedHash) { |
1366 | 0 | taosHashCleanup(mergedHash); |
1367 | 0 | } |
1368 | 0 | if (mergedProjIdxHash) { |
1369 | 0 | taosHashCleanup(mergedProjIdxHash); |
1370 | 0 | } |
1371 | 0 | nodesDestroyList(pRes); |
1372 | 0 | return code; |
1373 | 0 | } |
1374 | | |
1375 | 0 | static SPhysiNode* makePhysiNode(SPhysiPlanContext* pCxt, SLogicNode* pLogicNode, ENodeType type) { |
1376 | 0 | SPhysiNode* pPhysiNode = NULL; |
1377 | 0 | int32_t code = nodesMakeNode(type, (SNode**)&pPhysiNode); |
1378 | 0 | if (NULL == pPhysiNode) { |
1379 | 0 | terrno = code; |
1380 | 0 | return NULL; |
1381 | 0 | } |
1382 | | |
1383 | 0 | TSWAP(pPhysiNode->pLimit, pLogicNode->pLimit); |
1384 | 0 | TSWAP(pPhysiNode->pSlimit, pLogicNode->pSlimit); |
1385 | 0 | pPhysiNode->dynamicOp = pLogicNode->dynamicOp; |
1386 | 0 | pPhysiNode->inputTsOrder = pLogicNode->inputTsOrder; |
1387 | 0 | pPhysiNode->outputTsOrder = pLogicNode->outputTsOrder; |
1388 | 0 | pPhysiNode->requireDataOrder = pLogicNode->requireDataOrder; |
1389 | 0 | pPhysiNode->resultDataOrder = pLogicNode->resultDataOrder; |
1390 | |
|
1391 | 0 | code = createDataBlockDesc(pCxt, pLogicNode->pTargets, &pPhysiNode->pOutputDataBlockDesc); |
1392 | 0 | if (TSDB_CODE_SUCCESS != code) { |
1393 | 0 | planError("FQ-Slots: makePhysiNode failed type=%d logicType=%d targets=%d code=0x%x", |
1394 | 0 | (int)type, (int)nodeType((SNode*)pLogicNode), |
1395 | 0 | pLogicNode->pTargets ? LIST_LENGTH(pLogicNode->pTargets) : 0, code); |
1396 | 0 | nodesDestroyNode((SNode*)pPhysiNode); |
1397 | 0 | terrno = code; |
1398 | 0 | return NULL; |
1399 | 0 | } |
1400 | 0 | pPhysiNode->pOutputDataBlockDesc->precision = pLogicNode->precision; |
1401 | 0 | return pPhysiNode; |
1402 | 0 | } |
1403 | | |
1404 | 0 | static int32_t setConditionsSlotId(SPhysiPlanContext* pCxt, const SLogicNode* pLogicNode, SPhysiNode* pPhysiNode) { |
1405 | 0 | if (NULL != pLogicNode->pConditions) { |
1406 | 0 | planDebug("FQ-slotCond: logicType=%d physiType=%d dataBlockId=%" PRId64 " conditions=%p", |
1407 | 0 | (int)nodeType((SNode*)pLogicNode), (int)nodeType((SNode*)pPhysiNode), |
1408 | 0 | pPhysiNode->pOutputDataBlockDesc ? pPhysiNode->pOutputDataBlockDesc->dataBlockId : -1, |
1409 | 0 | pLogicNode->pConditions); |
1410 | 0 | return setNodeSlotId(pCxt, pPhysiNode->pOutputDataBlockDesc->dataBlockId, -1, pLogicNode->pConditions, |
1411 | 0 | &pPhysiNode->pConditions); |
1412 | 0 | } |
1413 | 0 | return TSDB_CODE_SUCCESS; |
1414 | 0 | } |
1415 | | |
1416 | 0 | static bool isTableScanPhysiNode(const SScanPhysiNode* pScanPhysiNode) { |
1417 | 0 | switch (nodeType(pScanPhysiNode)) { |
1418 | 0 | case QUERY_NODE_PHYSICAL_PLAN_TABLE_SCAN: |
1419 | 0 | case QUERY_NODE_PHYSICAL_PLAN_TABLE_MERGE_SCAN: |
1420 | 0 | case QUERY_NODE_PHYSICAL_PLAN_STREAM_SCAN: |
1421 | 0 | return true; |
1422 | 0 | default: |
1423 | 0 | return false; |
1424 | 0 | } |
1425 | 0 | } |
1426 | | |
1427 | | static int32_t setTableScanPrimaryCondSlotId(SPhysiPlanContext* pCxt, const SScanLogicNode* pScanLogicNode, |
1428 | 0 | SScanPhysiNode* pScanPhysiNode) { |
1429 | 0 | if (NULL == pScanLogicNode->pPrimaryCond || !isTableScanPhysiNode(pScanPhysiNode)) { |
1430 | 0 | return TSDB_CODE_SUCCESS; |
1431 | 0 | } |
1432 | | |
1433 | 0 | STableScanPhysiNode* pTableScan = (STableScanPhysiNode*)pScanPhysiNode; |
1434 | 0 | return setNodeSlotId(pCxt, pScanPhysiNode->node.pOutputDataBlockDesc->dataBlockId, -1, pScanLogicNode->pPrimaryCond, |
1435 | 0 | &pTableScan->pPrimaryCond); |
1436 | 0 | } |
1437 | | |
1438 | 0 | static int32_t colIdCompare(const void* pLeft, const void* pRight) { |
1439 | 0 | SColumnNode* pLeftCol = *(SColumnNode**)pLeft; |
1440 | 0 | SColumnNode* pRightCol = *(SColumnNode**)pRight; |
1441 | 0 | return pLeftCol->colId > pRightCol->colId ? 1 : -1; |
1442 | 0 | } |
1443 | | |
1444 | 0 | static int32_t sortScanCols(SNodeList* pScanCols) { |
1445 | 0 | SArray* pArray = taosArrayInit(LIST_LENGTH(pScanCols), POINTER_BYTES); |
1446 | 0 | if (NULL == pArray) { |
1447 | 0 | return terrno; |
1448 | 0 | } |
1449 | | |
1450 | 0 | int32_t code = 0; |
1451 | 0 | SNode* pCol = NULL; |
1452 | 0 | FOREACH(pCol, pScanCols) { |
1453 | 0 | if (NULL == taosArrayPush(pArray, &pCol)) { |
1454 | 0 | code = terrno; |
1455 | 0 | break; |
1456 | 0 | } |
1457 | 0 | } |
1458 | 0 | if (TSDB_CODE_SUCCESS != code) { |
1459 | 0 | taosArrayDestroy(pArray); |
1460 | 0 | return code; |
1461 | 0 | } |
1462 | 0 | taosArraySort(pArray, colIdCompare); |
1463 | |
|
1464 | 0 | int32_t index = 0; |
1465 | 0 | FOREACH(pCol, pScanCols) { REPLACE_NODE(taosArrayGetP(pArray, index++)); } |
1466 | 0 | taosArrayDestroy(pArray); |
1467 | |
|
1468 | 0 | return TSDB_CODE_SUCCESS; |
1469 | 0 | } |
1470 | | |
1471 | 0 | static bool physiScanHasColumn(SNodeList* pList, const SColumnNode* pCol) { |
1472 | 0 | if (pList == NULL || pCol == NULL) { |
1473 | 0 | return false; |
1474 | 0 | } |
1475 | | |
1476 | 0 | SNode* pNode = NULL; |
1477 | 0 | FOREACH(pNode, pList) { |
1478 | 0 | SColumnNode* pExist = NULL; |
1479 | 0 | if (nodeType(pNode) == QUERY_NODE_TARGET) { |
1480 | 0 | STargetNode* pTarget = (STargetNode*)pNode; |
1481 | 0 | if (pTarget->pExpr != NULL && nodeType(pTarget->pExpr) == QUERY_NODE_COLUMN) { |
1482 | 0 | pExist = (SColumnNode*)pTarget->pExpr; |
1483 | 0 | } |
1484 | 0 | } else if (nodeType(pNode) == QUERY_NODE_COLUMN) { |
1485 | 0 | pExist = (SColumnNode*)pNode; |
1486 | 0 | } |
1487 | |
|
1488 | 0 | if (pExist == NULL) { |
1489 | 0 | continue; |
1490 | 0 | } |
1491 | | |
1492 | 0 | if (pExist->colId == pCol->colId && pExist->colType == pCol->colType && pExist->hasRef == pCol->hasRef && |
1493 | 0 | 0 == strcmp(pExist->tableAlias, pCol->tableAlias) && 0 == strcmp(pExist->refDbName, pCol->refDbName) && |
1494 | 0 | 0 == strcmp(pExist->refTableName, pCol->refTableName) && 0 == strcmp(pExist->refColName, pCol->refColName)) { |
1495 | 0 | return true; |
1496 | 0 | } |
1497 | 0 | } |
1498 | | |
1499 | 0 | return false; |
1500 | 0 | } |
1501 | | |
1502 | 0 | static int32_t appendPhysiScanTbnameFunc(SNodeList** ppList, const SColumnNode* pCol) { |
1503 | 0 | if (ppList == NULL || pCol == NULL) { |
1504 | 0 | return TSDB_CODE_SUCCESS; |
1505 | 0 | } |
1506 | | |
1507 | 0 | SNode* pNode = NULL; |
1508 | 0 | FOREACH(pNode, *ppList) { |
1509 | 0 | if (QUERY_NODE_FUNCTION == nodeType(pNode) && FUNCTION_TYPE_TBNAME == ((SFunctionNode*)pNode)->funcType) { |
1510 | 0 | return TSDB_CODE_SUCCESS; |
1511 | 0 | } |
1512 | 0 | } |
1513 | | |
1514 | 0 | SFunctionNode* pFunc = NULL; |
1515 | 0 | int32_t code = nodesMakeNode(QUERY_NODE_FUNCTION, (SNode**)&pFunc); |
1516 | 0 | if (TSDB_CODE_SUCCESS != code) { |
1517 | 0 | return code; |
1518 | 0 | } |
1519 | | |
1520 | 0 | tstrncpy(pFunc->functionName, "tbname", TSDB_FUNC_NAME_LEN); |
1521 | 0 | pFunc->funcType = FUNCTION_TYPE_TBNAME; |
1522 | 0 | pFunc->node.resType = pCol->node.resType; |
1523 | 0 | code = fmGetFuncInfo(pFunc, NULL, 0); |
1524 | 0 | if (TSDB_CODE_SUCCESS != code) { |
1525 | 0 | nodesDestroyNode((SNode*)pFunc); |
1526 | 0 | return code; |
1527 | 0 | } |
1528 | | // Strict append consumes the node on both success and failure. |
1529 | 0 | return nodesListMakeStrictAppend(ppList, (SNode*)pFunc); |
1530 | 0 | } |
1531 | | |
1532 | 0 | static int32_t appendPhysiScanColumn(SNodeList** ppList, const SColumnNode* pCol) { |
1533 | 0 | if (ppList == NULL || pCol == NULL || physiScanHasColumn(*ppList, pCol)) { |
1534 | 0 | return TSDB_CODE_SUCCESS; |
1535 | 0 | } |
1536 | | |
1537 | 0 | SNode* pClone = NULL; |
1538 | 0 | int32_t code = nodesCloneNode((SNode*)pCol, &pClone); |
1539 | 0 | if (TSDB_CODE_SUCCESS == code) { |
1540 | 0 | code = nodesListMakeStrictAppend(ppList, pClone); |
1541 | 0 | } |
1542 | 0 | return code; |
1543 | 0 | } |
1544 | | |
1545 | 0 | static int32_t appendPhysiLocalTagsFromList(SNodeList* pSrc, SNodeList** ppDst) { |
1546 | 0 | if (pSrc == NULL || ppDst == NULL) { |
1547 | 0 | return TSDB_CODE_SUCCESS; |
1548 | 0 | } |
1549 | | |
1550 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
1551 | 0 | SNode* pNode = NULL; |
1552 | 0 | FOREACH(pNode, pSrc) { |
1553 | 0 | SColumnNode* pCol = NULL; |
1554 | 0 | if (nodeType(pNode) == QUERY_NODE_TARGET) { |
1555 | 0 | STargetNode* pTarget = (STargetNode*)pNode; |
1556 | 0 | if (pTarget->pExpr != NULL && nodeType(pTarget->pExpr) == QUERY_NODE_COLUMN) { |
1557 | 0 | pCol = (SColumnNode*)pTarget->pExpr; |
1558 | 0 | } |
1559 | 0 | } else if (nodeType(pNode) == QUERY_NODE_COLUMN) { |
1560 | 0 | pCol = (SColumnNode*)pNode; |
1561 | 0 | } |
1562 | |
|
1563 | 0 | if (pCol == NULL || pCol->colType != COLUMN_TYPE_TAG || pCol->hasRef) { |
1564 | 0 | continue; |
1565 | 0 | } |
1566 | | |
1567 | 0 | code = appendPhysiScanColumn(ppDst, pCol); |
1568 | 0 | if (TSDB_CODE_SUCCESS != code) { |
1569 | 0 | break; |
1570 | 0 | } |
1571 | 0 | } |
1572 | |
|
1573 | 0 | return code; |
1574 | 0 | } |
1575 | | |
1576 | 0 | static int32_t createScanCols(SPhysiPlanContext* pCxt, SScanPhysiNode* pScanPhysiNode, SNodeList* pScanCols) { |
1577 | 0 | if (NULL == pScanCols) { |
1578 | 0 | return TSDB_CODE_SUCCESS; |
1579 | 0 | } |
1580 | | |
1581 | 0 | pScanPhysiNode->pScanCols = NULL; |
1582 | 0 | int32_t code = nodesCloneList(pScanCols, &pScanPhysiNode->pScanCols); |
1583 | 0 | if (NULL == pScanPhysiNode->pScanCols) { |
1584 | 0 | return code; |
1585 | 0 | } |
1586 | 0 | return sortScanCols(pScanPhysiNode->pScanCols); |
1587 | 0 | } |
1588 | | |
1589 | 0 | static int32_t appendConditionColsToPhysiScan(SScanPhysiNode* pScanPhysiNode, SNode* pConditions) { |
1590 | 0 | if (NULL == pScanPhysiNode || NULL == pConditions) { |
1591 | 0 | return TSDB_CODE_SUCCESS; |
1592 | 0 | } |
1593 | | |
1594 | 0 | SNodeList* pCondCols = NULL; |
1595 | 0 | int32_t code = nodesCollectColumnsFromNode(pConditions, NULL, COLLECT_COL_TYPE_ALL, &pCondCols); |
1596 | 0 | if (TSDB_CODE_SUCCESS != code) { |
1597 | 0 | return code; |
1598 | 0 | } |
1599 | | |
1600 | 0 | SNode* pNode = NULL; |
1601 | 0 | FOREACH(pNode, pCondCols) { |
1602 | 0 | if (QUERY_NODE_COLUMN != nodeType(pNode)) { |
1603 | 0 | continue; |
1604 | 0 | } |
1605 | | |
1606 | 0 | SColumnNode* pCol = (SColumnNode*)pNode; |
1607 | 0 | if (COLUMN_TYPE_TAG == pCol->colType) { |
1608 | 0 | code = appendPhysiScanColumn(&pScanPhysiNode->pScanPseudoCols, pCol); |
1609 | 0 | } else if (COLUMN_TYPE_TBNAME == pCol->colType) { |
1610 | 0 | code = appendPhysiScanTbnameFunc(&pScanPhysiNode->pScanPseudoCols, pCol); |
1611 | 0 | } else { |
1612 | 0 | code = appendPhysiScanColumn(&pScanPhysiNode->pScanCols, pCol); |
1613 | 0 | } |
1614 | 0 | if (TSDB_CODE_SUCCESS != code) { |
1615 | 0 | break; |
1616 | 0 | } |
1617 | 0 | } |
1618 | |
|
1619 | 0 | nodesDestroyList(pCondCols); |
1620 | |
|
1621 | 0 | if (TSDB_CODE_SUCCESS == code) { |
1622 | 0 | code = sortScanCols(pScanPhysiNode->pScanCols); |
1623 | 0 | } |
1624 | |
|
1625 | 0 | return code; |
1626 | 0 | } |
1627 | | |
1628 | | static int32_t createScanPhysiNodeFinalize(SPhysiPlanContext* pCxt, SSubplan* pSubplan, SScanLogicNode* pScanLogicNode, |
1629 | 0 | SScanPhysiNode* pScanPhysiNode, SPhysiNode** pPhyNode) { |
1630 | 0 | int32_t code = createScanCols(pCxt, pScanPhysiNode, pScanLogicNode->pScanCols); |
1631 | 0 | if (TSDB_CODE_SUCCESS == code && NULL != pScanLogicNode->pScanPseudoCols) { |
1632 | 0 | pScanPhysiNode->pScanPseudoCols = NULL; |
1633 | 0 | code = nodesCloneList(pScanLogicNode->pScanPseudoCols, &pScanPhysiNode->pScanPseudoCols); |
1634 | 0 | } |
1635 | |
|
1636 | 0 | if (TSDB_CODE_SUCCESS == code) { |
1637 | 0 | code = appendConditionColsToPhysiScan(pScanPhysiNode, pScanLogicNode->node.pConditions); |
1638 | 0 | } |
1639 | |
|
1640 | 0 | if (TSDB_CODE_SUCCESS == code) { |
1641 | 0 | code = addDataBlockSlots(pCxt, pScanPhysiNode->pScanCols, pScanPhysiNode->node.pOutputDataBlockDesc); |
1642 | 0 | } |
1643 | |
|
1644 | 0 | if (TSDB_CODE_SUCCESS == code) { |
1645 | 0 | code = addDataBlockSlots(pCxt, pScanPhysiNode->pScanPseudoCols, pScanPhysiNode->node.pOutputDataBlockDesc); |
1646 | 0 | } |
1647 | |
|
1648 | 0 | if (TSDB_CODE_SUCCESS == code) { |
1649 | 0 | code = setConditionsSlotId(pCxt, (const SLogicNode*)pScanLogicNode, (SPhysiNode*)pScanPhysiNode); |
1650 | 0 | } |
1651 | |
|
1652 | 0 | if (TSDB_CODE_SUCCESS == code) { |
1653 | 0 | code = setTableScanPrimaryCondSlotId(pCxt, pScanLogicNode, pScanPhysiNode); |
1654 | 0 | } |
1655 | |
|
1656 | 0 | if (TSDB_CODE_SUCCESS == code) { |
1657 | 0 | pScanPhysiNode->uid = pScanLogicNode->tableId; |
1658 | 0 | pScanPhysiNode->suid = pScanLogicNode->stableId; |
1659 | 0 | pScanPhysiNode->tableType = pScanLogicNode->tableType; |
1660 | 0 | pScanPhysiNode->groupOrderScan = pScanLogicNode->groupOrderScan; |
1661 | 0 | pScanPhysiNode->virtualStableScan = pScanLogicNode->virtualStableScan; |
1662 | 0 | pScanPhysiNode->outputTsPrecision = pScanLogicNode->outputTsPrecision; |
1663 | 0 | pScanPhysiNode->useTriggerTableList = pScanLogicNode->phTbnameScan; |
1664 | 0 | memcpy(&pScanPhysiNode->tableName, &pScanLogicNode->tableName, sizeof(SName)); |
1665 | 0 | nodesDestroyNode(pSubplan->pTagCond); |
1666 | 0 | pSubplan->pTagCond = NULL; |
1667 | 0 | if (NULL != pScanLogicNode->pTagCond) { |
1668 | 0 | code = nodesCloneNode(pScanLogicNode->pTagCond, &pSubplan->pTagCond); |
1669 | 0 | } |
1670 | 0 | } |
1671 | |
|
1672 | 0 | if (TSDB_CODE_SUCCESS == code) { |
1673 | 0 | nodesDestroyNode(pSubplan->pTagIndexCond); |
1674 | 0 | pSubplan->pTagIndexCond = NULL; |
1675 | 0 | if (NULL != pScanLogicNode->pTagIndexCond) { |
1676 | 0 | code = nodesCloneNode(pScanLogicNode->pTagIndexCond, &pSubplan->pTagIndexCond); |
1677 | 0 | } |
1678 | 0 | } |
1679 | |
|
1680 | 0 | if (TSDB_CODE_SUCCESS == code) { |
1681 | 0 | *pPhyNode = (SPhysiNode*)pScanPhysiNode; |
1682 | 0 | } else { |
1683 | 0 | nodesDestroyNode((SNode*)pScanPhysiNode); |
1684 | 0 | } |
1685 | |
|
1686 | 0 | return code; |
1687 | 0 | } |
1688 | | |
1689 | 0 | static void vgroupInfoToNodeAddr(const SVgroupInfo* vg, SQueryNodeAddr* pNodeAddr) { |
1690 | 0 | pNodeAddr->nodeId = vg->vgId; |
1691 | 0 | pNodeAddr->epSet = vg->epSet; |
1692 | 0 | } |
1693 | | |
1694 | 0 | static ENodeType getScanOperatorType(EScanType scanType) { |
1695 | 0 | switch (scanType) { |
1696 | 0 | case SCAN_TYPE_TAG: |
1697 | 0 | return QUERY_NODE_PHYSICAL_PLAN_TAG_SCAN; |
1698 | 0 | case SCAN_TYPE_TABLE: |
1699 | 0 | return QUERY_NODE_PHYSICAL_PLAN_TABLE_SCAN; |
1700 | 0 | case SCAN_TYPE_STREAM: |
1701 | 0 | return QUERY_NODE_PHYSICAL_PLAN_STREAM_SCAN; |
1702 | 0 | case SCAN_TYPE_TABLE_MERGE: |
1703 | 0 | return QUERY_NODE_PHYSICAL_PLAN_TABLE_MERGE_SCAN; |
1704 | 0 | case SCAN_TYPE_BLOCK_INFO: |
1705 | 0 | return QUERY_NODE_PHYSICAL_PLAN_BLOCK_DIST_SCAN; |
1706 | 0 | case SCAN_TYPE_TABLE_COUNT: |
1707 | 0 | return QUERY_NODE_PHYSICAL_PLAN_TABLE_COUNT_SCAN; |
1708 | 0 | default: |
1709 | 0 | break; |
1710 | 0 | } |
1711 | 0 | return QUERY_NODE_PHYSICAL_PLAN_TABLE_SCAN; |
1712 | 0 | } |
1713 | | |
1714 | | static int32_t createSimpleScanPhysiNode(SPhysiPlanContext* pCxt, SSubplan* pSubplan, SScanLogicNode* pScanLogicNode, |
1715 | 0 | SPhysiNode** pPhyNode) { |
1716 | 0 | SScanPhysiNode* pScan = |
1717 | 0 | (SScanPhysiNode*)makePhysiNode(pCxt, (SLogicNode*)pScanLogicNode, getScanOperatorType(pScanLogicNode->scanType)); |
1718 | 0 | if (NULL == pScan) { |
1719 | 0 | return terrno; |
1720 | 0 | } |
1721 | | |
1722 | 0 | if (pScanLogicNode->pVgroupList) { |
1723 | 0 | vgroupInfoToNodeAddr(pScanLogicNode->pVgroupList->vgroups, &pSubplan->execNode); |
1724 | 0 | } |
1725 | 0 | return createScanPhysiNodeFinalize(pCxt, pSubplan, pScanLogicNode, pScan, pPhyNode); |
1726 | 0 | } |
1727 | | |
1728 | | static int32_t createTagScanPhysiNode(SPhysiPlanContext* pCxt, SSubplan* pSubplan, SScanLogicNode* pScanLogicNode, |
1729 | 0 | SPhysiNode** pPhyNode) { |
1730 | 0 | STagScanPhysiNode* pScan = |
1731 | 0 | (STagScanPhysiNode*)makePhysiNode(pCxt, (SLogicNode*)pScanLogicNode, QUERY_NODE_PHYSICAL_PLAN_TAG_SCAN); |
1732 | 0 | if (NULL == pScan) { |
1733 | 0 | return terrno; |
1734 | 0 | } |
1735 | 0 | if (pScanLogicNode->pVgroupList) { |
1736 | 0 | vgroupInfoToNodeAddr(pScanLogicNode->pVgroupList->vgroups, &pSubplan->execNode); |
1737 | 0 | } |
1738 | 0 | pScan->onlyMetaCtbIdx = pScanLogicNode->onlyMetaCtbIdx; |
1739 | |
|
1740 | 0 | return createScanPhysiNodeFinalize(pCxt, pSubplan, pScanLogicNode, (SScanPhysiNode*)pScan, pPhyNode); |
1741 | 0 | } |
1742 | | |
1743 | 0 | static bool canBatchLastRowScanRead(const SScanLogicNode* pScan) { |
1744 | 0 | return NULL != pScan && SCAN_TYPE_LAST_ROW == pScan->scanType; |
1745 | 0 | } |
1746 | | |
1747 | | static int32_t createLastRowScanPhysiNode(SPhysiPlanContext* pCxt, SSubplan* pSubplan, SScanLogicNode* pScanLogicNode, |
1748 | 0 | SPhysiNode** pPhyNode) { |
1749 | 0 | SLastRowScanPhysiNode* pScan = |
1750 | 0 | (SLastRowScanPhysiNode*)makePhysiNode(pCxt, (SLogicNode*)pScanLogicNode, QUERY_NODE_PHYSICAL_PLAN_LAST_ROW_SCAN); |
1751 | 0 | if (NULL == pScan) { |
1752 | 0 | return terrno; |
1753 | 0 | } |
1754 | 0 | pScan->pTargets = NULL; |
1755 | 0 | int32_t code = nodesCloneList(pScanLogicNode->node.pTargets, &pScan->pTargets); |
1756 | 0 | if (TSDB_CODE_SUCCESS != code) { |
1757 | 0 | nodesDestroyNode((SNode*)pScan); |
1758 | 0 | return code; |
1759 | 0 | } |
1760 | 0 | pScan->pGroupTags = NULL; |
1761 | 0 | code = nodesCloneList(pScanLogicNode->pGroupTags, &pScan->pGroupTags); |
1762 | 0 | if (TSDB_CODE_SUCCESS != code) { |
1763 | 0 | nodesDestroyNode((SNode*)pScan); |
1764 | 0 | return code; |
1765 | 0 | } |
1766 | | |
1767 | 0 | pScan->groupSort = pScanLogicNode->groupSort; |
1768 | 0 | pScan->ignoreNull = pScanLogicNode->igLastNull; |
1769 | 0 | pScan->batchMultiTableRead = canBatchLastRowScanRead(pScanLogicNode); |
1770 | |
|
1771 | 0 | if (pScanLogicNode->pVgroupList) { |
1772 | 0 | vgroupInfoToNodeAddr(pScanLogicNode->pVgroupList->vgroups, &pSubplan->execNode); |
1773 | 0 | } |
1774 | |
|
1775 | 0 | code = createScanPhysiNodeFinalize(pCxt, pSubplan, pScanLogicNode, (SScanPhysiNode*)pScan, pPhyNode); |
1776 | 0 | if (TSDB_CODE_SUCCESS == code && pScanLogicNode->pFuncTypes != NULL) { |
1777 | 0 | pScan->pFuncTypes = taosArrayInit(taosArrayGetSize(pScanLogicNode->pFuncTypes), sizeof(int32_t)); |
1778 | 0 | if (NULL == pScan->pFuncTypes) { |
1779 | 0 | return terrno; |
1780 | 0 | } |
1781 | | |
1782 | 0 | SNode* pTargetNode = NULL; |
1783 | 0 | int funcTypeIndex = 0; |
1784 | 0 | FOREACH(pTargetNode, ((SScanPhysiNode*)pScan)->pScanCols) { |
1785 | 0 | if (((STargetNode*)pTargetNode)->pExpr->type != QUERY_NODE_COLUMN) { |
1786 | 0 | continue; |
1787 | 0 | } |
1788 | 0 | SColumnNode* pColNode = (SColumnNode*)((STargetNode*)pTargetNode)->pExpr; |
1789 | |
|
1790 | 0 | for (int i = 0; i < TARRAY_SIZE(pScanLogicNode->pFuncTypes); ++i) { |
1791 | 0 | SFunctParam* pFunctParam = taosArrayGet(pScanLogicNode->pFuncTypes, i); |
1792 | 0 | if (pColNode->colId == pFunctParam->pCol->colId && |
1793 | 0 | 0 == strncmp(pColNode->colName, pFunctParam->pCol->name, strlen(pColNode->colName))) { |
1794 | 0 | if (NULL == taosArrayInsert(pScan->pFuncTypes, funcTypeIndex, &pFunctParam->type)) { |
1795 | 0 | code = terrno; |
1796 | 0 | } |
1797 | 0 | break; |
1798 | 0 | } |
1799 | 0 | } |
1800 | 0 | funcTypeIndex++; |
1801 | 0 | } |
1802 | 0 | } |
1803 | 0 | return code; |
1804 | 0 | } |
1805 | | |
1806 | | static int32_t createTableCountScanPhysiNode(SPhysiPlanContext* pCxt, SSubplan* pSubplan, |
1807 | 0 | SScanLogicNode* pScanLogicNode, SPhysiNode** pPhyNode) { |
1808 | | // A dedicated node type carries the row type filter: older vnodes fail loudly on the unknown node |
1809 | | // type instead of silently ignoring the filter and returning an unfiltered count. |
1810 | 0 | ENodeType nodeType = (0 != pScanLogicNode->tbCountType) ? QUERY_NODE_PHYSICAL_PLAN_TABLE_COUNT_SCAN_BY_TYPE |
1811 | 0 | : QUERY_NODE_PHYSICAL_PLAN_TABLE_COUNT_SCAN; |
1812 | 0 | STableCountScanPhysiNode* pScan = |
1813 | 0 | (STableCountScanPhysiNode*)makePhysiNode(pCxt, (SLogicNode*)pScanLogicNode, nodeType); |
1814 | 0 | if (NULL == pScan) { |
1815 | 0 | return terrno; |
1816 | 0 | } |
1817 | | |
1818 | 0 | pScan->pGroupTags = NULL; |
1819 | 0 | int32_t code = nodesCloneList(pScanLogicNode->pGroupTags, &pScan->pGroupTags); |
1820 | 0 | if (NULL != pScanLogicNode->pGroupTags && NULL == pScan->pGroupTags) { |
1821 | 0 | nodesDestroyNode((SNode*)pScan); |
1822 | 0 | return code; |
1823 | 0 | } |
1824 | | |
1825 | 0 | pScan->groupSort = pScanLogicNode->groupSort; |
1826 | 0 | pScan->tbCountType = pScanLogicNode->tbCountType; |
1827 | 0 | if (pScanLogicNode->pVgroupList) { |
1828 | 0 | vgroupInfoToNodeAddr(pScanLogicNode->pVgroupList->vgroups, &pSubplan->execNode); |
1829 | 0 | } |
1830 | 0 | return createScanPhysiNodeFinalize(pCxt, pSubplan, pScanLogicNode, (SScanPhysiNode*)pScan, pPhyNode); |
1831 | 0 | } |
1832 | | |
1833 | | static int32_t createTableScanPhysiNode(SPhysiPlanContext* pCxt, SSubplan* pSubplan, SScanLogicNode* pScanLogicNode, |
1834 | 0 | SPhysiNode** pPhyNode) { |
1835 | 0 | STableScanPhysiNode* pTableScan = (STableScanPhysiNode*)makePhysiNode(pCxt, (SLogicNode*)pScanLogicNode, |
1836 | 0 | getScanOperatorType(pScanLogicNode->scanType)); |
1837 | 0 | if (NULL == pTableScan) { |
1838 | 0 | return terrno; |
1839 | 0 | } |
1840 | | |
1841 | 0 | memcpy(pTableScan->scanSeq, pScanLogicNode->scanSeq, sizeof(pScanLogicNode->scanSeq)); |
1842 | 0 | pTableScan->twoPassRescanSource = pScanLogicNode->twoPassRescanSource; |
1843 | 0 | pTableScan->scanRange = pScanLogicNode->scanRange; |
1844 | 0 | TSWAP(pTableScan->pExtScanRange, pScanLogicNode->pExtScanRange); |
1845 | 0 | pTableScan->interpMode = pScanLogicNode->interpMode; |
1846 | 0 | pTableScan->interpFillMode = pScanLogicNode->interpFillMode; |
1847 | 0 | pTableScan->ratio = pScanLogicNode->ratio; |
1848 | 0 | if (pScanLogicNode->pVgroupList) { |
1849 | 0 | vgroupInfoToNodeAddr(pScanLogicNode->pVgroupList->vgroups, &pSubplan->execNode); |
1850 | 0 | pSubplan->execNodeStat.tableNum = pScanLogicNode->pVgroupList->vgroups[0].numOfTable; |
1851 | 0 | } |
1852 | 0 | (void)tNameGetFullDbName(&pScanLogicNode->tableName, pSubplan->dbFName); |
1853 | 0 | pTableScan->dataRequired = pScanLogicNode->dataRequired; |
1854 | 0 | pTableScan->lastOnlyScan = pScanLogicNode->lastOnlyScan; |
1855 | 0 | pTableScan->pDynamicScanFuncs = NULL; |
1856 | 0 | int32_t code = nodesCloneList(pScanLogicNode->pDynamicScanFuncs, &pTableScan->pDynamicScanFuncs); |
1857 | 0 | if (TSDB_CODE_SUCCESS != code) { |
1858 | 0 | nodesDestroyNode((SNode*)pTableScan); |
1859 | 0 | return code; |
1860 | 0 | } |
1861 | 0 | pTableScan->pGroupTags = NULL; |
1862 | 0 | code = nodesCloneList(pScanLogicNode->pGroupTags, &pTableScan->pGroupTags); |
1863 | 0 | if (TSDB_CODE_SUCCESS != code) { |
1864 | 0 | nodesDestroyNode((SNode*)pTableScan); |
1865 | 0 | return code; |
1866 | 0 | } |
1867 | 0 | code = nodesCloneNode(pScanLogicNode->pTimeRange, &pTableScan->pTimeRange); |
1868 | 0 | if (TSDB_CODE_SUCCESS != code) { |
1869 | 0 | nodesDestroyNode((SNode*)pTableScan); |
1870 | 0 | return code; |
1871 | 0 | } |
1872 | 0 | code = nodesCloneNode(pScanLogicNode->pExtTimeRange, &pTableScan->pExtTimeRange); |
1873 | 0 | if (TSDB_CODE_SUCCESS != code) { |
1874 | 0 | nodesDestroyNode((SNode*)pTableScan); |
1875 | 0 | return code; |
1876 | 0 | } |
1877 | 0 | pTableScan->groupSort = pScanLogicNode->groupSort; |
1878 | 0 | pTableScan->interval = pScanLogicNode->interval; |
1879 | 0 | pTableScan->offset = pScanLogicNode->offset; |
1880 | 0 | pTableScan->sliding = pScanLogicNode->sliding; |
1881 | 0 | pTableScan->intervalUnit = pScanLogicNode->intervalUnit; |
1882 | 0 | pTableScan->slidingUnit = pScanLogicNode->slidingUnit; |
1883 | 0 | pTableScan->fastInterval = pScanLogicNode->fastInterval; |
1884 | 0 | pTableScan->exInterval = pScanLogicNode->exInterval; |
1885 | 0 | pTableScan->firstDayOfWeek = pScanLogicNode->firstDayOfWeek; |
1886 | 0 | pTableScan->timezone = pScanLogicNode->timezone; |
1887 | 0 | tstrncpy(pTableScan->timezoneName, pScanLogicNode->timezoneName, sizeof(pTableScan->timezoneName)); |
1888 | 0 | pTableScan->triggerType = pScanLogicNode->triggerType; |
1889 | 0 | pTableScan->watermark = pScanLogicNode->watermark; |
1890 | 0 | pTableScan->igExpired = pScanLogicNode->igExpired; |
1891 | 0 | pTableScan->igCheckUpdate = pScanLogicNode->igCheckUpdate; |
1892 | 0 | pTableScan->assignBlockUid = pCxt->pPlanCxt->rSmaQuery ? true : false; |
1893 | 0 | pTableScan->filesetDelimited = pScanLogicNode->filesetDelimited; |
1894 | 0 | pTableScan->needCountEmptyTable = pScanLogicNode->isCountByTag; |
1895 | 0 | pTableScan->paraTablesSort = pScanLogicNode->paraTablesSort; |
1896 | 0 | pTableScan->smallDataTsSort = pScanLogicNode->smallDataTsSort; |
1897 | |
|
1898 | 0 | return createScanPhysiNodeFinalize(pCxt, pSubplan, pScanLogicNode, (SScanPhysiNode*)pTableScan, pPhyNode);; |
1899 | 0 | } |
1900 | | |
1901 | | static int32_t createSystemTableScanPhysiNode(SPhysiPlanContext* pCxt, SSubplan* pSubplan, |
1902 | 0 | SScanLogicNode* pScanLogicNode, SPhysiNode** pPhyNode) { |
1903 | 0 | SSystemTableScanPhysiNode* pScan = (SSystemTableScanPhysiNode*)makePhysiNode(pCxt, (SLogicNode*)pScanLogicNode, |
1904 | 0 | QUERY_NODE_PHYSICAL_PLAN_SYSTABLE_SCAN); |
1905 | 0 | if (NULL == pScan) { |
1906 | 0 | return terrno; |
1907 | 0 | } |
1908 | | |
1909 | 0 | pSubplan->showRewrite = pScanLogicNode->showRewrite; |
1910 | 0 | pScan->showRewrite = pScanLogicNode->showRewrite; |
1911 | 0 | pScan->xnodeDsnOutputMode = pScanLogicNode->xnodeDsnOutputMode; |
1912 | 0 | pScan->accountId = pCxt->pPlanCxt->acctId; |
1913 | 0 | pScan->sysInfo = pCxt->pPlanCxt->sysInfo; |
1914 | 0 | pScan->privInfo = pCxt->pPlanCxt->privInfo; |
1915 | | // Bind the connection's effective charset so the executor renders NCHAR/JSON |
1916 | | // system-table tag values in the client charset. taosConvCharset resolves a |
1917 | | // NULL context to the local process default (client-side plans carry the |
1918 | | // client charset; server-built plans carry the server charset), so serialize |
1919 | | // it unconditionally; only genuinely old plans lack the field and fall back to |
1920 | | // the server default at decode. |
1921 | 0 | tstrncpy(pScan->charsetName, taosConvCharset(pCxt->pPlanCxt->charsetCxt), |
1922 | 0 | TD_CHARSET_LEN); |
1923 | 0 | if (0 == strcmp(pScanLogicNode->tableName.tname, TSDB_INS_TABLE_TABLES) || |
1924 | 0 | 0 == strcmp(pScanLogicNode->tableName.tname, TSDB_INS_TABLE_TAGS) || |
1925 | 0 | 0 == strcmp(pScanLogicNode->tableName.tname, TSDB_INS_TABLE_COLS) || |
1926 | 0 | 0 == strcmp(pScanLogicNode->tableName.tname, TSDB_INS_DISK_USAGE) || |
1927 | 0 | 0 == strcmp(pScanLogicNode->tableName.tname, TSDB_INS_TABLE_LAST_CACHE_STATS) || |
1928 | 0 | 0 == strcmp(pScanLogicNode->tableName.tname, TSDB_INS_TABLE_FILESETS) || |
1929 | 0 | 0 == strcmp(pScanLogicNode->tableName.tname, TSDB_INS_TABLE_VC_COLS) || |
1930 | 0 | 0 == strcmp(pScanLogicNode->tableName.tname, TSDB_INS_TABLE_VIRTUAL_TABLES_REFERENCING) || |
1931 | 0 | 0 == strcmp(pScanLogicNode->tableName.tname, TSDB_INS_TABLE_TABLE_FIXED_DISTRIBUTED)) { |
1932 | 0 | if (pScanLogicNode->pVgroupList) { |
1933 | 0 | vgroupInfoToNodeAddr(pScanLogicNode->pVgroupList->vgroups, &pSubplan->execNode); |
1934 | 0 | } |
1935 | 0 | } else { |
1936 | 0 | pSubplan->execNode.nodeId = MNODE_HANDLE; |
1937 | 0 | pSubplan->execNode.epSet = pCxt->pPlanCxt->mgmtEpSet; |
1938 | 0 | } |
1939 | 0 | if ((0 == strcmp(pScanLogicNode->tableName.tname, TSDB_INS_TABLE_DNODE_VARIABLES) || |
1940 | 0 | 0 == strcmp(pScanLogicNode->tableName.tname, TSDB_INS_TABLE_CPU_ALLOCATION)) && |
1941 | 0 | pScanLogicNode->pVgroupList) { |
1942 | 0 | pScan->mgmtEpSet = pScanLogicNode->pVgroupList->vgroups->epSet; |
1943 | 0 | } else { |
1944 | 0 | pScan->mgmtEpSet = pCxt->pPlanCxt->mgmtEpSet; |
1945 | 0 | } |
1946 | 0 | (void)tNameGetFullDbName(&pScanLogicNode->tableName, pSubplan->dbFName); |
1947 | |
|
1948 | 0 | return createScanPhysiNodeFinalize(pCxt, pSubplan, pScanLogicNode, (SScanPhysiNode*)pScan, pPhyNode); |
1949 | 0 | } |
1950 | | |
1951 | | static int32_t createStreamScanPhysiNode(SPhysiPlanContext* pCxt, SSubplan* pSubplan, SScanLogicNode* pScanLogicNode, |
1952 | 0 | SPhysiNode** pPhyNode) { |
1953 | 0 | return createTableScanPhysiNode(pCxt, pSubplan, pScanLogicNode, pPhyNode); |
1954 | 0 | } |
1955 | | |
1956 | | static int32_t createTableMergeScanPhysiNode(SPhysiPlanContext* pCxt, SSubplan* pSubplan, |
1957 | 0 | SScanLogicNode* pScanLogicNode, SPhysiNode** pPhyNode) { |
1958 | 0 | return createTableScanPhysiNode(pCxt, pSubplan, pScanLogicNode, pPhyNode); |
1959 | 0 | } |
1960 | | |
1961 | | // --------------------------------------------------------------------------- |
1962 | | // --- Remote-plan helpers ---------------------------------------------------- |
1963 | | // Convert one logic node from pRemoteLogicPlan into its lightweight physi |
1964 | | // counterpart and wire pChild as its single child. |
1965 | | // pLeaf is passed so LIMIT can be propagated down to the leaf WHERE node. |
1966 | | static int32_t remoteLogicNodeToPhysi(SLogicNode* pLogicNode, SPhysiNode* pChild, |
1967 | 0 | SFederatedScanPhysiNode* pLeaf, SPhysiNode** pOut) { |
1968 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
1969 | 0 | ENodeType type = nodeType(pLogicNode); |
1970 | 0 | SPhysiNode* pPhys = NULL; |
1971 | 0 |
|
1972 | 0 | if (type == QUERY_NODE_LOGIC_PLAN_SORT) { |
1973 | 0 | SSortLogicNode* pSortLogic = (SSortLogicNode*)pLogicNode; |
1974 | 0 | SSortPhysiNode* pSort = NULL; |
1975 | 0 | code = nodesMakeNode(QUERY_NODE_PHYSICAL_PLAN_SORT, (SNode**)&pSort); |
1976 | 0 | if (TSDB_CODE_SUCCESS != code) return code; |
1977 | 0 |
|
1978 | 0 | code = nodesCloneList(pSortLogic->pSortKeys, &pSort->pSortKeys); |
1979 | 0 | if (TSDB_CODE_SUCCESS != code) { nodesDestroyNode((SNode*)pSort); return code; } |
1980 | 0 |
|
1981 | 0 | // Clone pTargets so the executor can derive output column info from the |
1982 | 0 | // topmost remote physical node (used for pColTypeMappings reconstruction). |
1983 | 0 | code = nodesCloneList(pSortLogic->node.pTargets, &pSort->pTargets); |
1984 | 0 | if (TSDB_CODE_SUCCESS != code) { nodesDestroyNode((SNode*)pSort); return code; } |
1985 | 0 |
|
1986 | 0 | if (NULL == pLeaf->node.pLimit && NULL != pSortLogic->node.pLimit) { |
1987 | 0 | code = nodesCloneNode(pSortLogic->node.pLimit, &pLeaf->node.pLimit); |
1988 | 0 | if (TSDB_CODE_SUCCESS != code) { nodesDestroyNode((SNode*)pSort); return code; } |
1989 | 0 | } |
1990 | 0 | code = nodesMakeList(&pSort->node.pChildren); |
1991 | 0 | if (TSDB_CODE_SUCCESS != code) { nodesDestroyNode((SNode*)pSort); return code; } |
1992 | 0 | code = nodesListStrictAppend(pSort->node.pChildren, (SNode*)pChild); |
1993 | 0 | if (TSDB_CODE_SUCCESS != code) { nodesDestroyNode((SNode*)pSort); return code; } |
1994 | 0 | pChild->pParent = (SPhysiNode*)pSort; |
1995 | 0 | pPhys = (SPhysiNode*)pSort; |
1996 | 0 |
|
1997 | 0 | } else if (type == QUERY_NODE_LOGIC_PLAN_PROJECT) { |
1998 | 0 | SProjectLogicNode* pProjLogic = (SProjectLogicNode*)pLogicNode; |
1999 | 0 | SProjectPhysiNode* pProj = NULL; |
2000 | 0 | code = nodesMakeNode(QUERY_NODE_PHYSICAL_PLAN_PROJECT, (SNode**)&pProj); |
2001 | 0 | if (TSDB_CODE_SUCCESS != code) return code; |
2002 | 0 |
|
2003 | 0 | code = nodesCloneList(pProjLogic->pProjections, &pProj->pProjections); |
2004 | 0 | if (TSDB_CODE_SUCCESS != code) { nodesDestroyNode((SNode*)pProj); return code; } |
2005 | 0 |
|
2006 | 0 | if (NULL == pLeaf->node.pLimit && NULL != pProjLogic->node.pLimit) { |
2007 | 0 | code = nodesCloneNode(pProjLogic->node.pLimit, &pLeaf->node.pLimit); |
2008 | 0 | if (TSDB_CODE_SUCCESS != code) { nodesDestroyNode((SNode*)pProj); return code; } |
2009 | 0 | } |
2010 | 0 | code = nodesMakeList(&pProj->node.pChildren); |
2011 | 0 | if (TSDB_CODE_SUCCESS != code) { nodesDestroyNode((SNode*)pProj); return code; } |
2012 | 0 | code = nodesListStrictAppend(pProj->node.pChildren, (SNode*)pChild); |
2013 | 0 | if (TSDB_CODE_SUCCESS != code) { nodesDestroyNode((SNode*)pProj); return code; } |
2014 | 0 | pChild->pParent = (SPhysiNode*)pProj; |
2015 | 0 | pPhys = (SPhysiNode*)pProj; |
2016 | 0 |
|
2017 | 0 | } else { |
2018 | 0 | planError("remoteLogicNodeToPhysi: unsupported logic node type %d in pRemoteLogicPlan", type); |
2019 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
2020 | 0 | } |
2021 | 0 |
|
2022 | 0 | *pOut = pPhys; |
2023 | 0 | return TSDB_CODE_SUCCESS; |
2024 | 0 | } |
2025 | 0 | static bool fqPhysiExprListAllColumns(const SNodeList* pExprList) { |
2026 | 0 | if (NULL == pExprList) { |
2027 | 0 | return true; |
2028 | 0 | } |
2029 | 0 |
|
2030 | 0 | SNode* pExpr = NULL; |
2031 | 0 | FOREACH(pExpr, pExprList) { |
2032 | 0 | const SNode* pInner = pExpr; |
2033 | 0 | if (nodeType(pInner) == QUERY_NODE_TARGET) { |
2034 | 0 | pInner = ((const STargetNode*)pInner)->pExpr; |
2035 | 0 | } |
2036 | 0 | if (NULL == pInner || nodeType(pInner) != QUERY_NODE_COLUMN) { |
2037 | 0 | return false; |
2038 | 0 | } |
2039 | 0 | } |
2040 | 0 |
|
2041 | 0 | return true; |
2042 | 0 | } |
2043 | | |
2044 | 0 | static bool fqPhysiOutputNeedsRemoteMapping(const SNode* pExprNode) { |
2045 | 0 | if (NULL == pExprNode) { |
2046 | 0 | return false; |
2047 | 0 | } |
2048 | 0 |
|
2049 | 0 | const SNode* pExpr = pExprNode; |
2050 | 0 | if (QUERY_NODE_TARGET == nodeType(pExpr)) { |
2051 | 0 | pExpr = ((const STargetNode*)pExpr)->pExpr; |
2052 | 0 | } |
2053 | 0 |
|
2054 | 0 | // Folded constant outputs (VALUE) do not need remote data mapping. |
2055 | 0 | // Remote side may execute SELECT 1 as row anchor, while the executor |
2056 | 0 | // overwrites output slots from VALUE expressions locally. |
2057 | 0 | return pExpr != NULL && nodeType(pExpr) != QUERY_NODE_VALUE; |
2058 | 0 | } |
2059 | | |
2060 | 0 | static void fqCopyTimezoneNameOnly(char* pDst, int32_t dstSize, const char* pSrc) { |
2061 | 0 | if (pDst == NULL || dstSize <= 0) { |
2062 | 0 | return; |
2063 | 0 | } |
2064 | 0 | pDst[0] = '\0'; |
2065 | 0 | if (pSrc == NULL || pSrc[0] == '\0') { |
2066 | 0 | return; |
2067 | 0 | } |
2068 | | |
2069 | 0 | const char* pSpace = strchr(pSrc, ' '); |
2070 | 0 | int32_t len = pSpace ? (int32_t)(pSpace - pSrc) : (int32_t)strlen(pSrc); |
2071 | 0 | if (len <= 0) { |
2072 | 0 | return; |
2073 | 0 | } |
2074 | 0 | if (len >= dstSize) { |
2075 | 0 | len = dstSize - 1; |
2076 | 0 | } |
2077 | 0 | memcpy(pDst, pSrc, len); |
2078 | 0 | pDst[len] = '\0'; |
2079 | 0 | } |
2080 | | |
2081 | 0 | static void fqSetFederatedScanTimezone(const SPhysiPlanContext* pCxt, SFederatedScanPhysiNode* pScan) { |
2082 | 0 | if (pCxt == NULL || pScan == NULL) { |
2083 | 0 | return; |
2084 | 0 | } |
2085 | | |
2086 | 0 | const SPlanContext* pPlanCxt = pCxt->pPlanCxt; |
2087 | 0 | if (pPlanCxt != NULL && pPlanCxt->timezoneExplicit && pPlanCxt->timezoneName[0] != '\0') { |
2088 | 0 | tstrncpy(pScan->timezone, pPlanCxt->timezoneName, sizeof(pScan->timezone)); |
2089 | 0 | return; |
2090 | 0 | } |
2091 | | |
2092 | 0 | fqCopyTimezoneNameOnly(pScan->timezone, sizeof(pScan->timezone), tsTimezoneStr); |
2093 | 0 | if (pScan->timezone[0] != '\0') { |
2094 | 0 | return; |
2095 | 0 | } |
2096 | | |
2097 | 0 | if (pPlanCxt != NULL && pPlanCxt->timezoneName[0] != '\0') { |
2098 | 0 | tstrncpy(pScan->timezone, pPlanCxt->timezoneName, sizeof(pScan->timezone)); |
2099 | 0 | return; |
2100 | 0 | } |
2101 | | |
2102 | 0 | char sysTz[TD_TIMEZONE_LEN] = {0}; |
2103 | 0 | (void)taosGetSystemTimezone(sysTz); |
2104 | 0 | fqCopyTimezoneNameOnly(pScan->timezone, sizeof(pScan->timezone), sysTz); |
2105 | 0 | } |
2106 | | |
2107 | 0 | static SNodeList* fqFindRemoteProjectOutputs(SLogicNode* pRoot) { |
2108 | 0 | SLogicNode* pCur = pRoot; |
2109 | 0 | while (pCur != NULL) { |
2110 | 0 | if (QUERY_NODE_LOGIC_PLAN_PROJECT == nodeType((SNode*)pCur)) { |
2111 | 0 | SNodeList* pProj = ((SProjectLogicNode*)pCur)->pProjections; |
2112 | 0 | if (pProj != NULL && LIST_LENGTH(pProj) > 0) { |
2113 | 0 | return pProj; |
2114 | 0 | } |
2115 | 0 | } |
2116 | 0 |
|
2117 | 0 | if (NULL == pCur->pChildren || LIST_LENGTH(pCur->pChildren) != 1) { |
2118 | 0 | break; |
2119 | 0 | } |
2120 | 0 | pCur = (SLogicNode*)nodesListGetNode(pCur->pChildren, 0); |
2121 | 0 | } |
2122 | 0 |
|
2123 | 0 | return NULL; |
2124 | 0 | } |
2125 | | |
2126 | 0 | static void fqFormatLogicColList(const SNodeList* pCols, char* pBuf, int32_t bufLen) { |
2127 | 0 | if (NULL == pBuf || bufLen <= 0) { |
2128 | 0 | return; |
2129 | 0 | } |
2130 | | |
2131 | 0 | pBuf[0] = '\0'; |
2132 | 0 | if (NULL == pCols) { |
2133 | 0 | tstrncpy(pBuf, "(NULL)", (size_t)bufLen); |
2134 | 0 | return; |
2135 | 0 | } |
2136 | | |
2137 | 0 | int32_t off = 0; |
2138 | 0 | SNode* pCol = NULL; |
2139 | 0 | FOREACH(pCol, pCols) { |
2140 | 0 | const char* name = "?"; |
2141 | 0 | if (QUERY_NODE_COLUMN == nodeType(pCol)) { |
2142 | 0 | name = ((const SColumnNode*)pCol)->colName; |
2143 | 0 | } else if (QUERY_NODE_TARGET == nodeType(pCol)) { |
2144 | 0 | const SNode* pExpr = ((const STargetNode*)pCol)->pExpr; |
2145 | 0 | if (pExpr != NULL && QUERY_NODE_COLUMN == nodeType(pExpr)) { |
2146 | 0 | name = ((const SColumnNode*)pExpr)->colName; |
2147 | 0 | } |
2148 | 0 | } |
2149 | |
|
2150 | 0 | off += snprintf(pBuf + off, (size_t)(bufLen - off), "%s%s", off > 0 ? "," : "", name); |
2151 | 0 | if (off >= bufLen - 1) { |
2152 | 0 | break; |
2153 | 0 | } |
2154 | 0 | } |
2155 | |
|
2156 | 0 | if ('\0' == pBuf[0]) { |
2157 | 0 | tstrncpy(pBuf, "(EMPTY)", (size_t)bufLen); |
2158 | 0 | } |
2159 | 0 | } |
2160 | | |
2161 | 0 | static int32_t fqReplaceLogicTargets(SLogicNode* pNode, const SNodeList* pAlignedCols, const char* pTag) { |
2162 | 0 | if (NULL == pNode || NULL == pAlignedCols) { |
2163 | 0 | return TSDB_CODE_SUCCESS; |
2164 | 0 | } |
2165 | | |
2166 | 0 | char beforeBuf[512] = {0}; |
2167 | 0 | char afterBuf[512] = {0}; |
2168 | 0 | fqFormatLogicColList(pNode->pTargets, beforeBuf, sizeof(beforeBuf)); |
2169 | 0 | fqFormatLogicColList(pAlignedCols, afterBuf, sizeof(afterBuf)); |
2170 | |
|
2171 | 0 | SNodeList* pCloned = NULL; |
2172 | 0 | int32_t code = nodesCloneList((SNodeList*)pAlignedCols, &pCloned); |
2173 | 0 | if (TSDB_CODE_SUCCESS != code) { |
2174 | 0 | planError("FQ-RemoteCols: clone aligned targets failed, tag=%s rootType=%d code:0x%x", |
2175 | 0 | NULL != pTag ? pTag : "(null)", (int)nodeType((SNode*)pNode), code); |
2176 | 0 | return code; |
2177 | 0 | } |
2178 | | |
2179 | 0 | nodesDestroyList(pNode->pTargets); |
2180 | 0 | pNode->pTargets = pCloned; |
2181 | 0 | planDebug("FQ-RemoteCols: aligned %s targets, nodeType=%d targetsBefore=[%s] targetsAfter=[%s]", |
2182 | 0 | NULL != pTag ? pTag : "(null)", (int)nodeType((SNode*)pNode), beforeBuf, afterBuf); |
2183 | 0 | return TSDB_CODE_SUCCESS; |
2184 | 0 | } |
2185 | | |
2186 | 0 | static SScanLogicNode* fqFindExternalLogicLeafScan(SLogicNode* pNode) { |
2187 | 0 | if (NULL == pNode) { |
2188 | 0 | return NULL; |
2189 | 0 | } |
2190 | | |
2191 | 0 | if (QUERY_NODE_LOGIC_PLAN_SCAN == nodeType((SNode*)pNode)) { |
2192 | 0 | SScanLogicNode* pScan = (SScanLogicNode*)pNode; |
2193 | 0 | if (SCAN_TYPE_EXTERNAL == pScan->scanType) { |
2194 | 0 | return pScan; |
2195 | 0 | } |
2196 | 0 | } |
2197 | | |
2198 | 0 | if (NULL == pNode->pChildren) { |
2199 | 0 | return NULL; |
2200 | 0 | } |
2201 | | |
2202 | 0 | SNode* pChild = NULL; |
2203 | 0 | FOREACH(pChild, pNode->pChildren) { |
2204 | 0 | SScanLogicNode* pFound = fqFindExternalLogicLeafScan((SLogicNode*)pChild); |
2205 | 0 | if (pFound != NULL) { |
2206 | 0 | return pFound; |
2207 | 0 | } |
2208 | 0 | } |
2209 | | |
2210 | 0 | return NULL; |
2211 | 0 | } |
2212 | | |
2213 | | // Build the pRemotePlan physical tree from pScanLogicNode->pRemoteLogicPlan. |
2214 | | // Walks the logic chain top-down (collecting), then converts bottom-up so the |
2215 | | // leaf SFederatedScanPhysiNode ends up at the bottom of the chain. |
2216 | | // On error the entire chain (including pLeaf) is left for the caller to destroy. |
2217 | | // |
2218 | | // UNION ALL support: when the root of pRemoteLogicPlan is a SProjectLogicNode |
2219 | | // with isSetOpProj=true and multiple children, each child branch is converted |
2220 | | // independently (each gets its own Mode-2 FederatedScan leaf cloned from |
2221 | | // pLeaf) and wired as children of a SProjectPhysiNode container. |
2222 | | |
2223 | | // Helper: convert a single-chain logic plan into a physi plan chain. |
2224 | | // pChainRoot: root of the chain (Sort or Scan logic node). |
2225 | | // pLeafTemplate: the Mode-1 outer FederatedScanPhysiNode (for cloning Mode-2 leaves). |
2226 | | // pScanLogic: the original SScanLogicNode (for pExtTable, pScanCols info). |
2227 | | // On success, *pOut is the physi chain root; the Mode-2 leaf is at the bottom. |
2228 | | static int32_t buildRemoteBranchPhysi(SLogicNode* pChainRoot, |
2229 | | SFederatedScanPhysiNode* pLeafTemplate, |
2230 | | SScanLogicNode* pScanLogic, |
2231 | 0 | SPhysiNode** pOut) { |
2232 | 0 | // Collect chain into array |
2233 | 0 | SArray* pArr = taosArrayInit(4, POINTER_BYTES); |
2234 | 0 | if (NULL == pArr) return terrno; |
2235 | 0 |
|
2236 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
2237 | 0 | SLogicNode* pCurr = pChainRoot; |
2238 | 0 | while (pCurr != NULL) { |
2239 | 0 | // Stop at SScanLogicNode - it becomes the leaf, not a logic-to-physi conversion |
2240 | 0 | if (nodeType(pCurr) == QUERY_NODE_LOGIC_PLAN_SCAN) break; |
2241 | 0 | if (NULL == taosArrayPush(pArr, &pCurr)) { |
2242 | 0 | code = terrno; |
2243 | 0 | taosArrayDestroy(pArr); |
2244 | 0 | return code; |
2245 | 0 | } |
2246 | 0 | SNodeList* pChildren = pCurr->pChildren; |
2247 | 0 | pCurr = (pChildren && LIST_LENGTH(pChildren) > 0) |
2248 | 0 | ? (SLogicNode*)nodesListGetNode(pChildren, 0) : NULL; |
2249 | 0 | } |
2250 | 0 |
|
2251 | 0 | // Create the Mode-2 FederatedScan leaf for this branch |
2252 | 0 | SFederatedScanPhysiNode* pBranchLeaf = NULL; |
2253 | 0 | code = nodesMakeNode(QUERY_NODE_PHYSICAL_PLAN_FEDERATED_SCAN, (SNode**)&pBranchLeaf); |
2254 | 0 | if (TSDB_CODE_SUCCESS != code) { taosArrayDestroy(pArr); return code; } |
2255 | 0 |
|
2256 | 0 | // The branch leaf has its own pExtTable, pScanCols, and pConditions |
2257 | 0 | // from the SScanLogicNode at the bottom of this branch's chain. |
2258 | 0 | SScanLogicNode* pBranchScan = NULL; |
2259 | 0 | if (pCurr != NULL && nodeType(pCurr) == QUERY_NODE_LOGIC_PLAN_SCAN) { |
2260 | 0 | pBranchScan = (SScanLogicNode*)pCurr; |
2261 | 0 | } |
2262 | 0 |
|
2263 | 0 | if (pBranchScan != NULL) { |
2264 | 0 | // Clone from the branch's scan node |
2265 | 0 | code = nodesCloneNode(pBranchScan->pExtTableNode, &pBranchLeaf->pExtTable); |
2266 | 0 | if (TSDB_CODE_SUCCESS != code) { nodesDestroyNode((SNode*)pBranchLeaf); taosArrayDestroy(pArr); return code; } |
2267 | 0 | code = nodesCloneList(pBranchScan->pScanCols, &pBranchLeaf->pScanCols); |
2268 | 0 | if (TSDB_CODE_SUCCESS != code) { nodesDestroyNode((SNode*)pBranchLeaf); taosArrayDestroy(pArr); return code; } |
2269 | 0 | if (pBranchScan->node.pConditions != NULL) { |
2270 | 0 | code = nodesCloneNode(pBranchScan->node.pConditions, &pBranchLeaf->node.pConditions); |
2271 | 0 | if (TSDB_CODE_SUCCESS != code) { nodesDestroyNode((SNode*)pBranchLeaf); taosArrayDestroy(pArr); return code; } |
2272 | 0 | } |
2273 | 0 | if (pBranchScan->node.pLimit != NULL) { |
2274 | 0 | code = nodesCloneNode(pBranchScan->node.pLimit, &pBranchLeaf->node.pLimit); |
2275 | 0 | if (TSDB_CODE_SUCCESS != code) { nodesDestroyNode((SNode*)pBranchLeaf); taosArrayDestroy(pArr); return code; } |
2276 | 0 | } |
2277 | 0 | } else { |
2278 | 0 | // Fallback: clone from the outer scan's info |
2279 | 0 | code = nodesCloneNode(pScanLogic->pExtTableNode, &pBranchLeaf->pExtTable); |
2280 | 0 | if (TSDB_CODE_SUCCESS != code) { nodesDestroyNode((SNode*)pBranchLeaf); taosArrayDestroy(pArr); return code; } |
2281 | 0 | code = nodesCloneList(pScanLogic->pScanCols, &pBranchLeaf->pScanCols); |
2282 | 0 | if (TSDB_CODE_SUCCESS != code) { nodesDestroyNode((SNode*)pBranchLeaf); taosArrayDestroy(pArr); return code; } |
2283 | 0 | } |
2284 | 0 |
|
2285 | 0 | pBranchLeaf->pRemotePlan = NULL; // Mode-2 leaf |
2286 | 0 |
|
2287 | 0 | // Convert chain bottom-up |
2288 | 0 | int32_t n = (int32_t)taosArrayGetSize(pArr); |
2289 | 0 | SPhysiNode* pBottom = (SPhysiNode*)pBranchLeaf; |
2290 | 0 | for (int32_t i = n - 1; i >= 0; i--) { |
2291 | 0 | SLogicNode* pLogic = *(SLogicNode**)taosArrayGet(pArr, i); |
2292 | 0 | SPhysiNode* pNewTop = NULL; |
2293 | 0 | code = remoteLogicNodeToPhysi(pLogic, pBottom, pBranchLeaf, &pNewTop); |
2294 | 0 | if (TSDB_CODE_SUCCESS != code) { |
2295 | 0 | nodesDestroyNode((SNode*)pBottom); |
2296 | 0 | taosArrayDestroy(pArr); |
2297 | 0 | return code; |
2298 | 0 | } |
2299 | 0 | pBottom = pNewTop; |
2300 | 0 | } |
2301 | 0 |
|
2302 | 0 | taosArrayDestroy(pArr); |
2303 | 0 | *pOut = pBottom; |
2304 | 0 | return TSDB_CODE_SUCCESS; |
2305 | 0 | } |
2306 | | |
2307 | | static int32_t buildRemotePlanFromLogicPlan(SScanLogicNode* pScanLogic, |
2308 | | SFederatedScanPhysiNode* pLeaf, |
2309 | 0 | SPhysiNode** pRemoteRoot) { |
2310 | 0 | if (NULL == pScanLogic->pRemoteLogicPlan) { |
2311 | 0 | *pRemoteRoot = (SPhysiNode*)pLeaf; |
2312 | 0 | return TSDB_CODE_SUCCESS; |
2313 | 0 | } |
2314 | 0 |
|
2315 | 0 | SLogicNode* pLogicRoot = (SLogicNode*)pScanLogic->pRemoteLogicPlan; |
2316 | 0 |
|
2317 | 0 | // -- UNION ALL: multi-child Project with isSetOpProj=true -- |
2318 | 0 | if (nodeType(pLogicRoot) == QUERY_NODE_LOGIC_PLAN_PROJECT && |
2319 | 0 | ((SProjectLogicNode*)pLogicRoot)->isSetOpProj && |
2320 | 0 | pLogicRoot->pChildren != NULL && |
2321 | 0 | LIST_LENGTH(pLogicRoot->pChildren) > 1) { |
2322 | 0 | SProjectLogicNode* pSetOpLogic = (SProjectLogicNode*)pLogicRoot; |
2323 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
2324 | 0 |
|
2325 | 0 | // Create container SProjectPhysiNode |
2326 | 0 | SProjectPhysiNode* pUnionPhysi = NULL; |
2327 | 0 | code = nodesMakeNode(QUERY_NODE_PHYSICAL_PLAN_PROJECT, (SNode**)&pUnionPhysi); |
2328 | 0 | if (TSDB_CODE_SUCCESS != code) { *pRemoteRoot = (SPhysiNode*)pLeaf; return code; } |
2329 | 0 |
|
2330 | 0 | // Clone projections |
2331 | 0 | code = nodesCloneList(pSetOpLogic->pProjections, &pUnionPhysi->pProjections); |
2332 | 0 | if (TSDB_CODE_SUCCESS != code) { nodesDestroyNode((SNode*)pUnionPhysi); *pRemoteRoot = (SPhysiNode*)pLeaf; return code; } |
2333 | 0 |
|
2334 | 0 | code = nodesMakeList(&pUnionPhysi->node.pChildren); |
2335 | 0 | if (TSDB_CODE_SUCCESS != code) { nodesDestroyNode((SNode*)pUnionPhysi); *pRemoteRoot = (SPhysiNode*)pLeaf; return code; } |
2336 | 0 |
|
2337 | 0 | // Convert each child branch |
2338 | 0 | SNode* pChild = NULL; |
2339 | 0 | FOREACH(pChild, pLogicRoot->pChildren) { |
2340 | 0 | SPhysiNode* pBranchPhysi = NULL; |
2341 | 0 | code = buildRemoteBranchPhysi((SLogicNode*)pChild, pLeaf, pScanLogic, &pBranchPhysi); |
2342 | 0 | if (TSDB_CODE_SUCCESS != code) { |
2343 | 0 | nodesDestroyNode((SNode*)pUnionPhysi); |
2344 | 0 | *pRemoteRoot = (SPhysiNode*)pLeaf; |
2345 | 0 | return code; |
2346 | 0 | } |
2347 | 0 | pBranchPhysi->pParent = (SPhysiNode*)pUnionPhysi; |
2348 | 0 | code = nodesListStrictAppend(pUnionPhysi->node.pChildren, (SNode*)pBranchPhysi); |
2349 | 0 | if (TSDB_CODE_SUCCESS != code) { |
2350 | 0 | nodesDestroyNode((SNode*)pUnionPhysi); |
2351 | 0 | *pRemoteRoot = (SPhysiNode*)pLeaf; |
2352 | 0 | return code; |
2353 | 0 | } |
2354 | 0 | } |
2355 | 0 |
|
2356 | 0 | *pRemoteRoot = (SPhysiNode*)pUnionPhysi; |
2357 | 0 | return TSDB_CODE_SUCCESS; |
2358 | 0 | } |
2359 | 0 |
|
2360 | 0 | // -- Single-chain: existing behavior -- |
2361 | 0 | // Collect chain top-down into a temporary array. |
2362 | 0 | SArray* pArr = taosArrayInit(4, POINTER_BYTES); |
2363 | 0 | if (NULL == pArr) { |
2364 | 0 | *pRemoteRoot = (SPhysiNode*)pLeaf; |
2365 | 0 | return terrno; |
2366 | 0 | } |
2367 | 0 |
|
2368 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
2369 | 0 | SNode* pCurr = pScanLogic->pRemoteLogicPlan; |
2370 | 0 | while (pCurr != NULL) { |
2371 | 0 | if (NULL == taosArrayPush(pArr, &pCurr)) { |
2372 | 0 | code = terrno; |
2373 | 0 | *pRemoteRoot = (SPhysiNode*)pLeaf; |
2374 | 0 | goto _done; |
2375 | 0 | } |
2376 | 0 | SNodeList* pChildren = ((SLogicNode*)pCurr)->pChildren; |
2377 | 0 | pCurr = (pChildren && LIST_LENGTH(pChildren) > 0) ? nodesListGetNode(pChildren, 0) : NULL; |
2378 | 0 | } |
2379 | 0 |
|
2380 | 0 | // Convert bottom-up: start with pLeaf as the initial "current bottom". |
2381 | 0 | { |
2382 | 0 | SPhysiNode* pBottom = (SPhysiNode*)pLeaf; |
2383 | 0 | int32_t n = (int32_t)taosArrayGetSize(pArr); |
2384 | 0 | for (int32_t i = n - 1; i >= 0; i--) { |
2385 | 0 | SLogicNode* pLogic = *(SLogicNode**)taosArrayGet(pArr, i); |
2386 | 0 | SPhysiNode* pNewTop = NULL; |
2387 | 0 | code = remoteLogicNodeToPhysi(pLogic, pBottom, pLeaf, &pNewTop); |
2388 | 0 | if (TSDB_CODE_SUCCESS != code) { |
2389 | 0 | // On error, pBottom owns the partial chain (including pLeaf at the |
2390 | 0 | // bottom). Let the caller destroy it via pRemoteRoot. |
2391 | 0 | *pRemoteRoot = pBottom; |
2392 | 0 | goto _done; |
2393 | 0 | } |
2394 | 0 | pBottom = pNewTop; |
2395 | 0 | } |
2396 | 0 | *pRemoteRoot = pBottom; |
2397 | 0 | } |
2398 | 0 |
|
2399 | 0 | _done: |
2400 | 0 | taosArrayDestroy(pArr); |
2401 | 0 | return code; |
2402 | 0 | } |
2403 | | static int32_t fqAlignRemotePassthroughOutputsImpl(SLogicNode* pNode, const SNodeList* pAlignedCols, |
2404 | 0 | bool* pPassthrough) { |
2405 | 0 | if (NULL != pPassthrough) { |
2406 | 0 | *pPassthrough = false; |
2407 | 0 | } |
2408 | 0 | if (NULL == pNode || NULL == pAlignedCols) { |
2409 | 0 | return TSDB_CODE_SUCCESS; |
2410 | 0 | } |
2411 | | |
2412 | 0 | if (QUERY_NODE_LOGIC_PLAN_SCAN == nodeType((SNode*)pNode)) { |
2413 | 0 | SScanLogicNode* pScan = (SScanLogicNode*)pNode; |
2414 | 0 | if (SCAN_TYPE_EXTERNAL != pScan->scanType) { |
2415 | 0 | return TSDB_CODE_SUCCESS; |
2416 | 0 | } |
2417 | | |
2418 | 0 | char beforeBuf[512] = {0}; |
2419 | 0 | char afterBuf[512] = {0}; |
2420 | 0 | fqFormatLogicColList(pScan->pScanCols, beforeBuf, sizeof(beforeBuf)); |
2421 | 0 | fqFormatLogicColList(pAlignedCols, afterBuf, sizeof(afterBuf)); |
2422 | |
|
2423 | 0 | SNodeList* pCloned = NULL; |
2424 | 0 | int32_t code = nodesCloneList((SNodeList*)pAlignedCols, &pCloned); |
2425 | 0 | if (TSDB_CODE_SUCCESS != code) { |
2426 | 0 | planError("FQ-RemoteCols: clone aligned scan cols failed, remoteRootType=%d code:0x%x", |
2427 | 0 | (int)nodeType((SNode*)pNode), code); |
2428 | 0 | return code; |
2429 | 0 | } |
2430 | | |
2431 | 0 | nodesDestroyList(pScan->pScanCols); |
2432 | 0 | pScan->pScanCols = pCloned; |
2433 | 0 | planDebug("FQ-RemoteCols: aligned remote leaf scan cols, remoteRootType=%d leafBefore=[%s] leafAfter=[%s]", |
2434 | 0 | (int)nodeType((SNode*)pNode), beforeBuf, afterBuf); |
2435 | |
|
2436 | 0 | code = fqReplaceLogicTargets((SLogicNode*)pScan, pAlignedCols, "leaf-scan"); |
2437 | 0 | if (TSDB_CODE_SUCCESS != code) { |
2438 | 0 | return code; |
2439 | 0 | } |
2440 | | |
2441 | 0 | if (NULL != pPassthrough) { |
2442 | 0 | *pPassthrough = true; |
2443 | 0 | } |
2444 | 0 | return TSDB_CODE_SUCCESS; |
2445 | 0 | } |
2446 | | |
2447 | 0 | if (QUERY_NODE_LOGIC_PLAN_SORT == nodeType((SNode*)pNode) && |
2448 | 0 | NULL != pNode->pChildren && 1 == LIST_LENGTH(pNode->pChildren)) { |
2449 | 0 | bool childPassthrough = false; |
2450 | 0 | int32_t code = |
2451 | 0 | fqAlignRemotePassthroughOutputsImpl((SLogicNode*)nodesListGetNode(pNode->pChildren, 0), |
2452 | 0 | pAlignedCols, &childPassthrough); |
2453 | 0 | if (TSDB_CODE_SUCCESS != code) { |
2454 | 0 | return code; |
2455 | 0 | } |
2456 | 0 | if (childPassthrough) { |
2457 | 0 | code = fqReplaceLogicTargets(pNode, pAlignedCols, "sort-passthrough"); |
2458 | 0 | if (TSDB_CODE_SUCCESS != code) { |
2459 | 0 | return code; |
2460 | 0 | } |
2461 | 0 | if (NULL != pPassthrough) { |
2462 | 0 | *pPassthrough = true; |
2463 | 0 | } |
2464 | 0 | } else { |
2465 | 0 | planDebug("FQ-RemoteCols: skip sort target alignment, child is not passthrough, rootType=%d", |
2466 | 0 | (int)nodeType((SNode*)pNode)); |
2467 | 0 | } |
2468 | 0 | return TSDB_CODE_SUCCESS; |
2469 | 0 | } |
2470 | | |
2471 | 0 | planDebug("FQ-RemoteCols: skip passthrough alignment for remoteRootType=%d", (int)nodeType((SNode*)pNode)); |
2472 | 0 | return TSDB_CODE_SUCCESS; |
2473 | 0 | } |
2474 | | |
2475 | 0 | static int32_t fqAlignRemotePassthroughOutputs(SNode* pRemoteRoot, const SNodeList* pAlignedCols) { |
2476 | 0 | if (NULL == pRemoteRoot || NULL == pAlignedCols) { |
2477 | 0 | return TSDB_CODE_SUCCESS; |
2478 | 0 | } |
2479 | | |
2480 | 0 | bool passthrough = false; |
2481 | 0 | int32_t code = fqAlignRemotePassthroughOutputsImpl((SLogicNode*)pRemoteRoot, pAlignedCols, &passthrough); |
2482 | 0 | if (TSDB_CODE_SUCCESS != code) { |
2483 | 0 | return code; |
2484 | 0 | } |
2485 | 0 | if (!passthrough) { |
2486 | 0 | SScanLogicNode* pLeaf = fqFindExternalLogicLeafScan((SLogicNode*)pRemoteRoot); |
2487 | 0 | if (NULL == pLeaf) { |
2488 | 0 | planDebug("FQ-RemoteCols: no external logic leaf found for remoteRootType=%d", (int)nodeType(pRemoteRoot)); |
2489 | 0 | } |
2490 | 0 | } |
2491 | 0 | return TSDB_CODE_SUCCESS; |
2492 | 0 | } |
2493 | | |
2494 | 0 | static SNodeList* fqGetRemoteOutputTargets(SNode* pRemoteRoot) { |
2495 | 0 | if (NULL == pRemoteRoot) { |
2496 | 0 | return NULL; |
2497 | 0 | } |
2498 | | |
2499 | 0 | return ((SLogicNode*)pRemoteRoot)->pTargets; |
2500 | 0 | } |
2501 | | |
2502 | 0 | static int32_t fqRefreshRemoteOutputTargets(SNode* pRemoteRoot) { |
2503 | 0 | if (NULL == pRemoteRoot) { |
2504 | 0 | return TSDB_CODE_SUCCESS; |
2505 | 0 | } |
2506 | | |
2507 | 0 | SNodesRemoteSelectOutputs outputs = {0}; |
2508 | 0 | int32_t code = nodesCollectRemoteQuerySelectOutputs((SLogicNode*)pRemoteRoot, &outputs); |
2509 | 0 | if (TSDB_CODE_SUCCESS != code) { |
2510 | 0 | planError("FQ-RemoteCols: collect remote select outputs failed, rootType=%d code:0x%x", |
2511 | 0 | (int)nodeType(pRemoteRoot), code); |
2512 | 0 | return code; |
2513 | 0 | } |
2514 | | |
2515 | 0 | SNodeList* pNewTargets = NULL; |
2516 | 0 | code = createColumnByRemoteOutputExprs(outputs.pSelectExprs, &pNewTargets); |
2517 | 0 | if (TSDB_CODE_SUCCESS != code) { |
2518 | 0 | nodesDestroyRemoteSelectOutputs(&outputs); |
2519 | 0 | return code; |
2520 | 0 | } |
2521 | | |
2522 | 0 | code = fqReplaceLogicTargets((SLogicNode*)pRemoteRoot, pNewTargets, "remote-select-outputs"); |
2523 | 0 | nodesDestroyList(pNewTargets); |
2524 | 0 | if (TSDB_CODE_SUCCESS != code) { |
2525 | 0 | nodesDestroyRemoteSelectOutputs(&outputs); |
2526 | 0 | return code; |
2527 | 0 | } |
2528 | | |
2529 | 0 | code = replaceProjectLogicProjections((SLogicNode*)pRemoteRoot, outputs.pSelectExprs); |
2530 | 0 | if (TSDB_CODE_SUCCESS != code) { |
2531 | 0 | nodesDestroyRemoteSelectOutputs(&outputs); |
2532 | 0 | return code; |
2533 | 0 | } |
2534 | | |
2535 | 0 | planDebug("FQ-RemoteCols: refreshed remote output targets, rootType=%d source=%d keyExprs=%d outputs=%d", |
2536 | 0 | (int)nodeType(pRemoteRoot), (int)outputs.source, outputs.keyExprCount, |
2537 | 0 | outputs.pSelectExprs ? LIST_LENGTH(outputs.pSelectExprs) : 0); |
2538 | 0 | nodesDestroyRemoteSelectOutputs(&outputs); |
2539 | 0 | return TSDB_CODE_SUCCESS; |
2540 | 0 | } |
2541 | | |
2542 | 0 | static SNode* fqResolveRemoteMappingExpr(SNode* pExprNode) { |
2543 | 0 | SNode* pExpr = pExprNode; |
2544 | 0 | if (NULL == pExpr) { |
2545 | 0 | return NULL; |
2546 | 0 | } |
2547 | | |
2548 | 0 | if (QUERY_NODE_TARGET == nodeType(pExpr)) { |
2549 | 0 | pExpr = ((STargetNode*)pExpr)->pExpr; |
2550 | 0 | } |
2551 | |
|
2552 | 0 | if (NULL != pExpr && QUERY_NODE_GROUPING_SET == nodeType(pExpr)) { |
2553 | 0 | pExpr = nodesListGetNode(((SGroupingSetNode*)pExpr)->pParameterList, 0); |
2554 | 0 | } |
2555 | | |
2556 | | // Mapping cardinality and order always follow the final remote output target |
2557 | | // list exactly. This helper only unwraps planner-internal wrappers so we can |
2558 | | // read the concrete result type for that SAME output slot. |
2559 | 0 | return pExpr; |
2560 | 0 | } |
2561 | | |
2562 | | // The physi federated scan only consumes the TOP-LEVEL remote SELECT output. |
2563 | | // Its column-name mappings therefore must follow the same output-name policy as |
2564 | | // the top-level remote renderer: |
2565 | | // - current-scope output refs expose userAlias when present, otherwise colName |
2566 | | // - leaf/external columns keep colName |
2567 | | // - computed expressions expose userAlias |
2568 | 0 | static const char* fqResolveRemoteOutputName(const SNode* pExprNode) { |
2569 | 0 | const SNode* pExpr = pExprNode; |
2570 | 0 | if (NULL == pExpr) { |
2571 | 0 | return NULL; |
2572 | 0 | } |
2573 | | |
2574 | 0 | if (QUERY_NODE_TARGET == nodeType(pExpr)) { |
2575 | 0 | pExpr = ((const STargetNode*)pExpr)->pExpr; |
2576 | 0 | } |
2577 | |
|
2578 | 0 | if (NULL != pExpr && QUERY_NODE_GROUPING_SET == nodeType(pExpr)) { |
2579 | 0 | pExpr = nodesListGetNode(((const SGroupingSetNode*)pExpr)->pParameterList, 0); |
2580 | 0 | } |
2581 | |
|
2582 | 0 | if (NULL == pExpr || !nodesIsExprNode((SNode*)pExpr)) { |
2583 | 0 | return NULL; |
2584 | 0 | } |
2585 | | |
2586 | 0 | const SExprNode* pResExpr = (const SExprNode*)pExpr; |
2587 | 0 | if (QUERY_NODE_COLUMN == nodeType(pExpr)) { |
2588 | 0 | const SColumnNode* pCol = (const SColumnNode*)pExpr; |
2589 | 0 | bool isCurrentScopeOutputRef = ('\0' == pCol->tableAlias[0] && '\0' == pCol->tableName[0]); |
2590 | 0 | if (isCurrentScopeOutputRef) { |
2591 | 0 | if ('\0' != pResExpr->userAlias[0]) { |
2592 | 0 | return pResExpr->userAlias; |
2593 | 0 | } |
2594 | 0 | if ('\0' != pCol->colName[0]) { |
2595 | 0 | return pCol->colName; |
2596 | 0 | } |
2597 | 0 | return NULL; |
2598 | 0 | } |
2599 | 0 | if ('\0' != pCol->colName[0]) { |
2600 | 0 | return pCol->colName; |
2601 | 0 | } |
2602 | 0 | } else { |
2603 | 0 | if ('\0' != pResExpr->userAlias[0]) { |
2604 | 0 | return pResExpr->userAlias; |
2605 | 0 | } |
2606 | 0 | } |
2607 | | |
2608 | 0 | return NULL; |
2609 | 0 | } |
2610 | | // ----------------------------------------------------------------------------- |
2611 | | |
2612 | | // fqLogFedScanPhysi - logs the result of createFederatedScanPhysiNode at DEBUG |
2613 | | // level. Gated by qDebugFlag so no string-building overhead when debug logging |
2614 | | // is off. Output example: |
2615 | | // FQ-PHY createFedScan: pScanCols=[time,val] pLeaf.pScanCols=[time,val] pRemoteRoot=Sort numColTypeMappings=2 |
2616 | | static void fqLogFedScanPhysi(const SFederatedScanPhysiNode* pScan, |
2617 | | const SFederatedScanPhysiNode* pLeaf, |
2618 | 0 | const SPhysiNode* pRemoteRoot) { |
2619 | 0 | if (!(qDebugFlag & DEBUG_DEBUG)) return; |
2620 | 0 |
|
2621 | 0 | // pScanCols (outer Mode-1 node) |
2622 | 0 | char scanColsBuf[512] = {0}; |
2623 | 0 | int off = 0; |
2624 | 0 | if (pScan->pScanCols) { |
2625 | 0 | SNode* pSc = NULL; |
2626 | 0 | FOREACH(pSc, pScan->pScanCols) { |
2627 | 0 | const char* cn = "?"; |
2628 | 0 | if (nodeType(pSc) == QUERY_NODE_COLUMN) cn = ((const SColumnNode*)pSc)->colName; |
2629 | 0 | else if (nodeType(pSc) == QUERY_NODE_TARGET) { |
2630 | 0 | const SNode* pi = ((const STargetNode*)pSc)->pExpr; |
2631 | 0 | if (pi && nodeType(pi) == QUERY_NODE_COLUMN) cn = ((const SColumnNode*)pi)->colName; |
2632 | 0 | } |
2633 | 0 | off += snprintf(scanColsBuf + off, sizeof(scanColsBuf) - (size_t)off - 1, "%s,", cn); |
2634 | 0 | if (off >= (int)sizeof(scanColsBuf) - 2) break; |
2635 | 0 | } |
2636 | 0 | if (off > 0 && scanColsBuf[off - 1] == ',') scanColsBuf[off - 1] = '\0'; |
2637 | 0 | } else { |
2638 | 0 | tstrncpy(scanColsBuf, "(NULL)", sizeof(scanColsBuf)); |
2639 | 0 | } |
2640 | 0 |
|
2641 | 0 | // pScanCols (inner Mode-2 leaf - what remote SQL SELECT is built from) |
2642 | 0 | char leafColsBuf[512] = {0}; |
2643 | 0 | off = 0; |
2644 | 0 | if (pLeaf->pScanCols) { |
2645 | 0 | SNode* pSc = NULL; |
2646 | 0 | FOREACH(pSc, pLeaf->pScanCols) { |
2647 | 0 | const char* cn = "?"; |
2648 | 0 | if (nodeType(pSc) == QUERY_NODE_COLUMN) cn = ((const SColumnNode*)pSc)->colName; |
2649 | 0 | off += snprintf(leafColsBuf + off, sizeof(leafColsBuf) - (size_t)off - 1, "%s,", cn); |
2650 | 0 | if (off >= (int)sizeof(leafColsBuf) - 2) break; |
2651 | 0 | } |
2652 | 0 | if (off > 0 && leafColsBuf[off - 1] == ',') leafColsBuf[off - 1] = '\0'; |
2653 | 0 | } else { |
2654 | 0 | tstrncpy(leafColsBuf, "(NULL)", sizeof(leafColsBuf)); |
2655 | 0 | } |
2656 | 0 |
|
2657 | 0 | // pRemoteRoot node type |
2658 | 0 | const char* rootTypeName = "(null)"; |
2659 | 0 | if (pRemoteRoot) { |
2660 | 0 | ENodeType rnt = nodeType(pRemoteRoot); |
2661 | 0 | rootTypeName = (rnt == QUERY_NODE_PHYSICAL_PLAN_SORT) ? "Sort" : |
2662 | 0 | (rnt == QUERY_NODE_PHYSICAL_PLAN_HASH_AGG) ? "HashAgg" : |
2663 | 0 | (rnt == QUERY_NODE_PHYSICAL_PLAN_PROJECT) ? "Project" : |
2664 | 0 | (rnt == QUERY_NODE_PHYSICAL_PLAN_FEDERATED_SCAN) ? "FedScan(leaf)" : "?"; |
2665 | 0 | } |
2666 | 0 |
|
2667 | 0 | planDebug("FQ-PHY createFedScan: pScanCols=[%s] pLeaf.pScanCols=[%s] " |
2668 | 0 | "pRemoteRoot=%s numColTypeMappings=%d", |
2669 | 0 | scanColsBuf, leafColsBuf, rootTypeName, |
2670 | 0 | pScan->numColTypeMappings); |
2671 | 0 | } |
2672 | | |
2673 | 0 | static bool fqTypeStartsWithIgnoreCase(const char* pTypeName, const char* pPrefix) { |
2674 | 0 | if (pTypeName == NULL || pPrefix == NULL) { |
2675 | 0 | return false; |
2676 | 0 | } |
2677 | | |
2678 | 0 | size_t prefixLen = strlen(pPrefix); |
2679 | 0 | return prefixLen > 0 && 0 == strncasecmp(pTypeName, pPrefix, prefixLen); |
2680 | 0 | } |
2681 | | |
2682 | 0 | static bool fqTypeContainsIgnoreCase(const char* pTypeName, const char* pNeedle) { |
2683 | 0 | if (pTypeName == NULL || pNeedle == NULL || pNeedle[0] == '\0') { |
2684 | 0 | return false; |
2685 | 0 | } |
2686 | | |
2687 | 0 | size_t hayLen = strlen(pTypeName); |
2688 | 0 | size_t needleLen = strlen(pNeedle); |
2689 | 0 | if (needleLen > hayLen) { |
2690 | 0 | return false; |
2691 | 0 | } |
2692 | | |
2693 | 0 | for (size_t i = 0; i + needleLen <= hayLen; ++i) { |
2694 | 0 | if (0 == strncasecmp(pTypeName + i, pNeedle, needleLen)) { |
2695 | 0 | return true; |
2696 | 0 | } |
2697 | 0 | } |
2698 | | |
2699 | 0 | return false; |
2700 | 0 | } |
2701 | | |
2702 | 0 | static EExtTimestampTzClass fqPlanClassifyTimestampType(int8_t sourceType, const char* pExtTypeName) { |
2703 | 0 | if (pExtTypeName == NULL || pExtTypeName[0] == '\0') { |
2704 | 0 | return EXT_TIMESTAMP_TZ_CLASS_UNKNOWN; |
2705 | 0 | } |
2706 | | |
2707 | 0 | switch ((EExtSourceType)sourceType) { |
2708 | 0 | case EXT_SOURCE_MYSQL: |
2709 | 0 | if (fqTypeStartsWithIgnoreCase(pExtTypeName, "timestamp")) { |
2710 | 0 | return EXT_TIMESTAMP_TZ_CLASS_AWARE; |
2711 | 0 | } |
2712 | 0 | if (fqTypeStartsWithIgnoreCase(pExtTypeName, "datetime") || |
2713 | 0 | fqTypeStartsWithIgnoreCase(pExtTypeName, "date")) { |
2714 | 0 | return EXT_TIMESTAMP_TZ_CLASS_NAIVE; |
2715 | 0 | } |
2716 | 0 | break; |
2717 | 0 | case EXT_SOURCE_POSTGRESQL: |
2718 | 0 | if (fqTypeStartsWithIgnoreCase(pExtTypeName, "timestamptz") || |
2719 | 0 | fqTypeContainsIgnoreCase(pExtTypeName, "with time zone")) { |
2720 | 0 | return EXT_TIMESTAMP_TZ_CLASS_AWARE; |
2721 | 0 | } |
2722 | 0 | if (fqTypeStartsWithIgnoreCase(pExtTypeName, "timestamp") || |
2723 | 0 | fqTypeStartsWithIgnoreCase(pExtTypeName, "date")) { |
2724 | 0 | return EXT_TIMESTAMP_TZ_CLASS_NAIVE; |
2725 | 0 | } |
2726 | 0 | break; |
2727 | 0 | case EXT_SOURCE_INFLUXDB: |
2728 | 0 | if (fqTypeStartsWithIgnoreCase(pExtTypeName, "timestamp")) { |
2729 | 0 | return EXT_TIMESTAMP_TZ_CLASS_AWARE; |
2730 | 0 | } |
2731 | 0 | if (fqTypeStartsWithIgnoreCase(pExtTypeName, "date32") || |
2732 | 0 | fqTypeStartsWithIgnoreCase(pExtTypeName, "date64")) { |
2733 | 0 | return EXT_TIMESTAMP_TZ_CLASS_NAIVE; |
2734 | 0 | } |
2735 | 0 | break; |
2736 | 0 | default: |
2737 | 0 | break; |
2738 | 0 | } |
2739 | | |
2740 | 0 | return EXT_TIMESTAMP_TZ_CLASS_UNKNOWN; |
2741 | 0 | } |
2742 | | |
2743 | 0 | static int32_t fqBuildTimestampTypeHints(SFederatedScanPhysiNode* pScan, const SExtTableNode* pExtNode) { |
2744 | 0 | if (pScan == NULL || pExtNode == NULL || pExtNode->pExtMeta == NULL || pExtNode->pExtMeta->pCols == NULL) { |
2745 | 0 | return TSDB_CODE_SUCCESS; |
2746 | 0 | } |
2747 | | |
2748 | 0 | int32_t hintCount = 0; |
2749 | 0 | for (int32_t i = 0; i < pExtNode->pExtMeta->numOfCols; ++i) { |
2750 | 0 | if (fqPlanClassifyTimestampType(pExtNode->sourceType, pExtNode->pExtMeta->pCols[i].extTypeName) != |
2751 | 0 | EXT_TIMESTAMP_TZ_CLASS_UNKNOWN) { |
2752 | 0 | ++hintCount; |
2753 | 0 | } |
2754 | 0 | } |
2755 | |
|
2756 | 0 | if (hintCount == 0) { |
2757 | 0 | return TSDB_CODE_SUCCESS; |
2758 | 0 | } |
2759 | | |
2760 | 0 | pScan->pTimestampTypeHints = |
2761 | 0 | (SExtTimestampTypeHint*)taosMemoryCalloc(hintCount, sizeof(SExtTimestampTypeHint)); |
2762 | 0 | if (pScan->pTimestampTypeHints == NULL) { |
2763 | 0 | return TSDB_CODE_OUT_OF_MEMORY; |
2764 | 0 | } |
2765 | | |
2766 | 0 | int32_t hintIdx = 0; |
2767 | 0 | for (int32_t i = 0; i < pExtNode->pExtMeta->numOfCols; ++i) { |
2768 | 0 | const SExtColumnDef* pCol = &pExtNode->pExtMeta->pCols[i]; |
2769 | 0 | EExtTimestampTzClass tzClass = fqPlanClassifyTimestampType(pExtNode->sourceType, pCol->extTypeName); |
2770 | 0 | if (tzClass == EXT_TIMESTAMP_TZ_CLASS_UNKNOWN) { |
2771 | 0 | continue; |
2772 | 0 | } |
2773 | | |
2774 | 0 | tstrncpy(pScan->pTimestampTypeHints[hintIdx].colName, pCol->colName, |
2775 | 0 | sizeof(pScan->pTimestampTypeHints[hintIdx].colName)); |
2776 | 0 | tstrncpy(pScan->pTimestampTypeHints[hintIdx].extTypeName, pCol->extTypeName, |
2777 | 0 | sizeof(pScan->pTimestampTypeHints[hintIdx].extTypeName)); |
2778 | 0 | pScan->pTimestampTypeHints[hintIdx].tzClass = (int8_t)tzClass; |
2779 | 0 | planDebug("FQ-TsTypeHints[%d]: source=%s col=%s extType=%s tzClass=%d", |
2780 | 0 | hintIdx, pExtNode->sourceName, pCol->colName, pCol->extTypeName, (int)tzClass); |
2781 | 0 | ++hintIdx; |
2782 | 0 | } |
2783 | |
|
2784 | 0 | pScan->numTimestampTypeHints = hintIdx; |
2785 | 0 | planDebug("FQ-TsTypeHints: source=%s builtHints=%d", |
2786 | 0 | pExtNode->sourceName, pScan->numTimestampTypeHints); |
2787 | 0 | return TSDB_CODE_SUCCESS; |
2788 | 0 | } |
2789 | | |
2790 | | // PostgreSQL federated scans require an explicit schema at both the planner |
2791 | | // node and connector-config levels. Keep them aligned before executor handoff. |
2792 | 0 | static int32_t fqEnsurePgExtSchemaNode(SExtTableNode* pExtNode) { |
2793 | 0 | if (NULL == pExtNode || EXT_SOURCE_POSTGRESQL != pExtNode->sourceType) { |
2794 | 0 | return TSDB_CODE_SUCCESS; |
2795 | 0 | } |
2796 | | |
2797 | 0 | if ('\0' == pExtNode->schemaName[0] && '\0' != pExtNode->srcSchema[0]) { |
2798 | 0 | tstrncpy(pExtNode->schemaName, pExtNode->srcSchema, sizeof(pExtNode->schemaName)); |
2799 | 0 | } else if ('\0' == pExtNode->srcSchema[0] && '\0' != pExtNode->schemaName[0]) { |
2800 | 0 | tstrncpy(pExtNode->srcSchema, pExtNode->schemaName, sizeof(pExtNode->srcSchema)); |
2801 | 0 | } |
2802 | |
|
2803 | 0 | if ('\0' == pExtNode->schemaName[0] || '\0' == pExtNode->srcSchema[0]) { |
2804 | 0 | planError("FQ-PHY: PostgreSQL schema missing source=%s table=%s schemaName=%s srcSchema=%s", |
2805 | 0 | pExtNode->sourceName, |
2806 | 0 | pExtNode->table.tableName, |
2807 | 0 | '\0' != pExtNode->schemaName[0] ? pExtNode->schemaName : "(empty)", |
2808 | 0 | '\0' != pExtNode->srcSchema[0] ? pExtNode->srcSchema : "(empty)"); |
2809 | 0 | return TSDB_CODE_PLAN_INVALID_FEDERATED_SCAN; |
2810 | 0 | } |
2811 | | |
2812 | 0 | return TSDB_CODE_SUCCESS; |
2813 | 0 | } |
2814 | | |
2815 | | static int32_t fqInitFederatedScanSource(SFederatedScanPhysiNode* pScan, |
2816 | 0 | const SExtTableNode* pExtNode) { |
2817 | 0 | PLAN_ERR_RET(nodesCloneNode((const SNode*)pExtNode, &pScan->pExtTable)); |
2818 | 0 | pScan->sourceType = pExtNode->sourceType; |
2819 | 0 | tstrncpy(pScan->srcHost, pExtNode->srcHost, sizeof(pScan->srcHost)); |
2820 | 0 | pScan->srcPort = pExtNode->srcPort; |
2821 | 0 | tstrncpy(pScan->srcUser, pExtNode->srcUser, sizeof(pScan->srcUser)); |
2822 | 0 | tstrncpy(pScan->srcPassword, pExtNode->srcPassword, sizeof(pScan->srcPassword)); |
2823 | 0 | tstrncpy(pScan->srcDatabase, pExtNode->srcDatabase, sizeof(pScan->srcDatabase)); |
2824 | 0 | tstrncpy(pScan->srcSchema, pExtNode->srcSchema, sizeof(pScan->srcSchema)); |
2825 | 0 | tstrncpy(pScan->srcOptions, pExtNode->srcOptions, sizeof(pScan->srcOptions)); |
2826 | 0 | pScan->metaVersion = pExtNode->metaVersion; |
2827 | 0 | return TSDB_CODE_SUCCESS; |
2828 | 0 | } |
2829 | | |
2830 | | // Consume required filters only in the remote-plan copy, after optional pushdown. |
2831 | 0 | static int32_t fqAttachRequiredScanConditions(SLogicNode* pNode, uint32_t* pPushdownFlags) { |
2832 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
2833 | 0 | int32_t lino = 0; |
2834 | |
|
2835 | 0 | if (QUERY_NODE_LOGIC_PLAN_SCAN == nodeType(pNode)) { |
2836 | 0 | SScanLogicNode* pScan = (SScanLogicNode*)pNode; |
2837 | 0 | if (NULL != pScan->pPushedConditions) { |
2838 | 0 | if (NULL != pNode->pConditions) { |
2839 | 0 | code = nodesMergeNode(&pScan->pPushedConditions, &pNode->pConditions); |
2840 | 0 | QUERY_CHECK_CODE(code, lino, _return); |
2841 | 0 | } |
2842 | 0 | TSWAP(pNode->pConditions, pScan->pPushedConditions); |
2843 | 0 | *pPushdownFlags |= FQ_PUSHDOWN_REQUIRED_FILTER; |
2844 | 0 | } |
2845 | 0 | } |
2846 | | |
2847 | 0 | SNode* pChild = NULL; |
2848 | 0 | FOREACH(pChild, pNode->pChildren) { |
2849 | 0 | code = fqAttachRequiredScanConditions((SLogicNode*)pChild, pPushdownFlags); |
2850 | 0 | QUERY_CHECK_CODE(code, lino, _return); |
2851 | 0 | } |
2852 | | |
2853 | 0 | _return: |
2854 | 0 | if (TSDB_CODE_SUCCESS != code) { |
2855 | 0 | qError("%s failed at line %d since %s", __func__, lino, tstrerror(code)); |
2856 | 0 | } |
2857 | 0 | return code; |
2858 | 0 | } |
2859 | | |
2860 | | // createFederatedScanPhysiNode: builds SFederatedScanPhysiNode from a logic |
2861 | | // node whose scanType == SCAN_TYPE_EXTERNAL. |
2862 | | // --------------------------------------------------------------------------- |
2863 | | static int32_t createFederatedScanPhysiNode(SPhysiPlanContext* pCxt, SSubplan* pSubplan, |
2864 | 0 | SScanLogicNode* pScanLogicNode, SPhysiNode** pPhyNode) { |
2865 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
2866 | 0 | int32_t lino = 0; |
2867 | 0 | SFederatedScanPhysiNode* pScan = NULL; |
2868 | 0 | SNodeList* pReordered = NULL; |
2869 | 0 | SNodeList* pReserveSlotCols = NULL; |
2870 | 0 | SNode* pRemoteRoot = NULL; |
2871 | |
|
2872 | 0 | if (NULL == pScanLogicNode->pExtTableNode) { |
2873 | 0 | planError("createFederatedScanPhysiNode: pExtTableNode is NULL"); |
2874 | 0 | PLAN_ERR_JRET(TSDB_CODE_PLAN_INVALID_FEDERATED_SCAN); |
2875 | 0 | } |
2876 | 0 | bool isDynamicVstableScan = pScanLogicNode->virtualStableScan && pScanLogicNode->node.dynamicOp; |
2877 | 0 | if (!isDynamicVstableScan && |
2878 | 0 | (NULL == pScanLogicNode->pScanCols || LIST_LENGTH(pScanLogicNode->pScanCols) == 0)) { |
2879 | 0 | planError("FQ-PHY: logic scan invariant violated, pScanCols empty source=%s table=%s remotePlan=%p", |
2880 | 0 | ((SExtTableNode*)pScanLogicNode->pExtTableNode)->sourceName, |
2881 | 0 | pScanLogicNode->tableName.tname, |
2882 | 0 | pScanLogicNode->pRemoteLogicPlan); |
2883 | 0 | PLAN_ERR_JRET(TSDB_CODE_PLAN_INVALID_FEDERATED_SCAN); |
2884 | 0 | } |
2885 | 0 | if (!isDynamicVstableScan && |
2886 | 0 | (NULL == pScanLogicNode->node.pTargets || LIST_LENGTH(pScanLogicNode->node.pTargets) == 0)) { |
2887 | 0 | planError("FQ-PHY: logic scan invariant violated, node targets empty source=%s table=%s scanCols=%d", |
2888 | 0 | ((SExtTableNode*)pScanLogicNode->pExtTableNode)->sourceName, |
2889 | 0 | pScanLogicNode->tableName.tname, |
2890 | 0 | (int)LIST_LENGTH(pScanLogicNode->pScanCols)); |
2891 | 0 | PLAN_ERR_JRET(TSDB_CODE_PLAN_INVALID_FEDERATED_SCAN); |
2892 | 0 | } |
2893 | 0 | SExtTableNode* pExtNode = (SExtTableNode*)pScanLogicNode->pExtTableNode; |
2894 | 0 | PLAN_ERR_JRET(fqEnsurePgExtSchemaNode(pExtNode)); |
2895 | 0 | bool useRemoteLogicPlan = |
2896 | 0 | (NULL != pScanLogicNode->pRemoteLogicPlan) && |
2897 | 0 | !fqShouldUseAnalyzeInfluxScalarAggFallback(pCxt, pScanLogicNode); |
2898 | | // Stream %%trows readers materialize source rows and run their calc plan locally. |
2899 | 0 | bool useRemoteResultSchema = useRemoteLogicPlan && !inStreamCalcClause(pCxt->pPlanCxt); |
2900 | |
|
2901 | 0 | pScan = (SFederatedScanPhysiNode*)makePhysiNode(pCxt, (SLogicNode*)pScanLogicNode, |
2902 | 0 | QUERY_NODE_PHYSICAL_PLAN_FEDERATED_SCAN); |
2903 | 0 | if (NULL == pScan) { |
2904 | 0 | planError("createFederatedScanPhysiNode: makePhysiNode OOM"); |
2905 | 0 | PLAN_ERR_JRET(terrno); |
2906 | 0 | } |
2907 | 0 | PLAN_ERR_JRET(fqInitFederatedScanSource(pScan, pExtNode)); |
2908 | | |
2909 | | // dynamicOp external scan nodes (VStb path) have NULL pTargets/pScanCols; |
2910 | | // DynQueryCtrl fills them at runtime after the common source initialization. |
2911 | 0 | if (isDynamicVstableScan) { |
2912 | 0 | pScan->scanRange = pScanLogicNode->scanRange; |
2913 | 0 | PLAN_ERR_JRET(nodesCloneList(pScanLogicNode->pScanCols, &pScan->pScanCols)); |
2914 | 0 | fqSetFederatedScanTimezone(pCxt, pScan); |
2915 | 0 | pCxt->hasFederatedScan = true; |
2916 | 0 | *pPhyNode = (SPhysiNode*)pScan; |
2917 | 0 | pScan = NULL; |
2918 | 0 | goto _return; |
2919 | 0 | } |
2920 | | |
2921 | | // When pRemoteLogicPlan is set, the remote connector executes the full |
2922 | | // pushed-down plan and returns exactly the topmost node's output columns |
2923 | | // (pTargets). The executor rebuilds pColTypeMappings from the physi-plan |
2924 | | // topmost node's pTargets (SSortPhysiNode.pTargets / SProjectPhysiNode.pProjections). |
2925 | | // We do NOT rebuild pOutputDataBlockDesc here because it uses pCxt's |
2926 | | // dataBlockId registry and downstream slot-ID resolution depends on it. |
2927 | | |
2928 | | // Clone scan columns in pTargets order. |
2929 | | // makePhysiNode() already built the output data block descriptor from |
2930 | | // pLogicNode->pTargets (which may have been reordered by |
2931 | | // eliminateProjOptimize to match the user's SELECT list). The output desc |
2932 | | // slot order = pTargets order. We must ensure pScanCols, pColTypeMappings, |
2933 | | // and the remote SQL SELECT list all use the same order so that the data |
2934 | | // block columns returned by the connector match the slot descriptors. |
2935 | | // |
2936 | | // pScanCols (from nodesCollectColumns) may differ in order from pTargets |
2937 | | // because the AST walker visits ORDER BY before PROJECTION. Reorder the |
2938 | | // clone to match pTargets. |
2939 | 0 | { |
2940 | 0 | bool reorderOk = true; |
2941 | |
|
2942 | 0 | if (pScanLogicNode->node.pTargets != NULL && pScanLogicNode->pScanCols != NULL) { |
2943 | 0 | SNode* pTarget = NULL; |
2944 | 0 | FOREACH(pTarget, pScanLogicNode->node.pTargets) { |
2945 | | // Unwrap STargetNode wrapper if present |
2946 | 0 | const SNode* pTgtInner = pTarget; |
2947 | 0 | if (nodeType(pTgtInner) == QUERY_NODE_TARGET) { |
2948 | 0 | pTgtInner = ((const STargetNode*)pTgtInner)->pExpr; |
2949 | 0 | } |
2950 | 0 | if (NULL == pTgtInner || nodeType(pTgtInner) != QUERY_NODE_COLUMN) { |
2951 | 0 | reorderOk = false; |
2952 | 0 | break; |
2953 | 0 | } |
2954 | 0 | const SColumnNode* pTgtCol = (const SColumnNode*)pTgtInner; |
2955 | 0 | bool found = false; |
2956 | 0 | SNode* pScanCol = NULL; |
2957 | 0 | FOREACH(pScanCol, pScanLogicNode->pScanCols) { |
2958 | 0 | SColumnNode* pSCol = (SColumnNode*)pScanCol; |
2959 | 0 | if ((pSCol->colId != 0 && pSCol->colId == pTgtCol->colId) || |
2960 | 0 | (pSCol->colId == 0 && 0 == strcmp(pSCol->colName, pTgtCol->colName))) { |
2961 | 0 | SNode* pClone = NULL; |
2962 | 0 | PLAN_ERR_JRET(nodesCloneNode(pScanCol, &pClone)); |
2963 | 0 | PLAN_ERR_JRET(nodesListMakeStrictAppend(&pReordered, pClone)); |
2964 | 0 | found = true; |
2965 | 0 | break; |
2966 | 0 | } |
2967 | 0 | } |
2968 | 0 | if (!found || !reorderOk) { reorderOk = false; break; } |
2969 | 0 | } |
2970 | 0 | if (!reorderOk || pReordered == NULL || |
2971 | 0 | LIST_LENGTH(pReordered) != LIST_LENGTH(pScanLogicNode->node.pTargets)) { |
2972 | 0 | NODES_DESTORY_LIST(pReordered); |
2973 | 0 | } else { |
2974 | | // Reorder succeeded. Append any extra pScanCols columns that are NOT in |
2975 | | // pTargets (e.g. primary-key columns added for WINDOW JOIN addPrimEqCond |
2976 | | // slot resolution that are absent from the SELECT list). These must be |
2977 | | // present in the slot hash so that createMergeJoinPhysiNode can resolve |
2978 | | // addPrimEqCond column slot IDs without PLAN_SLOT_NOT_FOUND. |
2979 | 0 | SNode* pSc = NULL; |
2980 | 0 | FOREACH(pSc, pScanLogicNode->pScanCols) { |
2981 | 0 | if (QUERY_NODE_COLUMN != nodeType(pSc)) continue; |
2982 | 0 | SColumnNode* pSCol = (SColumnNode*)pSc; |
2983 | 0 | bool alreadyIn = false; |
2984 | 0 | SNode* pEx = NULL; |
2985 | 0 | FOREACH(pEx, pReordered) { |
2986 | 0 | if (QUERY_NODE_COLUMN != nodeType(pEx)) continue; |
2987 | 0 | SColumnNode* pExCol = (SColumnNode*)pEx; |
2988 | 0 | if ((pExCol->colId != 0 && pExCol->colId == pSCol->colId) || |
2989 | 0 | (pExCol->colId == 0 && strcmp(pExCol->colName, pSCol->colName) == 0 && |
2990 | 0 | strcmp(pExCol->tableAlias, pSCol->tableAlias) == 0)) { |
2991 | 0 | alreadyIn = true; |
2992 | 0 | break; |
2993 | 0 | } |
2994 | 0 | } |
2995 | 0 | if (!alreadyIn) { |
2996 | 0 | SNode* pClone = NULL; |
2997 | 0 | PLAN_ERR_JRET(nodesCloneNode(pSc, &pClone)); |
2998 | 0 | PLAN_ERR_JRET(nodesListMakeStrictAppend(&pReordered, pClone)); |
2999 | 0 | } |
3000 | 0 | } |
3001 | 0 | } |
3002 | 0 | } |
3003 | | |
3004 | 0 | if (pReordered != NULL) { |
3005 | 0 | pScan->pScanCols = pReordered; |
3006 | 0 | pReordered = NULL; |
3007 | 0 | } else { |
3008 | | // Fallback: clone in original pScanCols order |
3009 | 0 | PLAN_ERR_JRET(nodesCloneList(pScanLogicNode->pScanCols, &pScan->pScanCols)); |
3010 | 0 | } |
3011 | 0 | } |
3012 | | |
3013 | | // Build pColTypeMappings from the same single source used by remote SQL |
3014 | | // rendering: the top-level remote plan's pTargets. Only when there is no |
3015 | | // remote plan at all do we fall back to the local scan columns. If a remote |
3016 | | // plan exists but its top-level outputs are still empty, that is a real plan |
3017 | | // inconsistency and must fail loudly; otherwise the descriptor, pTargets and |
3018 | | // remote SQL output order will diverge. |
3019 | 0 | { |
3020 | 0 | SNodeList* pOutputCols = pScan->pScanCols; // default: no pushed plan |
3021 | 0 | const char* pOutputColsSource = "pScanCols"; |
3022 | 0 | if (useRemoteResultSchema) { |
3023 | 0 | PLAN_ERR_JRET( |
3024 | 0 | fqAlignRemotePassthroughOutputs(pScanLogicNode->pRemoteLogicPlan, pScan->pScanCols)); |
3025 | 0 | PLAN_ERR_JRET(fqRefreshRemoteOutputTargets(pScanLogicNode->pRemoteLogicPlan)); |
3026 | | |
3027 | 0 | SNodeList* pRemoteTargets = fqGetRemoteOutputTargets(pScanLogicNode->pRemoteLogicPlan); |
3028 | 0 | planDebug("FQ-ColMappings: inspect top remote targets, remoteRootType=%d targets=%p len=%d", |
3029 | 0 | (int)nodeType((SNode*)pScanLogicNode->pRemoteLogicPlan), pRemoteTargets, |
3030 | 0 | pRemoteTargets ? LIST_LENGTH(pRemoteTargets) : 0); |
3031 | 0 | if (pRemoteTargets != NULL && LIST_LENGTH(pRemoteTargets) > 0) { |
3032 | 0 | pOutputCols = pRemoteTargets; |
3033 | 0 | pOutputColsSource = "pRemotePlan->pTargets"; |
3034 | 0 | } else { |
3035 | 0 | planError("FQ-ColMappings: remote plan exists but top remote targets are empty, rootType=%d scanCols=%d", |
3036 | 0 | (int)nodeType((SNode*)pScanLogicNode->pRemoteLogicPlan), |
3037 | 0 | pScan->pScanCols ? LIST_LENGTH(pScan->pScanCols) : 0); |
3038 | 0 | PLAN_ERR_JRET(TSDB_CODE_PLAN_INVALID_FEDERATED_SCAN); |
3039 | 0 | } |
3040 | 0 | } |
3041 | | |
3042 | 0 | int32_t numCols = pOutputCols ? LIST_LENGTH(pOutputCols) : 0; |
3043 | 0 | int32_t outputIdx = 0; |
3044 | 0 | SNode* pExprNode = NULL; |
3045 | 0 | FOREACH(pExprNode, pOutputCols) { |
3046 | 0 | SNode* pExpr = fqResolveRemoteMappingExpr(pExprNode); |
3047 | 0 | if (NULL == pExpr) { |
3048 | 0 | planError("FQ-ColMappings: outputIdx=%d has NULL mapping expr, source=%s exprNodeType=%d", |
3049 | 0 | outputIdx, pOutputColsSource, (int)nodeType(pExprNode)); |
3050 | 0 | PLAN_ERR_JRET(TSDB_CODE_PLAN_INVALID_FEDERATED_SCAN); |
3051 | 0 | } |
3052 | 0 | planDebug("FQ-ColMappings: count outputIdx=%d exprNodeType=%d exprType=%d includeInMappings=1", |
3053 | 0 | outputIdx, (int)nodeType(pExprNode), (int)nodeType(pExpr)); |
3054 | 0 | ++outputIdx; |
3055 | 0 | } |
3056 | | |
3057 | 0 | planDebug("FQ-ColMappings: source=%s outputLen=%d mappingCols=%d", |
3058 | 0 | pOutputColsSource, pOutputCols ? LIST_LENGTH(pOutputCols) : 0, numCols); |
3059 | 0 | if (numCols > 0) { |
3060 | 0 | pScan->pColTypeMappings = |
3061 | 0 | (SExtColTypeMapping*)taosMemoryCalloc(numCols, sizeof(SExtColTypeMapping)); |
3062 | 0 | if (NULL == pScan->pColTypeMappings) { |
3063 | 0 | PLAN_ERR_JRET(TSDB_CODE_OUT_OF_MEMORY); |
3064 | 0 | } |
3065 | 0 | pScan->numColTypeMappings = numCols; |
3066 | |
|
3067 | 0 | int32_t colIdx = 0; |
3068 | 0 | outputIdx = 0; |
3069 | 0 | FOREACH(pExprNode, pOutputCols) { |
3070 | 0 | SNode* pExpr = fqResolveRemoteMappingExpr(pExprNode); |
3071 | 0 | if (NULL == pExpr) { |
3072 | 0 | planError("FQ-ColMappings: outputIdx=%d resolved NULL expr during fill, source=%s exprNodeType=%d", |
3073 | 0 | outputIdx, pOutputColsSource, (int)nodeType(pExprNode)); |
3074 | 0 | PLAN_ERR_JRET(TSDB_CODE_PLAN_INVALID_FEDERATED_SCAN); |
3075 | 0 | } |
3076 | | |
3077 | 0 | planDebug("FQ-ColMappings[%d]: outputIdx=%d exprNodeType=%d exprType=%d type=%d precision=%d scale=%d bytes=%d", |
3078 | 0 | colIdx, outputIdx, (int)nodeType(pExprNode), (int)nodeType(pExpr), |
3079 | 0 | (int)((SExprNode*)pExpr)->resType.type, (int)((SExprNode*)pExpr)->resType.precision, |
3080 | 0 | (int)((SExprNode*)pExpr)->resType.scale, (int)((SExprNode*)pExpr)->resType.bytes); |
3081 | 0 | pScan->pColTypeMappings[colIdx].tdType = ((SExprNode*)pExpr)->resType; |
3082 | 0 | const char* pOutputName = fqResolveRemoteOutputName(pExprNode); |
3083 | 0 | if (NULL != pOutputName && '\0' != pOutputName[0]) { |
3084 | 0 | tstrncpy(pScan->pColTypeMappings[colIdx].colName, pOutputName, |
3085 | 0 | sizeof(pScan->pColTypeMappings[colIdx].colName)); |
3086 | 0 | } |
3087 | 0 | planDebug("FQ-ColMappings[%d]: outputIdx=%d outputName=%s source=%s", |
3088 | 0 | colIdx, outputIdx, |
3089 | 0 | pScan->pColTypeMappings[colIdx].colName[0] != '\0' ? pScan->pColTypeMappings[colIdx].colName : "(empty)", |
3090 | 0 | pOutputColsSource); |
3091 | 0 | ++colIdx; |
3092 | 0 | ++outputIdx; |
3093 | 0 | } |
3094 | | |
3095 | 0 | if (colIdx != numCols) { |
3096 | 0 | planError("FQ-ColMappings: filled mapping count mismatch, source=%s expected=%d actual=%d", |
3097 | 0 | pOutputColsSource, numCols, colIdx); |
3098 | 0 | PLAN_ERR_JRET(TSDB_CODE_PLAN_INVALID_FEDERATED_SCAN); |
3099 | 0 | } |
3100 | 0 | } |
3101 | 0 | } |
3102 | | |
3103 | 0 | PLAN_ERR_JRET(fqBuildTimestampTypeHints(pScan, pExtNode)); |
3104 | | // Propagate two-pass mode only when the repeat-scan aggregate still runs locally. |
3105 | | // If the remote subtree already contains the repeat-scan AGG, FederatedScan must |
3106 | | // return the final remote rows once, not PRE_SCAN + MAIN_SCAN duplicates. |
3107 | 0 | bool requestTwoPass = (pScanLogicNode->scanSeq[0] > 1); |
3108 | 0 | bool remoteOwnsRepeatScan = |
3109 | 0 | useRemoteLogicPlan && fqRemotePlanHasRepeatScanAgg((const SLogicNode*)pScanLogicNode->pRemoteLogicPlan); |
3110 | 0 | pScan->twoPassMode = requestTwoPass && !remoteOwnsRepeatScan; |
3111 | 0 | planDebug("FQ-PhysiFedScan: source=%s scanSeq0=%d requestTwoPass=%d remoteOwnsRepeatScan=%d finalTwoPass=%d" |
3112 | 0 | " useRemoteLogicPlan=%d remoteRootType=%d", |
3113 | 0 | pExtNode->sourceName, (int)pScanLogicNode->scanSeq[0], (int)requestTwoPass, |
3114 | 0 | (int)remoteOwnsRepeatScan, (int)pScan->twoPassMode, (int)useRemoteLogicPlan, |
3115 | 0 | pScanLogicNode->pRemoteLogicPlan ? (int)nodeType((SNode*)pScanLogicNode->pRemoteLogicPlan) : -1); |
3116 | | // Copy client timezone name so the Executor can reconstruct the timezone_t via tzalloc(). |
3117 | | // Used by the Connector to convert timezone-naive source timestamps (MySQL DATETIME, |
3118 | | // PG timestamp without time zone, etc.) using the correct client timezone. |
3119 | 0 | fqSetFederatedScanTimezone(pCxt, pScan); |
3120 | | |
3121 | | // Add output data block slots. |
3122 | | // When pRemoteLogicPlan exists, FedScan executes the remote plan and returns its |
3123 | | // top-level output. The output descriptor must reflect what the remote plan actually |
3124 | | // produces, not the original scan columns. Only when pRemoteLogicPlan is NULL (pure |
3125 | | // scan, no pushdown) do we fall back to pScanCols. A non-NULL remote plan with an |
3126 | | // empty output list is a real inconsistency and must fail loudly. |
3127 | 0 | SNodeList* pSlotCols = pScan->pScanCols; // default: no remote plan |
3128 | 0 | { |
3129 | 0 | if (useRemoteResultSchema) { |
3130 | 0 | PLAN_ERR_JRET(fqRefreshRemoteOutputTargets(pScanLogicNode->pRemoteLogicPlan)); |
3131 | | |
3132 | 0 | SNodeList* pRemoteTargets = fqGetRemoteOutputTargets(pScanLogicNode->pRemoteLogicPlan); |
3133 | 0 | planDebug("FQ-Slots: inspect top remote targets for FedScan output descriptor, type=%d len=%d", |
3134 | 0 | (int)nodeType((SNode*)pScanLogicNode->pRemoteLogicPlan), |
3135 | 0 | pRemoteTargets ? LIST_LENGTH(pRemoteTargets) : 0); |
3136 | 0 | if (pRemoteTargets != NULL && LIST_LENGTH(pRemoteTargets) > 0) { |
3137 | 0 | pSlotCols = pRemoteTargets; |
3138 | 0 | } else { |
3139 | 0 | planError("FQ-Slots: remote plan exists but top remote targets are empty, rootType=%d scanCols=%d", |
3140 | 0 | (int)nodeType((SNode*)pScanLogicNode->pRemoteLogicPlan), |
3141 | 0 | pScan->pScanCols ? LIST_LENGTH(pScan->pScanCols) : 0); |
3142 | 0 | PLAN_ERR_JRET(TSDB_CODE_PLAN_INVALID_FEDERATED_SCAN); |
3143 | 0 | } |
3144 | 0 | } |
3145 | | // When pRemoteLogicPlan is non-NULL, the FedScan output descriptor must be |
3146 | | // rebuilt from scratch in remote-result order, then local-only dependency |
3147 | | // columns are appended as reserve slots. Reusing makePhysiNode's initial |
3148 | | // descriptor leaks the local scan-target order into output slots and can |
3149 | | // swap visible/hidden columns for partial-project pushdown. |
3150 | 0 | if (useRemoteLogicPlan && pSlotCols != pScan->pScanCols && pScan->pScanCols != NULL) { |
3151 | 0 | PLAN_ERR_JRET(nodesCloneList(pScan->pScanCols, &pReserveSlotCols)); |
3152 | 0 | planDebug("FQ-Slots: rebuilt FedScan descriptor from remote targets (len=%d) plus reserve scanCols (len=%d)", |
3153 | 0 | (int)LIST_LENGTH(pSlotCols), (int)LIST_LENGTH(pReserveSlotCols)); |
3154 | 0 | PLAN_ERR_JRET( |
3155 | 0 | fqRebuildDataBlockDesc(pCxt, pScan->node.pOutputDataBlockDesc, pSlotCols, pReserveSlotCols)); |
3156 | 0 | } else { |
3157 | 0 | PLAN_ERR_JRET(addDataBlockSlots(pCxt, pSlotCols, pScan->node.pOutputDataBlockDesc)); |
3158 | 0 | } |
3159 | 0 | } |
3160 | | |
3161 | | // Add pseudo-column slots (e.g. TBNAME for PARTITION BY TBNAME on InfluxDB). |
3162 | | // Normal table scans handle this via pScanPseudoCols in createSimpleScanPhysiNode. |
3163 | | // Without this, PARTITION BY TBNAME on a federated scan crashes: the partition |
3164 | | // operator's group-key column references a slot that doesn't exist in the data |
3165 | | // block, causing a type mismatch and buffer overflow in doHashPartition. |
3166 | 0 | if (NULL != pScanLogicNode->pScanPseudoCols) { |
3167 | 0 | PLAN_ERR_JRET( |
3168 | 0 | addDataBlockSlots(pCxt, pScanLogicNode->pScanPseudoCols, pScan->node.pOutputDataBlockDesc)); |
3169 | 0 | } |
3170 | | |
3171 | 0 | if (pReserveSlotCols != NULL) { |
3172 | 0 | nodesDestroyList(pReserveSlotCols); |
3173 | 0 | pReserveSlotCols = NULL; |
3174 | 0 | } |
3175 | | // Set correct slot IDs in the cloned conditions using setNodeSlotId. |
3176 | | // Only columns that are present in the output/reserve slot descriptor can be |
3177 | | // resolved here; conditions pushed to the remote side are handled remotely. |
3178 | 0 | if (pScanLogicNode->node.pConditions != NULL) { |
3179 | 0 | PLAN_ERR_JRET(setNodeSlotId(pCxt, pScan->node.pOutputDataBlockDesc->dataBlockId, -1, |
3180 | 0 | pScanLogicNode->node.pConditions, &pScan->node.pConditions)); |
3181 | 0 | planDebug("FQ-PHY FedScan pConditions: setNodeSlotId code=0x%x pConditions=%p", |
3182 | 0 | code, pScan->node.pConditions); |
3183 | 0 | } else { |
3184 | 0 | planDebug("FQ-PHY FedScan pConditions: logic pConditions is NULL (already pushed or none)"); |
3185 | 0 | } |
3186 | | |
3187 | | // Force MERGE subplan type to avoid DATA_SRC_EP_MISS (external has no vnode) |
3188 | 0 | pSubplan->subplanType = SUBPLAN_TYPE_MERGE; |
3189 | 0 | pSubplan->msgType = TDMT_SCH_MERGE_QUERY; |
3190 | | |
3191 | | // * Mark the physical plan as containing a federated scan |
3192 | 0 | pCxt->hasFederatedScan = true; |
3193 | | |
3194 | | // -- Build the remote plan as a LOGIC tree (pure clone - no physi conversion) -- |
3195 | | // .pScanCols -> flat leaf SELECT list (must already be non-empty) |
3196 | | // .pConditions -> WHERE clause |
3197 | | // .node.pLimit -> LIMIT / OFFSET |
3198 | | |
3199 | | // pRemotePlan is a logic-node subtree: nodesRemotePlanToSQL renders it directly |
3200 | | // (it reads only column names / expressions / functions - never physi slot ids), |
3201 | | // and TLV ships it to the server which re-renders. Two cases: |
3202 | | // (a) pRemoteLogicPlan set (FqPushdown collected a chain): clone it verbatim - |
3203 | | // it already carries its own logic SCAN leaf (cloned by fqCommitPushChain). |
3204 | | // (b) pRemoteLogicPlan NULL: build a bare logic SCAN leaf carrying the remote |
3205 | | // FROM/SELECT/WHERE/LIMIT so the connector runs a flat "SELECT ... FROM ...". |
3206 | 0 | planDebug("FQ-PHY: pScanLogicNode=%p pRemoteLogicPlan=%p type=%d useRemoteLogicPlan=%d", pScanLogicNode, |
3207 | 0 | pScanLogicNode->pRemoteLogicPlan, |
3208 | 0 | pScanLogicNode->pRemoteLogicPlan ? (int)nodeType(pScanLogicNode->pRemoteLogicPlan) : -1, |
3209 | 0 | (int)useRemoteLogicPlan); |
3210 | 0 | if (useRemoteLogicPlan) { |
3211 | 0 | PLAN_ERR_JRET(nodesCloneNode(pScanLogicNode->pRemoteLogicPlan, &pRemoteRoot)); |
3212 | 0 | planDebug("FQ-PHY: after clone pRemoteRoot=%p type=%d code=0x%x", |
3213 | 0 | pRemoteRoot, pRemoteRoot ? (int)nodeType(pRemoteRoot) : -1, code); |
3214 | 0 | if (pRemoteRoot != NULL) { |
3215 | 0 | SLogicNode* pRemoteLogicRoot = (SLogicNode*)pRemoteRoot; |
3216 | 0 | planDebug("FQ-PHY: cloned remote root detail type=%d nChildren=%d targets=%d limit=%p", |
3217 | 0 | (int)nodeType(pRemoteRoot), |
3218 | 0 | pRemoteLogicRoot->pChildren ? LIST_LENGTH(pRemoteLogicRoot->pChildren) : 0, |
3219 | 0 | pRemoteLogicRoot->pTargets ? LIST_LENGTH(pRemoteLogicRoot->pTargets) : 0, |
3220 | 0 | pRemoteLogicRoot->pLimit); |
3221 | 0 | SScanLogicNode* pRemoteLeaf = fqFindExternalLogicLeafScan((SLogicNode*)pRemoteRoot); |
3222 | 0 | planDebug("FQ-PHY: cloned remote leaf detail leaf=%p hasCond=%d scanCols=%d targets=%d remotePlan=%p source=%s table=%s", |
3223 | 0 | pRemoteLeaf, (NULL != pRemoteLeaf && NULL != pRemoteLeaf->node.pConditions), |
3224 | 0 | (NULL != pRemoteLeaf && NULL != pRemoteLeaf->pScanCols) ? LIST_LENGTH(pRemoteLeaf->pScanCols) : 0, |
3225 | 0 | (NULL != pRemoteLeaf && NULL != pRemoteLeaf->node.pTargets) ? LIST_LENGTH(pRemoteLeaf->node.pTargets) : 0, |
3226 | 0 | NULL != pRemoteLeaf ? pRemoteLeaf->pRemoteLogicPlan : NULL, |
3227 | 0 | (NULL != pRemoteLeaf && NULL != pRemoteLeaf->pExtTableNode) |
3228 | 0 | ? ((SExtTableNode*)pRemoteLeaf->pExtTableNode)->sourceName |
3229 | 0 | : "(null)", |
3230 | 0 | (NULL != pRemoteLeaf && NULL != pRemoteLeaf->pExtTableNode) |
3231 | 0 | ? ((SExtTableNode*)pRemoteLeaf->pExtTableNode)->table.tableName |
3232 | 0 | : "(null)"); |
3233 | 0 | } |
3234 | 0 | PLAN_ERR_JRET(fqAlignRemotePassthroughOutputs(pRemoteRoot, pScan->pScanCols)); |
3235 | 0 | if (pRemoteRoot != NULL) { |
3236 | 0 | SLogicNode* pRemoteLogicRoot = (SLogicNode*)pRemoteRoot; |
3237 | 0 | planDebug("FQ-PHY: aligned remote root detail type=%d nChildren=%d targets=%d limit=%p", |
3238 | 0 | (int)nodeType(pRemoteRoot), |
3239 | 0 | pRemoteLogicRoot->pChildren ? LIST_LENGTH(pRemoteLogicRoot->pChildren) : 0, |
3240 | 0 | pRemoteLogicRoot->pTargets ? LIST_LENGTH(pRemoteLogicRoot->pTargets) : 0, |
3241 | 0 | pRemoteLogicRoot->pLimit); |
3242 | 0 | } |
3243 | 0 | PLAN_ERR_JRET(fqRefreshRemoteOutputTargets(pRemoteRoot)); |
3244 | 0 | if (pRemoteRoot != NULL) { |
3245 | 0 | SLogicNode* pRemoteLogicRoot = (SLogicNode*)pRemoteRoot; |
3246 | 0 | planDebug("FQ-PHY: refreshed remote output targets detail type=%d nChildren=%d targets=%d limit=%p", |
3247 | 0 | (int)nodeType(pRemoteRoot), |
3248 | 0 | pRemoteLogicRoot->pChildren ? LIST_LENGTH(pRemoteLogicRoot->pChildren) : 0, |
3249 | 0 | pRemoteLogicRoot->pTargets ? LIST_LENGTH(pRemoteLogicRoot->pTargets) : 0, |
3250 | 0 | pRemoteLogicRoot->pLimit); |
3251 | 0 | SScanLogicNode* pRemoteLeaf = fqFindExternalLogicLeafScan((SLogicNode*)pRemoteRoot); |
3252 | 0 | planDebug("FQ-PHY: refreshed remote leaf detail leaf=%p hasCond=%d scanCols=%d targets=%d remotePlan=%p source=%s table=%s", |
3253 | 0 | pRemoteLeaf, (NULL != pRemoteLeaf && NULL != pRemoteLeaf->node.pConditions), |
3254 | 0 | (NULL != pRemoteLeaf && NULL != pRemoteLeaf->pScanCols) ? LIST_LENGTH(pRemoteLeaf->pScanCols) : 0, |
3255 | 0 | (NULL != pRemoteLeaf && NULL != pRemoteLeaf->node.pTargets) ? LIST_LENGTH(pRemoteLeaf->node.pTargets) : 0, |
3256 | 0 | NULL != pRemoteLeaf ? pRemoteLeaf->pRemoteLogicPlan : NULL, |
3257 | 0 | (NULL != pRemoteLeaf && NULL != pRemoteLeaf->pExtTableNode) |
3258 | 0 | ? ((SExtTableNode*)pRemoteLeaf->pExtTableNode)->sourceName |
3259 | 0 | : "(null)", |
3260 | 0 | (NULL != pRemoteLeaf && NULL != pRemoteLeaf->pExtTableNode) |
3261 | 0 | ? ((SExtTableNode*)pRemoteLeaf->pExtTableNode)->table.tableName |
3262 | 0 | : "(null)"); |
3263 | 0 | } |
3264 | 0 | } else { |
3265 | 0 | PLAN_ERR_JRET(nodesMakeNode(QUERY_NODE_LOGIC_PLAN_SCAN, &pRemoteRoot)); |
3266 | 0 | SScanLogicNode* pLeaf = (SScanLogicNode*)pRemoteRoot; |
3267 | 0 | pLeaf->scanType = SCAN_TYPE_EXTERNAL; |
3268 | | // FROM: clone the external table node (table identity for SQL generation). |
3269 | 0 | PLAN_ERR_JRET(nodesCloneNode(pScanLogicNode->pExtTableNode, &pLeaf->pExtTableNode)); |
3270 | | // SELECT: clone the de-duplicated column set the optimizer collected. |
3271 | | // Use pScan->pScanCols (already reordered to pTargets order above), NOT the |
3272 | | // raw pScanLogicNode->pScanCols. The remote SQL SELECT list rendered from |
3273 | | // this leaf MUST match the column order of pColTypeMappings (built from |
3274 | | // pScan->pScanCols below); otherwise the connector decodes result column N |
3275 | | // with mapping[N] of a different column -> 0x6418 (e.g. "unexpected OID 701 |
3276 | | // for TIMESTAMP column 0"). nodesCollectColumns visits WHERE-subquery / |
3277 | | // ORDER BY columns before the projection, so the raw order diverges from |
3278 | | // pTargets only when a WHERE subquery (REMOTE_*) is present - exactly the |
3279 | | // failing case. |
3280 | 0 | PLAN_ERR_JRET(nodesCloneList(pScan->pScanCols, &pLeaf->pScanCols)); |
3281 | | // Optional query conditions stay local in this fallback. Saved binding filters |
3282 | | // still belong to the remote leaf, even when no optimizer rule runs. |
3283 | 0 | code = nodesCloneNode(pScanLogicNode->pPushedConditions, &pLeaf->pPushedConditions); |
3284 | 0 | QUERY_CHECK_CODE(code, lino, _return); |
3285 | | // LIMIT: makePhysiNode moved pScanLogicNode->pLimit to pScan->node.pLimit. |
3286 | 0 | if (pScan->node.pLimit != NULL) { |
3287 | 0 | PLAN_ERR_JRET(nodesCloneNode(pScan->node.pLimit, &pLeaf->node.pLimit)); |
3288 | 0 | } |
3289 | 0 | planDebug("FQ-PHY: built fallback bare remote scan leaf=%p scanCols=%d targets=%d hasCond=%d hasLimit=%d", |
3290 | 0 | pLeaf, pLeaf->pScanCols ? LIST_LENGTH(pLeaf->pScanCols) : 0, |
3291 | 0 | pLeaf->node.pTargets ? LIST_LENGTH(pLeaf->node.pTargets) : 0, |
3292 | 0 | NULL != pLeaf->node.pConditions, NULL != pLeaf->node.pLimit); |
3293 | 0 | } |
3294 | | |
3295 | 0 | if (pRemoteRoot != NULL) { |
3296 | 0 | code = fqAttachRequiredScanConditions((SLogicNode*)pRemoteRoot, &pScan->pushdownFlags); |
3297 | 0 | QUERY_CHECK_CODE(code, lino, _return); |
3298 | 0 | PLAN_ERR_JRET(fqRefreshRemoteOutputTargets(pRemoteRoot)); |
3299 | | |
3300 | 0 | SLogicNode* pRemoteLogicRoot = (SLogicNode*)pRemoteRoot; |
3301 | 0 | planDebug("FQ-PHY: finalized remote root detail type=%d nChildren=%d targets=%d hasCond=%d limit=%p", |
3302 | 0 | (int)nodeType(pRemoteRoot), |
3303 | 0 | pRemoteLogicRoot->pChildren ? LIST_LENGTH(pRemoteLogicRoot->pChildren) : 0, |
3304 | 0 | pRemoteLogicRoot->pTargets ? LIST_LENGTH(pRemoteLogicRoot->pTargets) : 0, |
3305 | 0 | NULL != pRemoteLogicRoot->pConditions, pRemoteLogicRoot->pLimit); |
3306 | 0 | SScanLogicNode* pRemoteLeaf = fqFindExternalLogicLeafScan((SLogicNode*)pRemoteRoot); |
3307 | 0 | planDebug("FQ-PHY: finalized remote leaf detail leaf=%p hasCond=%d scanCols=%d targets=%d remotePlan=%p source=%s table=%s", |
3308 | 0 | pRemoteLeaf, (NULL != pRemoteLeaf && NULL != pRemoteLeaf->node.pConditions), |
3309 | 0 | (NULL != pRemoteLeaf && NULL != pRemoteLeaf->pScanCols) ? LIST_LENGTH(pRemoteLeaf->pScanCols) : 0, |
3310 | 0 | (NULL != pRemoteLeaf && NULL != pRemoteLeaf->node.pTargets) ? LIST_LENGTH(pRemoteLeaf->node.pTargets) : 0, |
3311 | 0 | NULL != pRemoteLeaf ? pRemoteLeaf->pRemoteLogicPlan : NULL, |
3312 | 0 | (NULL != pRemoteLeaf && NULL != pRemoteLeaf->pExtTableNode) |
3313 | 0 | ? ((SExtTableNode*)pRemoteLeaf->pExtTableNode)->sourceName |
3314 | 0 | : "(null)", |
3315 | 0 | (NULL != pRemoteLeaf && NULL != pRemoteLeaf->pExtTableNode) |
3316 | 0 | ? ((SExtTableNode*)pRemoteLeaf->pExtTableNode)->table.tableName |
3317 | 0 | : "(null)"); |
3318 | 0 | } |
3319 | | |
3320 | | // Attach the inner pRemotePlan (logic) tree to the outer Mode-1 wrapper. |
3321 | 0 | pScan->pRemotePlan = pRemoteRoot; |
3322 | 0 | pRemoteRoot = NULL; |
3323 | |
|
3324 | 0 | planDebug("FQ-PHY: FedScan=%p pRemotePlan=%p type=%d", |
3325 | 0 | pScan, pScan->pRemotePlan, |
3326 | 0 | pScan->pRemotePlan ? (int)nodeType(pScan->pRemotePlan) : -1); |
3327 | 0 | *pPhyNode = (SPhysiNode*)pScan; |
3328 | 0 | pScan = NULL; |
3329 | |
|
3330 | 0 | _return: |
3331 | 0 | nodesDestroyList(pReordered); |
3332 | 0 | nodesDestroyList(pReserveSlotCols); |
3333 | 0 | nodesDestroyNode(pRemoteRoot); |
3334 | 0 | nodesDestroyNode((SNode*)pScan); |
3335 | 0 | if (TSDB_CODE_SUCCESS != code) { |
3336 | 0 | planError("%s failed since %s", __func__, tstrerror(code)); |
3337 | 0 | } |
3338 | 0 | return code; |
3339 | 0 | } |
3340 | | |
3341 | | static int32_t createScanPhysiNode(SPhysiPlanContext* pCxt, SSubplan* pSubplan, SScanLogicNode* pScanLogicNode, |
3342 | 0 | SPhysiNode** pPhyNode) { |
3343 | |
|
3344 | 0 | switch (pScanLogicNode->scanType) { |
3345 | 0 | case SCAN_TYPE_TAG: |
3346 | 0 | PLAN_ERR_RET(createTagScanPhysiNode(pCxt, pSubplan, pScanLogicNode, pPhyNode)); |
3347 | 0 | break; |
3348 | 0 | case SCAN_TYPE_BLOCK_INFO: |
3349 | 0 | PLAN_ERR_RET(createSimpleScanPhysiNode(pCxt, pSubplan, pScanLogicNode, pPhyNode)); |
3350 | 0 | break; |
3351 | 0 | case SCAN_TYPE_TABLE_COUNT: |
3352 | 0 | PLAN_ERR_RET(createTableCountScanPhysiNode(pCxt, pSubplan, pScanLogicNode, pPhyNode)); |
3353 | 0 | break; |
3354 | 0 | case SCAN_TYPE_LAST_ROW: |
3355 | 0 | PLAN_ERR_RET(createLastRowScanPhysiNode(pCxt, pSubplan, pScanLogicNode, pPhyNode)); |
3356 | 0 | break; |
3357 | 0 | case SCAN_TYPE_TABLE: |
3358 | 0 | PLAN_ERR_RET(createTableScanPhysiNode(pCxt, pSubplan, pScanLogicNode, pPhyNode)); |
3359 | 0 | break; |
3360 | 0 | case SCAN_TYPE_SYSTEM_TABLE: |
3361 | 0 | PLAN_ERR_RET(createSystemTableScanPhysiNode(pCxt, pSubplan, pScanLogicNode, pPhyNode)); |
3362 | 0 | break; |
3363 | 0 | case SCAN_TYPE_STREAM: |
3364 | 0 | PLAN_ERR_RET(createStreamScanPhysiNode(pCxt, pSubplan, pScanLogicNode, pPhyNode)); |
3365 | 0 | break; |
3366 | 0 | case SCAN_TYPE_TABLE_MERGE: |
3367 | 0 | PLAN_ERR_RET(createTableMergeScanPhysiNode(pCxt, pSubplan, pScanLogicNode, pPhyNode)); |
3368 | 0 | break; |
3369 | 0 | case SCAN_TYPE_EXTERNAL: |
3370 | 0 | PLAN_ERR_RET(createFederatedScanPhysiNode(pCxt, pSubplan, pScanLogicNode, pPhyNode)); |
3371 | 0 | break; |
3372 | 0 | default: |
3373 | 0 | PLAN_ERR_RET(generateUsageErrMsg(pCxt->pPlanCxt->pMsg, pCxt->pPlanCxt->msgLen, TSDB_CODE_PLAN_INTERNAL_ERROR, |
3374 | 0 | "invalid scan type:%d", pScanLogicNode->scanType)); |
3375 | 0 | break; |
3376 | 0 | } |
3377 | | |
3378 | 0 | if (inStreamTriggerClause(pCxt->pPlanCxt) && !pCxt->pPlanCxt->streamCxt.triggerScanSubplan) { |
3379 | 0 | pCxt->pPlanCxt->streamCxt.triggerScanSubplan = (SNode*)pSubplan; |
3380 | 0 | } |
3381 | 0 | if (inStreamCalcClause(pCxt->pPlanCxt)) { |
3382 | 0 | SStreamCalcScan pStreamCalcScan = {0}; |
3383 | 0 | pStreamCalcScan.vgList = taosArrayInit(1, sizeof(int32_t)); |
3384 | | // External-source scans have no vgroup; execNode.nodeId is 0 (unset). |
3385 | | // Use SNODE_HANDLE as a sentinel so mnode can distinguish ext-source calc |
3386 | | // readers from normal vnode readers and assign the real snodeId / epset. |
3387 | 0 | int32_t calcNodeId = (pScanLogicNode->scanType == SCAN_TYPE_EXTERNAL) |
3388 | 0 | ? SNODE_HANDLE |
3389 | 0 | : pSubplan->execNode.nodeId; |
3390 | 0 | if (NULL == taosArrayPush(pStreamCalcScan.vgList, &calcNodeId)) { |
3391 | 0 | PLAN_ERR_RET(terrno); |
3392 | 0 | } |
3393 | 0 | pStreamCalcScan.scanPlan = (void*)pSubplan; |
3394 | | // Federated calc: record this scan's external source/table identity so the |
3395 | | // mnode can bind each calc reader to the correct per-source spec when the |
3396 | | // calc query JOINs multiple external tables/sources. tsColumn is resolved |
3397 | | // here (from pExtMeta) because pExtMeta is runtime-only and not serialized. |
3398 | 0 | if (pScanLogicNode->scanType == SCAN_TYPE_EXTERNAL && pScanLogicNode->pExtTableNode != NULL) { |
3399 | 0 | SExtTableNode* pExt = (SExtTableNode*)pScanLogicNode->pExtTableNode; |
3400 | 0 | tstrncpy(pStreamCalcScan.sourceName, pExt->sourceName, sizeof(pStreamCalcScan.sourceName)); |
3401 | 0 | const char* remoteTbl = |
3402 | 0 | (pExt->remoteTableName[0] != '\0') ? pExt->remoteTableName : pExt->table.tableName; |
3403 | 0 | tstrncpy(pStreamCalcScan.extTable, remoteTbl, sizeof(pStreamCalcScan.extTable)); |
3404 | 0 | if (pExt->tsPrimaryColIdx >= 0 && pExt->pExtMeta != NULL && |
3405 | 0 | pExt->tsPrimaryColIdx < pExt->pExtMeta->numOfCols && pExt->pExtMeta->pCols != NULL) { |
3406 | 0 | tstrncpy(pStreamCalcScan.tsColumn, pExt->pExtMeta->pCols[pExt->tsPrimaryColIdx].colName, |
3407 | 0 | sizeof(pStreamCalcScan.tsColumn)); |
3408 | 0 | } |
3409 | 0 | } |
3410 | 0 | if (pScanLogicNode->placeholderType == SP_PARTITION_ROWS) { |
3411 | 0 | pStreamCalcScan.readFromCache = true; |
3412 | 0 | } |
3413 | 0 | if (NULL == taosArrayPush(pCxt->pPlanCxt->streamCxt.calcScanPlanArray, &pStreamCalcScan)) { |
3414 | 0 | PLAN_ERR_RET(terrno); |
3415 | 0 | } |
3416 | 0 | } |
3417 | | |
3418 | 0 | return TSDB_CODE_SUCCESS; |
3419 | 0 | } |
3420 | | |
3421 | 0 | static int32_t getJoinDataBlockDescNode(SNodeList* pChildren, int32_t idx, SDataBlockDescNode** ppDesc) { |
3422 | 0 | if (2 == pChildren->length) { |
3423 | 0 | *ppDesc = ((SPhysiNode*)nodesListGetNode(pChildren, idx))->pOutputDataBlockDesc; |
3424 | 0 | } else if (1 == pChildren->length && |
3425 | 0 | nodeType(nodesListGetNode(pChildren, 0)) == QUERY_NODE_PHYSICAL_PLAN_GROUP_CACHE) { |
3426 | 0 | SGroupCachePhysiNode* pGrpCache = (SGroupCachePhysiNode*)nodesListGetNode(pChildren, 0); |
3427 | 0 | *ppDesc = ((SPhysiNode*)nodesListGetNode(pGrpCache->node.pChildren, idx))->pOutputDataBlockDesc; |
3428 | 0 | } else { |
3429 | 0 | planError("Invalid join children num:%d or child type:%d", pChildren->length, |
3430 | 0 | nodeType(nodesListGetNode(pChildren, 0))); |
3431 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
3432 | 0 | } |
3433 | | |
3434 | 0 | return TSDB_CODE_SUCCESS; |
3435 | 0 | } |
3436 | | |
3437 | | static int32_t setColEqList(SNode* pEqCond, int64_t leftBlkId, int64_t rightBlkId, SNodeList** ppLeft, |
3438 | 0 | SNodeList** ppRight) { |
3439 | 0 | int32_t code = 0; |
3440 | 0 | if (QUERY_NODE_OPERATOR == nodeType(pEqCond) && ((SOperatorNode*)pEqCond)->opType == OP_TYPE_EQUAL) { |
3441 | 0 | SOperatorNode* pOp = (SOperatorNode*)pEqCond; |
3442 | 0 | SNode* pNew = NULL; |
3443 | 0 | if (QUERY_NODE_COLUMN != nodeType(pOp->pLeft) || QUERY_NODE_COLUMN != nodeType(pOp->pRight)) { |
3444 | 0 | planError("invalid col equal list node type, leftType:%d, rightType:%d", nodeType(pOp->pLeft), nodeType(pOp->pRight)); |
3445 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
3446 | 0 | } |
3447 | 0 | if (leftBlkId == ((SColumnNode*)pOp->pLeft)->dataBlockId) { |
3448 | 0 | code = nodesCloneNode(pOp->pLeft, &pNew); |
3449 | 0 | if (TSDB_CODE_SUCCESS == code) { |
3450 | 0 | code = nodesListMakeStrictAppend(ppLeft, pNew); |
3451 | 0 | } |
3452 | 0 | } else if (rightBlkId == ((SColumnNode*)pOp->pLeft)->dataBlockId) { |
3453 | 0 | code = nodesCloneNode(pOp->pLeft, &pNew); |
3454 | 0 | if (TSDB_CODE_SUCCESS == code) { |
3455 | 0 | code = nodesListMakeStrictAppend(ppRight, pNew); |
3456 | 0 | } |
3457 | 0 | } else { |
3458 | 0 | planError("invalid col equal list, leftBlockId:%" PRId64, ((SColumnNode*)pOp->pLeft)->dataBlockId); |
3459 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
3460 | 0 | } |
3461 | 0 | if (TSDB_CODE_SUCCESS == code) { |
3462 | 0 | pNew = NULL; |
3463 | 0 | if (leftBlkId == ((SColumnNode*)pOp->pRight)->dataBlockId) { |
3464 | 0 | code = nodesCloneNode(pOp->pRight, &pNew); |
3465 | 0 | if (TSDB_CODE_SUCCESS == code) { |
3466 | 0 | code = nodesListMakeStrictAppend(ppLeft, pNew); |
3467 | 0 | } |
3468 | 0 | } else if (rightBlkId == ((SColumnNode*)pOp->pRight)->dataBlockId) { |
3469 | 0 | code = nodesCloneNode(pOp->pRight, &pNew); |
3470 | 0 | if (TSDB_CODE_SUCCESS == code) { |
3471 | 0 | code = nodesListMakeStrictAppend(ppRight, pNew); |
3472 | 0 | } |
3473 | 0 | } else { |
3474 | 0 | planError("invalid col equal list, rightBlockId:%" PRId64, ((SColumnNode*)pOp->pRight)->dataBlockId); |
3475 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
3476 | 0 | } |
3477 | 0 | } |
3478 | 0 | } else if (QUERY_NODE_LOGIC_CONDITION == nodeType(pEqCond) && |
3479 | 0 | ((SLogicConditionNode*)pEqCond)->condType == LOGIC_COND_TYPE_AND) { |
3480 | 0 | SLogicConditionNode* pLogic = (SLogicConditionNode*)pEqCond; |
3481 | 0 | SNode* pNode = NULL; |
3482 | 0 | FOREACH(pNode, pLogic->pParameterList) { |
3483 | 0 | int32_t code = setColEqList(pNode, leftBlkId, rightBlkId, ppLeft, ppRight); |
3484 | 0 | if (code) { |
3485 | 0 | return code; |
3486 | 0 | } |
3487 | 0 | } |
3488 | 0 | } else { |
3489 | 0 | planError("invalid col equal cond, type:%d", nodeType(pEqCond)); |
3490 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
3491 | 0 | } |
3492 | | |
3493 | 0 | return code; |
3494 | 0 | } |
3495 | | |
3496 | | static int32_t setMergeJoinPrimColEqCond(SNode* pEqCond, int32_t subType, int64_t leftBlkId, int64_t rightBlkId, |
3497 | 0 | SSortMergeJoinPhysiNode* pJoin, SJoinLogicNode* pJoinLogicNode) { |
3498 | 0 | int32_t code = 0; |
3499 | 0 | if (QUERY_NODE_OPERATOR == nodeType(pEqCond)) { |
3500 | 0 | SOperatorNode* pOp = (SOperatorNode*)pEqCond; |
3501 | 0 | if (pOp->opType != OP_TYPE_EQUAL && JOIN_STYPE_ASOF != subType) { |
3502 | 0 | planError("invalid primary cond opType, opType:%d", pOp->opType); |
3503 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
3504 | 0 | } |
3505 | | |
3506 | | // Track whether the LEFT operand already set asofOpType. When two tables |
3507 | | // share the same column name (e.g. both have "ts"), doSetSlotId may |
3508 | | // incorrectly map the RIGHT operand to the left block too, causing the |
3509 | | // RIGHT branch below to overwrite asofOpType with the reversed operator. |
3510 | | // Giving priority to the LEFT operand preserves the correct direction. |
3511 | 0 | bool asofOpSetFromLeft = false; |
3512 | |
|
3513 | 0 | switch (nodeType(pOp->pLeft)) { |
3514 | 0 | case QUERY_NODE_COLUMN: { |
3515 | 0 | SColumnNode* pCol = (SColumnNode*)pOp->pLeft; |
3516 | 0 | if (leftBlkId == pCol->dataBlockId) { |
3517 | 0 | pJoin->leftPrimSlotId = pCol->slotId; |
3518 | 0 | pJoin->asofOpType = pOp->opType; |
3519 | 0 | asofOpSetFromLeft = true; |
3520 | 0 | } else if (rightBlkId == pCol->dataBlockId) { |
3521 | 0 | pJoin->rightPrimSlotId = pCol->slotId; |
3522 | 0 | } else { |
3523 | 0 | planError("invalid primary key col equal cond, leftBlockId:%" PRId64, pCol->dataBlockId); |
3524 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
3525 | 0 | } |
3526 | 0 | break; |
3527 | 0 | } |
3528 | 0 | case QUERY_NODE_VALUE: { |
3529 | 0 | if (pJoinLogicNode && pJoinLogicNode->leftConstPrimGot) { |
3530 | 0 | pJoin->leftPrimExpr = NULL; |
3531 | 0 | code = nodesCloneNode(pOp->pLeft, &pJoin->leftPrimExpr); |
3532 | 0 | break; |
3533 | 0 | } |
3534 | | |
3535 | 0 | planError("value node got in prim eq left cond, rightType:%d", pOp->pRight ? nodeType(pOp->pRight) : 0); |
3536 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
3537 | 0 | } |
3538 | 0 | case QUERY_NODE_FUNCTION: { |
3539 | 0 | SFunctionNode* pFunc = (SFunctionNode*)pOp->pLeft; |
3540 | 0 | if (FUNCTION_TYPE_TIMETRUNCATE != pFunc->funcType && |
3541 | 0 | FUNCTION_TYPE_TIMESTAMP_SCALE != pFunc->funcType) { |
3542 | 0 | planError("invalid primary cond left function type, leftFuncType:%d", pFunc->funcType); |
3543 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
3544 | 0 | } |
3545 | 0 | SNode* pParam = nodesListGetNode(pFunc->pParameterList, 0); |
3546 | 0 | if (QUERY_NODE_COLUMN != nodeType(pParam)) { |
3547 | 0 | planError("invalid primary cond left function param type, leftParamType:%d", nodeType(pParam)); |
3548 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
3549 | 0 | } |
3550 | 0 | SColumnNode* pCol = (SColumnNode*)pParam; |
3551 | 0 | if (leftBlkId == pCol->dataBlockId) { |
3552 | 0 | pJoin->leftPrimSlotId = pCol->slotId; |
3553 | 0 | pJoin->asofOpType = pOp->opType; |
3554 | 0 | asofOpSetFromLeft = true; |
3555 | 0 | pJoin->leftPrimExpr = NULL; |
3556 | 0 | code = nodesCloneNode((SNode*)pFunc, &pJoin->leftPrimExpr); |
3557 | 0 | } else if (rightBlkId == pCol->dataBlockId) { |
3558 | 0 | pJoin->rightPrimSlotId = pCol->slotId; |
3559 | 0 | pJoin->rightPrimExpr = NULL; |
3560 | 0 | code = nodesCloneNode((SNode*)pFunc, &pJoin->rightPrimExpr); |
3561 | 0 | } else { |
3562 | 0 | planError("invalid primary key col equal cond, leftBlockId:%" PRId64, pCol->dataBlockId); |
3563 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
3564 | 0 | } |
3565 | 0 | break; |
3566 | 0 | } |
3567 | 0 | default: { |
3568 | 0 | SNodeList* pCols = NULL; |
3569 | 0 | code = nodesCollectColumnsFromNode(pOp->pLeft, NULL, COLLECT_COL_TYPE_ALL, &pCols); |
3570 | 0 | if (TSDB_CODE_SUCCESS != code || NULL == pCols || 0 == LIST_LENGTH(pCols)) { |
3571 | 0 | nodesDestroyList(pCols); |
3572 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
3573 | 0 | } |
3574 | 0 | SColumnNode* pCol = (SColumnNode*)nodesListGetNode(pCols, 0); |
3575 | 0 | for (SListCell* pCell = pCols->pHead; pCell; pCell = pCell->pNext) { |
3576 | 0 | SColumnNode* pExprCol = (SColumnNode*)pCell->pNode; |
3577 | 0 | if (pExprCol->dataBlockId != pCol->dataBlockId) { |
3578 | 0 | nodesDestroyList(pCols); |
3579 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
3580 | 0 | } |
3581 | 0 | } |
3582 | 0 | if (leftBlkId == pCol->dataBlockId) { |
3583 | 0 | pJoin->leftPrimSlotId = pCol->slotId; |
3584 | 0 | pJoin->asofOpType = pOp->opType; |
3585 | 0 | asofOpSetFromLeft = true; |
3586 | 0 | code = nodesCloneNode(pOp->pLeft, &pJoin->leftPrimExpr); |
3587 | 0 | } else if (rightBlkId == pCol->dataBlockId) { |
3588 | 0 | pJoin->rightPrimSlotId = pCol->slotId; |
3589 | 0 | code = nodesCloneNode(pOp->pLeft, &pJoin->rightPrimExpr); |
3590 | 0 | } else { |
3591 | 0 | code = TSDB_CODE_PLAN_INTERNAL_ERROR; |
3592 | 0 | } |
3593 | 0 | nodesDestroyList(pCols); |
3594 | 0 | break; |
3595 | 0 | } |
3596 | 0 | } |
3597 | 0 | if (TSDB_CODE_SUCCESS != code) { |
3598 | 0 | return code; |
3599 | 0 | } |
3600 | 0 | switch (nodeType(pOp->pRight)) { |
3601 | 0 | case QUERY_NODE_COLUMN: { |
3602 | 0 | SColumnNode* pCol = (SColumnNode*)pOp->pRight; |
3603 | 0 | if (leftBlkId == pCol->dataBlockId && !asofOpSetFromLeft) { |
3604 | 0 | pJoin->leftPrimSlotId = pCol->slotId; |
3605 | 0 | pJoin->asofOpType = getAsofJoinReverseOp(pOp->opType); |
3606 | 0 | } else if (rightBlkId == pCol->dataBlockId) { |
3607 | 0 | pJoin->rightPrimSlotId = pCol->slotId; |
3608 | 0 | } else if (leftBlkId != pCol->dataBlockId) { |
3609 | 0 | planError("invalid primary key col equal cond, rightBlockId:%" PRId64, pCol->dataBlockId); |
3610 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
3611 | 0 | } |
3612 | 0 | break; |
3613 | 0 | } |
3614 | 0 | case QUERY_NODE_VALUE: { |
3615 | 0 | if (pJoinLogicNode && pJoinLogicNode->rightConstPrimGot) { |
3616 | 0 | pJoin->rightPrimExpr = NULL; |
3617 | 0 | code = nodesCloneNode(pOp->pRight, &pJoin->rightPrimExpr); |
3618 | 0 | break; |
3619 | 0 | } |
3620 | | |
3621 | 0 | planError("value node got in prim eq right cond, leftType:%d", pOp->pLeft ? nodeType(pOp->pLeft) : 0); |
3622 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
3623 | 0 | } |
3624 | 0 | case QUERY_NODE_FUNCTION: { |
3625 | 0 | SFunctionNode* pFunc = (SFunctionNode*)pOp->pRight; |
3626 | 0 | if (FUNCTION_TYPE_TIMETRUNCATE != pFunc->funcType && |
3627 | 0 | FUNCTION_TYPE_TIMESTAMP_SCALE != pFunc->funcType) { |
3628 | 0 | planError("invalid primary cond right function type, rightFuncType:%d", pFunc->funcType); |
3629 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
3630 | 0 | } |
3631 | 0 | SNode* pParam = nodesListGetNode(pFunc->pParameterList, 0); |
3632 | 0 | if (QUERY_NODE_COLUMN != nodeType(pParam)) { |
3633 | 0 | planError("invalid primary cond right function param type, rightParamType:%d", nodeType(pParam)); |
3634 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
3635 | 0 | } |
3636 | 0 | SColumnNode* pCol = (SColumnNode*)pParam; |
3637 | 0 | if (leftBlkId == pCol->dataBlockId && !asofOpSetFromLeft) { |
3638 | 0 | pJoin->leftPrimSlotId = pCol->slotId; |
3639 | 0 | pJoin->asofOpType = getAsofJoinReverseOp(pOp->opType); |
3640 | 0 | pJoin->leftPrimExpr = NULL; |
3641 | 0 | code = nodesCloneNode((SNode*)pFunc, &pJoin->leftPrimExpr); |
3642 | 0 | } else if (rightBlkId == pCol->dataBlockId) { |
3643 | 0 | pJoin->rightPrimSlotId = pCol->slotId; |
3644 | 0 | pJoin->rightPrimExpr = NULL; |
3645 | 0 | code = nodesCloneNode((SNode*)pFunc, &pJoin->rightPrimExpr); |
3646 | 0 | } else if (leftBlkId != pCol->dataBlockId) { |
3647 | 0 | planError("invalid primary key col equal cond, rightBlockId:%" PRId64, pCol->dataBlockId); |
3648 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
3649 | 0 | } |
3650 | 0 | break; |
3651 | 0 | } |
3652 | 0 | default: { |
3653 | 0 | SNodeList* pCols = NULL; |
3654 | 0 | code = nodesCollectColumnsFromNode(pOp->pRight, NULL, COLLECT_COL_TYPE_ALL, &pCols); |
3655 | 0 | if (TSDB_CODE_SUCCESS != code || NULL == pCols || 0 == LIST_LENGTH(pCols)) { |
3656 | 0 | nodesDestroyList(pCols); |
3657 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
3658 | 0 | } |
3659 | 0 | SColumnNode* pCol = (SColumnNode*)nodesListGetNode(pCols, 0); |
3660 | 0 | if (leftBlkId == pCol->dataBlockId && !asofOpSetFromLeft) { |
3661 | 0 | pJoin->leftPrimSlotId = pCol->slotId; |
3662 | 0 | pJoin->asofOpType = getAsofJoinReverseOp(pOp->opType); |
3663 | 0 | code = nodesCloneNode(pOp->pRight, &pJoin->leftPrimExpr); |
3664 | 0 | } else if (rightBlkId == pCol->dataBlockId) { |
3665 | 0 | pJoin->rightPrimSlotId = pCol->slotId; |
3666 | 0 | code = nodesCloneNode(pOp->pRight, &pJoin->rightPrimExpr); |
3667 | 0 | } else { |
3668 | 0 | planError("invalid primary key col equal cond, rightBlockId:%" PRId64, pCol->dataBlockId); |
3669 | 0 | code = TSDB_CODE_PLAN_INTERNAL_ERROR; |
3670 | 0 | } |
3671 | 0 | nodesDestroyList(pCols); |
3672 | 0 | break; |
3673 | 0 | } |
3674 | 0 | } |
3675 | 0 | } else { |
3676 | 0 | planError("invalid primary key col equal cond, type:%d", nodeType(pEqCond)); |
3677 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
3678 | 0 | } |
3679 | | |
3680 | 0 | return code; |
3681 | 0 | } |
3682 | | |
3683 | 0 | static int32_t removePrimColFromJoinTargets(SNodeList* pTargets, SValueNode* pPrimExpr, SColumnNode** ppRemoved) { |
3684 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
3685 | 0 | SNode* pNode = NULL; |
3686 | 0 | FOREACH(pNode, pTargets) { |
3687 | 0 | SColumnNode* pCol = (SColumnNode*)pNode; |
3688 | 0 | if (0 == strcmp(pCol->tableAlias, pPrimExpr->node.srcTable) && 0 == strcmp(pCol->colName, pPrimExpr->node.aliasName)) { |
3689 | 0 | code = nodesCloneNode(pNode, (SNode**)ppRemoved); |
3690 | 0 | ERASE_NODE(pTargets); |
3691 | 0 | break; |
3692 | 0 | } |
3693 | 0 | } |
3694 | |
|
3695 | 0 | return code; |
3696 | 0 | } |
3697 | | |
3698 | 0 | static int32_t appendPrimColToJoinTargets(SSortMergeJoinPhysiNode* pJoin, SColumnNode** ppTarget, STargetNode* primExpr, int64_t blkId) { |
3699 | 0 | SColumnNode* pCol = *ppTarget; |
3700 | 0 | if (TSDB_DATA_TYPE_TIMESTAMP != pCol->node.resType.type) { |
3701 | 0 | planError("primary key output type is not ts, type:%d", pCol->node.resType.type); |
3702 | 0 | return TSDB_CODE_PAR_PRIM_KEY_MUST_BE_TS; |
3703 | 0 | } |
3704 | 0 | pCol->dataBlockId = blkId; |
3705 | 0 | pCol->slotId = primExpr->slotId; |
3706 | 0 | int32_t code = nodesListMakeStrictAppend(&pJoin->pTargets, (SNode *)pCol); |
3707 | 0 | if (TSDB_CODE_SUCCESS == code) { |
3708 | 0 | *ppTarget = NULL; |
3709 | 0 | } |
3710 | |
|
3711 | 0 | return code; |
3712 | 0 | } |
3713 | | |
3714 | 0 | static const char* getLogicNodeTableAlias(const SLogicNode* pLogicNode) { |
3715 | 0 | if (NULL == pLogicNode) { |
3716 | 0 | return NULL; |
3717 | 0 | } |
3718 | | |
3719 | 0 | const SNodeList* pCols = NULL; |
3720 | 0 | if (QUERY_NODE_LOGIC_PLAN_SCAN == nodeType(pLogicNode)) { |
3721 | 0 | pCols = ((const SScanLogicNode*)pLogicNode)->pScanCols; |
3722 | 0 | } else if (QUERY_NODE_LOGIC_PLAN_VIRTUAL_TABLE_SCAN == nodeType(pLogicNode)) { |
3723 | 0 | pCols = ((const SVirtualScanLogicNode*)pLogicNode)->pScanCols; |
3724 | 0 | } |
3725 | |
|
3726 | 0 | const SNode* pNode = NULL; |
3727 | 0 | FOREACH(pNode, pCols) { |
3728 | 0 | if (QUERY_NODE_COLUMN == nodeType(pNode) && '\0' != ((const SColumnNode*)pNode)->tableAlias[0]) { |
3729 | 0 | return ((const SColumnNode*)pNode)->tableAlias; |
3730 | 0 | } |
3731 | 0 | } |
3732 | 0 | FOREACH(pNode, pLogicNode->pTargets) { |
3733 | 0 | if (QUERY_NODE_COLUMN == nodeType(pNode) && '\0' != ((const SColumnNode*)pNode)->tableAlias[0]) { |
3734 | 0 | return ((const SColumnNode*)pNode)->tableAlias; |
3735 | 0 | } |
3736 | 0 | } |
3737 | 0 | return NULL; |
3738 | 0 | } |
3739 | | |
3740 | 0 | static const char* getLogicNodeTargetAlias(const SLogicNode* pLogicNode) { |
3741 | 0 | if (NULL != pLogicNode && QUERY_NODE_LOGIC_PLAN_PROJECT == nodeType(pLogicNode)) { |
3742 | 0 | const char* pStmtName = ((const SProjectLogicNode*)pLogicNode)->stmtName; |
3743 | 0 | if ('\0' != pStmtName[0]) { |
3744 | 0 | return pStmtName; |
3745 | 0 | } |
3746 | 0 | } |
3747 | 0 | return getLogicNodeTableAlias(pLogicNode); |
3748 | 0 | } |
3749 | | |
3750 | | static void getJoinChildTableAliases(const SJoinLogicNode* pJoinLogicNode, const char** ppLeftAlias, |
3751 | 0 | const char** ppRightAlias) { |
3752 | 0 | const SLogicNode* pLeftLogic = |
3753 | 0 | (const SLogicNode*)nodesListGetNode(pJoinLogicNode->node.pChildren, 0); |
3754 | 0 | const SLogicNode* pRightLogic = |
3755 | 0 | (const SLogicNode*)nodesListGetNode(pJoinLogicNode->node.pChildren, 1); |
3756 | 0 | *ppLeftAlias = getLogicNodeTableAlias(pLeftLogic); |
3757 | 0 | *ppRightAlias = getLogicNodeTableAlias(pRightLogic); |
3758 | 0 | } |
3759 | | |
3760 | | static int32_t setJoinNodeSlotId(SPhysiPlanContext* pCxt, const SJoinLogicNode* pJoin, int64_t leftDataBlockId, |
3761 | 0 | int64_t rightDataBlockId, SNode* pNode, SNode** pOutput) { |
3762 | | // Conditions are translated with the aliases exposed by the child scan |
3763 | | // targets. For subqueries, stmtName (the outer alias) may differ from |
3764 | | // those target aliases; using it here makes both TIMETRUNCATE join sides |
3765 | | // resolve to the wrong descriptor and ends in "Planner slot key not found". |
3766 | 0 | const char* leftAlias = NULL; |
3767 | 0 | const char* rightAlias = NULL; |
3768 | 0 | getJoinChildTableAliases(pJoin, &leftAlias, &rightAlias); |
3769 | 0 | return setNodeSlotIdWithAliases(pCxt, leftDataBlockId, rightDataBlockId, leftAlias, rightAlias, pNode, pOutput); |
3770 | 0 | } |
3771 | | |
3772 | 0 | static bool getJoinExprTableAlias(SNode* pExpr, char* pAlias, int32_t aliasLen) { |
3773 | 0 | SNodeList* pCols = NULL; |
3774 | 0 | if (NULL == pExpr || TSDB_CODE_SUCCESS != nodesCollectColumnsFromNode(pExpr, NULL, COLLECT_COL_TYPE_ALL, &pCols)) { |
3775 | 0 | return false; |
3776 | 0 | } |
3777 | | |
3778 | 0 | bool found = false; |
3779 | 0 | SNode* pNode = NULL; |
3780 | 0 | FOREACH(pNode, pCols) { |
3781 | 0 | SColumnNode* pCol = (SColumnNode*)pNode; |
3782 | 0 | if ('\0' != pCol->tableAlias[0]) { |
3783 | 0 | tstrncpy(pAlias, pCol->tableAlias, aliasLen); |
3784 | 0 | found = true; |
3785 | 0 | break; |
3786 | 0 | } |
3787 | 0 | } |
3788 | 0 | nodesDestroyList(pCols); |
3789 | 0 | return found; |
3790 | 0 | } |
3791 | | |
3792 | 0 | static bool getJoinCondSideAlias(SNode* pCond, int32_t childIndex, char* pAlias, int32_t aliasLen) { |
3793 | 0 | if (NULL == pCond) return false; |
3794 | 0 | if (QUERY_NODE_OPERATOR == nodeType(pCond)) { |
3795 | 0 | SOperatorNode* pOp = (SOperatorNode*)pCond; |
3796 | 0 | return getJoinExprTableAlias(0 == childIndex ? pOp->pLeft : pOp->pRight, pAlias, aliasLen); |
3797 | 0 | } |
3798 | 0 | if (QUERY_NODE_LOGIC_CONDITION == nodeType(pCond)) { |
3799 | 0 | SNode* pNode = NULL; |
3800 | 0 | FOREACH(pNode, ((SLogicConditionNode*)pCond)->pParameterList) { |
3801 | 0 | if (getJoinCondSideAlias(pNode, childIndex, pAlias, aliasLen)) return true; |
3802 | 0 | } |
3803 | 0 | } |
3804 | 0 | return false; |
3805 | 0 | } |
3806 | | |
3807 | | static int32_t setJoinTargetListSlotId(SPhysiPlanContext* pCxt, const SJoinLogicNode* pJoin, |
3808 | | int64_t leftDataBlockId, int64_t rightDataBlockId, |
3809 | 0 | const SNodeList* pList, SNodeList** pOutput) { |
3810 | 0 | if (NULL == pList) return TSDB_CODE_SUCCESS; |
3811 | | |
3812 | 0 | SNodeList* pRes = NULL; |
3813 | 0 | int32_t code = nodesCloneList(pList, &pRes); |
3814 | 0 | if (TSDB_CODE_SUCCESS != code) return code; |
3815 | | |
3816 | 0 | char leftAlias[TSDB_TABLE_NAME_LEN] = {0}; |
3817 | 0 | char rightAlias[TSDB_TABLE_NAME_LEN] = {0}; |
3818 | 0 | SNode* pEqCond = NULL != pJoin->pPrimKeyEqCond ? pJoin->pPrimKeyEqCond : pJoin->pColEqCond; |
3819 | 0 | const char* pLeftAlias = getJoinCondSideAlias(pEqCond, 0, leftAlias, sizeof(leftAlias)) ? leftAlias : NULL; |
3820 | 0 | const char* pRightAlias = getJoinCondSideAlias(pEqCond, 1, rightAlias, sizeof(rightAlias)) ? rightAlias : NULL; |
3821 | 0 | if (pJoin->isCrossJoin && |
3822 | 0 | (NULL == pLeftAlias || NULL == pRightAlias || 0 == strcmp(pLeftAlias, pRightAlias))) { |
3823 | 0 | const SLogicNode* pLeftLogic = (const SLogicNode*)nodesListGetNode(pJoin->node.pChildren, 0); |
3824 | 0 | const SLogicNode* pRightLogic = (const SLogicNode*)nodesListGetNode(pJoin->node.pChildren, 1); |
3825 | 0 | pLeftAlias = getLogicNodeTargetAlias(pLeftLogic); |
3826 | 0 | pRightAlias = getLogicNodeTargetAlias(pRightLogic); |
3827 | 0 | } |
3828 | 0 | SSetSlotIdCxt cxt = { |
3829 | 0 | .errCode = TSDB_CODE_SUCCESS, |
3830 | 0 | .pLeftHash = taosArrayGetP(pCxt->pLocationHelper, leftDataBlockId), |
3831 | 0 | .pLeftProjIdxHash = taosArrayGetP(pCxt->pProjIdxLocHelper, leftDataBlockId), |
3832 | 0 | .pRightHash = taosArrayGetP(pCxt->pLocationHelper, rightDataBlockId), |
3833 | 0 | .pRightProdIdxHash = taosArrayGetP(pCxt->pProjIdxLocHelper, rightDataBlockId), |
3834 | 0 | .pLeftTableAlias = pLeftAlias, |
3835 | 0 | .pRightTableAlias = pRightAlias}; |
3836 | 0 | nodesWalkExprs(pRes, doSetSlotId, &cxt); |
3837 | 0 | if (TSDB_CODE_SUCCESS != cxt.errCode) { |
3838 | 0 | nodesDestroyList(pRes); |
3839 | 0 | return cxt.errCode; |
3840 | 0 | } |
3841 | 0 | *pOutput = pRes; |
3842 | 0 | return TSDB_CODE_SUCCESS; |
3843 | 0 | } |
3844 | | |
3845 | | static int32_t addCrossJoinChildAliasKeys(SPhysiPlanContext* pCxt, const SLogicNode* pLogicChild, |
3846 | 0 | const SDataBlockDescNode* pDesc) { |
3847 | 0 | if (NULL == pLogicChild || NULL == pLogicChild->pTargets || NULL == pDesc || NULL == pDesc->pSlots) { |
3848 | 0 | return TSDB_CODE_SUCCESS; |
3849 | 0 | } |
3850 | | |
3851 | 0 | SHashObj* pHash = taosArrayGetP(pCxt->pLocationHelper, pDesc->dataBlockId); |
3852 | 0 | int32_t targetNum = LIST_LENGTH(pLogicChild->pTargets); |
3853 | 0 | int32_t slotNum = LIST_LENGTH(pDesc->pSlots); |
3854 | 0 | for (int32_t i = 0; NULL != pHash && i < targetNum && i < slotNum; ++i) { |
3855 | 0 | SNode* pTarget = nodesListGetNode(pLogicChild->pTargets, i); |
3856 | 0 | SSlotDescNode* pSlot = (SSlotDescNode*)nodesListGetNode(pDesc->pSlots, i); |
3857 | 0 | if (QUERY_NODE_COLUMN != nodeType(pTarget) || '\0' == ((SColumnNode*)pTarget)->tableAlias[0]) { |
3858 | 0 | continue; |
3859 | 0 | } |
3860 | | |
3861 | 0 | char* pKey = NULL; |
3862 | 0 | int32_t keyLen = 0; |
3863 | 0 | int32_t keyCap = 0; |
3864 | 0 | int32_t code = getSlotKey(pTarget, NULL, &pKey, &keyLen, 0, &keyCap); |
3865 | 0 | if (TSDB_CODE_SUCCESS == code) { |
3866 | 0 | code = putSlotToHashImpl(pDesc->dataBlockId, pSlot->slotId, pKey, keyLen, pHash); |
3867 | 0 | } |
3868 | 0 | taosMemoryFree(pKey); |
3869 | 0 | if (TSDB_CODE_SUCCESS != code) { |
3870 | 0 | return code; |
3871 | 0 | } |
3872 | 0 | } |
3873 | 0 | return TSDB_CODE_SUCCESS; |
3874 | 0 | } |
3875 | | |
3876 | 0 | static bool fqJoinTargetExprExistsBySlotKey(const SNodeList* pTargets, SNode* pExpr) { |
3877 | 0 | if (NULL == pTargets || NULL == pExpr) { |
3878 | 0 | return false; |
3879 | 0 | } |
3880 | | |
3881 | 0 | char* pExprKey = NULL; |
3882 | 0 | int32_t exprKeyLen = 0; |
3883 | 0 | int32_t exprKeyCap = 0; |
3884 | 0 | int32_t code = getSlotKey(pExpr, NULL, &pExprKey, &exprKeyLen, 0, &exprKeyCap); |
3885 | 0 | if (TSDB_CODE_SUCCESS != code) { |
3886 | 0 | planError("FQ-joinCondTargets: build expr slot key failed exprType=%d code=0x%x", |
3887 | 0 | (int)nodeType(pExpr), code); |
3888 | 0 | return false; |
3889 | 0 | } |
3890 | | |
3891 | 0 | bool exists = false; |
3892 | 0 | SNode* pNode = NULL; |
3893 | 0 | FOREACH(pNode, pTargets) { |
3894 | 0 | char* pTargetKey = NULL; |
3895 | 0 | int32_t targetKeyLen = 0; |
3896 | 0 | int32_t targetKeyCap = 0; |
3897 | 0 | code = getSlotKey(pNode, NULL, &pTargetKey, &targetKeyLen, 0, &targetKeyCap); |
3898 | 0 | if (TSDB_CODE_SUCCESS == code && |
3899 | 0 | exprKeyLen == targetKeyLen && |
3900 | 0 | 0 == memcmp(pExprKey, pTargetKey, exprKeyLen)) { |
3901 | 0 | exists = true; |
3902 | 0 | } |
3903 | 0 | taosMemoryFree(pTargetKey); |
3904 | 0 | if (exists || TSDB_CODE_SUCCESS != code) { |
3905 | 0 | if (TSDB_CODE_SUCCESS != code) { |
3906 | 0 | planError("FQ-joinCondTargets: build target slot key failed exprType=%d code=0x%x", |
3907 | 0 | (int)nodeType(pNode), code); |
3908 | 0 | } |
3909 | 0 | break; |
3910 | 0 | } |
3911 | 0 | } |
3912 | |
|
3913 | 0 | taosMemoryFree(pExprKey); |
3914 | 0 | return exists; |
3915 | 0 | } |
3916 | | |
3917 | | static int32_t fqAppendJoinConditionTargetsFromNode(SPhysiPlanContext* pCxt, |
3918 | | SNode* pCond, |
3919 | | int64_t leftDataBlockId, |
3920 | | int64_t rightDataBlockId, |
3921 | | SSHashObj** pTables, |
3922 | | SNodeList* pTargets, |
3923 | 0 | int32_t* pAppended) { |
3924 | 0 | SNodeList* pCondCols = NULL; |
3925 | 0 | int32_t code = nodesCollectColumnsFromNode(pCond, NULL, COLLECT_COL_TYPE_ALL, |
3926 | 0 | &pCondCols); |
3927 | 0 | if (TSDB_CODE_SUCCESS != code) { |
3928 | 0 | nodesDestroyList(pCondCols); |
3929 | 0 | return code; |
3930 | 0 | } |
3931 | | |
3932 | 0 | int32_t appended = 0; |
3933 | 0 | SNode* pNode = NULL; |
3934 | 0 | FOREACH(pNode, pCondCols) { |
3935 | 0 | SColumnNode* pCol = (SColumnNode*)pNode; |
3936 | 0 | size_t aliasLen = strlen(pCol->tableAlias); |
3937 | 0 | bool left = NULL != tSimpleHashGet(pTables[0], pCol->tableAlias, aliasLen); |
3938 | 0 | bool right = NULL != tSimpleHashGet(pTables[1], pCol->tableAlias, aliasLen); |
3939 | 0 | int64_t firstBlockId = leftDataBlockId; |
3940 | 0 | int64_t secondBlockId = rightDataBlockId; |
3941 | | // A bare-name fallback must stay within the column's owning input. |
3942 | 0 | if (left != right) { |
3943 | 0 | firstBlockId = left ? leftDataBlockId : rightDataBlockId; |
3944 | 0 | secondBlockId = -1; |
3945 | 0 | } |
3946 | |
|
3947 | 0 | SNode* pBound = NULL; |
3948 | 0 | code = setNodeSlotId(pCxt, firstBlockId, secondBlockId, pNode, &pBound); |
3949 | 0 | if (TSDB_CODE_SUCCESS != code) { |
3950 | 0 | planError("FQ-joinCondTargets: bind condition columns failed " |
3951 | 0 | "leftBlockId=%" PRId64 " rightBlockId=%" PRId64 |
3952 | 0 | " code=0x%x cond=%p", |
3953 | 0 | leftDataBlockId, rightDataBlockId, code, pCond); |
3954 | 0 | break; |
3955 | 0 | } |
3956 | 0 | if (fqJoinTargetExprExistsBySlotKey(pTargets, pBound)) { |
3957 | 0 | nodesDestroyNode(pBound); |
3958 | 0 | continue; |
3959 | 0 | } |
3960 | 0 | code = nodesListStrictAppend(pTargets, pBound); |
3961 | 0 | if (TSDB_CODE_SUCCESS != code) { |
3962 | 0 | planError("FQ-joinCondTargets: append hidden target failed col=%s " |
3963 | 0 | "tableAlias=%s code=0x%x", pCol->colName, pCol->tableAlias, |
3964 | 0 | code); |
3965 | 0 | break; |
3966 | 0 | } |
3967 | 0 | ++appended; |
3968 | 0 | SColumnNode* pBoundCol = (SColumnNode*)pBound; |
3969 | 0 | planDebug("FQ-joinCondTargets: appended hidden condition column col=%s " |
3970 | 0 | "alias=%s tableAlias=%s dataBlockId=%" PRId64 " slotId=%d", |
3971 | 0 | pBoundCol->colName, pBoundCol->node.aliasName, |
3972 | 0 | pBoundCol->tableAlias, pBoundCol->dataBlockId, pBoundCol->slotId); |
3973 | 0 | } |
3974 | 0 | *pAppended += appended; |
3975 | 0 | planDebug("FQ-joinCondTargets: leftBlockId=%" PRId64 " rightBlockId=%" PRId64 |
3976 | 0 | " appended=%d condCols=%d finalTargets=%d cond=%p", |
3977 | 0 | leftDataBlockId, rightDataBlockId, appended, |
3978 | 0 | LIST_LENGTH(pCondCols), LIST_LENGTH(pTargets), pCond); |
3979 | 0 | nodesDestroyList(pCondCols); |
3980 | 0 | return code; |
3981 | 0 | } |
3982 | | |
3983 | | static int32_t fqAppendJoinConditionTargets(SPhysiPlanContext* pCxt, |
3984 | | SJoinLogicNode* pJoinLogicNode, |
3985 | | int64_t leftDataBlockId, |
3986 | | int64_t rightDataBlockId, |
3987 | 0 | SNodeList* pTargets) { |
3988 | 0 | if (NULL == pCxt || NULL == pJoinLogicNode || NULL == pTargets) { |
3989 | 0 | return TSDB_CODE_SUCCESS; |
3990 | 0 | } |
3991 | | |
3992 | 0 | SNode* pConditions[] = {pJoinLogicNode->pFullOnCond, |
3993 | 0 | pJoinLogicNode->pColOnCond, |
3994 | 0 | pJoinLogicNode->node.pConditions}; |
3995 | 0 | if (NULL == pConditions[0] && NULL == pConditions[1] && |
3996 | 0 | NULL == pConditions[2]) { |
3997 | 0 | return TSDB_CODE_SUCCESS; |
3998 | 0 | } |
3999 | | |
4000 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
4001 | 0 | int32_t appended = 0; |
4002 | 0 | SSHashObj* pTables[2] = {NULL, NULL}; |
4003 | 0 | for (int32_t i = 0; i < 2 && TSDB_CODE_SUCCESS == code; ++i) { |
4004 | 0 | SNode* pChild = nodesListGetNode(pJoinLogicNode->node.pChildren, i); |
4005 | 0 | code = collectTableAliasFromNodes(pChild, &pTables[i]); |
4006 | 0 | if (TSDB_CODE_SUCCESS == code) { |
4007 | 0 | code = collectSourceTableAliasFromNodes(pChild, &pTables[i]); |
4008 | 0 | } |
4009 | 0 | } |
4010 | | |
4011 | | // ON and WHERE predicates may read hidden columns from the JOIN output. |
4012 | 0 | for (int32_t i = 0; i < 3 && TSDB_CODE_SUCCESS == code; ++i) { |
4013 | 0 | if (NULL != pConditions[i]) { |
4014 | 0 | code = fqAppendJoinConditionTargetsFromNode(pCxt, pConditions[i], |
4015 | 0 | leftDataBlockId, |
4016 | 0 | rightDataBlockId, pTables, |
4017 | 0 | pTargets, &appended); |
4018 | 0 | } |
4019 | 0 | } |
4020 | 0 | planDebug("FQ-joinCondTargets: joinType=%d leftBlockId=%" PRId64 |
4021 | 0 | " rightBlockId=%" PRId64 " totalAppended=%d finalTargets=%d " |
4022 | 0 | "fullOn=%p colOn=%p where=%p", (int)pJoinLogicNode->joinType, |
4023 | 0 | leftDataBlockId, rightDataBlockId, appended, LIST_LENGTH(pTargets), |
4024 | 0 | pConditions[0], pConditions[1], pConditions[2]); |
4025 | 0 | tSimpleHashCleanup(pTables[0]); |
4026 | 0 | tSimpleHashCleanup(pTables[1]); |
4027 | 0 | return code; |
4028 | 0 | } |
4029 | | static int32_t createMergeJoinPhysiNode(SPhysiPlanContext* pCxt, SNodeList* pChildren, SJoinLogicNode* pJoinLogicNode, |
4030 | 0 | SPhysiNode** pPhyNode) { |
4031 | 0 | bool constPrimEqCond = |
4032 | 0 | NULL != pJoinLogicNode->pPrimKeyEqCond && QUERY_NODE_OPERATOR == nodeType(pJoinLogicNode->pPrimKeyEqCond) && |
4033 | 0 | QUERY_NODE_VALUE == nodeType(((SOperatorNode*)pJoinLogicNode->pPrimKeyEqCond)->pLeft) && |
4034 | 0 | QUERY_NODE_VALUE == nodeType(((SOperatorNode*)pJoinLogicNode->pPrimKeyEqCond)->pRight); |
4035 | 0 | if (!IS_WINDOW_JOIN(pJoinLogicNode->subType) && !IS_ASOF_JOIN(pJoinLogicNode->subType) && |
4036 | 0 | (NULL == pJoinLogicNode->pPrimKeyEqCond || |
4037 | 0 | ((!constPrimEqCond) && |
4038 | 0 | (pJoinLogicNode->noPrimKeyEqCond || pJoinLogicNode->leftNoOrderedSubQuery || |
4039 | 0 | pJoinLogicNode->rightNoOrderedSubQuery)))) { |
4040 | 0 | return generateUsageErrMsg(pCxt->pPlanCxt->pMsg, pCxt->pPlanCxt->msgLen, TSDB_CODE_PAR_NOT_SUPPORT_JOIN, |
4041 | 0 | "Merge Join requires ordered inputs and primary timestamp equal condition"); |
4042 | 0 | } |
4043 | | |
4044 | 0 | SSortMergeJoinPhysiNode* pJoin = |
4045 | 0 | (SSortMergeJoinPhysiNode*)makePhysiNode(pCxt, (SLogicNode*)pJoinLogicNode, QUERY_NODE_PHYSICAL_PLAN_MERGE_JOIN); |
4046 | 0 | if (NULL == pJoin) { |
4047 | 0 | return terrno; |
4048 | 0 | } |
4049 | | |
4050 | 0 | SDataBlockDescNode* pLeftDesc = NULL; |
4051 | 0 | SDataBlockDescNode* pRightDesc = NULL; |
4052 | 0 | pJoin->joinType = pJoinLogicNode->joinType; |
4053 | 0 | pJoin->subType = pJoinLogicNode->subType; |
4054 | 0 | pJoin->pWindowOffset = NULL; |
4055 | 0 | int32_t code = nodesCloneNode(pJoinLogicNode->pWindowOffset, &pJoin->pWindowOffset); |
4056 | 0 | if (TSDB_CODE_SUCCESS == code) { |
4057 | 0 | pJoin->pJLimit = NULL; |
4058 | 0 | code = nodesCloneNode(pJoinLogicNode->pJLimit, (SNode**)&pJoin->pJLimit); |
4059 | 0 | } |
4060 | 0 | if (TSDB_CODE_SUCCESS == code) { |
4061 | 0 | pJoin->node.inputTsOrder = pJoinLogicNode->node.inputTsOrder; |
4062 | 0 | pJoin->seqWinGroup = pJoinLogicNode->seqWinGroup; |
4063 | 0 | pJoin->grpJoin = pJoinLogicNode->grpJoin; |
4064 | 0 | code = getJoinDataBlockDescNode(pChildren, 0, &pLeftDesc); |
4065 | 0 | } |
4066 | |
|
4067 | 0 | if (TSDB_CODE_SUCCESS == code) { |
4068 | 0 | code = getJoinDataBlockDescNode(pChildren, 1, &pRightDesc); |
4069 | 0 | } |
4070 | |
|
4071 | 0 | if (TSDB_CODE_SUCCESS == code && NULL != pJoinLogicNode->pPrimKeyEqCond) { |
4072 | 0 | code = setJoinNodeSlotId(pCxt, pJoinLogicNode, pLeftDesc->dataBlockId, pRightDesc->dataBlockId, |
4073 | 0 | pJoinLogicNode->pPrimKeyEqCond, &pJoin->pPrimKeyCond); |
4074 | 0 | if (TSDB_CODE_SUCCESS == code) { |
4075 | 0 | code = setMergeJoinPrimColEqCond(pJoin->pPrimKeyCond, pJoin->subType, pLeftDesc->dataBlockId, |
4076 | 0 | pRightDesc->dataBlockId, pJoin, pJoinLogicNode); |
4077 | 0 | } |
4078 | 0 | if (TSDB_CODE_SUCCESS == code && NULL != pJoin->leftPrimExpr) { |
4079 | 0 | code = addDataBlockSlot(pCxt, &pJoin->leftPrimExpr, pLeftDesc); |
4080 | 0 | } |
4081 | 0 | if (TSDB_CODE_SUCCESS == code && NULL != pJoin->rightPrimExpr) { |
4082 | 0 | code = addDataBlockSlot(pCxt, &pJoin->rightPrimExpr, pRightDesc); |
4083 | 0 | } |
4084 | 0 | } |
4085 | |
|
4086 | 0 | if (TSDB_CODE_SUCCESS == code && NULL != pJoinLogicNode->addPrimEqCond) { |
4087 | 0 | SNode* pPrimKeyCond = NULL; |
4088 | 0 | code = setJoinNodeSlotId(pCxt, pJoinLogicNode, pLeftDesc->dataBlockId, |
4089 | 0 | pRightDesc->dataBlockId, |
4090 | 0 | pJoinLogicNode->addPrimEqCond, &pPrimKeyCond); |
4091 | 0 | if (TSDB_CODE_SUCCESS == code) { |
4092 | 0 | code = setMergeJoinPrimColEqCond(pPrimKeyCond, pJoin->subType, pLeftDesc->dataBlockId, pRightDesc->dataBlockId, |
4093 | 0 | pJoin, NULL); |
4094 | 0 | } |
4095 | 0 | if (TSDB_CODE_SUCCESS == code && NULL != pJoin->leftPrimExpr) { |
4096 | 0 | code = addDataBlockSlot(pCxt, &pJoin->leftPrimExpr, pLeftDesc); |
4097 | 0 | } |
4098 | 0 | if (TSDB_CODE_SUCCESS == code && NULL != pJoin->rightPrimExpr) { |
4099 | 0 | code = addDataBlockSlot(pCxt, &pJoin->rightPrimExpr, pRightDesc); |
4100 | 0 | } |
4101 | 0 | if (TSDB_CODE_SUCCESS == code && NULL == pJoin->pPrimKeyCond) { |
4102 | 0 | pJoin->pPrimKeyCond = pPrimKeyCond; |
4103 | 0 | pPrimKeyCond = NULL; |
4104 | 0 | } |
4105 | 0 | nodesDestroyNode(pPrimKeyCond); |
4106 | 0 | } |
4107 | |
|
4108 | 0 | SValueNode* pLeftPrimExpr = NULL, *pRightPrimExpr = NULL; |
4109 | 0 | SColumnNode* pLeftTarget = NULL, *pRightTarget = NULL; |
4110 | 0 | if (TSDB_CODE_SUCCESS == code && pJoinLogicNode->leftConstPrimGot && pJoin->leftPrimExpr |
4111 | 0 | && QUERY_NODE_VALUE == nodeType(((STargetNode*)pJoin->leftPrimExpr)->pExpr)) { |
4112 | 0 | pLeftPrimExpr = (SValueNode*)((STargetNode*)pJoin->leftPrimExpr)->pExpr; |
4113 | 0 | code = removePrimColFromJoinTargets(pJoinLogicNode->node.pTargets, pLeftPrimExpr, &pLeftTarget); |
4114 | 0 | } |
4115 | |
|
4116 | 0 | if (TSDB_CODE_SUCCESS == code && pJoinLogicNode->rightConstPrimGot && pJoin->rightPrimExpr |
4117 | 0 | && QUERY_NODE_VALUE == nodeType(((STargetNode*)pJoin->rightPrimExpr)->pExpr)) { |
4118 | 0 | pRightPrimExpr = (SValueNode*)((STargetNode*)pJoin->rightPrimExpr)->pExpr; |
4119 | 0 | code = removePrimColFromJoinTargets(pJoinLogicNode->node.pTargets, pRightPrimExpr, &pRightTarget); |
4120 | 0 | } |
4121 | |
|
4122 | 0 | if (TSDB_CODE_SUCCESS == code) { |
4123 | 0 | code = setJoinTargetListSlotId(pCxt, pJoinLogicNode, pLeftDesc->dataBlockId, pRightDesc->dataBlockId, |
4124 | 0 | pJoinLogicNode->node.pTargets, &pJoin->pTargets); |
4125 | 0 | } |
4126 | |
|
4127 | 0 | if (TSDB_CODE_SUCCESS == code && pLeftPrimExpr && pLeftTarget) { |
4128 | 0 | code = appendPrimColToJoinTargets(pJoin, &pLeftTarget, (STargetNode*)pJoin->leftPrimExpr, pLeftDesc->dataBlockId); |
4129 | 0 | } |
4130 | 0 | if (TSDB_CODE_SUCCESS == code && pRightPrimExpr && pRightTarget) { |
4131 | 0 | code = appendPrimColToJoinTargets(pJoin, &pRightTarget, (STargetNode*)pJoin->rightPrimExpr, pRightDesc->dataBlockId); |
4132 | 0 | } |
4133 | |
|
4134 | 0 | if (TSDB_CODE_SUCCESS == code && ((NULL != pJoinLogicNode->pColEqCond) || (NULL != pJoinLogicNode->pTagEqCond))) { |
4135 | 0 | code = mergeJoinConds(&pJoinLogicNode->pColEqCond, &pJoinLogicNode->pTagEqCond); |
4136 | 0 | } |
4137 | | // TODO set from input blocks for group algo |
4138 | | /* |
4139 | | if (TSDB_CODE_SUCCESS == code && NULL != pJoinLogicNode->pColEqCond) { |
4140 | | code = setNodeSlotId(pCxt, pLeftDesc->dataBlockId, pRightDesc->dataBlockId, pJoinLogicNode->pColEqCond, |
4141 | | &pJoin->pColEqCond); |
4142 | | } |
4143 | | */ |
4144 | 0 | if (TSDB_CODE_SUCCESS == code && NULL != pJoinLogicNode->pColEqCond) { |
4145 | 0 | code = setJoinNodeSlotId(pCxt, pJoinLogicNode, pLeftDesc->dataBlockId, pRightDesc->dataBlockId, |
4146 | 0 | pJoinLogicNode->pColEqCond, &pJoin->pColEqCond); |
4147 | 0 | if (TSDB_CODE_SUCCESS == code) { |
4148 | 0 | code = setColEqList(pJoin->pColEqCond, pLeftDesc->dataBlockId, pRightDesc->dataBlockId, &pJoin->pEqLeft, |
4149 | 0 | &pJoin->pEqRight); |
4150 | 0 | } |
4151 | 0 | } |
4152 | |
|
4153 | 0 | if (TSDB_CODE_SUCCESS == code && ((NULL != pJoinLogicNode->pColOnCond) || (NULL != pJoinLogicNode->pTagOnCond))) { |
4154 | 0 | code = mergeJoinConds(&pJoinLogicNode->pColOnCond, &pJoinLogicNode->pTagOnCond); |
4155 | 0 | } |
4156 | | // TODO set from input blocks for group algo |
4157 | | /* |
4158 | | if (TSDB_CODE_SUCCESS == code && NULL != pJoinLogicNode->pColOnCond) { |
4159 | | code = setJoinNodeSlotId(pCxt, pJoinLogicNode, pLeftDesc->dataBlockId, pRightDesc->dataBlockId, |
4160 | | pJoinLogicNode->pColOnCond, &pJoin->pColOnCond); |
4161 | | } |
4162 | | */ |
4163 | |
|
4164 | 0 | if (TSDB_CODE_SUCCESS == code) { |
4165 | 0 | code = fqAppendJoinConditionTargets(pCxt, pJoinLogicNode, pLeftDesc->dataBlockId, pRightDesc->dataBlockId, |
4166 | 0 | pJoin->pTargets); |
4167 | 0 | } |
4168 | |
|
4169 | 0 | if (TSDB_CODE_SUCCESS == code) { |
4170 | 0 | code = addDataBlockSlots(pCxt, pJoin->pTargets, pJoin->node.pOutputDataBlockDesc); |
4171 | 0 | } |
4172 | |
|
4173 | 0 | if (TSDB_CODE_SUCCESS == code && NULL != pJoinLogicNode->pFullOnCond) { |
4174 | 0 | code = setNodeSlotId(pCxt, pJoin->node.pOutputDataBlockDesc->dataBlockId, -1, pJoinLogicNode->pFullOnCond, |
4175 | 0 | &pJoin->pFullOnCond); |
4176 | 0 | planDebug("FQ-joinSlots: mergeJoin bind fullOnCond code=0x%x outputBlockId=%" PRId64 " cond=%p bound=%p", |
4177 | 0 | code, pJoin->node.pOutputDataBlockDesc->dataBlockId, pJoinLogicNode->pFullOnCond, pJoin->pFullOnCond); |
4178 | 0 | } |
4179 | |
|
4180 | 0 | if (TSDB_CODE_SUCCESS == code && NULL != pJoinLogicNode->pColOnCond) { |
4181 | 0 | code = setNodeSlotId(pCxt, pJoin->node.pOutputDataBlockDesc->dataBlockId, -1, pJoinLogicNode->pColOnCond, |
4182 | 0 | &pJoin->pColOnCond); |
4183 | 0 | planDebug("FQ-joinSlots: mergeJoin bind colOnCond code=0x%x outputBlockId=%" PRId64 " cond=%p bound=%p", |
4184 | 0 | code, pJoin->node.pOutputDataBlockDesc->dataBlockId, pJoinLogicNode->pColOnCond, pJoin->pColOnCond); |
4185 | 0 | } |
4186 | |
|
4187 | 0 | if (TSDB_CODE_SUCCESS == code) { |
4188 | 0 | code = setConditionsSlotId(pCxt, (const SLogicNode*)pJoinLogicNode, (SPhysiNode*)pJoin); |
4189 | 0 | } |
4190 | |
|
4191 | 0 | if (TSDB_CODE_SUCCESS == code) { |
4192 | 0 | *pPhyNode = (SPhysiNode*)pJoin; |
4193 | 0 | } else { |
4194 | 0 | nodesDestroyNode((SNode*)pJoin); |
4195 | 0 | nodesDestroyNode((SNode*)pLeftTarget); |
4196 | 0 | nodesDestroyNode((SNode*)pRightTarget); |
4197 | 0 | } |
4198 | |
|
4199 | 0 | return code; |
4200 | 0 | } |
4201 | | |
4202 | 0 | static int32_t createHashJoinKeyColFromPrimExpr(SPhysiPlanContext* pCxt, SNode* pExpr, SNode** ppCol) { |
4203 | 0 | if (NULL == pExpr || NULL == ppCol) { |
4204 | 0 | planError("Invalid hash join key target"); |
4205 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
4206 | 0 | } |
4207 | | |
4208 | 0 | if (QUERY_NODE_FUNCTION == nodeType(pExpr)) { |
4209 | 0 | SFunctionNode* pFunc = (SFunctionNode*)pExpr; |
4210 | 0 | if (FUNCTION_TYPE_TIMETRUNCATE != pFunc->funcType && |
4211 | 0 | FUNCTION_TYPE_TIMESTAMP_SCALE != pFunc->funcType) { |
4212 | 0 | planError("Invalid hash join key function type:%d", pFunc->funcType); |
4213 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
4214 | 0 | } |
4215 | 0 | SNode* pParam = nodesListGetNode(pFunc->pParameterList, 0); |
4216 | 0 | if (NULL == pParam || QUERY_NODE_COLUMN != nodeType(pParam)) { |
4217 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
4218 | 0 | } |
4219 | | |
4220 | 0 | char* pName = NULL; |
4221 | 0 | int32_t len = 0; |
4222 | 0 | int32_t cap = 0; |
4223 | 0 | int32_t code = getSlotKey(pExpr, NULL, &pName, &len, 0, &cap); |
4224 | 0 | if (TSDB_CODE_SUCCESS != code) return code; |
4225 | 0 | SHashObj* pHash = taosArrayGetP(pCxt->pLocationHelper, ((SColumnNode*)pParam)->dataBlockId); |
4226 | 0 | SSlotIndex* pIndex = pHash ? taosHashGet(pHash, pName, len) : NULL; |
4227 | 0 | taosMemoryFree(pName); |
4228 | 0 | if (NULL == pIndex) { |
4229 | 0 | return TSDB_CODE_PLAN_SLOT_NOT_FOUND; |
4230 | 0 | } |
4231 | 0 | if (NULL == pIndex->pSlotIdsInfo || 0 == taosArrayGetSize(pIndex->pSlotIdsInfo)) { |
4232 | 0 | return TSDB_CODE_PLAN_SLOT_NOT_FOUND; |
4233 | 0 | } |
4234 | 0 | SSlotIdInfo* pSlotInfo = taosArrayGet(pIndex->pSlotIdsInfo, 0); |
4235 | 0 | if (NULL == pSlotInfo) { |
4236 | 0 | return TSDB_CODE_PLAN_SLOT_NOT_FOUND; |
4237 | 0 | } |
4238 | | |
4239 | 0 | SColumnNode* pCol = NULL; |
4240 | 0 | code = nodesMakeNode(QUERY_NODE_COLUMN, (SNode**)&pCol); |
4241 | 0 | if (TSDB_CODE_SUCCESS != code) return code; |
4242 | 0 | pCol->dataBlockId = pIndex->dataBlockId; |
4243 | 0 | pCol->slotId = pSlotInfo->slotId; |
4244 | 0 | pCol->colType = COLUMN_TYPE_COLUMN; |
4245 | 0 | pCol->node.resType = ((SExprNode*)pExpr)->resType; |
4246 | 0 | tstrncpy(pCol->colName, ((SExprNode*)pExpr)->aliasName, TSDB_COL_NAME_LEN); |
4247 | 0 | tstrncpy(pCol->node.aliasName, ((SExprNode*)pExpr)->aliasName, TSDB_COL_NAME_LEN); |
4248 | 0 | tstrncpy(pCol->node.userAlias, ((SExprNode*)pExpr)->aliasName, TSDB_COL_NAME_LEN); |
4249 | 0 | *ppCol = (SNode*)pCol; |
4250 | 0 | return TSDB_CODE_SUCCESS; |
4251 | 0 | } |
4252 | | |
4253 | 0 | if (QUERY_NODE_TARGET != nodeType(pExpr)) { |
4254 | 0 | planError("Invalid hash join key target type:%d", nodeType(pExpr)); |
4255 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
4256 | 0 | } |
4257 | 0 | STargetNode* pTarget = (STargetNode*)pExpr; |
4258 | 0 | if (NULL == pTarget->pExpr) return TSDB_CODE_PLAN_INTERNAL_ERROR; |
4259 | | |
4260 | 0 | SColumnNode* pCol = NULL; |
4261 | 0 | int32_t code = nodesMakeNode(QUERY_NODE_COLUMN, (SNode**)&pCol); |
4262 | 0 | if (TSDB_CODE_SUCCESS != code) { |
4263 | 0 | return code; |
4264 | 0 | } |
4265 | | |
4266 | 0 | pCol->dataBlockId = pTarget->dataBlockId; |
4267 | 0 | pCol->slotId = pTarget->slotId; |
4268 | 0 | pCol->colType = COLUMN_TYPE_COLUMN; |
4269 | 0 | pCol->node.resType = ((SExprNode*)pTarget->pExpr)->resType; |
4270 | 0 | tstrncpy(pCol->colName, ((SExprNode*)pTarget->pExpr)->aliasName, TSDB_COL_NAME_LEN); |
4271 | 0 | tstrncpy(pCol->node.aliasName, ((SExprNode*)pTarget->pExpr)->aliasName, TSDB_COL_NAME_LEN); |
4272 | 0 | tstrncpy(pCol->node.userAlias, ((SExprNode*)pTarget->pExpr)->aliasName, TSDB_COL_NAME_LEN); |
4273 | 0 | *ppCol = (SNode*)pCol; |
4274 | 0 | return TSDB_CODE_SUCCESS; |
4275 | 0 | } |
4276 | | |
4277 | | static int32_t getHashJoinNodeBlkId(SPhysiPlanContext* pCxt, SNode* pNode, int64_t leftBlkId, int64_t rightBlkId, |
4278 | 0 | int64_t* pBlkId) { |
4279 | | // Columns have already been slot-bound; block zero is a valid input. |
4280 | 0 | if (QUERY_NODE_COLUMN == nodeType(pNode) && ((SColumnNode*)pNode)->dataBlockId >= 0) { |
4281 | 0 | int64_t blockId = ((SColumnNode*)pNode)->dataBlockId; |
4282 | 0 | if (blockId != leftBlkId && blockId != rightBlkId) return TSDB_CODE_PLAN_NOT_SUPPORT_JOIN_COND; |
4283 | 0 | *pBlkId = blockId; |
4284 | 0 | return TSDB_CODE_SUCCESS; |
4285 | 0 | } |
4286 | | |
4287 | 0 | char* pName = NULL; |
4288 | 0 | int32_t len = 0; |
4289 | 0 | int32_t cap = 0; |
4290 | 0 | int32_t code = getSlotKey(pNode, NULL, &pName, &len, 0, &cap); |
4291 | 0 | if (TSDB_CODE_SUCCESS != code) return code; |
4292 | | |
4293 | 0 | int64_t blockId = -1; |
4294 | 0 | SHashObj* pHash = taosArrayGetP(pCxt->pLocationHelper, leftBlkId); |
4295 | 0 | if (NULL != pHash && NULL != taosHashGet(pHash, pName, len)) { |
4296 | 0 | blockId = leftBlkId; |
4297 | 0 | } else { |
4298 | 0 | pHash = taosArrayGetP(pCxt->pLocationHelper, rightBlkId); |
4299 | 0 | if (NULL != pHash && NULL != taosHashGet(pHash, pName, len)) blockId = rightBlkId; |
4300 | 0 | } |
4301 | 0 | taosMemoryFree(pName); |
4302 | 0 | if (blockId < 0) return TSDB_CODE_PLAN_SLOT_NOT_FOUND; |
4303 | | |
4304 | 0 | *pBlkId = blockId; |
4305 | 0 | return TSDB_CODE_SUCCESS; |
4306 | 0 | } |
4307 | | |
4308 | | static int32_t getHashJoinExprBlkId(SPhysiPlanContext* pCxt, SNode* pExpr, int64_t leftBlkId, int64_t rightBlkId, |
4309 | 0 | int64_t* pBlkId) { |
4310 | 0 | if (QUERY_NODE_COLUMN == nodeType(pExpr)) { |
4311 | 0 | return getHashJoinNodeBlkId(pCxt, pExpr, leftBlkId, rightBlkId, pBlkId); |
4312 | 0 | } |
4313 | | |
4314 | 0 | if (QUERY_NODE_FUNCTION == nodeType(pExpr) && FUNCTION_TYPE_TBNAME == ((SFunctionNode*)pExpr)->funcType) { |
4315 | 0 | int32_t code = getHashJoinNodeBlkId(pCxt, pExpr, leftBlkId, rightBlkId, pBlkId); |
4316 | 0 | if (TSDB_CODE_PLAN_SLOT_NOT_FOUND == code) { |
4317 | 0 | planError("%s", "Invalid hash join tbname key slot"); |
4318 | 0 | } |
4319 | 0 | return code; |
4320 | 0 | } |
4321 | | |
4322 | 0 | SNodeList* pCols = NULL; |
4323 | 0 | int32_t code = nodesCollectColumnsFromNode(pExpr, NULL, COLLECT_COL_TYPE_ALL, &pCols); |
4324 | 0 | if (TSDB_CODE_SUCCESS != code) return code; |
4325 | 0 | if (NULL == pCols || 0 == LIST_LENGTH(pCols)) { |
4326 | 0 | nodesDestroyList(pCols); |
4327 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
4328 | 0 | } |
4329 | 0 | int64_t blockId = -1; |
4330 | 0 | SNode* pCol = NULL; |
4331 | 0 | FOREACH(pCol, pCols) { |
4332 | 0 | if (QUERY_NODE_COLUMN != nodeType(pCol)) { |
4333 | 0 | nodesDestroyList(pCols); |
4334 | 0 | return TSDB_CODE_PLAN_NOT_SUPPORT_JOIN_COND; |
4335 | 0 | } |
4336 | | |
4337 | 0 | int64_t colBlockId = -1; |
4338 | 0 | code = getHashJoinNodeBlkId(pCxt, pCol, leftBlkId, rightBlkId, &colBlockId); |
4339 | 0 | if (TSDB_CODE_SUCCESS != code) { |
4340 | 0 | nodesDestroyList(pCols); |
4341 | 0 | return code; |
4342 | 0 | } |
4343 | | |
4344 | 0 | if (blockId < 0) { |
4345 | 0 | blockId = colBlockId; |
4346 | 0 | } else if (blockId != colBlockId) { |
4347 | 0 | nodesDestroyList(pCols); |
4348 | 0 | return TSDB_CODE_PLAN_NOT_SUPPORT_JOIN_COND; |
4349 | 0 | } |
4350 | 0 | } |
4351 | 0 | nodesDestroyList(pCols); |
4352 | 0 | if (blockId != leftBlkId && blockId != rightBlkId) { |
4353 | 0 | return TSDB_CODE_PLAN_NOT_SUPPORT_JOIN_COND; |
4354 | 0 | } |
4355 | 0 | *pBlkId = blockId; |
4356 | 0 | return TSDB_CODE_SUCCESS; |
4357 | 0 | } |
4358 | | |
4359 | 0 | static int32_t createHashJoinKeyCol(SPhysiPlanContext* pCxt, SNode* pExpr, int64_t inputBlockId, SNode** ppCol) { |
4360 | 0 | if (QUERY_NODE_COLUMN == nodeType(pExpr)) { |
4361 | 0 | return nodesCloneNode(pExpr, ppCol); |
4362 | 0 | } |
4363 | | |
4364 | 0 | if (QUERY_NODE_FUNCTION == nodeType(pExpr) && FUNCTION_TYPE_TBNAME == ((SFunctionNode*)pExpr)->funcType) { |
4365 | 0 | char* pName = NULL; |
4366 | 0 | int32_t len = 0; |
4367 | 0 | int32_t cap = 0; |
4368 | 0 | int32_t code = getSlotKey(pExpr, NULL, &pName, &len, 0, &cap); |
4369 | 0 | if (TSDB_CODE_SUCCESS != code) { |
4370 | 0 | return code; |
4371 | 0 | } |
4372 | | |
4373 | | // The caller has already resolved which JOIN input owns this expression. |
4374 | 0 | SHashObj* pHash = taosArrayGetP(pCxt->pLocationHelper, inputBlockId); |
4375 | 0 | SSlotIndex* pIndex = pHash != NULL ? taosHashGet(pHash, pName, len) : NULL; |
4376 | 0 | taosMemoryFree(pName); |
4377 | |
|
4378 | 0 | if (NULL == pIndex) { |
4379 | 0 | planError("%s", "Invalid hash join tbname key slot"); |
4380 | 0 | return TSDB_CODE_PLAN_SLOT_NOT_FOUND; |
4381 | 0 | } |
4382 | 0 | if (NULL == pIndex->pSlotIdsInfo || 0 == taosArrayGetSize(pIndex->pSlotIdsInfo)) { |
4383 | 0 | planError("%s", "Invalid hash join tbname key slot info"); |
4384 | 0 | return TSDB_CODE_PLAN_SLOT_NOT_FOUND; |
4385 | 0 | } |
4386 | | |
4387 | 0 | SColumnNode* pCol = NULL; |
4388 | 0 | code = nodesMakeNode(QUERY_NODE_COLUMN, (SNode**)&pCol); |
4389 | 0 | if (TSDB_CODE_SUCCESS != code) { |
4390 | 0 | return code; |
4391 | 0 | } |
4392 | 0 | pCol->dataBlockId = pIndex->dataBlockId; |
4393 | 0 | pCol->slotId = ((SSlotIdInfo*)taosArrayGet(pIndex->pSlotIdsInfo, 0))->slotId; |
4394 | 0 | pCol->colType = COLUMN_TYPE_COLUMN; |
4395 | 0 | pCol->node.resType = ((SExprNode*)pExpr)->resType; |
4396 | 0 | tstrncpy(pCol->colName, ((SExprNode*)pExpr)->aliasName, TSDB_COL_NAME_LEN); |
4397 | 0 | tstrncpy(pCol->node.aliasName, ((SExprNode*)pExpr)->aliasName, TSDB_COL_NAME_LEN); |
4398 | 0 | tstrncpy(pCol->node.userAlias, ((SExprNode*)pExpr)->aliasName, TSDB_COL_NAME_LEN); |
4399 | 0 | *ppCol = (SNode*)pCol; |
4400 | 0 | return TSDB_CODE_SUCCESS; |
4401 | 0 | } |
4402 | | |
4403 | 0 | planError("Invalid hash join key node type:%d", nodeType(pExpr)); |
4404 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
4405 | 0 | } |
4406 | | |
4407 | 0 | static int32_t normalizeHashJoinKeyTypes(SNode* pLeft, SNode* pRight) { |
4408 | 0 | if (NULL == pLeft || NULL == pRight) { |
4409 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
4410 | 0 | } |
4411 | | |
4412 | 0 | SNode* pLeftExpr = QUERY_NODE_TARGET == nodeType(pLeft) ? ((STargetNode*)pLeft)->pExpr : pLeft; |
4413 | 0 | SNode* pRightExpr = QUERY_NODE_TARGET == nodeType(pRight) ? ((STargetNode*)pRight)->pExpr : pRight; |
4414 | 0 | if (!nodesIsExprNode(pLeftExpr) || !nodesIsExprNode(pRightExpr)) return TSDB_CODE_PLAN_INTERNAL_ERROR; |
4415 | 0 | SDataType* pLeftType = &((SExprNode*)pLeftExpr)->resType; |
4416 | 0 | SDataType* pRightType = &((SExprNode*)pRightExpr)->resType; |
4417 | 0 | if (pLeftType->type == pRightType->type) { |
4418 | 0 | return TSDB_CODE_SUCCESS; |
4419 | 0 | } |
4420 | | |
4421 | 0 | if (!IS_NUMERIC_TYPE(pLeftType->type) || !IS_NUMERIC_TYPE(pRightType->type)) { |
4422 | 0 | return TSDB_CODE_PLAN_NOT_SUPPORT_JOIN_COND; |
4423 | 0 | } |
4424 | | |
4425 | 0 | int32_t commonType = vectorGetConvertType(pLeftType->type, pRightType->type); |
4426 | 0 | if (commonType < TSDB_DATA_TYPE_NULL || commonType >= TSDB_DATA_TYPE_MAX) { |
4427 | 0 | return TSDB_CODE_PLAN_NOT_SUPPORT_JOIN_COND; |
4428 | 0 | } |
4429 | | |
4430 | 0 | pLeftType->type = commonType; |
4431 | 0 | pRightType->type = commonType; |
4432 | 0 | pLeftType->bytes = tDataTypes[commonType].bytes; |
4433 | 0 | pRightType->bytes = tDataTypes[commonType].bytes; |
4434 | 0 | return TSDB_CODE_SUCCESS; |
4435 | 0 | } |
4436 | | |
4437 | | static int32_t createHashJoinExprTarget(SPhysiPlanContext* pCxt, SNode* pExpr, SDataBlockDescNode* pDesc, |
4438 | 0 | SNode** ppTarget) { |
4439 | 0 | int32_t code = setNodeSlotId(pCxt, pDesc->dataBlockId, -1, pExpr, ppTarget); |
4440 | 0 | if (TSDB_CODE_SUCCESS == code) { |
4441 | 0 | code = addDataBlockSlot(pCxt, ppTarget, pDesc); |
4442 | 0 | } |
4443 | 0 | return code; |
4444 | 0 | } |
4445 | | |
4446 | | static int32_t extractHashJoinOpCols(SPhysiPlanContext* pCxt, SDataBlockDescNode* pLeftDesc, |
4447 | 0 | SDataBlockDescNode* pRightDesc, SNode* pEq, SHashJoinPhysiNode* pJoin) { |
4448 | 0 | int32_t code = 0; |
4449 | 0 | int64_t lBlkId = pLeftDesc->dataBlockId; |
4450 | 0 | int64_t rBlkId = pRightDesc->dataBlockId; |
4451 | 0 | if (QUERY_NODE_OPERATOR != nodeType(pEq)) { |
4452 | 0 | planError("Invalid join equal node type:%d", nodeType(pEq)); |
4453 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
4454 | 0 | } |
4455 | | |
4456 | 0 | SOperatorNode* pOp = (SOperatorNode*)pEq; |
4457 | 0 | int64_t leftExprBlkId = 0; |
4458 | 0 | int64_t rightExprBlkId = 0; |
4459 | |
|
4460 | 0 | switch (nodeType(pOp->pLeft)) { |
4461 | 0 | case QUERY_NODE_COLUMN: |
4462 | 0 | leftExprBlkId = ((SColumnNode*)pOp->pLeft)->dataBlockId; |
4463 | 0 | break; |
4464 | 0 | case QUERY_NODE_TARGET: |
4465 | 0 | leftExprBlkId = ((STargetNode*)pOp->pLeft)->dataBlockId; |
4466 | 0 | break; |
4467 | 0 | case QUERY_NODE_VALUE: |
4468 | 0 | if (NULL == pJoin->leftPrimExpr || QUERY_NODE_TARGET != nodeType(pJoin->leftPrimExpr)) { |
4469 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
4470 | 0 | } |
4471 | 0 | leftExprBlkId = ((STargetNode*)pJoin->leftPrimExpr)->dataBlockId; |
4472 | 0 | break; |
4473 | 0 | case QUERY_NODE_FUNCTION: { |
4474 | 0 | SFunctionNode* pFunc = (SFunctionNode*)pOp->pLeft; |
4475 | 0 | if (FUNCTION_TYPE_TBNAME == pFunc->funcType) { |
4476 | 0 | code = getHashJoinExprBlkId(pCxt, pOp->pLeft, lBlkId, rBlkId, &leftExprBlkId); |
4477 | 0 | if (TSDB_CODE_SUCCESS != code) { |
4478 | 0 | return code; |
4479 | 0 | } |
4480 | 0 | break; |
4481 | 0 | } |
4482 | 0 | if (FUNCTION_TYPE_TIMETRUNCATE != pFunc->funcType && FUNCTION_TYPE_TIMESTAMP_SCALE != pFunc->funcType) { |
4483 | 0 | code = getHashJoinExprBlkId(pCxt, pOp->pLeft, lBlkId, rBlkId, &leftExprBlkId); |
4484 | 0 | if (TSDB_CODE_SUCCESS != code) return code; |
4485 | 0 | break; |
4486 | 0 | } |
4487 | 0 | code = getHashJoinExprBlkId(pCxt, pOp->pLeft, lBlkId, rBlkId, &leftExprBlkId); |
4488 | 0 | if (TSDB_CODE_SUCCESS != code) return code; |
4489 | 0 | break; |
4490 | 0 | } |
4491 | 0 | default: |
4492 | 0 | code = getHashJoinExprBlkId(pCxt, pOp->pLeft, lBlkId, rBlkId, &leftExprBlkId); |
4493 | 0 | if (TSDB_CODE_SUCCESS != code) return code; |
4494 | 0 | break; |
4495 | 0 | } |
4496 | | |
4497 | 0 | switch (nodeType(pOp->pRight)) { |
4498 | 0 | case QUERY_NODE_COLUMN: |
4499 | 0 | rightExprBlkId = ((SColumnNode*)pOp->pRight)->dataBlockId; |
4500 | 0 | break; |
4501 | 0 | case QUERY_NODE_TARGET: |
4502 | 0 | rightExprBlkId = ((STargetNode*)pOp->pRight)->dataBlockId; |
4503 | 0 | break; |
4504 | 0 | case QUERY_NODE_VALUE: |
4505 | 0 | if (NULL == pJoin->rightPrimExpr || QUERY_NODE_TARGET != nodeType(pJoin->rightPrimExpr)) { |
4506 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
4507 | 0 | } |
4508 | 0 | rightExprBlkId = ((STargetNode*)pJoin->rightPrimExpr)->dataBlockId; |
4509 | 0 | break; |
4510 | 0 | case QUERY_NODE_FUNCTION: { |
4511 | 0 | SFunctionNode* pFunc = (SFunctionNode*)pOp->pRight; |
4512 | 0 | if (FUNCTION_TYPE_TBNAME == pFunc->funcType) { |
4513 | 0 | code = getHashJoinExprBlkId(pCxt, pOp->pRight, lBlkId, rBlkId, &rightExprBlkId); |
4514 | 0 | if (TSDB_CODE_SUCCESS != code) { |
4515 | 0 | return code; |
4516 | 0 | } |
4517 | 0 | break; |
4518 | 0 | } |
4519 | 0 | if (FUNCTION_TYPE_TIMETRUNCATE != pFunc->funcType && FUNCTION_TYPE_TIMESTAMP_SCALE != pFunc->funcType) { |
4520 | 0 | code = getHashJoinExprBlkId(pCxt, pOp->pRight, lBlkId, rBlkId, &rightExprBlkId); |
4521 | 0 | if (TSDB_CODE_SUCCESS != code) return code; |
4522 | 0 | break; |
4523 | 0 | } |
4524 | 0 | code = getHashJoinExprBlkId(pCxt, pOp->pRight, lBlkId, rBlkId, &rightExprBlkId); |
4525 | 0 | if (TSDB_CODE_SUCCESS != code) return code; |
4526 | 0 | break; |
4527 | 0 | } |
4528 | 0 | default: |
4529 | 0 | code = getHashJoinExprBlkId(pCxt, pOp->pRight, lBlkId, rBlkId, &rightExprBlkId); |
4530 | 0 | if (TSDB_CODE_SUCCESS != code) return code; |
4531 | 0 | break; |
4532 | 0 | } |
4533 | | |
4534 | 0 | bool validExprBlocks = (lBlkId == leftExprBlkId && rBlkId == rightExprBlkId) || |
4535 | 0 | (rBlkId == leftExprBlkId && lBlkId == rightExprBlkId); |
4536 | 0 | if (!validExprBlocks && QUERY_NODE_FUNCTION == nodeType(pOp->pLeft) && |
4537 | 0 | QUERY_NODE_FUNCTION == nodeType(pOp->pRight)) { |
4538 | 0 | SFunctionNode* pLeftFunc = (SFunctionNode*)pOp->pLeft; |
4539 | 0 | SFunctionNode* pRightFunc = (SFunctionNode*)pOp->pRight; |
4540 | 0 | bool leftIsPrimFunc = FUNCTION_TYPE_TIMETRUNCATE == pLeftFunc->funcType || |
4541 | 0 | FUNCTION_TYPE_TIMESTAMP_SCALE == pLeftFunc->funcType; |
4542 | 0 | bool rightIsPrimFunc = FUNCTION_TYPE_TIMETRUNCATE == pRightFunc->funcType || |
4543 | 0 | FUNCTION_TYPE_TIMESTAMP_SCALE == pRightFunc->funcType; |
4544 | 0 | if (leftIsPrimFunc && rightIsPrimFunc) { |
4545 | 0 | leftExprBlkId = lBlkId; |
4546 | 0 | rightExprBlkId = rBlkId; |
4547 | 0 | } |
4548 | 0 | } |
4549 | |
|
4550 | 0 | SNode* pLeftExpr = NULL; |
4551 | 0 | SNode* pRightExpr = NULL; |
4552 | |
|
4553 | 0 | if (lBlkId == leftExprBlkId && rBlkId == rightExprBlkId) { |
4554 | 0 | if (QUERY_NODE_COLUMN == nodeType(pOp->pLeft)) { |
4555 | 0 | code = nodesCloneNode(pOp->pLeft, &pLeftExpr); |
4556 | 0 | } else if (QUERY_NODE_TARGET == nodeType(pOp->pLeft)) { |
4557 | 0 | code = createHashJoinKeyColFromPrimExpr(pCxt, pOp->pLeft, &pLeftExpr); |
4558 | 0 | } else if (QUERY_NODE_FUNCTION == nodeType(pOp->pLeft) && |
4559 | 0 | FUNCTION_TYPE_TBNAME == ((SFunctionNode*)pOp->pLeft)->funcType) { |
4560 | 0 | code = createHashJoinKeyCol(pCxt, pOp->pLeft, leftExprBlkId, &pLeftExpr); |
4561 | 0 | } else if (NULL != pJoin->leftPrimExpr && QUERY_NODE_FUNCTION == nodeType(pOp->pLeft) && |
4562 | 0 | (FUNCTION_TYPE_TIMETRUNCATE == ((SFunctionNode*)pOp->pLeft)->funcType || |
4563 | 0 | FUNCTION_TYPE_TIMESTAMP_SCALE == ((SFunctionNode*)pOp->pLeft)->funcType)) { |
4564 | 0 | code = createHashJoinKeyColFromPrimExpr(pCxt, pJoin->leftPrimExpr, &pLeftExpr); |
4565 | 0 | } else { |
4566 | 0 | code = createHashJoinExprTarget(pCxt, pOp->pLeft, pLeftDesc, &pLeftExpr); |
4567 | 0 | } |
4568 | 0 | if (TSDB_CODE_SUCCESS == code) { |
4569 | 0 | code = nodesListStrictAppend(pJoin->pOnLeft, pLeftExpr); |
4570 | 0 | } |
4571 | 0 | if (TSDB_CODE_SUCCESS == code) { |
4572 | 0 | if (QUERY_NODE_COLUMN == nodeType(pOp->pRight)) { |
4573 | 0 | code = nodesCloneNode(pOp->pRight, &pRightExpr); |
4574 | 0 | } else if (QUERY_NODE_TARGET == nodeType(pOp->pRight)) { |
4575 | 0 | code = createHashJoinKeyColFromPrimExpr(pCxt, pOp->pRight, &pRightExpr); |
4576 | 0 | } else if (QUERY_NODE_FUNCTION == nodeType(pOp->pRight) && |
4577 | 0 | FUNCTION_TYPE_TBNAME == ((SFunctionNode*)pOp->pRight)->funcType) { |
4578 | 0 | code = createHashJoinKeyCol(pCxt, pOp->pRight, rightExprBlkId, &pRightExpr); |
4579 | 0 | } else if (NULL != pJoin->rightPrimExpr && QUERY_NODE_FUNCTION == nodeType(pOp->pRight) && |
4580 | 0 | (FUNCTION_TYPE_TIMETRUNCATE == ((SFunctionNode*)pOp->pRight)->funcType || |
4581 | 0 | FUNCTION_TYPE_TIMESTAMP_SCALE == ((SFunctionNode*)pOp->pRight)->funcType)) { |
4582 | 0 | code = createHashJoinKeyColFromPrimExpr(pCxt, pJoin->rightPrimExpr, &pRightExpr); |
4583 | 0 | } else { |
4584 | 0 | code = createHashJoinExprTarget(pCxt, pOp->pRight, pRightDesc, &pRightExpr); |
4585 | 0 | } |
4586 | 0 | } |
4587 | 0 | if (TSDB_CODE_SUCCESS == code) { |
4588 | 0 | code = nodesListStrictAppend(pJoin->pOnRight, pRightExpr); |
4589 | 0 | } |
4590 | 0 | } else if (rBlkId == leftExprBlkId && lBlkId == rightExprBlkId) { |
4591 | 0 | if (QUERY_NODE_COLUMN == nodeType(pOp->pRight)) { |
4592 | 0 | code = nodesCloneNode(pOp->pRight, &pRightExpr); |
4593 | 0 | } else if (QUERY_NODE_TARGET == nodeType(pOp->pRight)) { |
4594 | 0 | code = createHashJoinKeyColFromPrimExpr(pCxt, pOp->pRight, &pRightExpr); |
4595 | 0 | } else if (QUERY_NODE_FUNCTION == nodeType(pOp->pRight) && |
4596 | 0 | FUNCTION_TYPE_TBNAME == ((SFunctionNode*)pOp->pRight)->funcType) { |
4597 | 0 | code = createHashJoinKeyCol(pCxt, pOp->pRight, rightExprBlkId, &pRightExpr); |
4598 | 0 | } else if (NULL != pJoin->leftPrimExpr && QUERY_NODE_FUNCTION == nodeType(pOp->pRight) && |
4599 | 0 | (FUNCTION_TYPE_TIMETRUNCATE == ((SFunctionNode*)pOp->pRight)->funcType || |
4600 | 0 | FUNCTION_TYPE_TIMESTAMP_SCALE == ((SFunctionNode*)pOp->pRight)->funcType)) { |
4601 | 0 | code = createHashJoinKeyColFromPrimExpr(pCxt, pJoin->leftPrimExpr, &pRightExpr); |
4602 | 0 | } else { |
4603 | 0 | code = createHashJoinExprTarget(pCxt, pOp->pRight, pLeftDesc, &pRightExpr); |
4604 | 0 | } |
4605 | 0 | if (TSDB_CODE_SUCCESS == code) { |
4606 | 0 | code = nodesListStrictAppend(pJoin->pOnLeft, pRightExpr); |
4607 | 0 | } |
4608 | 0 | if (TSDB_CODE_SUCCESS == code) { |
4609 | 0 | if (QUERY_NODE_COLUMN == nodeType(pOp->pLeft)) { |
4610 | 0 | code = nodesCloneNode(pOp->pLeft, &pLeftExpr); |
4611 | 0 | } else if (QUERY_NODE_TARGET == nodeType(pOp->pLeft)) { |
4612 | 0 | code = createHashJoinKeyColFromPrimExpr(pCxt, pOp->pLeft, &pLeftExpr); |
4613 | 0 | } else if (QUERY_NODE_FUNCTION == nodeType(pOp->pLeft) && |
4614 | 0 | FUNCTION_TYPE_TBNAME == ((SFunctionNode*)pOp->pLeft)->funcType) { |
4615 | 0 | code = createHashJoinKeyCol(pCxt, pOp->pLeft, leftExprBlkId, &pLeftExpr); |
4616 | 0 | } else if (NULL != pJoin->rightPrimExpr && QUERY_NODE_FUNCTION == nodeType(pOp->pLeft) && |
4617 | 0 | (FUNCTION_TYPE_TIMETRUNCATE == ((SFunctionNode*)pOp->pLeft)->funcType || |
4618 | 0 | FUNCTION_TYPE_TIMESTAMP_SCALE == ((SFunctionNode*)pOp->pLeft)->funcType)) { |
4619 | 0 | code = createHashJoinKeyColFromPrimExpr(pCxt, pJoin->rightPrimExpr, &pLeftExpr); |
4620 | 0 | } else { |
4621 | 0 | code = createHashJoinExprTarget(pCxt, pOp->pLeft, pRightDesc, &pLeftExpr); |
4622 | 0 | } |
4623 | 0 | } |
4624 | 0 | if (TSDB_CODE_SUCCESS == code) { |
4625 | 0 | code = nodesListStrictAppend(pJoin->pOnRight, pLeftExpr); |
4626 | 0 | } |
4627 | 0 | } else { |
4628 | 0 | planError("Invalid join equal cond, lbid:%" PRId64 ", rbid:%" PRId64 ", oplid:%" PRId64 ", oprid:%" PRId64, |
4629 | 0 | lBlkId, rBlkId, leftExprBlkId, rightExprBlkId); |
4630 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
4631 | 0 | } |
4632 | | |
4633 | 0 | if (TSDB_CODE_SUCCESS == code) { |
4634 | 0 | code = normalizeHashJoinKeyTypes(pLeftExpr, pRightExpr); |
4635 | 0 | } |
4636 | 0 | return code; |
4637 | 0 | } |
4638 | | |
4639 | | static int32_t extractHashJoinOnCols(SPhysiPlanContext* pCxt, SDataBlockDescNode* pLeftDesc, |
4640 | 0 | SDataBlockDescNode* pRightDesc, SNode* pEq, SHashJoinPhysiNode* pJoin) { |
4641 | 0 | if (NULL == pEq) { |
4642 | 0 | return TSDB_CODE_SUCCESS; |
4643 | 0 | } |
4644 | | |
4645 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
4646 | 0 | if (QUERY_NODE_OPERATOR == nodeType(pEq)) { |
4647 | 0 | code = extractHashJoinOpCols(pCxt, pLeftDesc, pRightDesc, pEq, pJoin); |
4648 | 0 | } else if (QUERY_NODE_LOGIC_CONDITION == nodeType(pEq)) { |
4649 | 0 | SLogicConditionNode* pLogic = (SLogicConditionNode*)pEq; |
4650 | 0 | SNode* pNode = NULL; |
4651 | 0 | FOREACH(pNode, pLogic->pParameterList) { |
4652 | 0 | code = extractHashJoinOpCols(pCxt, pLeftDesc, pRightDesc, pNode, pJoin); |
4653 | 0 | if (code) { |
4654 | 0 | break; |
4655 | 0 | } |
4656 | 0 | } |
4657 | 0 | } else { |
4658 | 0 | planError("Invalid join equal node type:%d", nodeType(pEq)); |
4659 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
4660 | 0 | } |
4661 | | |
4662 | 0 | return code; |
4663 | 0 | } |
4664 | | |
4665 | | static int32_t createHashJoinColList(SPhysiPlanContext* pCxt, SDataBlockDescNode* pLeftDesc, |
4666 | | SDataBlockDescNode* pRightDesc, SNode* pEq1, SNode* pEq2, SNode* pEq3, |
4667 | 0 | SHashJoinPhysiNode* pJoin) { |
4668 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
4669 | 0 | pJoin->pOnLeft = NULL; |
4670 | 0 | code = nodesMakeList(&pJoin->pOnLeft); |
4671 | 0 | if (TSDB_CODE_SUCCESS != code) { |
4672 | 0 | return code; |
4673 | 0 | } |
4674 | 0 | pJoin->pOnRight = NULL; |
4675 | 0 | code = nodesMakeList(&pJoin->pOnRight); |
4676 | 0 | if (TSDB_CODE_SUCCESS != code) { |
4677 | 0 | return code; |
4678 | 0 | } |
4679 | | |
4680 | 0 | code = extractHashJoinOnCols(pCxt, pLeftDesc, pRightDesc, pEq1, pJoin); |
4681 | 0 | if (TSDB_CODE_SUCCESS == code) { |
4682 | 0 | code = extractHashJoinOnCols(pCxt, pLeftDesc, pRightDesc, pEq2, pJoin); |
4683 | 0 | } |
4684 | 0 | if (TSDB_CODE_SUCCESS == code) { |
4685 | 0 | code = extractHashJoinOnCols(pCxt, pLeftDesc, pRightDesc, pEq3, pJoin); |
4686 | 0 | } |
4687 | 0 | if (TSDB_CODE_SUCCESS == code && pJoin->pOnLeft->length <= 0) { |
4688 | 0 | planError("Invalid join equal column num: %d", pJoin->pOnLeft->length); |
4689 | 0 | code = TSDB_CODE_PLAN_INTERNAL_ERROR; |
4690 | 0 | } |
4691 | |
|
4692 | 0 | return code; |
4693 | 0 | } |
4694 | | |
4695 | 0 | static int32_t sortHashJoinTargets(int64_t lBlkId, int64_t rBlkId, SHashJoinPhysiNode* pJoin) { |
4696 | 0 | SNode* pNode = NULL; |
4697 | 0 | SSHashObj* pHash = tSimpleHashInit(pJoin->pTargets->length, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY)); |
4698 | 0 | if (NULL == pHash) { |
4699 | 0 | return TSDB_CODE_OUT_OF_MEMORY; |
4700 | 0 | } |
4701 | 0 | SNodeList* pNew = NULL; |
4702 | 0 | int32_t code = nodesMakeList(&pNew); |
4703 | |
|
4704 | 0 | if (TSDB_CODE_SUCCESS == code) { |
4705 | 0 | FOREACH(pNode, pJoin->pTargets) { |
4706 | 0 | SColumnNode* pCol = (SColumnNode*)pNode; |
4707 | 0 | char* pName = NULL; |
4708 | 0 | int32_t len = 0; |
4709 | 0 | int32_t cap = 0; |
4710 | 0 | code = getSlotKey(pNode, NULL, &pName, &len, 0, &cap); |
4711 | 0 | if (TSDB_CODE_SUCCESS == code) { |
4712 | 0 | code = tSimpleHashPut(pHash, pName, len, &pCol, POINTER_BYTES); |
4713 | 0 | } |
4714 | 0 | taosMemoryFree(pName); |
4715 | 0 | if (TSDB_CODE_SUCCESS != code) { |
4716 | 0 | break; |
4717 | 0 | } |
4718 | 0 | } |
4719 | 0 | } |
4720 | 0 | if (TSDB_CODE_SUCCESS == code) { |
4721 | 0 | nodesClearList(pJoin->pTargets); |
4722 | 0 | pJoin->pTargets = pNew; |
4723 | |
|
4724 | 0 | FOREACH(pNode, pJoin->pOnLeft) { |
4725 | 0 | char* pName = NULL; |
4726 | 0 | SColumnNode* pCol = (SColumnNode*)pNode; |
4727 | 0 | int32_t len = 0; |
4728 | 0 | int32_t cap = 0; |
4729 | 0 | code = getSlotKey(pNode, NULL, &pName, &len, 0, &cap); |
4730 | 0 | if (TSDB_CODE_SUCCESS == code) { |
4731 | 0 | SNode** p = tSimpleHashGet(pHash, pName, len); |
4732 | 0 | if (p) { |
4733 | 0 | code = nodesListStrictAppend(pJoin->pTargets, *p); |
4734 | 0 | if (TSDB_CODE_SUCCESS == code) { |
4735 | 0 | code = tSimpleHashRemove(pHash, pName, len); |
4736 | 0 | } |
4737 | 0 | } |
4738 | 0 | } |
4739 | 0 | taosMemoryFree(pName); |
4740 | 0 | if (TSDB_CODE_SUCCESS != code) { |
4741 | 0 | break; |
4742 | 0 | } |
4743 | 0 | } |
4744 | 0 | } |
4745 | 0 | if (TSDB_CODE_SUCCESS == code) { |
4746 | 0 | FOREACH(pNode, pJoin->pOnRight) { |
4747 | 0 | char* pName = NULL; |
4748 | 0 | SColumnNode* pCol = (SColumnNode*)pNode; |
4749 | 0 | int32_t len = 0; |
4750 | 0 | int32_t cap = 0; |
4751 | 0 | code = getSlotKey(pNode, NULL, &pName, &len, 0, &cap); |
4752 | 0 | if (TSDB_CODE_SUCCESS == code) { |
4753 | 0 | SNode** p = tSimpleHashGet(pHash, pName, len); |
4754 | 0 | if (p) { |
4755 | 0 | code = nodesListStrictAppend(pJoin->pTargets, *p); |
4756 | 0 | if (TSDB_CODE_SUCCESS == code) { |
4757 | 0 | code = tSimpleHashRemove(pHash, pName, len); |
4758 | 0 | } |
4759 | 0 | } |
4760 | 0 | } |
4761 | 0 | taosMemoryFree(pName); |
4762 | 0 | if (TSDB_CODE_SUCCESS != code) { |
4763 | 0 | break; |
4764 | 0 | } |
4765 | 0 | } |
4766 | 0 | } |
4767 | 0 | if (TSDB_CODE_SUCCESS == code) { |
4768 | 0 | if (tSimpleHashGetSize(pHash) > 0) { |
4769 | 0 | SNode** p = NULL; |
4770 | 0 | int32_t iter = 0; |
4771 | 0 | while (1) { |
4772 | 0 | p = tSimpleHashIterate(pHash, p, &iter); |
4773 | 0 | if (p == NULL) { |
4774 | 0 | break; |
4775 | 0 | } |
4776 | | |
4777 | 0 | code = nodesListStrictAppend(pJoin->pTargets, *p); |
4778 | 0 | if (TSDB_CODE_SUCCESS != code) { |
4779 | 0 | break; |
4780 | 0 | } |
4781 | 0 | } |
4782 | 0 | } |
4783 | 0 | } |
4784 | |
|
4785 | 0 | tSimpleHashCleanup(pHash); |
4786 | |
|
4787 | 0 | return code; |
4788 | 0 | } |
4789 | | |
4790 | | static int32_t setHashJoinPrimColEqCond(SNode* pEqCond, int64_t leftBlkId, int64_t rightBlkId, |
4791 | 0 | SHashJoinPhysiNode* pJoin) { |
4792 | 0 | int32_t code = 0; |
4793 | 0 | if (QUERY_NODE_OPERATOR == nodeType(pEqCond)) { |
4794 | 0 | SOperatorNode* pOp = (SOperatorNode*)pEqCond; |
4795 | 0 | if (pOp->opType != OP_TYPE_EQUAL) { |
4796 | 0 | planError("invalid primary cond opType, opType:%d", pOp->opType); |
4797 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
4798 | 0 | } |
4799 | | |
4800 | | // Projection-backed subqueries can leave one direct column operand with |
4801 | | // an unset dataBlockId even after slot binding. When the other operand |
4802 | | // identifies its side, the missing side is unambiguous; normalize it |
4803 | | // before assigning the hash-join primary slots. |
4804 | 0 | SColumnNode* pLeftCol = NULL; |
4805 | 0 | SColumnNode* pRightCol = NULL; |
4806 | 0 | if (QUERY_NODE_COLUMN == nodeType(pOp->pLeft)) { |
4807 | 0 | pLeftCol = (SColumnNode*)pOp->pLeft; |
4808 | 0 | } else if (QUERY_NODE_FUNCTION == nodeType(pOp->pLeft)) { |
4809 | 0 | SFunctionNode* pFunc = (SFunctionNode*)pOp->pLeft; |
4810 | 0 | SNode* pParam = nodesListGetNode(pFunc->pParameterList, 0); |
4811 | 0 | if (NULL != pParam && QUERY_NODE_COLUMN == nodeType(pParam)) { |
4812 | 0 | pLeftCol = (SColumnNode*)pParam; |
4813 | 0 | } |
4814 | 0 | } |
4815 | 0 | if (QUERY_NODE_COLUMN == nodeType(pOp->pRight)) { |
4816 | 0 | pRightCol = (SColumnNode*)pOp->pRight; |
4817 | 0 | } else if (QUERY_NODE_FUNCTION == nodeType(pOp->pRight)) { |
4818 | 0 | SFunctionNode* pFunc = (SFunctionNode*)pOp->pRight; |
4819 | 0 | SNode* pParam = nodesListGetNode(pFunc->pParameterList, 0); |
4820 | 0 | if (NULL != pParam && QUERY_NODE_COLUMN == nodeType(pParam)) { |
4821 | 0 | pRightCol = (SColumnNode*)pParam; |
4822 | 0 | } |
4823 | 0 | } |
4824 | 0 | if (NULL != pLeftCol && NULL != pRightCol) { |
4825 | 0 | bool leftKnown = (pLeftCol->dataBlockId == leftBlkId || pLeftCol->dataBlockId == rightBlkId); |
4826 | 0 | bool rightKnown = (pRightCol->dataBlockId == leftBlkId || pRightCol->dataBlockId == rightBlkId); |
4827 | 0 | if (leftKnown && rightKnown && pLeftCol->dataBlockId == pRightCol->dataBlockId) { |
4828 | 0 | pLeftCol->dataBlockId = leftBlkId; |
4829 | 0 | pRightCol->dataBlockId = rightBlkId; |
4830 | 0 | } else if (!leftKnown && rightKnown) { |
4831 | 0 | pLeftCol->dataBlockId = (pRightCol->dataBlockId == rightBlkId) ? leftBlkId : rightBlkId; |
4832 | 0 | } else if (leftKnown && !rightKnown) { |
4833 | 0 | pRightCol->dataBlockId = (pLeftCol->dataBlockId == leftBlkId) ? rightBlkId : leftBlkId; |
4834 | 0 | } else if (!leftKnown && !rightKnown) { |
4835 | 0 | pLeftCol->dataBlockId = leftBlkId; |
4836 | 0 | pRightCol->dataBlockId = rightBlkId; |
4837 | 0 | } |
4838 | 0 | } |
4839 | |
|
4840 | 0 | switch (nodeType(pOp->pLeft)) { |
4841 | 0 | case QUERY_NODE_COLUMN: { |
4842 | 0 | SColumnNode* pCol = (SColumnNode*)pOp->pLeft; |
4843 | 0 | if (leftBlkId == pCol->dataBlockId) { |
4844 | 0 | pJoin->leftPrimSlotId = pCol->slotId; |
4845 | 0 | } else if (rightBlkId == pCol->dataBlockId) { |
4846 | 0 | pJoin->rightPrimSlotId = pCol->slotId; |
4847 | 0 | } else { |
4848 | 0 | planError("invalid primary key col equal cond, leftBlockId:%" PRId64, pCol->dataBlockId); |
4849 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
4850 | 0 | } |
4851 | 0 | break; |
4852 | 0 | } |
4853 | 0 | case QUERY_NODE_VALUE: { |
4854 | 0 | pJoin->leftPrimExpr = NULL; |
4855 | 0 | code = nodesCloneNode(pOp->pLeft, &pJoin->leftPrimExpr); |
4856 | 0 | break; |
4857 | 0 | } |
4858 | 0 | case QUERY_NODE_FUNCTION: { |
4859 | 0 | SFunctionNode* pFunc = (SFunctionNode*)pOp->pLeft; |
4860 | 0 | if (FUNCTION_TYPE_TIMETRUNCATE != pFunc->funcType && |
4861 | 0 | FUNCTION_TYPE_TIMESTAMP_SCALE != pFunc->funcType) { |
4862 | 0 | planError("invalid primary cond left function type, leftFuncType:%d", pFunc->funcType); |
4863 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
4864 | 0 | } |
4865 | 0 | SNode* pParam = nodesListGetNode(pFunc->pParameterList, 0); |
4866 | 0 | if (NULL == pParam || QUERY_NODE_COLUMN != nodeType(pParam)) { |
4867 | 0 | planError("invalid primary cond left timetruncate param"); |
4868 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
4869 | 0 | } |
4870 | 0 | SColumnNode* pCol = (SColumnNode*)pParam; |
4871 | 0 | if (leftBlkId == pCol->dataBlockId) { |
4872 | 0 | pJoin->leftPrimSlotId = pCol->slotId; |
4873 | 0 | pJoin->leftPrimExpr = NULL; |
4874 | 0 | code = nodesCloneNode((SNode*)pFunc, &pJoin->leftPrimExpr); |
4875 | 0 | } else if (rightBlkId == pCol->dataBlockId) { |
4876 | 0 | pJoin->rightPrimSlotId = pCol->slotId; |
4877 | 0 | pJoin->rightPrimExpr = NULL; |
4878 | 0 | code = nodesCloneNode((SNode*)pFunc, &pJoin->rightPrimExpr); |
4879 | 0 | } else { |
4880 | 0 | planError("invalid primary key col equal cond, leftBlockId:%" PRId64, pCol->dataBlockId); |
4881 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
4882 | 0 | } |
4883 | 0 | break; |
4884 | 0 | } |
4885 | 0 | default: |
4886 | 0 | planError("invalid primary cond left node type, leftNodeType:%d", nodeType(pOp->pLeft)); |
4887 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
4888 | 0 | } |
4889 | 0 | if (TSDB_CODE_SUCCESS != code) { |
4890 | 0 | return code; |
4891 | 0 | } |
4892 | 0 | switch (nodeType(pOp->pRight)) { |
4893 | 0 | case QUERY_NODE_COLUMN: { |
4894 | 0 | SColumnNode* pCol = (SColumnNode*)pOp->pRight; |
4895 | 0 | if (leftBlkId == pCol->dataBlockId) { |
4896 | 0 | pJoin->leftPrimSlotId = pCol->slotId; |
4897 | 0 | } else if (rightBlkId == pCol->dataBlockId) { |
4898 | 0 | pJoin->rightPrimSlotId = pCol->slotId; |
4899 | 0 | } else { |
4900 | 0 | planError("invalid primary key col equal cond, rightBlockId:%" PRId64, pCol->dataBlockId); |
4901 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
4902 | 0 | } |
4903 | 0 | break; |
4904 | 0 | } |
4905 | 0 | case QUERY_NODE_VALUE: { |
4906 | 0 | pJoin->rightPrimExpr = NULL; |
4907 | 0 | code = nodesCloneNode(pOp->pRight, &pJoin->rightPrimExpr); |
4908 | 0 | break; |
4909 | 0 | } |
4910 | 0 | case QUERY_NODE_FUNCTION: { |
4911 | 0 | SFunctionNode* pFunc = (SFunctionNode*)pOp->pRight; |
4912 | 0 | if (FUNCTION_TYPE_TIMETRUNCATE != pFunc->funcType && |
4913 | 0 | FUNCTION_TYPE_TIMESTAMP_SCALE != pFunc->funcType) { |
4914 | 0 | planError("invalid primary cond right function type, rightFuncType:%d", pFunc->funcType); |
4915 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
4916 | 0 | } |
4917 | 0 | SNode* pParam = nodesListGetNode(pFunc->pParameterList, 0); |
4918 | 0 | if (NULL == pParam || QUERY_NODE_COLUMN != nodeType(pParam)) { |
4919 | 0 | planError("invalid primary cond right timetruncate param"); |
4920 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
4921 | 0 | } |
4922 | 0 | SColumnNode* pCol = (SColumnNode*)pParam; |
4923 | 0 | if (leftBlkId == pCol->dataBlockId) { |
4924 | 0 | pJoin->leftPrimSlotId = pCol->slotId; |
4925 | 0 | pJoin->leftPrimExpr = NULL; |
4926 | 0 | code = nodesCloneNode((SNode*)pFunc, &pJoin->leftPrimExpr); |
4927 | 0 | } else if (rightBlkId == pCol->dataBlockId) { |
4928 | 0 | pJoin->rightPrimSlotId = pCol->slotId; |
4929 | 0 | pJoin->rightPrimExpr = NULL; |
4930 | 0 | code = nodesCloneNode((SNode*)pFunc, &pJoin->rightPrimExpr); |
4931 | 0 | } else { |
4932 | 0 | planError("invalid primary key col equal cond, rightBlockId:%" PRId64, pCol->dataBlockId); |
4933 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
4934 | 0 | } |
4935 | 0 | break; |
4936 | 0 | } |
4937 | 0 | default: |
4938 | 0 | planError("invalid primary cond right node type, rightNodeType:%d", nodeType(pOp->pRight)); |
4939 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
4940 | 0 | } |
4941 | 0 | } else { |
4942 | 0 | planError("invalid primary key col equal cond, type:%d", nodeType(pEqCond)); |
4943 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
4944 | 0 | } |
4945 | | |
4946 | 0 | return code; |
4947 | 0 | } |
4948 | | |
4949 | 0 | static bool getTbnameFuncTableAlias(SFunctionNode* pFunc, char* pAlias, int32_t aliasLen) { |
4950 | 0 | if (FUNCTION_TYPE_TBNAME != pFunc->funcType) { |
4951 | 0 | return false; |
4952 | 0 | } |
4953 | | |
4954 | 0 | SNode* pParam = nodesListGetNode(pFunc->pParameterList, 0); |
4955 | 0 | if (NULL != pParam && QUERY_NODE_VALUE == nodeType(pParam)) { |
4956 | 0 | SValueNode* pVal = (SValueNode*)pParam; |
4957 | 0 | tstrncpy(pAlias, pVal->literal, aliasLen); |
4958 | 0 | return pAlias[0] != '\0'; |
4959 | 0 | } |
4960 | | |
4961 | 0 | char* pSuffix = NULL; |
4962 | 0 | if (NULL != pFunc->node.userAlias) { |
4963 | 0 | pSuffix = strstr(pFunc->node.userAlias, ".tbname"); |
4964 | 0 | } |
4965 | 0 | if (NULL != pSuffix && pSuffix != pFunc->node.userAlias) { |
4966 | 0 | int32_t len = TMIN((int32_t)(pSuffix - pFunc->node.userAlias), aliasLen - 1); |
4967 | 0 | memcpy(pAlias, pFunc->node.userAlias, len); |
4968 | 0 | pAlias[len] = '\0'; |
4969 | 0 | return true; |
4970 | 0 | } |
4971 | | |
4972 | 0 | return false; |
4973 | 0 | } |
4974 | | |
4975 | 0 | static bool logicNodeHasTableAlias(SLogicNode* pLogic, const char* pAlias) { |
4976 | 0 | if (NULL == pLogic || NULL == pLogic->pTargets || NULL == pAlias || '\0' == pAlias[0]) { |
4977 | 0 | return false; |
4978 | 0 | } |
4979 | | |
4980 | 0 | SNode* pNode = NULL; |
4981 | 0 | FOREACH(pNode, pLogic->pTargets) { |
4982 | 0 | if (QUERY_NODE_COLUMN == nodeType(pNode) && 0 == strcmp(((SColumnNode*)pNode)->tableAlias, pAlias)) { |
4983 | 0 | return true; |
4984 | 0 | } |
4985 | 0 | if (QUERY_NODE_FUNCTION == nodeType(pNode) && FUNCTION_TYPE_TBNAME == ((SFunctionNode*)pNode)->funcType) { |
4986 | 0 | char funcAlias[TSDB_TABLE_NAME_LEN] = {0}; |
4987 | 0 | if (getTbnameFuncTableAlias((SFunctionNode*)pNode, funcAlias, sizeof(funcAlias)) && |
4988 | 0 | 0 == strcmp(funcAlias, pAlias)) { |
4989 | 0 | return true; |
4990 | 0 | } |
4991 | 0 | } |
4992 | 0 | } |
4993 | | |
4994 | 0 | return false; |
4995 | 0 | } |
4996 | | |
4997 | | static int32_t ensureHashJoinTbnameKeySlot(SPhysiPlanContext* pCxt, SFunctionNode* pFunc, |
4998 | | SJoinLogicNode* pJoinLogicNode, |
4999 | | SDataBlockDescNode* pLeftDesc, |
5000 | 0 | SDataBlockDescNode* pRightDesc) { |
5001 | 0 | char alias[TSDB_TABLE_NAME_LEN] = {0}; |
5002 | 0 | if (!getTbnameFuncTableAlias(pFunc, alias, sizeof(alias))) { |
5003 | 0 | return TSDB_CODE_SUCCESS; |
5004 | 0 | } |
5005 | | |
5006 | 0 | SLogicNode* pLeftLogic = (SLogicNode*)nodesListGetNode(pJoinLogicNode->node.pChildren, 0); |
5007 | 0 | SLogicNode* pRightLogic = (SLogicNode*)nodesListGetNode(pJoinLogicNode->node.pChildren, 1); |
5008 | 0 | SDataBlockDescNode* pDesc = NULL; |
5009 | 0 | if (logicNodeHasTableAlias(pLeftLogic, alias)) { |
5010 | 0 | pDesc = pLeftDesc; |
5011 | 0 | } else if (logicNodeHasTableAlias(pRightLogic, alias)) { |
5012 | 0 | pDesc = pRightDesc; |
5013 | 0 | } else { |
5014 | 0 | planError("Invalid hash join tbname key alias:%s", alias); |
5015 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
5016 | 0 | } |
5017 | | |
5018 | 0 | SNode* pNode = NULL; |
5019 | 0 | int32_t code = nodesCloneNode((SNode*)pFunc, &pNode); |
5020 | 0 | if (TSDB_CODE_SUCCESS == code) { |
5021 | 0 | code = addDataBlockSlot(pCxt, &pNode, pDesc); |
5022 | 0 | } |
5023 | 0 | nodesDestroyNode(pNode); |
5024 | 0 | return code; |
5025 | 0 | } |
5026 | | |
5027 | | static int32_t ensureHashJoinTbnameKeySlots(SPhysiPlanContext* pCxt, SNode* pEqCond, |
5028 | | SJoinLogicNode* pJoinLogicNode, |
5029 | | SDataBlockDescNode* pLeftDesc, |
5030 | 0 | SDataBlockDescNode* pRightDesc) { |
5031 | 0 | if (NULL == pEqCond) { |
5032 | 0 | return TSDB_CODE_SUCCESS; |
5033 | 0 | } |
5034 | | |
5035 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
5036 | 0 | if (QUERY_NODE_OPERATOR == nodeType(pEqCond)) { |
5037 | 0 | SOperatorNode* pOp = (SOperatorNode*)pEqCond; |
5038 | 0 | if (QUERY_NODE_FUNCTION == nodeType(pOp->pLeft) && |
5039 | 0 | FUNCTION_TYPE_TBNAME == ((SFunctionNode*)pOp->pLeft)->funcType) { |
5040 | 0 | code = ensureHashJoinTbnameKeySlot(pCxt, (SFunctionNode*)pOp->pLeft, pJoinLogicNode, pLeftDesc, pRightDesc); |
5041 | 0 | } |
5042 | 0 | if (TSDB_CODE_SUCCESS == code && QUERY_NODE_FUNCTION == nodeType(pOp->pRight) && |
5043 | 0 | FUNCTION_TYPE_TBNAME == ((SFunctionNode*)pOp->pRight)->funcType) { |
5044 | 0 | code = ensureHashJoinTbnameKeySlot(pCxt, (SFunctionNode*)pOp->pRight, pJoinLogicNode, pLeftDesc, pRightDesc); |
5045 | 0 | } |
5046 | 0 | } else if (QUERY_NODE_LOGIC_CONDITION == nodeType(pEqCond)) { |
5047 | 0 | SNode* pNode = NULL; |
5048 | 0 | FOREACH(pNode, ((SLogicConditionNode*)pEqCond)->pParameterList) { |
5049 | 0 | code = ensureHashJoinTbnameKeySlots(pCxt, pNode, pJoinLogicNode, pLeftDesc, pRightDesc); |
5050 | 0 | if (TSDB_CODE_SUCCESS != code) { |
5051 | 0 | break; |
5052 | 0 | } |
5053 | 0 | } |
5054 | 0 | } |
5055 | |
|
5056 | 0 | return code; |
5057 | 0 | } |
5058 | | |
5059 | | static int32_t createHashJoinPhysiNode(SPhysiPlanContext* pCxt, SNodeList* pChildren, SJoinLogicNode* pJoinLogicNode, |
5060 | 0 | SPhysiNode** pPhyNode) { |
5061 | 0 | SHashJoinPhysiNode* pJoin = |
5062 | 0 | (SHashJoinPhysiNode*)makePhysiNode(pCxt, (SLogicNode*)pJoinLogicNode, QUERY_NODE_PHYSICAL_PLAN_HASH_JOIN); |
5063 | 0 | if (NULL == pJoin) { |
5064 | 0 | return terrno; |
5065 | 0 | } |
5066 | | |
5067 | 0 | SDataBlockDescNode* pLeftDesc = ((SPhysiNode*)nodesListGetNode(pChildren, 0))->pOutputDataBlockDesc; |
5068 | 0 | SDataBlockDescNode* pRightDesc = ((SPhysiNode*)nodesListGetNode(pChildren, 1))->pOutputDataBlockDesc; |
5069 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
5070 | |
|
5071 | 0 | pJoin->joinType = pJoinLogicNode->joinType; |
5072 | 0 | pJoin->subType = pJoinLogicNode->subType; |
5073 | 0 | pJoin->multiGroupJoin = pJoinLogicNode->multiGroupJoin; |
5074 | 0 | pJoin->pWindowOffset = NULL; |
5075 | 0 | code = nodesCloneNode(pJoinLogicNode->pWindowOffset, &pJoin->pWindowOffset); |
5076 | 0 | if (TSDB_CODE_SUCCESS != code) { |
5077 | 0 | nodesDestroyNode((SNode*)pJoin); |
5078 | 0 | return code; |
5079 | 0 | } |
5080 | 0 | pJoin->pJLimit = NULL; |
5081 | 0 | code = nodesCloneNode(pJoinLogicNode->pJLimit, &pJoin->pJLimit); |
5082 | 0 | if (TSDB_CODE_SUCCESS != code) { |
5083 | 0 | nodesDestroyNode((SNode*)pJoin); |
5084 | 0 | return code; |
5085 | 0 | } |
5086 | 0 | pJoin->node.inputTsOrder = pJoinLogicNode->node.inputTsOrder; |
5087 | 0 | pJoin->timeRangeTarget = pJoinLogicNode->timeRangeTarget; |
5088 | 0 | pJoin->timeRange.skey = pJoinLogicNode->timeRange.skey; |
5089 | 0 | pJoin->timeRange.ekey = pJoinLogicNode->timeRange.ekey; |
5090 | |
|
5091 | 0 | if (NULL != pJoinLogicNode->pPrimKeyEqCond) { |
5092 | 0 | code = setJoinNodeSlotId(pCxt, pJoinLogicNode, pLeftDesc->dataBlockId, pRightDesc->dataBlockId, |
5093 | 0 | pJoinLogicNode->pPrimKeyEqCond, &pJoin->pPrimKeyCond); |
5094 | 0 | if (TSDB_CODE_SUCCESS == code) { |
5095 | 0 | code = setHashJoinPrimColEqCond(pJoin->pPrimKeyCond, pLeftDesc->dataBlockId, pRightDesc->dataBlockId, pJoin); |
5096 | 0 | } |
5097 | 0 | if (TSDB_CODE_SUCCESS == code && NULL != pJoin->leftPrimExpr) { |
5098 | 0 | code = addDataBlockSlot(pCxt, &pJoin->leftPrimExpr, pLeftDesc); |
5099 | 0 | } |
5100 | 0 | if (TSDB_CODE_SUCCESS == code && NULL != pJoin->rightPrimExpr) { |
5101 | 0 | code = addDataBlockSlot(pCxt, &pJoin->rightPrimExpr, pRightDesc); |
5102 | 0 | } |
5103 | 0 | } |
5104 | 0 | if (TSDB_CODE_SUCCESS == code) { |
5105 | 0 | code = ensureHashJoinTbnameKeySlots(pCxt, pJoinLogicNode->pColEqCond, pJoinLogicNode, pLeftDesc, pRightDesc); |
5106 | 0 | } |
5107 | 0 | if (TSDB_CODE_SUCCESS == code) { |
5108 | 0 | code = ensureHashJoinTbnameKeySlots(pCxt, pJoinLogicNode->pTagEqCond, pJoinLogicNode, pLeftDesc, pRightDesc); |
5109 | 0 | } |
5110 | 0 | if (TSDB_CODE_SUCCESS == code) { |
5111 | 0 | code = setJoinNodeSlotId(pCxt, pJoinLogicNode, pLeftDesc->dataBlockId, pRightDesc->dataBlockId, |
5112 | 0 | pJoinLogicNode->pColEqCond, &pJoin->pColEqCond); |
5113 | 0 | } |
5114 | 0 | if (TSDB_CODE_SUCCESS == code) { |
5115 | 0 | code = setJoinNodeSlotId(pCxt, pJoinLogicNode, pLeftDesc->dataBlockId, pRightDesc->dataBlockId, |
5116 | 0 | pJoinLogicNode->pTagEqCond, &pJoin->pTagEqCond); |
5117 | 0 | } |
5118 | 0 | if (TSDB_CODE_SUCCESS == code) { |
5119 | 0 | code = setNodeSlotId(pCxt, pLeftDesc->dataBlockId, -1, pJoinLogicNode->pLeftOnCond, &pJoin->pLeftOnCond); |
5120 | 0 | } |
5121 | 0 | if (TSDB_CODE_SUCCESS == code) { |
5122 | 0 | code = setNodeSlotId(pCxt, -1, pRightDesc->dataBlockId, pJoinLogicNode->pRightOnCond, &pJoin->pRightOnCond); |
5123 | 0 | } |
5124 | 0 | if (TSDB_CODE_SUCCESS == code && ((NULL != pJoinLogicNode->pColOnCond) || (NULL != pJoinLogicNode->pTagOnCond))) { |
5125 | 0 | code = mergeJoinConds(&pJoinLogicNode->pColOnCond, &pJoinLogicNode->pTagOnCond); |
5126 | 0 | } |
5127 | 0 | SNode* pOnCond = (NULL != pJoinLogicNode->pColOnCond) ? pJoinLogicNode->pColOnCond : pJoinLogicNode->pTagOnCond; |
5128 | 0 | if (TSDB_CODE_SUCCESS == code) { |
5129 | | // Output targets retain outer aliases (a/b); use them only to disambiguate |
5130 | | // same-name slots across the two child descriptors. |
5131 | 0 | code = setJoinTargetListSlotId(pCxt, pJoinLogicNode, pLeftDesc->dataBlockId, pRightDesc->dataBlockId, |
5132 | 0 | pJoinLogicNode->node.pTargets, &pJoin->pTargets); |
5133 | 0 | } |
5134 | 0 | if (TSDB_CODE_SUCCESS == code) { |
5135 | 0 | code = createHashJoinColList(pCxt, pLeftDesc, pRightDesc, pJoin->pPrimKeyCond, pJoin->pColEqCond, |
5136 | 0 | pJoin->pTagEqCond, pJoin); |
5137 | 0 | } |
5138 | 0 | if (TSDB_CODE_SUCCESS == code) { |
5139 | 0 | code = sortHashJoinTargets(pLeftDesc->dataBlockId, pRightDesc->dataBlockId, pJoin); |
5140 | 0 | } |
5141 | 0 | if (TSDB_CODE_SUCCESS == code) { |
5142 | 0 | code = fqAppendJoinConditionTargets(pCxt, pJoinLogicNode, pLeftDesc->dataBlockId, pRightDesc->dataBlockId, |
5143 | 0 | pJoin->pTargets); |
5144 | 0 | } |
5145 | 0 | if (TSDB_CODE_SUCCESS == code) { |
5146 | 0 | code = addDataBlockSlots(pCxt, pJoin->pTargets, pJoin->node.pOutputDataBlockDesc); |
5147 | 0 | } |
5148 | 0 | if (TSDB_CODE_SUCCESS == code && NULL != pOnCond) { |
5149 | 0 | code = setNodeSlotId(pCxt, pJoin->node.pOutputDataBlockDesc->dataBlockId, -1, pOnCond, &pJoin->pFullOnCond); |
5150 | 0 | planDebug("FQ-joinSlots: hashJoin bind fullOnCond code=0x%x outputBlockId=%" PRId64 " cond=%p bound=%p", |
5151 | 0 | code, pJoin->node.pOutputDataBlockDesc->dataBlockId, pOnCond, pJoin->pFullOnCond); |
5152 | 0 | } |
5153 | 0 | if (TSDB_CODE_SUCCESS == code) { |
5154 | 0 | code = setConditionsSlotId(pCxt, (const SLogicNode*)pJoinLogicNode, (SPhysiNode*)pJoin); |
5155 | 0 | } |
5156 | |
|
5157 | 0 | if (TSDB_CODE_SUCCESS == code) { |
5158 | 0 | *pPhyNode = (SPhysiNode*)pJoin; |
5159 | 0 | } else { |
5160 | 0 | nodesDestroyNode((SNode*)pJoin); |
5161 | 0 | } |
5162 | |
|
5163 | 0 | return code; |
5164 | 0 | } |
5165 | | |
5166 | | static int32_t createThetaJoinPhysiNode(SPhysiPlanContext* pCxt, SNodeList* pChildren, |
5167 | 0 | SJoinLogicNode* pJoinLogicNode, SPhysiNode** pPhyNode) { |
5168 | 0 | SThetaJoinPhysiNode* pJoin = |
5169 | 0 | (SThetaJoinPhysiNode*)makePhysiNode(pCxt, (SLogicNode*)pJoinLogicNode, QUERY_NODE_PHYSICAL_PLAN_THETA_JOIN); |
5170 | 0 | if (NULL == pJoin) return terrno; |
5171 | | |
5172 | 0 | SDataBlockDescNode* pLeftDesc = ((SPhysiNode*)nodesListGetNode(pChildren, 0))->pOutputDataBlockDesc; |
5173 | 0 | SDataBlockDescNode* pRightDesc = ((SPhysiNode*)nodesListGetNode(pChildren, 1))->pOutputDataBlockDesc; |
5174 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
5175 | 0 | pJoin->joinType = pJoinLogicNode->joinType; |
5176 | 0 | pJoin->subType = pJoinLogicNode->subType; |
5177 | 0 | pJoin->leftPrimSlotId = (int32_t)pLeftDesc->dataBlockId; |
5178 | 0 | pJoin->rightPrimSlotId = (int32_t)pRightDesc->dataBlockId; |
5179 | 0 | if (pJoinLogicNode->isCrossJoin) { |
5180 | 0 | code = addCrossJoinChildAliasKeys( |
5181 | 0 | pCxt, (SLogicNode*)nodesListGetNode(pJoinLogicNode->node.pChildren, 0), pLeftDesc); |
5182 | 0 | if (TSDB_CODE_SUCCESS == code) { |
5183 | 0 | code = addCrossJoinChildAliasKeys( |
5184 | 0 | pCxt, (SLogicNode*)nodesListGetNode(pJoinLogicNode->node.pChildren, 1), pRightDesc); |
5185 | 0 | } |
5186 | 0 | if (TSDB_CODE_SUCCESS == code) { |
5187 | 0 | code = setJoinTargetListSlotId(pCxt, pJoinLogicNode, pLeftDesc->dataBlockId, pRightDesc->dataBlockId, |
5188 | 0 | pJoinLogicNode->node.pTargets, &pJoin->pTargets); |
5189 | 0 | } |
5190 | 0 | } else { |
5191 | 0 | code = setListSlotId(pCxt, pLeftDesc->dataBlockId, pRightDesc->dataBlockId, pJoinLogicNode->node.pTargets, |
5192 | 0 | &pJoin->pTargets); |
5193 | 0 | } |
5194 | 0 | if (TSDB_CODE_SUCCESS == code) { |
5195 | 0 | code = fqAppendJoinConditionTargets(pCxt, pJoinLogicNode, pLeftDesc->dataBlockId, pRightDesc->dataBlockId, |
5196 | 0 | pJoin->pTargets); |
5197 | 0 | } |
5198 | 0 | if (TSDB_CODE_SUCCESS == code) code = addDataBlockSlots(pCxt, pJoin->pTargets, pJoin->node.pOutputDataBlockDesc); |
5199 | 0 | if (TSDB_CODE_SUCCESS == code) { |
5200 | 0 | code = setNodeSlotId(pCxt, pJoin->node.pOutputDataBlockDesc->dataBlockId, -1, pJoinLogicNode->pFullOnCond, |
5201 | 0 | &pJoin->pFullOnCond); |
5202 | 0 | } |
5203 | 0 | if (TSDB_CODE_SUCCESS == code) code = setConditionsSlotId(pCxt, (SLogicNode*)pJoinLogicNode, (SPhysiNode*)pJoin); |
5204 | 0 | if (TSDB_CODE_SUCCESS == code) { |
5205 | 0 | *pPhyNode = (SPhysiNode*)pJoin; |
5206 | 0 | } else { |
5207 | 0 | nodesDestroyNode((SNode*)pJoin); |
5208 | 0 | } |
5209 | 0 | return code; |
5210 | 0 | } |
5211 | | |
5212 | | static int32_t createJoinPhysiNode(SPhysiPlanContext* pCxt, SNodeList* pChildren, SJoinLogicNode* pJoinLogicNode, |
5213 | 0 | SPhysiNode** pPhyNode) { |
5214 | 0 | if (pJoinLogicNode->multiGroupJoin) { |
5215 | 0 | if (JOIN_ALGO_HASH != pJoinLogicNode->joinAlgo) { |
5216 | 0 | planError("multi-group JOIN requires hash algorithm, actual:%d", pJoinLogicNode->joinAlgo); |
5217 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
5218 | 0 | } |
5219 | 0 | int32_t code = createHashJoinPhysiNode(pCxt, pChildren, pJoinLogicNode, pPhyNode); |
5220 | 0 | if (TSDB_CODE_SUCCESS == code && (QUERY_NODE_PHYSICAL_PLAN_HASH_JOIN != nodeType(*pPhyNode) || |
5221 | 0 | !((SHashJoinPhysiNode*)*pPhyNode)->multiGroupJoin)) { |
5222 | 0 | planError("%s", "marked logical JOIN did not produce a marked physical hash JOIN"); |
5223 | 0 | nodesDestroyNode((SNode*)*pPhyNode); |
5224 | 0 | *pPhyNode = NULL; |
5225 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
5226 | 0 | } |
5227 | 0 | return code; |
5228 | 0 | } |
5229 | | |
5230 | 0 | switch (pJoinLogicNode->joinAlgo) { |
5231 | 0 | case JOIN_ALGO_MERGE: |
5232 | 0 | return createMergeJoinPhysiNode(pCxt, pChildren, pJoinLogicNode, pPhyNode); |
5233 | 0 | case JOIN_ALGO_HASH: |
5234 | 0 | return createHashJoinPhysiNode(pCxt, pChildren, pJoinLogicNode, pPhyNode); |
5235 | 0 | case JOIN_ALGO_THETA: |
5236 | 0 | return createThetaJoinPhysiNode(pCxt, pChildren, pJoinLogicNode, pPhyNode); |
5237 | 0 | default: |
5238 | 0 | planError("Invalid join algorithm:%d", pJoinLogicNode->joinAlgo); |
5239 | 0 | break; |
5240 | 0 | } |
5241 | | |
5242 | 0 | return TSDB_CODE_FAILED; |
5243 | 0 | } |
5244 | | |
5245 | 0 | static int32_t createVirtualScanCols(SPhysiPlanContext* pCxt, SVirtualScanPhysiNode* pScanPhysiNode, SNodeList* pScanCols) { |
5246 | 0 | if (NULL == pScanCols) { |
5247 | 0 | return TSDB_CODE_SUCCESS; |
5248 | 0 | } |
5249 | | |
5250 | 0 | pScanPhysiNode->scan.pScanCols = NULL; |
5251 | 0 | int32_t code = nodesCloneList(pScanCols, &pScanPhysiNode->scan.pScanCols); |
5252 | 0 | if (NULL == pScanPhysiNode->scan.pScanCols) { |
5253 | 0 | return code; |
5254 | 0 | } |
5255 | 0 | return sortScanCols(pScanPhysiNode->scan.pScanCols); |
5256 | 0 | } |
5257 | | |
5258 | 0 | static const SColumnNode* getFederatedScanColumn(const SNode* pNode) { |
5259 | 0 | if (pNode != NULL && QUERY_NODE_TARGET == nodeType(pNode)) { |
5260 | 0 | pNode = ((const STargetNode*)pNode)->pExpr; |
5261 | 0 | } |
5262 | 0 | return (pNode != NULL && QUERY_NODE_COLUMN == nodeType(pNode)) ? (const SColumnNode*)pNode : NULL; |
5263 | 0 | } |
5264 | | |
5265 | 0 | static bool federatedOutputNameMatchesScanColumn(const char* pOutputName, const SColumnNode* pCol) { |
5266 | 0 | if (pOutputName == NULL || pOutputName[0] == '\0' || pCol == NULL) { |
5267 | 0 | return false; |
5268 | 0 | } |
5269 | | |
5270 | 0 | const char* pRefName = pCol->hasRef && pCol->refColName[0] != '\0' ? pCol->refColName : pCol->colName; |
5271 | 0 | return (pRefName[0] != '\0' && strcasecmp(pOutputName, pRefName) == 0) || |
5272 | 0 | (pCol->colName[0] != '\0' && strcasecmp(pOutputName, pCol->colName) == 0) || |
5273 | 0 | (pCol->node.aliasName[0] != '\0' && strcasecmp(pOutputName, pCol->node.aliasName) == 0) || |
5274 | 0 | (pCol->node.userAlias[0] != '\0' && strcasecmp(pOutputName, pCol->node.userAlias) == 0); |
5275 | 0 | } |
5276 | | |
5277 | | static int16_t getFederatedOutputSlot(const SFederatedScanPhysiNode* pScan, const SColumnNode* pCol, |
5278 | 0 | int32_t outputIdx) { |
5279 | 0 | if (pScan == NULL || pCol == NULL || pScan->pColTypeMappings == NULL || |
5280 | 0 | outputIdx < 0 || outputIdx >= pScan->numColTypeMappings || pScan->node.pOutputDataBlockDesc == NULL || |
5281 | 0 | pScan->node.pOutputDataBlockDesc->pSlots == NULL || |
5282 | 0 | outputIdx >= LIST_LENGTH(pScan->node.pOutputDataBlockDesc->pSlots)) { |
5283 | 0 | return -1; |
5284 | 0 | } |
5285 | | |
5286 | 0 | const SExtColTypeMapping* pMapping = &pScan->pColTypeMappings[outputIdx]; |
5287 | 0 | SSlotDescNode* pSlot = (SSlotDescNode*)nodesListGetNode(pScan->node.pOutputDataBlockDesc->pSlots, outputIdx); |
5288 | 0 | if (pMapping->tdType.type != pCol->node.resType.type || |
5289 | 0 | !federatedOutputNameMatchesScanColumn(pMapping->colName, pCol) || pSlot == NULL || !pSlot->output || |
5290 | 0 | pSlot->reserve) { |
5291 | 0 | return -1; |
5292 | 0 | } |
5293 | 0 | return pSlot->slotId; |
5294 | 0 | } |
5295 | | |
5296 | 0 | static int32_t prioritizeFederatedOutputSlot(SSlotIndex* pIndex, int16_t outputSlotId) { |
5297 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
5298 | |
|
5299 | 0 | if (pIndex == NULL || pIndex->pSlotIdsInfo == NULL || taosArrayGetSize(pIndex->pSlotIdsInfo) == 0) { |
5300 | 0 | PLAN_ERR_JRET(TSDB_CODE_INVALID_PARA); |
5301 | 0 | } |
5302 | | |
5303 | 0 | SSlotIdInfo* pFirst = taosArrayGet(pIndex->pSlotIdsInfo, 0); |
5304 | 0 | if (pFirst->slotId == outputSlotId) { |
5305 | 0 | return TSDB_CODE_SUCCESS; |
5306 | 0 | } |
5307 | | |
5308 | 0 | for (int32_t i = 1; i < taosArrayGetSize(pIndex->pSlotIdsInfo); ++i) { |
5309 | 0 | SSlotIdInfo* pInfo = taosArrayGet(pIndex->pSlotIdsInfo, i); |
5310 | 0 | if (pInfo->slotId == outputSlotId) { |
5311 | 0 | SSlotIdInfo tmp = *pFirst; |
5312 | 0 | *pFirst = *pInfo; |
5313 | 0 | *pInfo = tmp; |
5314 | 0 | return TSDB_CODE_SUCCESS; |
5315 | 0 | } |
5316 | 0 | } |
5317 | | |
5318 | 0 | SSlotIdInfo oldFirst = *pFirst; |
5319 | 0 | SSlotIdInfo outputInfo = {.slotId = outputSlotId, .set = false}; |
5320 | 0 | if (NULL == taosArrayPush(pIndex->pSlotIdsInfo, &oldFirst)) { |
5321 | 0 | PLAN_ERR_JRET(terrno); |
5322 | 0 | } |
5323 | 0 | pFirst = taosArrayGet(pIndex->pSlotIdsInfo, 0); |
5324 | 0 | *pFirst = outputInfo; |
5325 | 0 | return code; |
5326 | | |
5327 | 0 | _return: |
5328 | 0 | planError("%s failed since %s", __func__, tstrerror(code)); |
5329 | 0 | return code; |
5330 | 0 | } |
5331 | | |
5332 | 0 | static int32_t registerVtableFederatedOutputSlots(SPhysiPlanContext* pCxt, SFederatedScanPhysiNode* pScan) { |
5333 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
5334 | 0 | int32_t lino = 0; |
5335 | 0 | char* pKey = NULL; |
5336 | |
|
5337 | 0 | if (pCxt == NULL || pScan == NULL || pScan->pScanCols == NULL || pScan->node.pOutputDataBlockDesc == NULL) { |
5338 | 0 | return TSDB_CODE_INVALID_PARA; |
5339 | 0 | } |
5340 | | |
5341 | 0 | SHashObj* pHash = taosArrayGetP(pCxt->pLocationHelper, pScan->node.pOutputDataBlockDesc->dataBlockId); |
5342 | 0 | QUERY_CHECK_NULL(pHash, code, lino, _return, terrno); |
5343 | | |
5344 | | // createFederatedScanPhysiNode keeps scan columns, type mappings, and output |
5345 | | // slots in the same order; reserve-only scan columns are appended last. |
5346 | 0 | int32_t outputIdx = 0; |
5347 | 0 | SNode* pNode = NULL; |
5348 | 0 | FOREACH(pNode, pScan->pScanCols) { |
5349 | 0 | const SNode* pScanExpr = pNode; |
5350 | 0 | if (NULL != pScanExpr && QUERY_NODE_TARGET == nodeType(pScanExpr)) { |
5351 | 0 | pScanExpr = ((const STargetNode*)pScanExpr)->pExpr; |
5352 | 0 | } |
5353 | 0 | const SColumnNode* pCol = getFederatedScanColumn(pNode); |
5354 | 0 | int16_t outputSlotId = -1; |
5355 | 0 | bool mappedOutput = outputIdx < pScan->numColTypeMappings; |
5356 | 0 | if (mappedOutput) { |
5357 | 0 | outputSlotId = getFederatedOutputSlot(pScan, pCol, outputIdx); |
5358 | 0 | } else { |
5359 | 0 | SSlotDescNode* pSlot = |
5360 | 0 | (SSlotDescNode*)nodesListGetNode(pScan->node.pOutputDataBlockDesc->pSlots, outputIdx); |
5361 | 0 | outputSlotId = NULL != pSlot ? pSlot->slotId : -1; |
5362 | 0 | } |
5363 | 0 | ++outputIdx; |
5364 | 0 | if (NULL == pScanExpr || outputSlotId < 0 || (mappedOutput && NULL == pCol)) { |
5365 | 0 | planError("Invalid federated scan expression or output slot, expr=%p, outputSlotId=%d", pScanExpr, |
5366 | 0 | outputSlotId); |
5367 | 0 | PLAN_ERR_JRET(TSDB_CODE_INVALID_PARA); |
5368 | 0 | } |
5369 | | |
5370 | 0 | int32_t keyLen = 0; |
5371 | 0 | int32_t cap = 0; |
5372 | 0 | PLAN_ERR_JRET(getSlotKey((SNode*)pScanExpr, NULL, &pKey, &keyLen, 0, &cap)); |
5373 | | |
5374 | 0 | SSlotIndex* pIndex = taosHashGet(pHash, pKey, keyLen); |
5375 | 0 | if (pIndex == NULL) { |
5376 | 0 | code = putSlotToHashImpl(pScan->node.pOutputDataBlockDesc->dataBlockId, outputSlotId, pKey, keyLen, pHash); |
5377 | 0 | } else { |
5378 | 0 | code = prioritizeFederatedOutputSlot(pIndex, outputSlotId); |
5379 | 0 | } |
5380 | 0 | taosMemoryFreeClear(pKey); |
5381 | 0 | PLAN_ERR_JRET(code); |
5382 | 0 | } |
5383 | 0 | return code; |
5384 | | |
5385 | 0 | _return: |
5386 | 0 | taosMemoryFree(pKey); |
5387 | 0 | planError("%s failed since %s", __func__, tstrerror(code)); |
5388 | 0 | return code; |
5389 | 0 | } |
5390 | | |
5391 | | static int32_t initializeDynamicVtableFederatedOutput(SPhysiPlanContext* pCxt, |
5392 | | const SVirtualScanLogicNode* pVirtualScan, |
5393 | 0 | SFederatedScanPhysiNode* pFederatedScan) { |
5394 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
5395 | |
|
5396 | 0 | if (NULL == pCxt || NULL == pVirtualScan || NULL == pFederatedScan || |
5397 | 0 | NULL == pFederatedScan->node.pOutputDataBlockDesc || |
5398 | 0 | (NULL != pFederatedScan->pScanCols && LIST_LENGTH(pFederatedScan->pScanCols) > 0)) { |
5399 | 0 | return TSDB_CODE_SUCCESS; |
5400 | 0 | } |
5401 | | |
5402 | 0 | PLAN_ERR_JRET(nodesCloneList(pVirtualScan->pScanCols, &pFederatedScan->pScanCols)); |
5403 | 0 | if (NULL == pFederatedScan->pScanCols) { |
5404 | 0 | PLAN_ERR_JRET(TSDB_CODE_PLAN_INVALID_FEDERATED_SCAN); |
5405 | 0 | } |
5406 | | |
5407 | | // A dynamic FederatedScan chooses its real table and SELECT list only after |
5408 | | // DynQueryCtrl supplies a batch. Its physical template still needs the |
5409 | | // complete virtual-row schema, though: every table in the batch is |
5410 | | // normalized into this schema before it reaches VirtualScan. Without this |
5411 | | // common shape, the second table in a source batch inherits the first |
5412 | | // table's slot mapping and writes values into the wrong virtual column. |
5413 | 0 | PLAN_ERR_JRET(addDataBlockSlotsImpl(pCxt, pFederatedScan->pScanCols, |
5414 | 0 | pFederatedScan->node.pOutputDataBlockDesc, |
5415 | 0 | NULL, true, false)); |
5416 | | |
5417 | 0 | _return: |
5418 | 0 | if (TSDB_CODE_SUCCESS != code) { |
5419 | 0 | planError("%s failed since %s", __func__, tstrerror(code)); |
5420 | 0 | } |
5421 | 0 | return code; |
5422 | 0 | } |
5423 | | |
5424 | | static int32_t createVirtualTableScanPhysiNodeFinalize(SPhysiPlanContext* pCxt, |
5425 | | SNodeList* pChild, |
5426 | | SVirtualScanLogicNode* pScanLogicNode, |
5427 | | SVirtualScanPhysiNode* pScanPhysiNode, |
5428 | 0 | SPhysiNode** pPhyNode) { |
5429 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
5430 | 0 | SNodeList* pCondCols = NULL; |
5431 | 0 | SNodeList* pCondScanCols = NULL; |
5432 | |
|
5433 | 0 | PLAN_ERR_JRET(createVirtualScanCols(pCxt, pScanPhysiNode, pScanLogicNode->pScanCols)); |
5434 | 0 | PLAN_ERR_JRET(addDataBlockSlots(pCxt, pScanPhysiNode->scan.pScanCols, pScanPhysiNode->scan.node.pOutputDataBlockDesc)); |
5435 | 0 | if (NULL != pScanLogicNode->pScanPseudoCols) { |
5436 | 0 | pScanPhysiNode->scan.pScanPseudoCols = NULL; |
5437 | 0 | PLAN_ERR_JRET(nodesCloneList(pScanLogicNode->pScanPseudoCols, &pScanPhysiNode->scan.pScanPseudoCols)); |
5438 | 0 | PLAN_ERR_JRET(addDataBlockSlots(pCxt, pScanPhysiNode->scan.pScanPseudoCols, pScanPhysiNode->scan.node.pOutputDataBlockDesc)); |
5439 | 0 | } |
5440 | | |
5441 | 0 | if (NULL != pScanLogicNode->node.pConditions) { |
5442 | 0 | PLAN_ERR_JRET(nodesCollectColumnsFromNode(pScanLogicNode->node.pConditions, NULL, COLLECT_COL_TYPE_ALL, &pCondCols)); |
5443 | 0 | if (pCondCols != NULL) { |
5444 | 0 | PLAN_ERR_JRET(nodesCloneList(pCondCols, &pCondScanCols)); |
5445 | 0 | } |
5446 | 0 | PLAN_ERR_JRET(addDataBlockSlots(pCxt, pCondCols, pScanPhysiNode->scan.node.pOutputDataBlockDesc)); |
5447 | 0 | } |
5448 | | |
5449 | 0 | PLAN_ERR_JRET(setConditionsSlotId(pCxt, (const SLogicNode*)pScanLogicNode, (SPhysiNode*)pScanPhysiNode)); |
5450 | | |
5451 | 0 | pScanPhysiNode->scan.uid = pScanLogicNode->tableId; |
5452 | 0 | pScanPhysiNode->scan.suid = pScanLogicNode->stableId; |
5453 | 0 | pScanPhysiNode->scan.tableType = pScanLogicNode->tableType; |
5454 | 0 | memcpy(&pScanPhysiNode->scan.tableName, &pScanLogicNode->tableName, sizeof(SName)); |
5455 | 0 | pScanPhysiNode->scanAllCols = pScanLogicNode->scanAllCols; |
5456 | | // clone the const-ref tag list right after the scalar fields and BEFORE the sibling |
5457 | | // list clones (pTagRefSources/pLocalTags) that follow -- not before the slot |
5458 | | // machinery above (createVirtualScanCols/addDataBlockSlots/setConditionsSlotId may |
5459 | | // already have failed by this point); the physi node must own its own copy. |
5460 | | // Unlike pRefTagCols, this list deliberately gets NO setMultiBlockSlotId rewrite in |
5461 | | // createVirtualTableScanPhysiNode: its only runtime consumer (ensureRefTagsResolved) |
5462 | | // reads logical identity fields only (colId, refDb/Table/ColName, resType) and never |
5463 | | // slotId/dataBlockId -- output placement flows through scan.pScanPseudoCols' TARGET |
5464 | | // slots (assigned by addDataBlockSlots above) and findResolvedTagVal's colId lookup. |
5465 | | // A rewrite would fail outright anyway: no child operator emits const-ref tags (by |
5466 | | // design no TagRefSource scan node is built for them), so the merged-children slot |
5467 | | // hash lookup would raise TSDB_CODE_PLAN_SLOT_NOT_FOUND. |
5468 | 0 | if (pScanLogicNode->pConstRefTags) { |
5469 | 0 | PLAN_ERR_JRET(nodesCloneList(pScanLogicNode->pConstRefTags, &pScanPhysiNode->pConstRefTags)); |
5470 | 0 | } |
5471 | | |
5472 | | // Clone TagRef fields from logic node to physical node |
5473 | 0 | pScanPhysiNode->hasTagRef = pScanLogicNode->hasTagRef; |
5474 | 0 | pScanPhysiNode->hasLocalTag = pScanLogicNode->hasLocalTag; |
5475 | 0 | pScanPhysiNode->hasConstRefTag = pScanLogicNode->hasConstRefTag; |
5476 | 0 | pScanPhysiNode->mgmtEpSet = pCxt->pPlanCxt->mgmtEpSet; // for const-ref chain remote hops |
5477 | |
|
5478 | 0 | if (pScanLogicNode->pTagRefSources) { |
5479 | 0 | PLAN_ERR_JRET(nodesCloneList(pScanLogicNode->pTagRefSources, &pScanPhysiNode->pTagRefSources)); |
5480 | 0 | } |
5481 | 0 | if (pScanLogicNode->pLocalTags) { |
5482 | 0 | PLAN_ERR_JRET(nodesCloneList(pScanLogicNode->pLocalTags, &pScanPhysiNode->pLocalTags)); |
5483 | 0 | } |
5484 | 0 | if (NULL == pScanPhysiNode->pLocalTags || LIST_LENGTH(pScanPhysiNode->pLocalTags) <= 0) { |
5485 | 0 | if (pScanPhysiNode->pLocalTags != NULL && LIST_LENGTH(pScanPhysiNode->pLocalTags) <= 0) { |
5486 | 0 | nodesDestroyList(pScanPhysiNode->pLocalTags); |
5487 | 0 | pScanPhysiNode->pLocalTags = NULL; |
5488 | 0 | } |
5489 | 0 | PLAN_ERR_JRET(appendPhysiLocalTagsFromList(pScanLogicNode->pScanPseudoCols, &pScanPhysiNode->pLocalTags)); |
5490 | 0 | pScanPhysiNode->hasLocalTag = (pScanPhysiNode->pLocalTags != NULL && LIST_LENGTH(pScanPhysiNode->pLocalTags) > 0); |
5491 | 0 | } |
5492 | 0 | if (pScanLogicNode->pRefTagCols) { |
5493 | 0 | PLAN_ERR_JRET(nodesCloneList(pScanLogicNode->pRefTagCols, &pScanPhysiNode->pRefTagCols)); |
5494 | 0 | } |
5495 | 0 | if (pScanLogicNode->pTagFilterCond) { |
5496 | 0 | PLAN_ERR_JRET(nodesCloneNode(pScanLogicNode->pTagFilterCond, &pScanPhysiNode->pTagFilterCond)); |
5497 | 0 | } |
5498 | | |
5499 | 0 | SNode* pNode = NULL; |
5500 | 0 | int32_t condIdx = 0; |
5501 | 0 | FOREACH(pNode, pCondScanCols) { |
5502 | 0 | if (nodeType(pNode) != QUERY_NODE_COLUMN) { |
5503 | 0 | ++condIdx; |
5504 | 0 | continue; |
5505 | 0 | } |
5506 | | |
5507 | 0 | SColumnNode* pCondCol = (SColumnNode*)pNode; |
5508 | 0 | if (pCondCol->colType == COLUMN_TYPE_TAG) { |
5509 | 0 | if (pCondCol->hasRef) { |
5510 | 0 | PLAN_ERR_JRET(appendPhysiScanColumn(&pScanPhysiNode->pRefTagCols, pCondCol)); |
5511 | 0 | } else { |
5512 | 0 | PLAN_ERR_JRET(appendPhysiScanColumn(&pScanPhysiNode->scan.pScanPseudoCols, pCondCol)); |
5513 | 0 | } |
5514 | 0 | } else { |
5515 | 0 | PLAN_ERR_JRET(appendPhysiScanColumn(&pScanPhysiNode->scan.pScanCols, pCondCol)); |
5516 | 0 | } |
5517 | 0 | ++condIdx; |
5518 | 0 | } |
5519 | | |
5520 | | // Mark every federate-scan downstream as feeding a virtual-table scan so |
5521 | | // the executor can gate vtable-specific behavior (e.g. per-block TIMESTAMP |
5522 | | // precision conversion) at plan time without the parent operator reaching |
5523 | | // into child state at runtime. |
5524 | 0 | if (pChild != NULL) { |
5525 | 0 | SNode* pChildNode = NULL; |
5526 | 0 | FOREACH(pChildNode, pChild) { |
5527 | 0 | if (pChildNode != NULL && |
5528 | 0 | nodeType(pChildNode) == QUERY_NODE_PHYSICAL_PLAN_FEDERATED_SCAN) { |
5529 | 0 | SFederatedScanPhysiNode* pFedScan = (SFederatedScanPhysiNode*)pChildNode; |
5530 | 0 | pFedScan->underVTableScan = true; |
5531 | 0 | PLAN_ERR_JRET(initializeDynamicVtableFederatedOutput(pCxt, pScanLogicNode, pFedScan)); |
5532 | 0 | PLAN_ERR_JRET(registerVtableFederatedOutputSlots(pCxt, pFedScan)); |
5533 | 0 | } |
5534 | 0 | } |
5535 | 0 | } |
5536 | 0 | *pPhyNode = (SPhysiNode*)pScanPhysiNode; |
5537 | 0 | nodesDestroyList(pCondCols); |
5538 | 0 | nodesDestroyList(pCondScanCols); |
5539 | 0 | return code; |
5540 | | |
5541 | 0 | _return: |
5542 | 0 | nodesDestroyList(pCondCols); |
5543 | 0 | nodesDestroyList(pCondScanCols); |
5544 | 0 | nodesDestroyNode((SNode*)pScanPhysiNode); |
5545 | 0 | return code; |
5546 | 0 | } |
5547 | | |
5548 | | static int32_t createVirtualTableScanPhysiNode(SPhysiPlanContext* pCxt, SSubplan* pSubplan, SNodeList* pChildren, |
5549 | 0 | SVirtualScanLogicNode* pScanLogicNode, SPhysiNode** pPhyNode) { |
5550 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
5551 | 0 | SVirtualScanPhysiNode * pVirtualScan = |
5552 | 0 | (SVirtualScanPhysiNode*)makePhysiNode(pCxt, (SLogicNode*)pScanLogicNode, QUERY_NODE_PHYSICAL_PLAN_VIRTUAL_TABLE_SCAN); |
5553 | 0 | if (NULL == pVirtualScan) { |
5554 | 0 | return terrno; |
5555 | 0 | } |
5556 | | |
5557 | 0 | pVirtualScan->twoPassMode = pScanLogicNode->twoPassMode; |
5558 | |
|
5559 | 0 | if (pScanLogicNode->pVgroupList) { |
5560 | 0 | vgroupInfoToNodeAddr(pScanLogicNode->pVgroupList->vgroups, &pSubplan->execNode); |
5561 | 0 | pSubplan->execNodeStat.tableNum = pScanLogicNode->pVgroupList->vgroups[0].numOfTable; |
5562 | 0 | } |
5563 | |
|
5564 | 0 | (void)tNameGetFullDbName(&pScanLogicNode->tableName, pSubplan->dbFName); |
5565 | 0 | PLAN_ERR_RET(createVirtualTableScanPhysiNodeFinalize(pCxt, pChildren, pScanLogicNode, (SVirtualScanPhysiNode*)pVirtualScan, pPhyNode)); |
5566 | 0 | PLAN_ERR_RET(setMultiBlockSlotId(pCxt, pChildren, true, pScanLogicNode->node.pTargets, &pVirtualScan->pTargets)); |
5567 | 0 | if (pVirtualScan->pRefTagCols != NULL) { |
5568 | 0 | nodesDestroyList(pVirtualScan->pRefTagCols); |
5569 | 0 | pVirtualScan->pRefTagCols = NULL; |
5570 | 0 | } |
5571 | 0 | PLAN_ERR_RET(setMultiBlockSlotId(pCxt, pChildren, true, pScanLogicNode->pRefTagCols, &pVirtualScan->pRefTagCols)); |
5572 | 0 | return code; |
5573 | 0 | } |
5574 | | |
5575 | | static int32_t createGroupCachePhysiNode(SPhysiPlanContext* pCxt, SNodeList* pChildren, |
5576 | 0 | SGroupCacheLogicNode* pLogicNode, SPhysiNode** pPhyNode) { |
5577 | 0 | SGroupCachePhysiNode* pGrpCache = |
5578 | 0 | (SGroupCachePhysiNode*)makePhysiNode(pCxt, (SLogicNode*)pLogicNode, QUERY_NODE_PHYSICAL_PLAN_GROUP_CACHE); |
5579 | 0 | if (NULL == pGrpCache) { |
5580 | 0 | return terrno; |
5581 | 0 | } |
5582 | | |
5583 | 0 | pGrpCache->grpColsMayBeNull = pLogicNode->grpColsMayBeNull; |
5584 | 0 | pGrpCache->grpByUid = pLogicNode->grpByUid; |
5585 | 0 | pGrpCache->globalGrp = pLogicNode->globalGrp; |
5586 | 0 | pGrpCache->batchFetch = pLogicNode->batchFetch; |
5587 | 0 | pGrpCache->twoPassMode = pLogicNode->twoPassMode; |
5588 | 0 | SDataBlockDescNode* pChildDesc = ((SPhysiNode*)nodesListGetNode(pChildren, 0))->pOutputDataBlockDesc; |
5589 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
5590 | | /* |
5591 | | if (TSDB_CODE_SUCCESS == code) { |
5592 | | code = setListSlotId(pCxt, pChildDesc->dataBlockId, -1, pLogicNode->pGroupCols, &pGrpCache->pGroupCols); |
5593 | | } |
5594 | | */ |
5595 | |
|
5596 | 0 | *pPhyNode = (SPhysiNode*)pGrpCache; |
5597 | |
|
5598 | 0 | return code; |
5599 | 0 | } |
5600 | | |
5601 | | static int32_t createTagRefSourcePhysiNode(SPhysiPlanContext* pCxt, SSubplan* pSubplan, SNodeList* pChildren, |
5602 | 0 | STagRefSourceLogicNode* pLogicNode, SPhysiNode** pPhyNode) { |
5603 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
5604 | 0 | STagRefSourcePhysiNode* pTagRefSource = |
5605 | 0 | (STagRefSourcePhysiNode*)makePhysiNode(pCxt, (SLogicNode*)pLogicNode, QUERY_NODE_PHYSICAL_PLAN_TAG_REF_SOURCE); |
5606 | 0 | if (NULL == pTagRefSource) { |
5607 | 0 | return terrno; |
5608 | 0 | } |
5609 | | |
5610 | | // Copy source table information |
5611 | 0 | memcpy(&pTagRefSource->sourceTableName, &pLogicNode->sourceTableName, sizeof(SName)); |
5612 | 0 | pTagRefSource->sourceSuid = pLogicNode->sourceSuid; |
5613 | 0 | pTagRefSource->sourceId = pLogicNode->sourceId; |
5614 | 0 | pTagRefSource->isUsedInFilter = pLogicNode->isUsedInFilter; |
5615 | 0 | pTagRefSource->isUsedInProjection = pLogicNode->isUsedInProjection; |
5616 | | |
5617 | | // Clone referenced columns |
5618 | 0 | if (pLogicNode->pRefCols) { |
5619 | 0 | PLAN_ERR_JRET(nodesCloneList(pLogicNode->pRefCols, &pTagRefSource->pRefCols)); |
5620 | 0 | } |
5621 | | |
5622 | | // Clone vgroup list to physical node |
5623 | | // Note: After split phase, pVgroupList is transferred from logic node to logic subplan via TSWAP |
5624 | | // The execNode should already be set in createPhysiSubplan from the logic subplan's vgroup list |
5625 | 0 | if (pLogicNode->pVgroupList) { |
5626 | | // vgroup list is still in the logic node (no split or special case) |
5627 | 0 | int32_t numOfVgroups = pLogicNode->pVgroupList->numOfVgroups; |
5628 | 0 | pTagRefSource->pVgroupList = taosMemoryCalloc(1, sizeof(SVgroupsInfo) + numOfVgroups * sizeof(SVgroupInfo)); |
5629 | 0 | if (NULL == pTagRefSource->pVgroupList) { |
5630 | 0 | PLAN_ERR_JRET(TSDB_CODE_OUT_OF_MEMORY); |
5631 | 0 | } |
5632 | 0 | pTagRefSource->pVgroupList->numOfVgroups = numOfVgroups; |
5633 | 0 | memcpy(pTagRefSource->pVgroupList->vgroups, pLogicNode->pVgroupList->vgroups, numOfVgroups * sizeof(SVgroupInfo)); |
5634 | | |
5635 | | // Set subplan execNode from vgroup info for scheduling |
5636 | 0 | vgroupInfoToNodeAddr(pLogicNode->pVgroupList->vgroups, &pSubplan->execNode); |
5637 | 0 | pSubplan->execNodeStat.tableNum = pLogicNode->pVgroupList->vgroups[0].numOfTable; |
5638 | 0 | } else { |
5639 | | // vgroup list was transferred to logic subplan during split |
5640 | | // execNode should already be set in createPhysiSubplan |
5641 | | // We still create a minimal vgroup list for the physical node if needed |
5642 | 0 | if (pSubplan->execNode.nodeId > 0) { |
5643 | 0 | pTagRefSource->pVgroupList = taosMemoryCalloc(1, sizeof(SVgroupsInfo) + sizeof(SVgroupInfo)); |
5644 | 0 | if (NULL == pTagRefSource->pVgroupList) { |
5645 | 0 | PLAN_ERR_JRET(TSDB_CODE_OUT_OF_MEMORY); |
5646 | 0 | } |
5647 | 0 | pTagRefSource->pVgroupList->numOfVgroups = 1; |
5648 | | // Reverse the vgroupInfoToNodeAddr conversion to populate vgroup info |
5649 | 0 | pTagRefSource->pVgroupList->vgroups[0].vgId = pSubplan->execNode.nodeId; |
5650 | 0 | pTagRefSource->pVgroupList->vgroups[0].epSet = pSubplan->execNode.epSet; |
5651 | | // tableNum should already be set in execNodeStat |
5652 | 0 | } |
5653 | 0 | } |
5654 | | |
5655 | | // Create scan columns from referenced columns for source table scan. |
5656 | | // IMPORTANT: pScanCols must use hasRef=true with the same refDbName/refTableName/refColName |
5657 | | // as the pTargets columns. getSlotKey() uses these ref fields to generate the slot key, |
5658 | | // so matching keys ensure addDataBlockSlots reuses existing slots from pTargets |
5659 | | // rather than creating duplicate slots with different keys. |
5660 | 0 | if (pLogicNode->pRefCols) { |
5661 | 0 | PLAN_ERR_JRET(nodesMakeList(&pTagRefSource->pScanCols)); |
5662 | 0 | SNode* pRefCol = NULL; |
5663 | 0 | FOREACH(pRefCol, pLogicNode->pRefCols) { |
5664 | 0 | STagRefColumn* pTagRef = (STagRefColumn*)pRefCol; |
5665 | 0 | SColumnNode* pScanCol = NULL; |
5666 | 0 | PLAN_ERR_JRET(nodesMakeNode(QUERY_NODE_COLUMN, (SNode**)&pScanCol)); |
5667 | 0 | pScanCol->tableId = pLogicNode->sourceSuid; |
5668 | 0 | pScanCol->colId = pTagRef->sourceColId; |
5669 | 0 | pScanCol->colType = COLUMN_TYPE_TAG; |
5670 | 0 | pScanCol->node.resType.type = pTagRef->dataType; |
5671 | 0 | pScanCol->node.resType.bytes = pTagRef->bytes; |
5672 | 0 | tstrncpy(pScanCol->colName, pTagRef->colName, TSDB_COL_NAME_LEN); |
5673 | 0 | tstrncpy(pScanCol->dbName, pLogicNode->sourceTableName.dbname, TSDB_DB_NAME_LEN); |
5674 | 0 | tstrncpy(pScanCol->tableName, pLogicNode->sourceTableName.tname, TSDB_TABLE_NAME_LEN); |
5675 | | // tableAlias must be non-empty so getSlotKey reaches the hasRef branch |
5676 | | // (empty tableAlias causes early return with just colName as key) |
5677 | 0 | tstrncpy(pScanCol->tableAlias, pLogicNode->sourceTableName.tname, TSDB_TABLE_NAME_LEN); |
5678 | 0 | pScanCol->hasRef = true; |
5679 | 0 | tstrncpy(pScanCol->refDbName, pLogicNode->sourceTableName.dbname, TSDB_DB_NAME_LEN); |
5680 | 0 | tstrncpy(pScanCol->refTableName, pLogicNode->sourceTableName.tname, TSDB_TABLE_NAME_LEN); |
5681 | 0 | tstrncpy(pScanCol->refColName, pTagRef->sourceColName, TSDB_COL_NAME_LEN); |
5682 | 0 | PLAN_ERR_JRET(nodesListStrictAppend(pTagRefSource->pScanCols, (SNode*)pScanCol)); |
5683 | 0 | } |
5684 | 0 | } |
5685 | | |
5686 | | // addDataBlockSlots reuses existing slots from pTargets since slot keys match |
5687 | 0 | if (pTagRefSource->pScanCols) { |
5688 | 0 | PLAN_ERR_JRET(addDataBlockSlots(pCxt, pTagRefSource->pScanCols, pTagRefSource->node.pOutputDataBlockDesc)); |
5689 | 0 | } |
5690 | | |
5691 | | // Set conditions slot id |
5692 | 0 | PLAN_ERR_JRET(setConditionsSlotId(pCxt, (const SLogicNode*)pLogicNode, (SPhysiNode*)pTagRefSource)); |
5693 | | |
5694 | 0 | *pPhyNode = (SPhysiNode*)pTagRefSource; |
5695 | 0 | return code; |
5696 | | |
5697 | 0 | _return: |
5698 | 0 | nodesDestroyNode((SNode*)pTagRefSource); |
5699 | 0 | return code; |
5700 | 0 | } |
5701 | | |
5702 | | static int32_t updateDynQueryCtrlStbJoinInfo(SPhysiPlanContext* pCxt, SNodeList* pChildren, |
5703 | 0 | SDynQueryCtrlLogicNode* pLogicNode, SDynQueryCtrlPhysiNode* pDynCtrl) { |
5704 | 0 | SDataBlockDescNode* pPrevDesc = ((SPhysiNode*)nodesListGetNode(pChildren, 0))->pOutputDataBlockDesc; |
5705 | 0 | SNodeList* pVgList = NULL; |
5706 | 0 | SNodeList* pUidList = NULL; |
5707 | 0 | int32_t code = setListSlotId(pCxt, pPrevDesc->dataBlockId, -1, pLogicNode->stbJoin.pVgList, &pVgList); |
5708 | 0 | if (TSDB_CODE_SUCCESS == code) { |
5709 | 0 | code = setListSlotId(pCxt, pPrevDesc->dataBlockId, -1, pLogicNode->stbJoin.pUidList, &pUidList); |
5710 | 0 | } |
5711 | 0 | if (TSDB_CODE_SUCCESS == code) { |
5712 | 0 | memcpy(pDynCtrl->stbJoin.srcScan, pLogicNode->stbJoin.srcScan, sizeof(pDynCtrl->stbJoin.srcScan)); |
5713 | |
|
5714 | 0 | SNode* pNode = NULL; |
5715 | 0 | int32_t i = 0; |
5716 | 0 | FOREACH(pNode, pVgList) { |
5717 | 0 | pDynCtrl->stbJoin.vgSlot[i] = ((SColumnNode*)pNode)->slotId; |
5718 | 0 | ++i; |
5719 | 0 | } |
5720 | 0 | i = 0; |
5721 | 0 | FOREACH(pNode, pUidList) { |
5722 | 0 | pDynCtrl->stbJoin.uidSlot[i] = ((SColumnNode*)pNode)->slotId; |
5723 | 0 | ++i; |
5724 | 0 | } |
5725 | 0 | pDynCtrl->stbJoin.batchFetch = pLogicNode->stbJoin.batchFetch; |
5726 | 0 | } |
5727 | 0 | nodesDestroyList(pVgList); |
5728 | 0 | nodesDestroyList(pUidList); |
5729 | |
|
5730 | 0 | return code; |
5731 | 0 | } |
5732 | | |
5733 | | static int32_t updateDynQueryCtrlVtbScanInfo(SPhysiPlanContext* pCxt, SNodeList* pChildren, |
5734 | | SDynQueryCtrlLogicNode* pLogicNode, SDynQueryCtrlPhysiNode* pDynCtrl, |
5735 | 0 | SSubplan* pSubPlan) { |
5736 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
5737 | |
|
5738 | 0 | if (pLogicNode->vtbScan.pVgroupList) { |
5739 | 0 | vgroupInfoToNodeAddr(pLogicNode->vtbScan.pVgroupList->vgroups, &pSubPlan->execNode); |
5740 | 0 | pSubPlan->execNodeStat.tableNum = pLogicNode->vtbScan.pVgroupList->vgroups[0].numOfTable; |
5741 | 0 | } |
5742 | |
|
5743 | 0 | TSWAP(pLogicNode->vtbScan.pOrgVgIds, pDynCtrl->vtbScan.pOrgVgIds); |
5744 | 0 | if (pLogicNode->vtbScan.pScanCols) { |
5745 | 0 | PLAN_ERR_JRET(nodesCloneList(pLogicNode->vtbScan.pScanCols, &pDynCtrl->vtbScan.pScanCols)); |
5746 | 0 | } else { |
5747 | 0 | PLAN_ERR_JRET(nodesCloneList(pLogicNode->node.pTargets, &pDynCtrl->vtbScan.pScanCols)); |
5748 | 0 | } |
5749 | | |
5750 | 0 | pDynCtrl->vtbScan.scanAllCols = pLogicNode->vtbScan.scanAllCols; |
5751 | 0 | pDynCtrl->vtbScan.suid = pLogicNode->vtbScan.suid; |
5752 | 0 | pDynCtrl->vtbScan.uid = pLogicNode->vtbScan.uid; |
5753 | 0 | pDynCtrl->vtbScan.isSuperTable = pLogicNode->vtbScan.isSuperTable; |
5754 | 0 | pDynCtrl->vtbScan.hasLocalTag = false; |
5755 | 0 | pDynCtrl->vtbScan.batchProcessChild = pLogicNode->vtbScan.batchProcessChild; |
5756 | 0 | pDynCtrl->vtbScan.hasPartition = pLogicNode->vtbScan.hasPartition; |
5757 | 0 | pDynCtrl->vtbScan.rversion = pLogicNode->vtbScan.rversion; |
5758 | 0 | pDynCtrl->vtbScan.mgmtEpSet = pCxt->pPlanCxt->mgmtEpSet; |
5759 | 0 | pDynCtrl->vtbScan.accountId = pCxt->pPlanCxt->acctId; |
5760 | 0 | tstrncpy(pDynCtrl->vtbScan.dbName, pLogicNode->vtbScan.dbName, TSDB_DB_NAME_LEN); |
5761 | 0 | tstrncpy(pDynCtrl->vtbScan.tbName, pLogicNode->vtbScan.tbName, TSDB_TABLE_NAME_LEN); |
5762 | | |
5763 | | // Propagate tag-ref filter info from VirtualScanLogicNode (logic node's child, still intact) |
5764 | | // NOTE: pChildren (physi) are Exchange nodes after plan splitting - VirtualTableScan is NOT there. |
5765 | | // We access the logic tree directly to get pTagFilterCond and pRefTagCols. |
5766 | 0 | SNode* pLogicChild = NULL; |
5767 | 0 | FOREACH(pLogicChild, pLogicNode->node.pChildren) { |
5768 | 0 | if (nodeType(pLogicChild) == QUERY_NODE_LOGIC_PLAN_VIRTUAL_TABLE_SCAN) { |
5769 | 0 | SVirtualScanLogicNode* pVScanLogic = (SVirtualScanLogicNode*)pLogicChild; |
5770 | 0 | if (pVScanLogic->pTagFilterCond) { |
5771 | 0 | PLAN_ERR_JRET(nodesCloneNode(pVScanLogic->pTagFilterCond, &pDynCtrl->vtbScan.pTagFilterCond)); |
5772 | 0 | } |
5773 | 0 | if (pVScanLogic->pRefTagCols) { |
5774 | 0 | PLAN_ERR_JRET(nodesCloneList(pVScanLogic->pRefTagCols, &pDynCtrl->vtbScan.pRefTagCols)); |
5775 | 0 | } |
5776 | 0 | pDynCtrl->vtbScan.hasLocalTag = pVScanLogic->hasLocalTag; |
5777 | 0 | break; |
5778 | 0 | } |
5779 | 0 | } |
5780 | | // Copy tag-ref source scalars from logic node (populated before plan splitting) |
5781 | 0 | pDynCtrl->vtbScan.tagRefSourceSuid = pLogicNode->vtbScan.tagRefSourceSuid; |
5782 | 0 | pDynCtrl->vtbScan.tagRefSourceColId = pLogicNode->vtbScan.tagRefSourceColId; |
5783 | 0 | pDynCtrl->vtbScan.tagRefSourceColType = pLogicNode->vtbScan.tagRefSourceColType; |
5784 | 0 | tstrncpy(pDynCtrl->vtbScan.tagRefTerminalColName, pLogicNode->vtbScan.tagRefTerminalColName, TSDB_COL_NAME_LEN); |
5785 | |
|
5786 | 0 | return code; |
5787 | 0 | _return: |
5788 | 0 | planError("%s failed at line %d since %s", __func__, __LINE__, tstrerror(code)); |
5789 | 0 | return code; |
5790 | 0 | } |
5791 | | |
5792 | | static int32_t rewritePrecalcExpr(SPhysiPlanContext* pCxt, SNode* pNode, SNodeList** pPrecalcExprs, |
5793 | | SNode** pRewritten); |
5794 | | static int32_t rewritePrecalcExprs(SPhysiPlanContext* pCxt, SNodeList* pList, SNodeList** pPrecalcExprs, |
5795 | | SNodeList** pRewrittenList); |
5796 | | static int32_t getChildTuple(SDataBlockDescNode **pChildTuple, SNodeList* pChildren); |
5797 | | |
5798 | | static int32_t updateDynQueryCtrlVtbWindowInfo(SPhysiPlanContext* pCxt, SNodeList* pChildren, |
5799 | 0 | SDynQueryCtrlLogicNode* pLogicNode, SDynQueryCtrlPhysiNode* pDynCtrl) { |
5800 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
5801 | |
|
5802 | 0 | pDynCtrl->vtbWindow.wstartSlotId = pLogicNode->vtbWindow.wstartSlotId; |
5803 | 0 | pDynCtrl->vtbWindow.wendSlotId = pLogicNode->vtbWindow.wendSlotId; |
5804 | 0 | pDynCtrl->vtbWindow.wdurationSlotId = pLogicNode->vtbWindow.wdurationSlotId; |
5805 | 0 | pDynCtrl->vtbWindow.isVstb = pLogicNode->vtbWindow.isVstb; |
5806 | 0 | pDynCtrl->vtbWindow.extendOption = pLogicNode->vtbWindow.extendOption; |
5807 | |
|
5808 | 0 | PLAN_ERR_RET(setMultiBlockSlotId(pCxt, pChildren, false, pLogicNode->node.pTargets, &pDynCtrl->vtbWindow.pTargets)); |
5809 | 0 | PLAN_ERR_RET(addDataBlockSlots(pCxt, pDynCtrl->vtbWindow.pTargets, pDynCtrl->node.pOutputDataBlockDesc)); |
5810 | | |
5811 | 0 | return code; |
5812 | 0 | } |
5813 | | |
5814 | 0 | static int32_t markVtableFederatedScans(SPhysiPlanContext* pCxt, SPhysiNode* pNode) { |
5815 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
5816 | |
|
5817 | 0 | if (NULL == pNode) { |
5818 | 0 | return TSDB_CODE_INVALID_PARA; |
5819 | 0 | } |
5820 | 0 | if (QUERY_NODE_PHYSICAL_PLAN_FEDERATED_SCAN == nodeType((SNode*)pNode)) { |
5821 | 0 | SFederatedScanPhysiNode* pScan = (SFederatedScanPhysiNode*)pNode; |
5822 | 0 | pScan->underVTableScan = true; |
5823 | 0 | PLAN_ERR_JRET(registerVtableFederatedOutputSlots(pCxt, pScan)); |
5824 | 0 | goto _return; |
5825 | 0 | } |
5826 | | |
5827 | 0 | SNode* pChild = NULL; |
5828 | 0 | FOREACH(pChild, pNode->pChildren) { |
5829 | 0 | PLAN_ERR_JRET(markVtableFederatedScans(pCxt, (SPhysiNode*)pChild)); |
5830 | 0 | } |
5831 | | |
5832 | 0 | _return: |
5833 | 0 | if (TSDB_CODE_SUCCESS != code) { |
5834 | 0 | planError("%s failed since %s", __func__, tstrerror(code)); |
5835 | 0 | } |
5836 | 0 | return code; |
5837 | 0 | } |
5838 | | |
5839 | 0 | static void markVtableWindowFederatedScansFlagOnly(SPhysiNode* pNode) { |
5840 | 0 | if (NULL == pNode) { |
5841 | 0 | return; |
5842 | 0 | } |
5843 | 0 | if (QUERY_NODE_PHYSICAL_PLAN_FEDERATED_SCAN == nodeType((SNode*)pNode)) { |
5844 | 0 | ((SFederatedScanPhysiNode*)pNode)->underVTableScan = true; |
5845 | 0 | return; |
5846 | 0 | } |
5847 | 0 | SNode* pChild = NULL; |
5848 | 0 | FOREACH(pChild, pNode->pChildren) { |
5849 | 0 | markVtableWindowFederatedScansFlagOnly((SPhysiNode*)pChild); |
5850 | 0 | } |
5851 | 0 | } |
5852 | | |
5853 | | static int32_t createDynQueryCtrlPhysiNode(SPhysiPlanContext* pCxt, SNodeList* pChildren, |
5854 | 0 | SDynQueryCtrlLogicNode* pLogicNode, SPhysiNode** pPhyNode, SSubplan* pSubPlan) { |
5855 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
5856 | 0 | SNode* pChild = NULL; |
5857 | 0 | SDynQueryCtrlPhysiNode* pDynCtrl = |
5858 | 0 | (SDynQueryCtrlPhysiNode*)makePhysiNode(pCxt, (SLogicNode*)pLogicNode, QUERY_NODE_PHYSICAL_PLAN_DYN_QUERY_CTRL); |
5859 | 0 | if (NULL == pDynCtrl) { |
5860 | 0 | PLAN_ERR_JRET(terrno); |
5861 | 0 | } |
5862 | | |
5863 | 0 | switch (pLogicNode->qType) { |
5864 | 0 | case DYN_QTYPE_STB_HASH: |
5865 | 0 | PLAN_ERR_JRET(updateDynQueryCtrlStbJoinInfo(pCxt, pChildren, pLogicNode, pDynCtrl)); |
5866 | 0 | break; |
5867 | 0 | case DYN_QTYPE_VTB_TS_SCAN: |
5868 | 0 | PLAN_ERR_JRET(updateDynQueryCtrlVtbScanInfo(pCxt, pChildren, pLogicNode, pDynCtrl, pSubPlan)); |
5869 | 0 | FOREACH(pChild, pChildren) { |
5870 | 0 | markVtableWindowFederatedScansFlagOnly((SPhysiNode*)pChild); |
5871 | 0 | } |
5872 | 0 | break; |
5873 | 0 | case DYN_QTYPE_VTB_SCAN: |
5874 | 0 | PLAN_ERR_JRET(updateDynQueryCtrlVtbScanInfo(pCxt, pChildren, pLogicNode, pDynCtrl, pSubPlan)); |
5875 | 0 | break; |
5876 | 0 | case DYN_QTYPE_VTB_AGG: |
5877 | 0 | PLAN_ERR_JRET(updateDynQueryCtrlVtbScanInfo(pCxt, pChildren, pLogicNode, pDynCtrl, pSubPlan)); |
5878 | 0 | FOREACH(pChild, pChildren) { |
5879 | 0 | PLAN_ERR_JRET(markVtableFederatedScans(pCxt, (SPhysiNode*)pChild)); |
5880 | 0 | } |
5881 | 0 | break; |
5882 | 0 | case DYN_QTYPE_VTB_INTERVAL: |
5883 | 0 | PLAN_ERR_JRET(updateDynQueryCtrlVtbScanInfo(pCxt, pChildren, pLogicNode, pDynCtrl, pSubPlan)); |
5884 | 0 | FOREACH(pChild, pChildren) { |
5885 | 0 | PLAN_ERR_JRET(markVtableFederatedScans(pCxt, (SPhysiNode*)pChild)); |
5886 | 0 | } |
5887 | 0 | break; |
5888 | 0 | case DYN_QTYPE_VTB_WINDOW: |
5889 | 0 | PLAN_ERR_JRET(updateDynQueryCtrlVtbScanInfo(pCxt, pChildren, pLogicNode, pDynCtrl, pSubPlan)); |
5890 | 0 | PLAN_ERR_JRET(updateDynQueryCtrlVtbWindowInfo(pCxt, pChildren, pLogicNode, pDynCtrl)); |
5891 | 0 | FOREACH(pChild, pChildren) { |
5892 | 0 | PLAN_ERR_JRET(markVtableFederatedScans(pCxt, (SPhysiNode*)pChild)); |
5893 | 0 | } |
5894 | 0 | break; |
5895 | 0 | default: |
5896 | 0 | PLAN_ERR_JRET(TSDB_CODE_PLAN_INVALID_DYN_CTRL_TYPE); |
5897 | 0 | } |
5898 | | |
5899 | 0 | pDynCtrl->qType = pLogicNode->qType; |
5900 | 0 | pDynCtrl->dynTbname = pLogicNode->dynTbname; |
5901 | 0 | *pPhyNode = (SPhysiNode*)pDynCtrl; |
5902 | |
|
5903 | 0 | return code; |
5904 | 0 | _return: |
5905 | 0 | planError("%s failed since %s", __func__, tstrerror(code)); |
5906 | 0 | return code; |
5907 | 0 | } |
5908 | | |
5909 | | typedef struct SRewritePrecalcExprsCxt { |
5910 | | int32_t errCode; |
5911 | | int32_t planNodeId; |
5912 | | int32_t rewriteId; |
5913 | | SNodeList* pPrecalcExprs; |
5914 | | SHashObj* pSeenNames; // tracks aliasNames already used as slot keys |
5915 | | } SRewritePrecalcExprsCxt; |
5916 | | |
5917 | 0 | static EDealRes collectAndRewrite(SRewritePrecalcExprsCxt* pCxt, SNode** pNode) { |
5918 | 0 | SNode* pExpr = NULL; |
5919 | 0 | pCxt->errCode = nodesCloneNode(*pNode, &pExpr); |
5920 | 0 | if (NULL == pExpr) { |
5921 | 0 | return DEAL_RES_ERROR; |
5922 | 0 | } |
5923 | 0 | if (TSDB_CODE_SUCCESS != (pCxt->errCode = nodesListAppend(pCxt->pPrecalcExprs, pExpr))) { |
5924 | 0 | nodesDestroyNode(pExpr); |
5925 | 0 | return DEAL_RES_ERROR; |
5926 | 0 | } |
5927 | 0 | SColumnNode* pCol = NULL; |
5928 | 0 | pCxt->errCode = nodesMakeNode(QUERY_NODE_COLUMN, (SNode**)&pCol); |
5929 | 0 | if (NULL == pCol) { |
5930 | 0 | nodesDestroyNode(pExpr); |
5931 | 0 | return DEAL_RES_ERROR; |
5932 | 0 | } |
5933 | 0 | SExprNode* pRewrittenExpr = (SExprNode*)pExpr; |
5934 | 0 | pCol->node.resType = pRewrittenExpr->resType; |
5935 | 0 | if ('\0' == pRewrittenExpr->aliasName[0]) { |
5936 | 0 | snprintf(pRewrittenExpr->aliasName, sizeof(pRewrittenExpr->aliasName), "#expr_%d_%d", pCxt->planNodeId, |
5937 | 0 | pCxt->rewriteId++); |
5938 | 0 | } else if (pCxt->pSeenNames != NULL) { |
5939 | 0 | int32_t nameLen = (int32_t)strlen(pRewrittenExpr->aliasName); |
5940 | 0 | SNode** ppSeenExpr = taosHashGet(pCxt->pSeenNames, pRewrittenExpr->aliasName, nameLen); |
5941 | 0 | if (NULL != ppSeenExpr && !nodesEqualNode(*ppSeenExpr, pExpr)) { |
5942 | 0 | snprintf(pRewrittenExpr->aliasName, sizeof(pRewrittenExpr->aliasName), "#expr_%d_%d", pCxt->planNodeId, |
5943 | 0 | pCxt->rewriteId++); |
5944 | 0 | } |
5945 | 0 | } |
5946 | 0 | int32_t nameLen = (int32_t)strlen(pRewrittenExpr->aliasName); |
5947 | 0 | if (pCxt->pSeenNames != NULL && nameLen > 0 && |
5948 | 0 | NULL == taosHashGet(pCxt->pSeenNames, pRewrittenExpr->aliasName, nameLen)) { |
5949 | 0 | pCxt->errCode = taosHashPut(pCxt->pSeenNames, pRewrittenExpr->aliasName, nameLen, &pExpr, POINTER_BYTES); |
5950 | 0 | if (TSDB_CODE_SUCCESS != pCxt->errCode) { |
5951 | 0 | nodesDestroyNode((SNode*)pCol); |
5952 | 0 | return DEAL_RES_ERROR; |
5953 | 0 | } |
5954 | 0 | } |
5955 | 0 | tstrncpy(pCol->colName, pRewrittenExpr->aliasName, TSDB_COL_NAME_LEN); |
5956 | 0 | tstrncpy(pCol->node.userAlias, pRewrittenExpr->userAlias, TSDB_COL_NAME_LEN); |
5957 | 0 | nodesDestroyNode(*pNode); |
5958 | 0 | *pNode = (SNode*)pCol; |
5959 | 0 | return DEAL_RES_IGNORE_CHILD; |
5960 | 0 | } |
5961 | | |
5962 | 0 | static int32_t rewriteValueToOperator(SRewritePrecalcExprsCxt* pCxt, SNode** pNode) { |
5963 | 0 | SOperatorNode* pOper = NULL; |
5964 | 0 | int32_t code = nodesMakeNode(QUERY_NODE_OPERATOR, (SNode**)&pOper); |
5965 | 0 | if (NULL == pOper) { |
5966 | 0 | return code; |
5967 | 0 | } |
5968 | 0 | pOper->pLeft = NULL; |
5969 | 0 | code = nodesMakeNode(QUERY_NODE_LEFT_VALUE, &pOper->pLeft); |
5970 | 0 | if (NULL == pOper->pLeft) { |
5971 | 0 | nodesDestroyNode((SNode*)pOper); |
5972 | 0 | return code; |
5973 | 0 | } |
5974 | 0 | SValueNode* pVal = (SValueNode*)*pNode; |
5975 | 0 | pOper->node.resType = pVal->node.resType; |
5976 | 0 | tstrncpy(pOper->node.aliasName, pVal->node.aliasName, TSDB_COL_NAME_LEN); |
5977 | 0 | tstrncpy(pOper->node.userAlias, pVal->node.userAlias, TSDB_COL_NAME_LEN); |
5978 | 0 | pOper->opType = OP_TYPE_ASSIGN; |
5979 | 0 | pOper->pRight = *pNode; |
5980 | 0 | *pNode = (SNode*)pOper; |
5981 | 0 | return TSDB_CODE_SUCCESS; |
5982 | 0 | } |
5983 | | |
5984 | 0 | static EDealRes doRewritePrecalcExprs(SNode** pNode, void* pContext) { |
5985 | 0 | SRewritePrecalcExprsCxt* pCxt = (SRewritePrecalcExprsCxt*)pContext; |
5986 | 0 | switch (nodeType(*pNode)) { |
5987 | 0 | case QUERY_NODE_VALUE: { |
5988 | 0 | if (((SValueNode*)*pNode)->notReserved) { |
5989 | 0 | break; |
5990 | 0 | } |
5991 | 0 | pCxt->errCode = rewriteValueToOperator(pCxt, pNode); |
5992 | 0 | if (TSDB_CODE_SUCCESS != pCxt->errCode) { |
5993 | 0 | return DEAL_RES_ERROR; |
5994 | 0 | } |
5995 | 0 | return collectAndRewrite(pCxt, pNode); |
5996 | 0 | } |
5997 | 0 | case QUERY_NODE_OPERATOR: |
5998 | 0 | case QUERY_NODE_LOGIC_CONDITION: |
5999 | 0 | case QUERY_NODE_CASE_WHEN: { |
6000 | 0 | return collectAndRewrite(pCxt, pNode); |
6001 | 0 | } |
6002 | 0 | case QUERY_NODE_FUNCTION: { |
6003 | 0 | SFunctionNode* pFunc = (SFunctionNode*)(*pNode); |
6004 | 0 | if (fmIsScalarFunc(pFunc->funcId) && !fmIsNoPushdownFunc(pFunc->funcId) && |
6005 | 0 | !fmIsVolatileFunc(pFunc->funcId)) { |
6006 | 0 | return collectAndRewrite(pCxt, pNode); |
6007 | 0 | } |
6008 | 0 | break; |
6009 | 0 | } |
6010 | 0 | case QUERY_NODE_REMOTE_VALUE: { |
6011 | 0 | return collectAndRewrite(pCxt, pNode); |
6012 | 0 | } |
6013 | 0 | case QUERY_NODE_CORRELATED_SUBQUERY: { |
6014 | 0 | return collectAndRewrite(pCxt, pNode); |
6015 | 0 | } |
6016 | 0 | default: |
6017 | 0 | break; |
6018 | 0 | } |
6019 | 0 | return DEAL_RES_CONTINUE; |
6020 | 0 | } |
6021 | | |
6022 | | static int32_t rewritePrecalcExprs(SPhysiPlanContext* pCxt, SNodeList* pList, SNodeList** pPrecalcExprs, |
6023 | 0 | SNodeList** pRewrittenList) { |
6024 | 0 | if (NULL == pList) { |
6025 | 0 | return TSDB_CODE_SUCCESS; |
6026 | 0 | } |
6027 | 0 | int32_t code = 0; |
6028 | 0 | if (NULL == *pPrecalcExprs) { |
6029 | 0 | code = nodesMakeList(pPrecalcExprs); |
6030 | 0 | if (NULL == *pPrecalcExprs) { |
6031 | 0 | return code; |
6032 | 0 | } |
6033 | 0 | } |
6034 | 0 | if (NULL == *pRewrittenList) { |
6035 | 0 | code = nodesMakeList(pRewrittenList); |
6036 | 0 | if (NULL == *pRewrittenList) { |
6037 | 0 | return code; |
6038 | 0 | } |
6039 | 0 | } |
6040 | 0 | SNode* pNode = NULL; |
6041 | 0 | FOREACH(pNode, pList) { |
6042 | 0 | SNode* pNew = NULL; |
6043 | 0 | if (QUERY_NODE_GROUPING_SET == nodeType(pNode)) { |
6044 | 0 | code = nodesCloneNode(nodesListGetNode(((SGroupingSetNode*)pNode)->pParameterList, 0), &pNew); |
6045 | 0 | } else { |
6046 | 0 | code = nodesCloneNode(pNode, &pNew); |
6047 | 0 | } |
6048 | 0 | if (NULL == pNew) { |
6049 | 0 | return code; |
6050 | 0 | } |
6051 | 0 | if (TSDB_CODE_SUCCESS != (code = nodesListAppend(*pRewrittenList, pNew))) { |
6052 | 0 | return code; |
6053 | 0 | } |
6054 | 0 | } |
6055 | 0 | SHashObj* pSeenNames = |
6056 | 0 | taosHashInit(LIST_LENGTH(pList), taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), false, HASH_NO_LOCK); |
6057 | 0 | SRewritePrecalcExprsCxt cxt = {.errCode = TSDB_CODE_SUCCESS, .pPrecalcExprs = *pPrecalcExprs, |
6058 | 0 | .pSeenNames = pSeenNames}; |
6059 | 0 | nodesRewriteExprs(*pRewrittenList, doRewritePrecalcExprs, &cxt); |
6060 | 0 | taosHashCleanup(pSeenNames); |
6061 | 0 | if (0 == LIST_LENGTH(cxt.pPrecalcExprs) || TSDB_CODE_SUCCESS != cxt.errCode) { |
6062 | 0 | NODES_DESTORY_LIST(*pPrecalcExprs); |
6063 | 0 | } |
6064 | 0 | return cxt.errCode; |
6065 | 0 | } |
6066 | | |
6067 | | static int32_t rewritePrecalcExpr(SPhysiPlanContext* pCxt, SNode* pNode, SNodeList** pPrecalcExprs, |
6068 | 0 | SNode** pRewritten) { |
6069 | 0 | if (NULL == pNode) { |
6070 | 0 | return TSDB_CODE_SUCCESS; |
6071 | 0 | } |
6072 | 0 |
|
6073 | 0 | SNodeList* pList = NULL; |
6074 | 0 | int32_t code = nodesListMakeAppend(&pList, pNode); |
6075 | 0 | SNodeList* pRewrittenList = NULL; |
6076 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6077 | 0 | code = rewritePrecalcExprs(pCxt, pList, pPrecalcExprs, &pRewrittenList); |
6078 | 0 | } |
6079 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6080 | 0 | *pRewritten = nodesListGetNode(pRewrittenList, 0); |
6081 | 0 | } |
6082 | 0 | nodesClearList(pList); |
6083 | 0 | nodesClearList(pRewrittenList); |
6084 | 0 | return code; |
6085 | 0 | } |
6086 | | |
6087 | 0 | static EDealRes hasCountLikeFunc(SNode* pNode, void* res) { |
6088 | 0 | if (QUERY_NODE_FUNCTION == nodeType(pNode)) { |
6089 | 0 | SFunctionNode* pFunc = (SFunctionNode*)pNode; |
6090 | 0 | if (fmIsCountLikeFunc(pFunc->funcId) || (pFunc->hasOriginalFunc && fmIsCountLikeFunc(pFunc->originalFuncId))) { |
6091 | 0 | *(bool*)res = true; |
6092 | 0 | return DEAL_RES_END; |
6093 | 0 | } |
6094 | 0 | } |
6095 | 0 | return DEAL_RES_CONTINUE; |
6096 | 0 | } |
6097 | | |
6098 | 0 | static bool isDynVirtualStableScan(SNode* pNode) { |
6099 | 0 | if (NULL == pNode || QUERY_NODE_PHYSICAL_PLAN_DYN_QUERY_CTRL != nodeType(pNode)) { |
6100 | 0 | return false; |
6101 | 0 | } |
6102 | 0 | SDynQueryCtrlPhysiNode* pDynCtrl = (SDynQueryCtrlPhysiNode*)pNode; |
6103 | 0 | if (DYN_QTYPE_VTB_SCAN != pDynCtrl->qType) { |
6104 | 0 | return false; |
6105 | 0 | } |
6106 | 0 | if (nodesListGetNode(pDynCtrl->node.pChildren, 0)== NULL) { |
6107 | 0 | return false; |
6108 | 0 | } |
6109 | 0 | if (QUERY_NODE_PHYSICAL_PLAN_VIRTUAL_TABLE_SCAN != nodeType(nodesListGetNode(pDynCtrl->node.pChildren, 0))) { |
6110 | 0 | return false; |
6111 | 0 | } |
6112 | 0 | return true; |
6113 | 0 | } |
6114 | | |
6115 | 0 | static bool isDynVirtualStableAgg(SNode* pNode) { |
6116 | 0 | if (NULL == pNode || QUERY_NODE_PHYSICAL_PLAN_DYN_QUERY_CTRL != nodeType(pNode)) { |
6117 | 0 | return false; |
6118 | 0 | } |
6119 | 0 | SDynQueryCtrlPhysiNode* pDynCtrl = (SDynQueryCtrlPhysiNode*)pNode; |
6120 | 0 | if (DYN_QTYPE_VTB_AGG != pDynCtrl->qType && DYN_QTYPE_VTB_INTERVAL != pDynCtrl->qType) { |
6121 | 0 | return false; |
6122 | 0 | } |
6123 | 0 | if (nodesListGetNode(pDynCtrl->node.pChildren, 0)== NULL) { |
6124 | 0 | return false; |
6125 | 0 | } |
6126 | 0 | return true; |
6127 | 0 | } |
6128 | | |
6129 | 0 | static int32_t getChildTuple(SDataBlockDescNode **pChildTuple, SNodeList* pChildren) { |
6130 | 0 | if (isDynVirtualStableScan(nodesListGetNode(pChildren, 0))) { |
6131 | 0 | SPhysiNode* pDynNode = (SPhysiNode*)nodesListGetNode(pChildren, 0); |
6132 | 0 | if (pDynNode == NULL) { |
6133 | 0 | planError("get child tuple failed, pDynNode is NULL, childrenNum:%d", pChildren->length); |
6134 | 0 | return TSDB_CODE_INVALID_PARA; |
6135 | 0 | } |
6136 | 0 | SPhysiNode* pVtbScan = (SPhysiNode*)nodesListGetNode(pDynNode->pChildren, 0); |
6137 | 0 | if (pVtbScan == NULL) { |
6138 | 0 | planError("get child tuple failed, pVtbScan is NULL, dynNode childrenNum:%d", pDynNode->pChildren->length); |
6139 | 0 | return TSDB_CODE_INVALID_PARA; |
6140 | 0 | } |
6141 | 0 | *pChildTuple = pVtbScan->pOutputDataBlockDesc; |
6142 | 0 | } else if (isDynVirtualStableAgg(nodesListGetNode(pChildren, 0))) { |
6143 | 0 | SPhysiNode* pDynNode = (SPhysiNode*)nodesListGetNode(pChildren, 0); |
6144 | 0 | if (pDynNode == NULL) { |
6145 | 0 | planError("get child tuple failed, pDynNode is NULL, childrenNum:%d", pChildren->length); |
6146 | 0 | return TSDB_CODE_INVALID_PARA; |
6147 | 0 | } |
6148 | 0 | SPhysiNode* pAgg = (SPhysiNode*)nodesListGetNode(pDynNode->pChildren, LIST_LENGTH(pDynNode->pChildren) - 1); |
6149 | 0 | if (pAgg == NULL) { |
6150 | 0 | planError("get child tuple failed, pVtbScan is NULL, dynNode childrenNum:%d", pDynNode->pChildren->length); |
6151 | 0 | return TSDB_CODE_INVALID_PARA; |
6152 | 0 | } |
6153 | 0 | *pChildTuple = pAgg->pOutputDataBlockDesc; |
6154 | 0 | } else { |
6155 | 0 | SPhysiNode* pChild = (SPhysiNode*)nodesListGetNode(pChildren, 0); |
6156 | 0 | if (pChild == NULL) { |
6157 | 0 | planError("get child tuple failed, pChild is NULL, childrenNum:%d", pChildren->length); |
6158 | 0 | return TSDB_CODE_INVALID_PARA; |
6159 | 0 | } |
6160 | 0 | *pChildTuple = (((SPhysiNode*)nodesListGetNode(pChildren, 0))->pOutputDataBlockDesc); |
6161 | 0 | } |
6162 | 0 | return TSDB_CODE_SUCCESS; |
6163 | 0 | } |
6164 | | |
6165 | 0 | static bool forceNoMergeDataBlock(const SPhysiPlanContext* pCxt) { |
6166 | 0 | return (pCxt != NULL && pCxt->pPlanCxt != NULL && pCxt->pPlanCxt->forceNoMergeDataBlock); |
6167 | 0 | } |
6168 | | |
6169 | | static int32_t createAggPhysiNode(SPhysiPlanContext* pCxt, SNodeList* pChildren, SAggLogicNode* pAggLogicNode, |
6170 | 0 | SPhysiNode** pPhyNode, SSubplan* pSubPlan) { |
6171 | 0 | if (fqDiagEnabled()) { |
6172 | 0 | fprintf(stderr, |
6173 | 0 | "[FQ-DIAG] createAggPhysiNode logic=%p targets=%d groupKeys=%d aggFuncs=%d cond=%p childCnt=%d\n", |
6174 | 0 | pAggLogicNode, pAggLogicNode->node.pTargets ? LIST_LENGTH(pAggLogicNode->node.pTargets) : 0, |
6175 | 0 | pAggLogicNode->pGroupKeys ? LIST_LENGTH(pAggLogicNode->pGroupKeys) : 0, |
6176 | 0 | pAggLogicNode->pAggFuncs ? LIST_LENGTH(pAggLogicNode->pAggFuncs) : 0, |
6177 | 0 | pAggLogicNode->node.pConditions, pChildren ? LIST_LENGTH(pChildren) : 0); |
6178 | 0 | fqDiagDumpExprList("agg.logic.targets", pAggLogicNode->node.pTargets); |
6179 | 0 | fqDiagDumpExprList("agg.logic.groupKeys", pAggLogicNode->pGroupKeys); |
6180 | 0 | fqDiagDumpExprList("agg.logic.aggFuncs", pAggLogicNode->pAggFuncs); |
6181 | 0 | } |
6182 | 0 | SAggPhysiNode* pAgg = |
6183 | 0 | (SAggPhysiNode*)makePhysiNode(pCxt, (SLogicNode*)pAggLogicNode, QUERY_NODE_PHYSICAL_PLAN_HASH_AGG); |
6184 | 0 | if (NULL == pAgg) { |
6185 | 0 | return terrno; |
6186 | 0 | } |
6187 | 0 | if (pAgg->node.pSlimit && ((SLimitNode*)pAgg->node.pSlimit)->limit) { |
6188 | 0 | pSubPlan->dynamicRowThreshold = true; |
6189 | 0 | pSubPlan->rowsThreshold = ((SLimitNode*)pAgg->node.pSlimit)->limit->datum.i; |
6190 | 0 | } |
6191 | |
|
6192 | 0 | pAgg->mergeDataBlock = |
6193 | 0 | (forceNoMergeDataBlock(pCxt) || GROUP_ACTION_KEEP == pAggLogicNode->node.groupAction ? false : true); |
6194 | 0 | pAgg->groupKeyOptimized = pAggLogicNode->hasGroupKeyOptimized; |
6195 | 0 | pAgg->hasMixedDistinct = pAggLogicNode->hasMixedDistinct; |
6196 | 0 | pAgg->numDistinctFuncs = pAggLogicNode->numDistinctFuncs; |
6197 | 0 | pAgg->node.forceCreateNonBlockingOptr = pAggLogicNode->node.forceCreateNonBlockingOptr; |
6198 | |
|
6199 | 0 | SNodeList* pPrecalcExprs = NULL; |
6200 | 0 | SNodeList* pGroupKeys = NULL; |
6201 | 0 | SNodeList* pAggFuncs = NULL; |
6202 | 0 | int32_t code = rewritePrecalcExprs(pCxt, pAggLogicNode->pGroupKeys, &pPrecalcExprs, &pGroupKeys); |
6203 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6204 | 0 | code = rewritePrecalcExprs(pCxt, pAggLogicNode->pAggFuncs, &pPrecalcExprs, &pAggFuncs); |
6205 | 0 | } |
6206 | 0 | nodesWalkExprs(pAggFuncs, hasCountLikeFunc, &pAgg->hasCountLikeFunc); |
6207 | |
|
6208 | 0 | SDataBlockDescNode* pChildTupe = NULL; |
6209 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6210 | 0 | code = getChildTuple(&pChildTupe, pChildren); |
6211 | 0 | } |
6212 | | |
6213 | | // push down expression to pOutputDataBlockDesc of child node |
6214 | 0 | if (TSDB_CODE_SUCCESS == code && NULL != pPrecalcExprs) { |
6215 | 0 | code = setListSlotId(pCxt, pChildTupe->dataBlockId, -1, pPrecalcExprs, &pAgg->pExprs); |
6216 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6217 | 0 | code = pushdownDataBlockSlots(pCxt, pAgg->pExprs, pChildTupe); |
6218 | 0 | } |
6219 | | // For mixed distinct: also push precalc exprs to child[1]'s descriptor |
6220 | 0 | if (TSDB_CODE_SUCCESS == code && pAggLogicNode->hasMixedDistinct && pChildren->length >= 2) { |
6221 | 0 | SPhysiNode* pChild1 = (SPhysiNode*)nodesListGetNode(pChildren, 1); |
6222 | 0 | if (pChild1 != NULL) { |
6223 | 0 | code = pushdownDataBlockSlots(pCxt, pAgg->pExprs, pChild1->pOutputDataBlockDesc); |
6224 | 0 | } |
6225 | 0 | } |
6226 | 0 | } |
6227 | |
|
6228 | 0 | if (TSDB_CODE_SUCCESS == code && NULL != pGroupKeys) { |
6229 | 0 | code = setListSlotId(pCxt, pChildTupe->dataBlockId, -1, pGroupKeys, &pAgg->pGroupKeys); |
6230 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6231 | 0 | code = addDataBlockSlots(pCxt, pAgg->pGroupKeys, pAgg->node.pOutputDataBlockDesc); |
6232 | 0 | } |
6233 | 0 | } |
6234 | |
|
6235 | 0 | if (TSDB_CODE_SUCCESS == code && NULL != pAggFuncs) { |
6236 | 0 | code = setListSlotId(pCxt, pChildTupe->dataBlockId, -1, pAggFuncs, &pAgg->pAggFuncs); |
6237 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6238 | 0 | code = addDataBlockSlots(pCxt, pAgg->pAggFuncs, pAgg->node.pOutputDataBlockDesc); |
6239 | 0 | } |
6240 | 0 | } |
6241 | | |
6242 | |
|
6243 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6244 | 0 | code = setConditionsSlotId(pCxt, (const SLogicNode*)pAggLogicNode, (SPhysiNode*)pAgg); |
6245 | 0 | } |
6246 | |
|
6247 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6248 | 0 | *pPhyNode = (SPhysiNode*)pAgg; |
6249 | 0 | } else { |
6250 | 0 | nodesDestroyNode((SNode*)pAgg); |
6251 | 0 | } |
6252 | |
|
6253 | 0 | nodesDestroyList(pPrecalcExprs); |
6254 | 0 | nodesDestroyList(pGroupKeys); |
6255 | 0 | nodesDestroyList(pAggFuncs); |
6256 | |
|
6257 | 0 | return code; |
6258 | 0 | } |
6259 | | |
6260 | | static int32_t createIndefRowsFuncPhysiNode(SPhysiPlanContext* pCxt, SNodeList* pChildren, |
6261 | 0 | SIndefRowsFuncLogicNode* pFuncLogicNode, SPhysiNode** pPhyNode) { |
6262 | 0 | SIndefRowsFuncPhysiNode* pIdfRowsFunc = (SIndefRowsFuncPhysiNode*)makePhysiNode( |
6263 | 0 | pCxt, (SLogicNode*)pFuncLogicNode, QUERY_NODE_PHYSICAL_PLAN_INDEF_ROWS_FUNC); |
6264 | 0 | if (NULL == pIdfRowsFunc) { |
6265 | 0 | return terrno; |
6266 | 0 | } |
6267 | | |
6268 | 0 | SNodeList* pPrecalcExprs = NULL; |
6269 | 0 | SNodeList* pFuncs = NULL; |
6270 | 0 | int32_t code = rewritePrecalcExprs(pCxt, pFuncLogicNode->pFuncs, &pPrecalcExprs, &pFuncs); |
6271 | |
|
6272 | 0 | if (pIdfRowsFunc->node.inputTsOrder == 0) { |
6273 | | // default to asc |
6274 | 0 | pIdfRowsFunc->node.inputTsOrder = TSDB_ORDER_ASC; |
6275 | 0 | } |
6276 | |
|
6277 | 0 | SDataBlockDescNode* pChildTupe = NULL; |
6278 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6279 | 0 | code = getChildTuple(&pChildTupe, pChildren); |
6280 | 0 | } |
6281 | | |
6282 | | // push down expression to pOutputDataBlockDesc of child node |
6283 | 0 | if (TSDB_CODE_SUCCESS == code && NULL != pPrecalcExprs) { |
6284 | 0 | code = setListSlotId(pCxt, pChildTupe->dataBlockId, -1, pPrecalcExprs, &pIdfRowsFunc->pExprs); |
6285 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6286 | 0 | code = pushdownDataBlockSlots(pCxt, pIdfRowsFunc->pExprs, pChildTupe); |
6287 | 0 | } |
6288 | 0 | } |
6289 | |
|
6290 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6291 | 0 | code = setListSlotId(pCxt, pChildTupe->dataBlockId, -1, pFuncs, &pIdfRowsFunc->pFuncs); |
6292 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6293 | 0 | code = addDataBlockSlots(pCxt, pIdfRowsFunc->pFuncs, pIdfRowsFunc->node.pOutputDataBlockDesc); |
6294 | 0 | } |
6295 | 0 | } |
6296 | |
|
6297 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6298 | 0 | code = setConditionsSlotId(pCxt, (const SLogicNode*)pFuncLogicNode, (SPhysiNode*)pIdfRowsFunc); |
6299 | 0 | } |
6300 | |
|
6301 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6302 | 0 | *pPhyNode = (SPhysiNode*)pIdfRowsFunc; |
6303 | 0 | } else { |
6304 | 0 | nodesDestroyNode((SNode*)pIdfRowsFunc); |
6305 | 0 | } |
6306 | |
|
6307 | 0 | nodesDestroyList(pPrecalcExprs); |
6308 | 0 | nodesDestroyList(pFuncs); |
6309 | |
|
6310 | 0 | return code; |
6311 | 0 | } |
6312 | | |
6313 | | static int32_t createInterpFuncPhysiNode(SPhysiPlanContext* pCxt, SNodeList* pChildren, |
6314 | 0 | SInterpFuncLogicNode* pFuncLogicNode, SPhysiNode** pPhyNode) { |
6315 | 0 | SInterpFuncPhysiNode* pInterpFunc = (SInterpFuncPhysiNode*)makePhysiNode( |
6316 | 0 | pCxt, (SLogicNode*)pFuncLogicNode, QUERY_NODE_PHYSICAL_PLAN_INTERP_FUNC); |
6317 | 0 | if (NULL == pInterpFunc) { |
6318 | 0 | return terrno; |
6319 | 0 | } |
6320 | | |
6321 | 0 | pInterpFunc->mergeDataBlock = !forceNoMergeDataBlock(pCxt) && |
6322 | 0 | GROUP_ACTION_KEEP != pFuncLogicNode->node.groupAction; |
6323 | |
|
6324 | 0 | SNodeList* pPrecalcExprs = NULL; |
6325 | 0 | SNodeList* pFuncs = NULL; |
6326 | 0 | int32_t code = rewritePrecalcExprs(pCxt, pFuncLogicNode->pFuncs, &pPrecalcExprs, &pFuncs); |
6327 | |
|
6328 | 0 | SDataBlockDescNode* pChildTupe = NULL; |
6329 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6330 | 0 | code = getChildTuple(&pChildTupe, pChildren); |
6331 | 0 | } |
6332 | | |
6333 | | // push down expression to pOutputDataBlockDesc of child node |
6334 | 0 | if (TSDB_CODE_SUCCESS == code && NULL != pPrecalcExprs) { |
6335 | 0 | code = setListSlotId(pCxt, pChildTupe->dataBlockId, -1, pPrecalcExprs, &pInterpFunc->pExprs); |
6336 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6337 | 0 | code = pushdownDataBlockSlots(pCxt, pInterpFunc->pExprs, pChildTupe); |
6338 | 0 | } |
6339 | 0 | } |
6340 | |
|
6341 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6342 | 0 | code = setListSlotId(pCxt, pChildTupe->dataBlockId, -1, pFuncs, &pInterpFunc->pFuncs); |
6343 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6344 | 0 | code = addDataBlockSlots(pCxt, pInterpFunc->pFuncs, pInterpFunc->node.pOutputDataBlockDesc); |
6345 | 0 | } |
6346 | 0 | } |
6347 | |
|
6348 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6349 | 0 | pInterpFunc->timeRange = pFuncLogicNode->timeRange; |
6350 | 0 | pInterpFunc->interval = pFuncLogicNode->interval; |
6351 | 0 | pInterpFunc->fillMode = pFuncLogicNode->fillMode; |
6352 | 0 | pInterpFunc->timelineSource = pFuncLogicNode->timelineSource; |
6353 | 0 | pInterpFunc->interpMode = pFuncLogicNode->interpMode; |
6354 | 0 | pInterpFunc->requireMainMembership = |
6355 | 0 | pFuncLogicNode->requireMainMembership; |
6356 | 0 | pInterpFunc->intervalUnit = pFuncLogicNode->intervalUnit; |
6357 | 0 | pInterpFunc->precision = pFuncLogicNode->node.precision; |
6358 | 0 | pInterpFunc->timezone = pFuncLogicNode->timezone; |
6359 | 0 | tstrncpy(pInterpFunc->timezoneName, pFuncLogicNode->timezoneName, |
6360 | 0 | sizeof(pInterpFunc->timezoneName)); |
6361 | 0 | pInterpFunc->pFillValues = NULL; |
6362 | 0 | pInterpFunc->surroundingTime = pFuncLogicNode->surroundingTime; |
6363 | 0 | code = nodesCloneNode(pFuncLogicNode->pTimeRange, &pInterpFunc->pTimeRange); |
6364 | 0 | } |
6365 | | |
6366 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6367 | 0 | code = nodesCloneNode(pFuncLogicNode->pFillValues, &pInterpFunc->pFillValues); |
6368 | 0 | } |
6369 | |
|
6370 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6371 | 0 | code = setNodeSlotId(pCxt, pChildTupe->dataBlockId, -1, pFuncLogicNode->pTimeSeries, &pInterpFunc->pTimeSeries); |
6372 | 0 | } |
6373 | |
|
6374 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6375 | 0 | code = setConditionsSlotId(pCxt, (const SLogicNode*)pFuncLogicNode, (SPhysiNode*)pInterpFunc); |
6376 | 0 | } |
6377 | |
|
6378 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6379 | 0 | *pPhyNode = (SPhysiNode*)pInterpFunc; |
6380 | 0 | } else { |
6381 | 0 | nodesDestroyNode((SNode*)pInterpFunc); |
6382 | 0 | } |
6383 | |
|
6384 | 0 | nodesDestroyList(pPrecalcExprs); |
6385 | 0 | nodesDestroyList(pFuncs); |
6386 | |
|
6387 | 0 | return code; |
6388 | 0 | } |
6389 | | |
6390 | | static int32_t createForecastFuncPhysiNode(SPhysiPlanContext* pCxt, SNodeList* pChildren, |
6391 | 0 | SForecastFuncLogicNode* pFuncLogicNode, SPhysiNode** pPhyNode) { |
6392 | 0 | SForecastFuncPhysiNode* pForecastFunc = |
6393 | 0 | (SForecastFuncPhysiNode*)makePhysiNode(pCxt, (SLogicNode*)pFuncLogicNode, QUERY_NODE_PHYSICAL_PLAN_FORECAST_FUNC); |
6394 | 0 | if (NULL == pForecastFunc) { |
6395 | 0 | return terrno; |
6396 | 0 | } |
6397 | | |
6398 | 0 | SNodeList* pPrecalcExprs = NULL; |
6399 | 0 | SNodeList* pFuncs = NULL; |
6400 | 0 | int32_t code = rewritePrecalcExprs(pCxt, pFuncLogicNode->pFuncs, &pPrecalcExprs, &pFuncs); |
6401 | |
|
6402 | 0 | SDataBlockDescNode* pChildTupe = NULL; |
6403 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6404 | 0 | code = getChildTuple(&pChildTupe, pChildren); |
6405 | 0 | } |
6406 | | |
6407 | | // push down expression to pOutputDataBlockDesc of child node |
6408 | 0 | if (TSDB_CODE_SUCCESS == code && NULL != pPrecalcExprs) { |
6409 | 0 | code = setListSlotId(pCxt, pChildTupe->dataBlockId, -1, pPrecalcExprs, &pForecastFunc->pExprs); |
6410 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6411 | 0 | code = pushdownDataBlockSlots(pCxt, pForecastFunc->pExprs, pChildTupe); |
6412 | 0 | } |
6413 | 0 | } |
6414 | |
|
6415 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6416 | 0 | code = setListSlotId(pCxt, pChildTupe->dataBlockId, -1, pFuncs, &pForecastFunc->pFuncs); |
6417 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6418 | 0 | code = addDataBlockSlots(pCxt, pForecastFunc->pFuncs, pForecastFunc->node.pOutputDataBlockDesc); |
6419 | 0 | } |
6420 | 0 | } |
6421 | |
|
6422 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6423 | 0 | code = setConditionsSlotId(pCxt, (const SLogicNode*)pFuncLogicNode, (SPhysiNode*)pForecastFunc); |
6424 | 0 | } |
6425 | |
|
6426 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6427 | 0 | *pPhyNode = (SPhysiNode*)pForecastFunc; |
6428 | 0 | } else { |
6429 | 0 | nodesDestroyNode((SNode*)pForecastFunc); |
6430 | 0 | } |
6431 | |
|
6432 | 0 | nodesDestroyList(pPrecalcExprs); |
6433 | 0 | nodesDestroyList(pFuncs); |
6434 | |
|
6435 | 0 | return code; |
6436 | 0 | } |
6437 | | |
6438 | | static int32_t createWindowFuncPhysiNode(SPhysiPlanContext* pCxt, SNodeList* pChildren, |
6439 | 0 | SWindowFuncLogicNode* pWindowLogicNode, SPhysiNode** pPhyNode) { |
6440 | 0 | SWindowFuncPhysiNode* pWindow = |
6441 | 0 | (SWindowFuncPhysiNode*)makePhysiNode(pCxt, (SLogicNode*)pWindowLogicNode, QUERY_NODE_PHYSICAL_PLAN_WINDOW_FUNC); |
6442 | 0 | if (NULL == pWindow) { |
6443 | 0 | return terrno; |
6444 | 0 | } |
6445 | | |
6446 | 0 | SNodeList* pPrecalcExprs = NULL; |
6447 | 0 | SNodeList* pFuncs = NULL; |
6448 | 0 | SNodeList* pOrderKeys = NULL; |
6449 | 0 | int32_t code = rewritePrecalcExprs(pCxt, pWindowLogicNode->pFuncs, &pPrecalcExprs, &pFuncs); |
6450 | |
|
6451 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6452 | 0 | code = rewritePrecalcExprs(pCxt, pWindowLogicNode->pOrderKeys, &pPrecalcExprs, &pOrderKeys); |
6453 | 0 | } |
6454 | |
|
6455 | 0 | SDataBlockDescNode* pChildTuple = NULL; |
6456 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6457 | 0 | code = getChildTuple(&pChildTuple, pChildren); |
6458 | 0 | } |
6459 | 0 | if (TSDB_CODE_SUCCESS == code && NULL != pPrecalcExprs) { |
6460 | 0 | code = setListSlotId(pCxt, pChildTuple->dataBlockId, -1, pPrecalcExprs, &pWindow->pExprs); |
6461 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6462 | 0 | code = pushdownDataBlockSlots(pCxt, pWindow->pExprs, pChildTuple); |
6463 | 0 | } |
6464 | 0 | } |
6465 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6466 | 0 | code = |
6467 | 0 | setListSlotId(pCxt, pChildTuple->dataBlockId, -1, pWindowLogicNode->pPartitionKeys, &pWindow->pPartitionKeys); |
6468 | 0 | } |
6469 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6470 | 0 | code = setListSlotId(pCxt, pChildTuple->dataBlockId, -1, pOrderKeys, &pWindow->pOrderKeys); |
6471 | 0 | } |
6472 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6473 | 0 | code = setListSlotId(pCxt, pChildTuple->dataBlockId, -1, pFuncs, &pWindow->pFuncs); |
6474 | 0 | } |
6475 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6476 | 0 | code = nodesCloneNode(pWindowLogicNode->pFrame, &pWindow->pFrame); |
6477 | 0 | } |
6478 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6479 | 0 | code = addDataBlockSlots(pCxt, pWindow->pFuncs, pWindow->node.pOutputDataBlockDesc); |
6480 | 0 | } |
6481 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6482 | 0 | code = setConditionsSlotId(pCxt, (const SLogicNode*)pWindowLogicNode, (SPhysiNode*)pWindow); |
6483 | 0 | } |
6484 | |
|
6485 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6486 | 0 | *pPhyNode = (SPhysiNode*)pWindow; |
6487 | 0 | } else { |
6488 | 0 | nodesDestroyNode((SNode*)pWindow); |
6489 | 0 | } |
6490 | |
|
6491 | 0 | nodesDestroyList(pPrecalcExprs); |
6492 | 0 | nodesDestroyList(pFuncs); |
6493 | 0 | nodesDestroyList(pOrderKeys); |
6494 | |
|
6495 | 0 | return code; |
6496 | 0 | } |
6497 | | |
6498 | | static int32_t createGenericAnalysisPhysiNode(SPhysiPlanContext* pCxt, SNodeList* pChildren, |
6499 | 0 | SGenericAnalysisLogicNode* pFuncLogicNode, SPhysiNode** pPhyNode) { |
6500 | 0 | SGenericAnalysisPhysiNode* pFunc = (SGenericAnalysisPhysiNode*)makePhysiNode(pCxt, (SLogicNode*)pFuncLogicNode, |
6501 | 0 | QUERY_NODE_PHYSICAL_PLAN_ANALYSIS_FUNC); |
6502 | 0 | if (NULL == pFunc) { |
6503 | 0 | return terrno; |
6504 | 0 | } |
6505 | | |
6506 | 0 | SNodeList* pPrecalcExprs = NULL; |
6507 | 0 | SNodeList* pFuncs = NULL; |
6508 | 0 | int32_t code = rewritePrecalcExprs(pCxt, pFuncLogicNode->pFuncs, &pPrecalcExprs, &pFuncs); |
6509 | |
|
6510 | 0 | SDataBlockDescNode* pChildTupe = (((SPhysiNode*)nodesListGetNode(pChildren, 0))->pOutputDataBlockDesc); |
6511 | | // push down expression to pOutputDataBlockDesc of child node |
6512 | 0 | if (TSDB_CODE_SUCCESS == code && NULL != pPrecalcExprs) { |
6513 | 0 | code = setListSlotId(pCxt, pChildTupe->dataBlockId, -1, pPrecalcExprs, &pFunc->pExprs); |
6514 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6515 | 0 | code = pushdownDataBlockSlots(pCxt, pFunc->pExprs, pChildTupe); |
6516 | 0 | } |
6517 | 0 | } |
6518 | |
|
6519 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6520 | 0 | code = setListSlotId(pCxt, pChildTupe->dataBlockId, -1, pFuncs, &pFunc->pFuncs); |
6521 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6522 | 0 | code = addDataBlockSlots(pCxt, pFunc->pFuncs, pFunc->node.pOutputDataBlockDesc); |
6523 | 0 | } |
6524 | 0 | } |
6525 | |
|
6526 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6527 | 0 | code = setConditionsSlotId(pCxt, (const SLogicNode*)pFuncLogicNode, (SPhysiNode*)pFunc); |
6528 | 0 | } |
6529 | |
|
6530 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6531 | 0 | *pPhyNode = (SPhysiNode*)pFunc; |
6532 | 0 | } else { |
6533 | 0 | nodesDestroyNode((SNode*)pFunc); |
6534 | 0 | } |
6535 | |
|
6536 | 0 | nodesDestroyList(pPrecalcExprs); |
6537 | 0 | nodesDestroyList(pFuncs); |
6538 | |
|
6539 | 0 | return code; |
6540 | 0 | } |
6541 | | |
6542 | | static int32_t createRowsetSourcePhysiNode(SPhysiPlanContext* pCxt, SRowsetSourceLogicNode* pLogicNode, |
6543 | 0 | SPhysiNode** pPhyNode) { |
6544 | 0 | SRowsetSourcePhysiNode* pRowset = |
6545 | 0 | (SRowsetSourcePhysiNode*)makePhysiNode(pCxt, (SLogicNode*)pLogicNode, QUERY_NODE_PHYSICAL_PLAN_ROWSET_SOURCE); |
6546 | 0 | if (NULL == pRowset) { |
6547 | 0 | return terrno; |
6548 | 0 | } |
6549 | | |
6550 | 0 | pRowset->colCount = pLogicNode->colCount; |
6551 | 0 | pRowset->numBlocks = pLogicNode->numBlocks; |
6552 | 0 | pRowset->totalRows = pLogicNode->totalRows; |
6553 | 0 | pRowset->hasPrimaryTs = pLogicNode->hasPrimaryTs; |
6554 | 0 | pRowset->isSortedByTs = pLogicNode->isSortedByTs; |
6555 | 0 | pRowset->primaryTsSlot = pLogicNode->primaryTsSlot; |
6556 | 0 | pRowset->blockBufLen = pLogicNode->blockBufLen; |
6557 | 0 | pRowset->pBlockBuf = pLogicNode->pBlockBuf; |
6558 | 0 | pLogicNode->pBlockBuf = NULL; // ownership transferred |
6559 | |
|
6560 | 0 | int32_t code = setConditionsSlotId(pCxt, (const SLogicNode*)pLogicNode, (SPhysiNode*)pRowset); |
6561 | 0 | if (TSDB_CODE_SUCCESS != code) { |
6562 | 0 | nodesDestroyNode((SNode*)pRowset); |
6563 | 0 | return code; |
6564 | 0 | } |
6565 | | |
6566 | 0 | *pPhyNode = (SPhysiNode*)pRowset; |
6567 | 0 | return TSDB_CODE_SUCCESS; |
6568 | 0 | } |
6569 | | |
6570 | 0 | static bool projectCanMergeDataBlock(SProjectLogicNode* pProject, bool topLevelSubplan) { |
6571 | | // Split/scale-out may reset logic-parent pointers at subplan boundaries. |
6572 | | // Allow merge only when Project is the root output of the top-level subplan. |
6573 | 0 | if (!topLevelSubplan || pProject->node.pParent != NULL) { |
6574 | 0 | return false; |
6575 | 0 | } |
6576 | | |
6577 | 0 | if (GROUP_ACTION_KEEP == pProject->node.groupAction) { |
6578 | 0 | return false; |
6579 | 0 | } |
6580 | 0 | if (DATA_ORDER_LEVEL_NONE == pProject->node.resultDataOrder) { |
6581 | 0 | return true; |
6582 | 0 | } |
6583 | 0 | if (1 != LIST_LENGTH(pProject->node.pChildren)) { |
6584 | 0 | return true; |
6585 | 0 | } |
6586 | 0 | SLogicNode* pChild = (SLogicNode*)nodesListGetNode(pProject->node.pChildren, 0); |
6587 | 0 | return DATA_ORDER_LEVEL_GLOBAL == pChild->resultDataOrder ? true : false; |
6588 | 0 | } |
6589 | | |
6590 | 0 | bool projectCouldMergeUnsortDataBlock(SProjectLogicNode* pProject) { |
6591 | 0 | SLogicNode* pChild = (SLogicNode*)nodesListGetNode(pProject->node.pChildren, 0); |
6592 | 0 | if (DATA_ORDER_LEVEL_GLOBAL == pChild->resultDataOrder) { |
6593 | 0 | return false; |
6594 | 0 | } |
6595 | 0 | if (GROUP_ACTION_KEEP == pProject->node.groupAction) { |
6596 | 0 | return false; |
6597 | 0 | } |
6598 | 0 | if (DATA_ORDER_LEVEL_NONE == pProject->node.resultDataOrder) { |
6599 | 0 | return true; |
6600 | 0 | } |
6601 | 0 | if (1 != LIST_LENGTH(pProject->node.pChildren)) { |
6602 | 0 | return true; |
6603 | 0 | } |
6604 | 0 | return false; |
6605 | 0 | } |
6606 | | |
6607 | | static int32_t createProjectPhysiNode(SPhysiPlanContext* pCxt, SNodeList* pChildren, |
6608 | | SProjectLogicNode* pProjectLogicNode, SSubplan* pSubplan, |
6609 | 0 | SPhysiNode** pPhyNode) { |
6610 | 0 | SProjectPhysiNode* pProject = |
6611 | 0 | (SProjectPhysiNode*)makePhysiNode(pCxt, (SLogicNode*)pProjectLogicNode, QUERY_NODE_PHYSICAL_PLAN_PROJECT); |
6612 | 0 | if (NULL == pProject) { |
6613 | 0 | return terrno; |
6614 | 0 | } |
6615 | | |
6616 | 0 | pProject->mergeDataBlock = |
6617 | 0 | (forceNoMergeDataBlock(pCxt) ? false : projectCanMergeDataBlock(pProjectLogicNode, (0 == pSubplan->level))); |
6618 | 0 | pProject->ignoreGroupId = pProjectLogicNode->ignoreGroupId; |
6619 | 0 | pProject->inputIgnoreGroup = pProjectLogicNode->inputIgnoreGroup; |
6620 | |
|
6621 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
6622 | 0 | if (0 == LIST_LENGTH(pChildren)) { |
6623 | 0 | code = nodesCloneList(pProjectLogicNode->pProjections, &pProject->pProjections); |
6624 | 0 | } else { |
6625 | 0 | code = setListSlotId(pCxt, ((SPhysiNode*)nodesListGetNode(pChildren, 0))->pOutputDataBlockDesc->dataBlockId, -1, |
6626 | 0 | pProjectLogicNode->pProjections, &pProject->pProjections); |
6627 | 0 | } |
6628 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6629 | 0 | code = addDataBlockSlotsForProject(pCxt, pProjectLogicNode->stmtName, pProject->pProjections, |
6630 | 0 | pProject->node.pOutputDataBlockDesc); |
6631 | 0 | } |
6632 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6633 | 0 | code = setConditionsSlotId(pCxt, (const SLogicNode*)pProjectLogicNode, (SPhysiNode*)pProject); |
6634 | 0 | } |
6635 | |
|
6636 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6637 | 0 | *pPhyNode = (SPhysiNode*)pProject; |
6638 | 0 | } else { |
6639 | 0 | nodesDestroyNode((SNode*)pProject); |
6640 | 0 | } |
6641 | |
|
6642 | 0 | return code; |
6643 | 0 | } |
6644 | | |
6645 | | static int32_t doCreateExchangePhysiNode(SPhysiPlanContext* pCxt, SExchangeLogicNode* pExchangeLogicNode, |
6646 | 0 | SPhysiNode** pPhyNode) { |
6647 | 0 | SExchangePhysiNode* pExchange = |
6648 | 0 | (SExchangePhysiNode*)makePhysiNode(pCxt, (SLogicNode*)pExchangeLogicNode, QUERY_NODE_PHYSICAL_PLAN_EXCHANGE); |
6649 | 0 | if (NULL == pExchange) { |
6650 | 0 | return terrno; |
6651 | 0 | } |
6652 | | |
6653 | 0 | pExchange->srcStartGroupId = pExchangeLogicNode->srcStartGroupId; |
6654 | 0 | pExchange->srcEndGroupId = pExchangeLogicNode->srcEndGroupId; |
6655 | 0 | pExchange->seqRecvData = pExchangeLogicNode->seqRecvData; |
6656 | 0 | pExchange->dynTbname = pExchangeLogicNode->dynTbname; |
6657 | 0 | pExchange->fastInterval = pExchangeLogicNode->fastInterval; |
6658 | 0 | pExchange->localBlockExchange = pExchangeLogicNode->localBlockExchange; |
6659 | |
|
6660 | 0 | int32_t code = setConditionsSlotId(pCxt, (const SLogicNode*)pExchangeLogicNode, (SPhysiNode*)pExchange); |
6661 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6662 | 0 | *pPhyNode = (SPhysiNode*)pExchange; |
6663 | 0 | } else { |
6664 | 0 | nodesDestroyNode((SNode*)pExchange); |
6665 | 0 | } |
6666 | |
|
6667 | 0 | return code; |
6668 | 0 | } |
6669 | | |
6670 | | static int32_t createExchangePhysiNode(SPhysiPlanContext* pCxt, SExchangeLogicNode* pExchangeLogicNode, |
6671 | 0 | SPhysiNode** pPhyNode) { |
6672 | 0 | return doCreateExchangePhysiNode(pCxt, pExchangeLogicNode, pPhyNode); |
6673 | 0 | } |
6674 | | |
6675 | | static int32_t createWindowPhysiNodeFinalize(SPhysiPlanContext* pCxt, SNodeList* pChildren, SWindowPhysiNode* pWindow, |
6676 | 0 | SWindowLogicNode* pWindowLogicNode) { |
6677 | 0 | pWindow->indefRowsFunc = pWindowLogicNode->indefRowsFunc; |
6678 | 0 | pWindow->mergeDataBlock = |
6679 | 0 | (forceNoMergeDataBlock(pCxt) || GROUP_ACTION_KEEP == pWindowLogicNode->node.groupAction ? false : true); |
6680 | 0 | pWindow->node.inputTsOrder = pWindowLogicNode->node.inputTsOrder; |
6681 | 0 | pWindow->node.outputTsOrder = pWindowLogicNode->node.outputTsOrder; |
6682 | 0 | if (nodeType(pWindow) == QUERY_NODE_PHYSICAL_PLAN_MERGE_ALIGNED_INTERVAL) { |
6683 | 0 | pWindow->node.inputTsOrder = pWindowLogicNode->node.outputTsOrder; |
6684 | 0 | } |
6685 | |
|
6686 | 0 | SNodeList* pPrecalcExprs = NULL; |
6687 | 0 | SNodeList* pFuncs = NULL; |
6688 | 0 | SNodeList* pProjs = pWindowLogicNode->pProjs; |
6689 | 0 | int32_t code = rewritePrecalcExprs(pCxt, pWindowLogicNode->pFuncs, &pPrecalcExprs, &pFuncs); |
6690 | |
|
6691 | 0 | SDataBlockDescNode* pChildTupe = NULL; |
6692 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6693 | 0 | code = getChildTuple(&pChildTupe, pChildren); |
6694 | 0 | } |
6695 | | // push down expression to pOutputDataBlockDesc of child node |
6696 | 0 | if (TSDB_CODE_SUCCESS == code && NULL != pPrecalcExprs) { |
6697 | 0 | SNodeList* pOutput; |
6698 | 0 | code = setListSlotId(pCxt, pChildTupe->dataBlockId, -1, pPrecalcExprs, &pOutput); |
6699 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6700 | 0 | code = addDataBlockSlots(pCxt, pOutput, pChildTupe); |
6701 | 0 | } |
6702 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6703 | 0 | if (pWindow->pExprs == NULL) { |
6704 | 0 | pWindow->pExprs = pOutput; |
6705 | 0 | } else { |
6706 | 0 | code = nodesListAppendList(pWindow->pExprs, pOutput); |
6707 | 0 | } |
6708 | 0 | } |
6709 | 0 | } |
6710 | |
|
6711 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6712 | 0 | code = setNodeSlotId(pCxt, pChildTupe->dataBlockId, -1, pWindowLogicNode->pTspk, &pWindow->pTspk); |
6713 | 0 | } |
6714 | 0 | if (TSDB_CODE_SUCCESS == code && pWindowLogicNode->pTsEnd) { |
6715 | 0 | code = setNodeSlotId(pCxt, pChildTupe->dataBlockId, -1, pWindowLogicNode->pTsEnd, &pWindow->pTsEnd); |
6716 | 0 | } |
6717 | |
|
6718 | 0 | if (TSDB_CODE_SUCCESS == code && NULL != pFuncs) { |
6719 | 0 | code = setListSlotId(pCxt, pChildTupe->dataBlockId, -1, pFuncs, &pWindow->pFuncs); |
6720 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6721 | 0 | code = addDataBlockSlots(pCxt, pWindow->pFuncs, pWindow->node.pOutputDataBlockDesc); |
6722 | 0 | } |
6723 | 0 | } |
6724 | |
|
6725 | 0 | if (TSDB_CODE_SUCCESS == code && NULL != pProjs) { |
6726 | | // For the agg + fill case, pProjs contains expressions like sum(v)_col_ref + 1 |
6727 | | // where sum(v)_col_ref was substituted by the logic-layer rewrite. The agg result |
6728 | | // slot (sum(v)) lives in the ExtWin output block, which was populated by |
6729 | | // addDataBlockSlots(pFuncs) above. Use that block as the primary lookup target |
6730 | | // so the col_ref resolves to the correct slot. Fall back to the child block for |
6731 | | // any other column refs (e.g. _wstart pseudo-column on the child side). |
6732 | 0 | int64_t projPrimaryBlockId = (NULL != pFuncs) |
6733 | 0 | ? pWindow->node.pOutputDataBlockDesc->dataBlockId |
6734 | 0 | : pChildTupe->dataBlockId; |
6735 | 0 | int64_t projSecondaryBlockId = (NULL != pFuncs) ? pChildTupe->dataBlockId : -1; |
6736 | 0 | code = setListSlotId(pCxt, projPrimaryBlockId, projSecondaryBlockId, pProjs, &pWindow->pProjs); |
6737 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6738 | 0 | code = addDataBlockSlots(pCxt, pWindow->pProjs, pWindow->node.pOutputDataBlockDesc); |
6739 | 0 | } |
6740 | 0 | } |
6741 | |
|
6742 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6743 | 0 | code = setConditionsSlotId(pCxt, (const SLogicNode*)pWindowLogicNode, (SPhysiNode*)pWindow); |
6744 | 0 | } |
6745 | |
|
6746 | 0 | nodesDestroyList(pPrecalcExprs); |
6747 | 0 | nodesDestroyList(pFuncs); |
6748 | |
|
6749 | 0 | return code; |
6750 | 0 | } |
6751 | | |
6752 | 0 | static ENodeType getIntervalOperatorType(EWindowAlgorithm windowAlgo) { |
6753 | 0 | switch (windowAlgo) { |
6754 | 0 | case INTERVAL_ALGO_HASH: |
6755 | 0 | return QUERY_NODE_PHYSICAL_PLAN_HASH_INTERVAL; |
6756 | 0 | case INTERVAL_ALGO_MERGE: |
6757 | 0 | return QUERY_NODE_PHYSICAL_PLAN_MERGE_ALIGNED_INTERVAL; |
6758 | 0 | default: |
6759 | 0 | break; |
6760 | 0 | } |
6761 | 0 | return QUERY_NODE_PHYSICAL_PLAN_HASH_INTERVAL; |
6762 | 0 | } |
6763 | | |
6764 | 0 | static ENodeType getExternalOperatorType(EWindowAlgorithm windowAlgo) { |
6765 | 0 | switch (windowAlgo) { |
6766 | 0 | case EXTERNAL_ALGO_HASH: |
6767 | 0 | return QUERY_NODE_PHYSICAL_PLAN_HASH_EXTERNAL; |
6768 | 0 | case EXTERNAL_ALGO_MERGE: |
6769 | 0 | return QUERY_NODE_PHYSICAL_PLAN_MERGE_ALIGNED_EXTERNAL; |
6770 | 0 | default: |
6771 | 0 | break; |
6772 | 0 | } |
6773 | 0 | return QUERY_NODE_PHYSICAL_PLAN_HASH_EXTERNAL; |
6774 | 0 | } |
6775 | | |
6776 | | static int32_t createIntervalPhysiNode(SPhysiPlanContext* pCxt, SNodeList* pChildren, |
6777 | 0 | SWindowLogicNode* pWindowLogicNode, SPhysiNode** pPhyNode) { |
6778 | 0 | SIntervalPhysiNode* pInterval = (SIntervalPhysiNode*)makePhysiNode( |
6779 | 0 | pCxt, (SLogicNode*)pWindowLogicNode, getIntervalOperatorType(pWindowLogicNode->windowAlgo)); |
6780 | 0 | if (NULL == pInterval) { |
6781 | 0 | return terrno; |
6782 | 0 | } |
6783 | | |
6784 | 0 | pInterval->interval = pWindowLogicNode->interval; |
6785 | 0 | pInterval->offset = pWindowLogicNode->offset; |
6786 | 0 | pInterval->sliding = pWindowLogicNode->sliding; |
6787 | 0 | pInterval->intervalUnit = pWindowLogicNode->intervalUnit; |
6788 | 0 | pInterval->slidingUnit = pWindowLogicNode->slidingUnit; |
6789 | 0 | pInterval->timeRange = pWindowLogicNode->timeRange; |
6790 | 0 | pInterval->firstDayOfWeek = pWindowLogicNode->firstDayOfWeek; |
6791 | 0 | pInterval->fastInterval = pWindowLogicNode->fastInterval; |
6792 | 0 | pInterval->exInterval = pWindowLogicNode->exInterval; |
6793 | 0 | pInterval->timezone = pWindowLogicNode->timezone; |
6794 | 0 | tstrncpy(pInterval->timezoneName, pWindowLogicNode->timezoneName, sizeof(pInterval->timezoneName)); |
6795 | 0 | int32_t code = createWindowPhysiNodeFinalize(pCxt, pChildren, &pInterval->window, pWindowLogicNode); |
6796 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6797 | 0 | *pPhyNode = (SPhysiNode*)pInterval; |
6798 | 0 | } else { |
6799 | 0 | nodesDestroyNode((SNode*)pInterval); |
6800 | 0 | } |
6801 | |
|
6802 | 0 | return code; |
6803 | 0 | } |
6804 | | |
6805 | | static int32_t createSessionWindowPhysiNode(SPhysiPlanContext* pCxt, SNodeList* pChildren, |
6806 | 0 | SWindowLogicNode* pWindowLogicNode, SPhysiNode** pPhyNode) { |
6807 | 0 | SSessionWinodwPhysiNode* pSession = (SSessionWinodwPhysiNode*)makePhysiNode( |
6808 | 0 | pCxt, (SLogicNode*)pWindowLogicNode, QUERY_NODE_PHYSICAL_PLAN_MERGE_SESSION); |
6809 | 0 | if (NULL == pSession) { |
6810 | 0 | return terrno; |
6811 | 0 | } |
6812 | | |
6813 | 0 | pSession->gap = pWindowLogicNode->sessionGap; |
6814 | |
|
6815 | 0 | int32_t code = createWindowPhysiNodeFinalize(pCxt, pChildren, &pSession->window, pWindowLogicNode); |
6816 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6817 | 0 | *pPhyNode = (SPhysiNode*)pSession; |
6818 | 0 | } else { |
6819 | 0 | nodesDestroyNode((SNode*)pSession); |
6820 | 0 | } |
6821 | |
|
6822 | 0 | return code; |
6823 | 0 | } |
6824 | | |
6825 | | static int32_t createStateWindowPhysiNode(SPhysiPlanContext* pCxt, SNodeList* pChildren, |
6826 | 0 | SWindowLogicNode* pWindowLogicNode, SPhysiNode** pPhyNode) { |
6827 | 0 | ENodeType type = QUERY_NODE_PHYSICAL_PLAN_MERGE_STATE; |
6828 | 0 | SStateWindowPhysiNode* pState = (SStateWindowPhysiNode*)makePhysiNode( |
6829 | 0 | pCxt, (SLogicNode*)pWindowLogicNode, type); |
6830 | 0 | if (NULL == pState) { |
6831 | 0 | return terrno; |
6832 | 0 | } |
6833 | | |
6834 | 0 | SNodeList* pPrecalcExprs = NULL; |
6835 | 0 | SNodeList* pStateKeys = NULL; |
6836 | 0 | int32_t code = rewritePrecalcExprs(pCxt, pWindowLogicNode->pStateExprs, &pPrecalcExprs, &pStateKeys); |
6837 | |
|
6838 | 0 | SDataBlockDescNode* pChildTupe = NULL; |
6839 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6840 | 0 | code = getChildTuple(&pChildTupe, pChildren); |
6841 | 0 | } |
6842 | | // push down expression to pOutputDataBlockDesc of child node |
6843 | 0 | if (TSDB_CODE_SUCCESS == code && NULL != pPrecalcExprs) { |
6844 | 0 | code = setListSlotId(pCxt, pChildTupe->dataBlockId, -1, pPrecalcExprs, &pState->window.pExprs); |
6845 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6846 | 0 | code = addDataBlockSlots(pCxt, pState->window.pExprs, pChildTupe); |
6847 | 0 | } |
6848 | 0 | } |
6849 | |
|
6850 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6851 | 0 | code = setListSlotId(pCxt, pChildTupe->dataBlockId, -1, pStateKeys, &pState->pStateKeys); |
6852 | 0 | } |
6853 | |
|
6854 | 0 | pState->extendOption = pWindowLogicNode->extendOption; |
6855 | 0 | pState->trueForType = pWindowLogicNode->trueForType; |
6856 | 0 | pState->trueForCount = pWindowLogicNode->trueForCount; |
6857 | 0 | pState->trueForDuration = pWindowLogicNode->trueForDuration; |
6858 | |
|
6859 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6860 | 0 | code = createWindowPhysiNodeFinalize(pCxt, pChildren, &pState->window, pWindowLogicNode); |
6861 | 0 | } |
6862 | |
|
6863 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6864 | 0 | *pPhyNode = (SPhysiNode*)pState; |
6865 | 0 | } else { |
6866 | 0 | nodesDestroyNode((SNode*)pState); |
6867 | 0 | } |
6868 | |
|
6869 | 0 | nodesDestroyList(pPrecalcExprs); |
6870 | 0 | nodesDestroyList(pStateKeys); |
6871 | |
|
6872 | 0 | return code; |
6873 | 0 | } |
6874 | | |
6875 | | static int32_t createEventWindowPhysiNode(SPhysiPlanContext* pCxt, SNodeList* pChildren, |
6876 | 0 | SWindowLogicNode* pWindowLogicNode, SPhysiNode** pPhyNode) { |
6877 | 0 | ENodeType type = QUERY_NODE_PHYSICAL_PLAN_MERGE_EVENT; |
6878 | |
|
6879 | 0 | SEventWinodwPhysiNode* pEvent = (SEventWinodwPhysiNode*)makePhysiNode( |
6880 | 0 | pCxt, (SLogicNode*)pWindowLogicNode, type); |
6881 | 0 | if (NULL == pEvent) { |
6882 | 0 | return terrno; |
6883 | 0 | } |
6884 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
6885 | 0 | SDataBlockDescNode* pChildTupe = NULL; |
6886 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6887 | 0 | code = getChildTuple(&pChildTupe, pChildren); |
6888 | 0 | } |
6889 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6890 | 0 | code = setNodeSlotId(pCxt, pChildTupe->dataBlockId, -1, pWindowLogicNode->pStartCond, &pEvent->pStartCond); |
6891 | 0 | } |
6892 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6893 | 0 | code = setNodeSlotId(pCxt, pChildTupe->dataBlockId, -1, pWindowLogicNode->pEndCond, &pEvent->pEndCond); |
6894 | 0 | } |
6895 | 0 | pEvent->trueForType = pWindowLogicNode->trueForType; |
6896 | 0 | pEvent->trueForCount = pWindowLogicNode->trueForCount; |
6897 | 0 | pEvent->trueForDuration = pWindowLogicNode->trueForDuration; |
6898 | 0 | pEvent->startTrueForType = pWindowLogicNode->startTrueForType; |
6899 | 0 | pEvent->startTrueForCount = pWindowLogicNode->startTrueForCount; |
6900 | 0 | pEvent->startTrueForDuration = pWindowLogicNode->startTrueForDuration; |
6901 | 0 | pEvent->endTrueForType = pWindowLogicNode->endTrueForType; |
6902 | 0 | pEvent->endTrueForCount = pWindowLogicNode->endTrueForCount; |
6903 | 0 | pEvent->endTrueForDuration = pWindowLogicNode->endTrueForDuration; |
6904 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6905 | 0 | code = createWindowPhysiNodeFinalize(pCxt, pChildren, &pEvent->window, pWindowLogicNode); |
6906 | 0 | } |
6907 | |
|
6908 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6909 | 0 | *pPhyNode = (SPhysiNode*)pEvent; |
6910 | 0 | } else { |
6911 | 0 | nodesDestroyNode((SNode*)pEvent); |
6912 | 0 | } |
6913 | |
|
6914 | 0 | return code; |
6915 | 0 | } |
6916 | | |
6917 | | static int32_t createCountWindowPhysiNode(SPhysiPlanContext* pCxt, SNodeList* pChildren, |
6918 | 0 | SWindowLogicNode* pWindowLogicNode, SPhysiNode** pPhyNode) { |
6919 | 0 | ENodeType type = QUERY_NODE_PHYSICAL_PLAN_MERGE_COUNT; |
6920 | |
|
6921 | 0 | SCountWindowPhysiNode* pCount = (SCountWindowPhysiNode*)makePhysiNode( |
6922 | 0 | pCxt, (SLogicNode*)pWindowLogicNode, type); |
6923 | 0 | if (NULL == pCount) { |
6924 | 0 | return terrno; |
6925 | 0 | } |
6926 | 0 | pCount->windowCount = pWindowLogicNode->windowCount; |
6927 | 0 | pCount->windowSliding = pWindowLogicNode->windowSliding; |
6928 | |
|
6929 | 0 | int32_t code = createWindowPhysiNodeFinalize(pCxt, pChildren, &pCount->window, pWindowLogicNode); |
6930 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6931 | 0 | *pPhyNode = (SPhysiNode*)pCount; |
6932 | 0 | } else { |
6933 | 0 | nodesDestroyNode((SNode*)pCount); |
6934 | 0 | } |
6935 | |
|
6936 | 0 | return code; |
6937 | 0 | } |
6938 | | |
6939 | | static int32_t createAnomalyWindowPhysiNode(SPhysiPlanContext* pCxt, SNodeList* pChildren, |
6940 | 0 | SWindowLogicNode* pWindowLogicNode, SPhysiNode** pPhyNode) { |
6941 | 0 | SAnomalyWindowPhysiNode* pAnomaly = (SAnomalyWindowPhysiNode*)makePhysiNode(pCxt, (SLogicNode*)pWindowLogicNode, |
6942 | 0 | QUERY_NODE_PHYSICAL_PLAN_MERGE_ANOMALY); |
6943 | 0 | if (NULL == pAnomaly) { |
6944 | 0 | return terrno; |
6945 | 0 | } |
6946 | | |
6947 | 0 | SNodeList* pPrecalcExprs = NULL; |
6948 | 0 | SNodeList* pAnomalyKeys = NULL; |
6949 | 0 | SDataBlockDescNode* pChildTupe = NULL; |
6950 | |
|
6951 | 0 | int32_t code = rewritePrecalcExprs(pCxt, pWindowLogicNode->pAnomalyExpr, &pPrecalcExprs, &pAnomalyKeys); |
6952 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6953 | 0 | code = getChildTuple(&pChildTupe, pChildren); |
6954 | 0 | } |
6955 | | |
6956 | | // push down expression to pOutputDataBlockDesc of child node |
6957 | 0 | if (TSDB_CODE_SUCCESS == code && NULL != pPrecalcExprs) { |
6958 | 0 | code = setListSlotId(pCxt, pChildTupe->dataBlockId, -1, pPrecalcExprs, &pAnomaly->window.pExprs); |
6959 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6960 | 0 | code = addDataBlockSlots(pCxt, pAnomaly->window.pExprs, pChildTupe); |
6961 | 0 | } |
6962 | 0 | } |
6963 | |
|
6964 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6965 | 0 | code = setListSlotId(pCxt, pChildTupe->dataBlockId, -1, pAnomalyKeys, &pAnomaly->pAnomalyKeys); |
6966 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6967 | | // code = addDataBlockSlots(pCxt, pAnomaly->pAnomalyKeys, pAnomaly->window.node.pOutputDataBlockDesc); |
6968 | 0 | } |
6969 | 0 | } |
6970 | |
|
6971 | 0 | tstrncpy(pAnomaly->anomalyOpt, pWindowLogicNode->anomalyOpt, sizeof(pAnomaly->anomalyOpt)); |
6972 | |
|
6973 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6974 | 0 | code = createWindowPhysiNodeFinalize(pCxt, pChildren, &pAnomaly->window, pWindowLogicNode); |
6975 | 0 | } |
6976 | |
|
6977 | 0 | if (TSDB_CODE_SUCCESS == code) { |
6978 | 0 | *pPhyNode = (SPhysiNode*)pAnomaly; |
6979 | 0 | } else { |
6980 | 0 | nodesDestroyNode((SNode*)pAnomaly); |
6981 | 0 | } |
6982 | |
|
6983 | 0 | nodesDestroyList(pPrecalcExprs); |
6984 | 0 | nodesDestroyList(pAnomalyKeys); |
6985 | |
|
6986 | 0 | return code; |
6987 | 0 | } |
6988 | | |
6989 | 0 | static const char* getExternalWindowExprOutputName(SNode* pNode) { |
6990 | 0 | if (pNode == NULL) { |
6991 | 0 | return NULL; |
6992 | 0 | } |
6993 | | |
6994 | 0 | if (QUERY_NODE_TARGET == nodeType(pNode)) { |
6995 | 0 | pNode = ((STargetNode*)pNode)->pExpr; |
6996 | 0 | if (pNode == NULL) { |
6997 | 0 | return NULL; |
6998 | 0 | } |
6999 | 0 | } |
7000 | | |
7001 | 0 | if ('\0' != ((SExprNode*)pNode)->aliasName[0]) { |
7002 | 0 | return ((SExprNode*)pNode)->aliasName; |
7003 | 0 | } |
7004 | | |
7005 | 0 | if (QUERY_NODE_COLUMN == nodeType(pNode) && '\0' != ((SColumnNode*)pNode)->colName[0]) { |
7006 | 0 | return ((SColumnNode*)pNode)->colName; |
7007 | 0 | } |
7008 | | |
7009 | 0 | return NULL; |
7010 | 0 | } |
7011 | | |
7012 | | static int32_t createExternalWindowOutputColumn(const SExternalWindowPhysiNode* pExternal, int32_t targetIdx, |
7013 | 0 | SNode** pOutput) { |
7014 | 0 | if (pExternal == NULL || pOutput == NULL || pExternal->window.node.pOutputDataBlockDesc == NULL) { |
7015 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
7016 | 0 | } |
7017 | | |
7018 | 0 | SSlotDescNode* pSlotDesc = |
7019 | 0 | (SSlotDescNode*)nodesListGetNode(pExternal->window.node.pOutputDataBlockDesc->pSlots, targetIdx); |
7020 | 0 | if (pSlotDesc == NULL) { |
7021 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
7022 | 0 | } |
7023 | | |
7024 | 0 | SColumnNode* pCol = NULL; |
7025 | 0 | int32_t code = nodesMakeNode(QUERY_NODE_COLUMN, (SNode**)&pCol); |
7026 | 0 | if (NULL == pCol) { |
7027 | 0 | return code; |
7028 | 0 | } |
7029 | | |
7030 | 0 | pCol->dataBlockId = pExternal->window.node.pOutputDataBlockDesc->dataBlockId; |
7031 | 0 | pCol->slotId = pSlotDesc->slotId; |
7032 | 0 | pCol->colType = COLUMN_TYPE_COLUMN; |
7033 | 0 | pCol->node.resType = pSlotDesc->dataType; |
7034 | 0 | tstrncpy(pCol->colName, pSlotDesc->name, TSDB_COL_NAME_LEN); |
7035 | 0 | tstrncpy(pCol->node.aliasName, pSlotDesc->name, TSDB_COL_NAME_LEN); |
7036 | 0 | tstrncpy(pCol->node.userAlias, pSlotDesc->name, TSDB_COL_NAME_LEN); |
7037 | |
|
7038 | 0 | *pOutput = (SNode*)pCol; |
7039 | 0 | return TSDB_CODE_SUCCESS; |
7040 | 0 | } |
7041 | | |
7042 | | // Build a fill output column using the TARGET node from pProjs (after addDataBlockSlots has run). |
7043 | | // The TARGET node's slotId is the correct OPERATOR slot, not the phantom slot from makePhysiNode. |
7044 | | static int32_t createExternalWindowOutputColumnByProjIdx(const SExternalWindowPhysiNode* pExternal, |
7045 | 0 | int32_t projIdx, SNode** pOutput) { |
7046 | 0 | if (pExternal == NULL || pOutput == NULL || pExternal->window.node.pOutputDataBlockDesc == NULL) { |
7047 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
7048 | 0 | } |
7049 | | |
7050 | 0 | STargetNode* pTargetNode = |
7051 | 0 | (STargetNode*)nodesListGetNode(pExternal->window.pProjs, projIdx); |
7052 | 0 | if (pTargetNode == NULL || QUERY_NODE_TARGET != nodeType(pTargetNode)) { |
7053 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
7054 | 0 | } |
7055 | | |
7056 | | // Find the SlotDescNode that matches this TARGET's slotId. |
7057 | 0 | SSlotDescNode* pSlotDesc = NULL; |
7058 | 0 | SNode* pSlotNode = NULL; |
7059 | 0 | FOREACH(pSlotNode, pExternal->window.node.pOutputDataBlockDesc->pSlots) { |
7060 | 0 | SSlotDescNode* pSlot = (SSlotDescNode*)pSlotNode; |
7061 | 0 | if (pSlot->slotId == pTargetNode->slotId) { |
7062 | 0 | pSlotDesc = pSlot; |
7063 | 0 | break; |
7064 | 0 | } |
7065 | 0 | } |
7066 | 0 | if (pSlotDesc == NULL) { |
7067 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
7068 | 0 | } |
7069 | | |
7070 | 0 | SColumnNode* pCol = NULL; |
7071 | 0 | int32_t code = nodesMakeNode(QUERY_NODE_COLUMN, (SNode**)&pCol); |
7072 | 0 | if (NULL == pCol) { |
7073 | 0 | return code; |
7074 | 0 | } |
7075 | | |
7076 | 0 | pCol->dataBlockId = pExternal->window.node.pOutputDataBlockDesc->dataBlockId; |
7077 | 0 | pCol->slotId = pSlotDesc->slotId; |
7078 | 0 | pCol->colType = COLUMN_TYPE_COLUMN; |
7079 | 0 | pCol->node.resType = pSlotDesc->dataType; |
7080 | 0 | tstrncpy(pCol->colName, pSlotDesc->name, TSDB_COL_NAME_LEN); |
7081 | 0 | tstrncpy(pCol->node.aliasName, pSlotDesc->name, TSDB_COL_NAME_LEN); |
7082 | 0 | tstrncpy(pCol->node.userAlias, pSlotDesc->name, TSDB_COL_NAME_LEN); |
7083 | |
|
7084 | 0 | *pOutput = (SNode*)pCol; |
7085 | 0 | return TSDB_CODE_SUCCESS; |
7086 | 0 | } |
7087 | | |
7088 | 0 | static int32_t getExternalWindowOutputIndexByExpr(const SWindowLogicNode* pWindowLogicNode, SNode* pFillExpr) { |
7089 | 0 | if (LIST_LENGTH(pWindowLogicNode->node.pTargets) == LIST_LENGTH(pWindowLogicNode->pProjs)) { |
7090 | 0 | int32_t targetIdx = 0; |
7091 | 0 | SNode* pTarget = NULL; |
7092 | |
|
7093 | 0 | FOREACH(pTarget, pWindowLogicNode->pProjs) { |
7094 | 0 | if (nodesEqualNode(pFillExpr, pTarget)) { |
7095 | 0 | return targetIdx; |
7096 | 0 | } |
7097 | 0 | ++targetIdx; |
7098 | 0 | } |
7099 | | |
7100 | 0 | return -1; |
7101 | 0 | } |
7102 | | |
7103 | 0 | int32_t targetIdx = 0; |
7104 | 0 | SNode* pTarget = NULL; |
7105 | |
|
7106 | 0 | FOREACH(pTarget, pWindowLogicNode->pFuncs) { |
7107 | 0 | if (nodesEqualNode(pFillExpr, pTarget)) { |
7108 | 0 | return targetIdx; |
7109 | 0 | } |
7110 | 0 | ++targetIdx; |
7111 | 0 | } |
7112 | | |
7113 | 0 | FOREACH(pTarget, pWindowLogicNode->pProjs) { |
7114 | 0 | if (nodesEqualNode(pFillExpr, pTarget)) { |
7115 | 0 | return targetIdx; |
7116 | 0 | } |
7117 | 0 | ++targetIdx; |
7118 | 0 | } |
7119 | | |
7120 | 0 | return -1; |
7121 | 0 | } |
7122 | | |
7123 | | static int32_t createExternalWindowPhysiNode(SPhysiPlanContext* pCxt, SNodeList* pChildren, |
7124 | 0 | SWindowLogicNode* pWindowLogicNode, SPhysiNode** pPhyNode) { |
7125 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
7126 | 0 | SExternalWindowPhysiNode* pExternal = (SExternalWindowPhysiNode*)makePhysiNode( |
7127 | 0 | pCxt, (SLogicNode*)pWindowLogicNode, getExternalOperatorType(pWindowLogicNode->windowAlgo)); |
7128 | 0 | if (NULL == pExternal) { |
7129 | 0 | return terrno; |
7130 | 0 | } |
7131 | 0 | pExternal->timeRange = pWindowLogicNode->timeRange; |
7132 | 0 | pExternal->isSingleTable = pWindowLogicNode->isSingleTable; |
7133 | 0 | pExternal->inputHasOrder = pWindowLogicNode->inputHasOrder; |
7134 | 0 | pExternal->needGroupSort = pWindowLogicNode->needGroupSort; |
7135 | 0 | pExternal->extWinSplit = pWindowLogicNode->extWinSplit; |
7136 | 0 | pExternal->calcWithPartition = pWindowLogicNode->calcWithPartition; |
7137 | 0 | pExternal->matchPartitionBy = pWindowLogicNode->pSubquery != NULL && |
7138 | 0 | nodeType(pWindowLogicNode->pSubquery) == QUERY_NODE_REMOTE_TABLE && |
7139 | 0 | ((((SRemoteTableNode*)pWindowLogicNode->pSubquery)->flag & |
7140 | 0 | REMOTE_TABLE_FLAG_EXT_PART_KEYS_MATCH) != 0); |
7141 | 0 | pExternal->extWinInputMode = pWindowLogicNode->extWinInputMode; |
7142 | 0 | pExternal->extFill.mode = pWindowLogicNode->extFill.mode; |
7143 | 0 | pExternal->orgTableUid = pWindowLogicNode->orgTableUid; |
7144 | 0 | pExternal->orgTableVgId = pWindowLogicNode->orgTableVgId; |
7145 | 0 | PLAN_ERR_JRET(nodesCloneNode(pWindowLogicNode->pSubquery, &pExternal->pSubquery)); |
7146 | 0 | PLAN_ERR_JRET(nodesCloneNode(pWindowLogicNode->pTimeRange, &pExternal->pTimeRange)); |
7147 | 0 | PLAN_ERR_JRET(nodesCloneNode(pWindowLogicNode->pWindowConditions, &pExternal->pWindowConditions)); |
7148 | | |
7149 | 0 | PLAN_ERR_JRET(createWindowPhysiNodeFinalize(pCxt, pChildren, &pExternal->window, pWindowLogicNode)); |
7150 | 0 | if (pWindowLogicNode->extFill.pFillExprs != NULL) { |
7151 | | // Whether targets.len == projs.len (fast path in getExternalWindowOutputIndexByExpr). |
7152 | | // In this case targetIdx is a pProjs-relative index and we must read the slotId from |
7153 | | // pExternal->window.pProjs[targetIdx] (TARGET node) because addDataBlockSlots may have |
7154 | | // created a different slot key for the OPERATOR expression than buildDataBlockSlots |
7155 | | // created for the corresponding pTargets column. |
7156 | 0 | bool useProjIdx = (LIST_LENGTH(pWindowLogicNode->node.pTargets) == LIST_LENGTH(pWindowLogicNode->pProjs)); |
7157 | |
|
7158 | 0 | SNode* pFillExpr = NULL; |
7159 | 0 | FOREACH(pFillExpr, pWindowLogicNode->extFill.pFillExprs) { |
7160 | 0 | int32_t targetIdx = getExternalWindowOutputIndexByExpr(pWindowLogicNode, pFillExpr); |
7161 | 0 | bool fromProj = useProjIdx && (targetIdx >= 0); |
7162 | |
|
7163 | 0 | if (targetIdx < 0) { |
7164 | 0 | const char* pOutputName = getExternalWindowExprOutputName(pFillExpr); |
7165 | 0 | if (pOutputName == NULL) { |
7166 | 0 | PLAN_ERR_JRET(TSDB_CODE_PLAN_INTERNAL_ERROR); |
7167 | 0 | } |
7168 | | |
7169 | 0 | SNode* pTarget = NULL; |
7170 | 0 | bool found = false; |
7171 | 0 | targetIdx = 0; |
7172 | 0 | FOREACH(pTarget, pWindowLogicNode->node.pTargets) { |
7173 | 0 | if (QUERY_NODE_COLUMN == nodeType(pTarget) && |
7174 | 0 | (0 == strcmp(((SColumnNode*)pTarget)->colName, pOutputName) || |
7175 | 0 | 0 == strcmp(((SExprNode*)pTarget)->aliasName, pOutputName))) { |
7176 | 0 | found = true; |
7177 | 0 | break; |
7178 | 0 | } |
7179 | 0 | ++targetIdx; |
7180 | 0 | } |
7181 | |
|
7182 | 0 | if (!found) { |
7183 | 0 | PLAN_ERR_JRET(TSDB_CODE_PLAN_INTERNAL_ERROR); |
7184 | 0 | } |
7185 | 0 | } |
7186 | | |
7187 | 0 | SNode* pClone = NULL; |
7188 | 0 | if (fromProj) { |
7189 | | // Use the TARGET node from pProjs to get the correct OPERATOR slot id. |
7190 | 0 | PLAN_ERR_JRET(createExternalWindowOutputColumnByProjIdx(pExternal, targetIdx, &pClone)); |
7191 | 0 | } else { |
7192 | 0 | PLAN_ERR_JRET(createExternalWindowOutputColumn(pExternal, targetIdx, &pClone)); |
7193 | 0 | } |
7194 | 0 | PLAN_ERR_JRET(nodesListMakeStrictAppend(&pExternal->extFill.pFillExprs, pClone)); |
7195 | 0 | } |
7196 | 0 | } |
7197 | 0 | if (pWindowLogicNode->extFill.pFillValues != NULL) { |
7198 | 0 | PLAN_ERR_JRET(nodesCloneNode(pWindowLogicNode->extFill.pFillValues, &pExternal->extFill.pFillValues)); |
7199 | 0 | } |
7200 | 0 | *pPhyNode = (SPhysiNode*)pExternal; |
7201 | |
|
7202 | 0 | return code; |
7203 | 0 | _return: |
7204 | 0 | nodesDestroyNode((SNode*)pExternal); |
7205 | 0 | return code; |
7206 | 0 | } |
7207 | | |
7208 | | static int32_t createWindowPhysiNode(SPhysiPlanContext* pCxt, SNodeList* pChildren, SWindowLogicNode* pWindowLogicNode, |
7209 | 0 | SPhysiNode** pPhyNode) { |
7210 | 0 | switch (pWindowLogicNode->winType) { |
7211 | 0 | case WINDOW_TYPE_INTERVAL: |
7212 | 0 | return createIntervalPhysiNode(pCxt, pChildren, pWindowLogicNode, pPhyNode); |
7213 | 0 | case WINDOW_TYPE_SESSION: |
7214 | 0 | return createSessionWindowPhysiNode(pCxt, pChildren, pWindowLogicNode, pPhyNode); |
7215 | 0 | case WINDOW_TYPE_STATE: |
7216 | 0 | return createStateWindowPhysiNode(pCxt, pChildren, pWindowLogicNode, pPhyNode); |
7217 | 0 | case WINDOW_TYPE_EVENT: |
7218 | 0 | return createEventWindowPhysiNode(pCxt, pChildren, pWindowLogicNode, pPhyNode); |
7219 | 0 | case WINDOW_TYPE_COUNT: |
7220 | 0 | return createCountWindowPhysiNode(pCxt, pChildren, pWindowLogicNode, pPhyNode); |
7221 | 0 | case WINDOW_TYPE_ANOMALY: |
7222 | 0 | return createAnomalyWindowPhysiNode(pCxt, pChildren, pWindowLogicNode, pPhyNode); |
7223 | 0 | case WINDOW_TYPE_EXTERNAL: |
7224 | 0 | return createExternalWindowPhysiNode(pCxt, pChildren, pWindowLogicNode, pPhyNode); |
7225 | 0 | default: |
7226 | 0 | return generateUsageErrMsg(pCxt->pPlanCxt->pMsg, pCxt->pPlanCxt->msgLen, TSDB_CODE_PLAN_INVALID_WINDOW_TYPE, " invalid window type"); |
7227 | 0 | } |
7228 | 0 | return TSDB_CODE_FAILED; |
7229 | 0 | } |
7230 | | |
7231 | | // createDistinctFilterPhysiNode() was removed with the DistinctAggFilter rule. New logical plans |
7232 | | // no longer contain this node; the physical node and its serialization remain only for already |
7233 | | // materialized plans received from older nodes during rolling upgrades. |
7234 | | |
7235 | | static int32_t createSortPhysiNode(SPhysiPlanContext* pCxt, SNodeList* pChildren, SSortLogicNode* pSortLogicNode, |
7236 | 0 | SPhysiNode** pPhyNode) { |
7237 | 0 | SSortPhysiNode* pSort = (SSortPhysiNode*)makePhysiNode( |
7238 | 0 | pCxt, (SLogicNode*)pSortLogicNode, |
7239 | 0 | pSortLogicNode->groupSort ? QUERY_NODE_PHYSICAL_PLAN_GROUP_SORT : QUERY_NODE_PHYSICAL_PLAN_SORT); |
7240 | 0 | if (NULL == pSort) { |
7241 | 0 | return terrno; |
7242 | 0 | } |
7243 | | |
7244 | 0 | SNodeList* pPrecalcExprs = NULL; |
7245 | 0 | SNodeList* pSortKeys = NULL; |
7246 | 0 | int32_t code = rewritePrecalcExprs(pCxt, pSortLogicNode->pSortKeys, &pPrecalcExprs, &pSortKeys); |
7247 | 0 | pSort->calcGroupId = pSortLogicNode->calcGroupId; |
7248 | 0 | pSort->excludePkCol = pSortLogicNode->excludePkCol; |
7249 | 0 | pSort->numOfGroupKeys = pSortLogicNode->numOfGroupKeys; |
7250 | |
|
7251 | 0 | SDataBlockDescNode* pChildTupe = NULL; |
7252 | 0 | if (TSDB_CODE_SUCCESS == code) { |
7253 | 0 | code = getChildTuple(&pChildTupe, pChildren); |
7254 | 0 | } |
7255 | | |
7256 | | // push down expression to pOutputDataBlockDesc of child node |
7257 | 0 | if (TSDB_CODE_SUCCESS == code && NULL != pPrecalcExprs) { |
7258 | 0 | code = setListSlotId(pCxt, pChildTupe->dataBlockId, -1, pPrecalcExprs, &pSort->pExprs); |
7259 | 0 | if (TSDB_CODE_SUCCESS == code) { |
7260 | 0 | code = pushdownDataBlockSlots(pCxt, pSort->pExprs, pChildTupe); |
7261 | 0 | } |
7262 | 0 | } |
7263 | |
|
7264 | 0 | if (TSDB_CODE_SUCCESS == code) { |
7265 | 0 | code = setListSlotId(pCxt, pChildTupe->dataBlockId, -1, pSortKeys, &pSort->pSortKeys); |
7266 | 0 | } |
7267 | |
|
7268 | 0 | if (TSDB_CODE_SUCCESS == code) { |
7269 | 0 | code = setListSlotId(pCxt, pChildTupe->dataBlockId, -1, pSortLogicNode->node.pTargets, &pSort->pTargets); |
7270 | 0 | if (TSDB_CODE_SUCCESS == code) { |
7271 | 0 | code = addDataBlockSlots(pCxt, pSort->pTargets, pSort->node.pOutputDataBlockDesc); |
7272 | 0 | } |
7273 | 0 | } |
7274 | | |
7275 | | // For external-window + fill queries: the fill operator writes its output into the |
7276 | | // ExtWin output block (slots for s1, s2, ...) but Sort only copies columns listed in |
7277 | | // its pTargets. Those columns are only in pTargets when they appear in the ORDER BY |
7278 | | // clause; projection-only columns are missing. Append them here so Sort passes the |
7279 | | // fill values through to the parent Project operator. |
7280 | | // |
7281 | | // NOTE: This injection only handles the single-node topology where Sort's direct |
7282 | | // child is ExtWin. In distributed plans (extWinSplit=true), the plan is split into |
7283 | | // HASH_EXTERNAL (partition) + Merge + MERGE_ALIGNED_EXTERNAL (coordinator); Sort |
7284 | | // sits above the Merge node, so this code does not fire. Fill + ORDER BY in |
7285 | | // distributed external-window queries is currently not supported. |
7286 | 0 | if (TSDB_CODE_SUCCESS == code) { |
7287 | 0 | SPhysiNode* pChildNode = (SPhysiNode*)nodesListGetNode(pChildren, 0); |
7288 | 0 | if (pChildNode != NULL && (nodeType(pChildNode) == QUERY_NODE_PHYSICAL_PLAN_HASH_EXTERNAL || |
7289 | 0 | nodeType(pChildNode) == QUERY_NODE_PHYSICAL_PLAN_MERGE_ALIGNED_EXTERNAL)) { |
7290 | 0 | SExternalWindowPhysiNode* pExtWin = (SExternalWindowPhysiNode*)pChildNode; |
7291 | 0 | if (pExtWin->extFill.pFillExprs != NULL && pExtWin->window.pProjs != NULL) { |
7292 | | // Iterate ExtWin's pProjs (STargetNode list): each contains the output slotId for |
7293 | | // a fill-output column (s1, s2, ...). For each one that is not yet in Sort's |
7294 | | // pTargets, create a passthrough STargetNode and append it. |
7295 | 0 | SNode* pProjNode = NULL; |
7296 | 0 | FOREACH(pProjNode, pExtWin->window.pProjs) { |
7297 | 0 | if (nodeType(pProjNode) != QUERY_NODE_TARGET) continue; |
7298 | 0 | STargetNode* pExtTarget = (STargetNode*)pProjNode; |
7299 | 0 | int16_t projSlotId = pExtTarget->slotId; |
7300 | | |
7301 | | // Check if this slot is already covered by Sort's pTargets. |
7302 | 0 | bool alreadyCovered = false; |
7303 | 0 | SNode* pSortTarget = NULL; |
7304 | 0 | FOREACH(pSortTarget, pSort->pTargets) { |
7305 | 0 | if (nodeType(pSortTarget) == QUERY_NODE_TARGET) { |
7306 | 0 | STargetNode* pST = (STargetNode*)pSortTarget; |
7307 | 0 | if (nodeType(pST->pExpr) == QUERY_NODE_COLUMN) { |
7308 | 0 | SColumnNode* pSC = (SColumnNode*)pST->pExpr; |
7309 | 0 | if (pSC->dataBlockId == pChildTupe->dataBlockId && pSC->slotId == projSlotId) { |
7310 | 0 | alreadyCovered = true; |
7311 | 0 | break; |
7312 | 0 | } |
7313 | 0 | } |
7314 | 0 | } |
7315 | 0 | } |
7316 | 0 | if (alreadyCovered) continue; |
7317 | | |
7318 | | // Find the corresponding SlotDescNode in ExtWin's output to get the data type. |
7319 | 0 | SSlotDescNode* pSlotDesc = NULL; |
7320 | 0 | SNode* pSlotNode = NULL; |
7321 | 0 | FOREACH(pSlotNode, pExtWin->window.node.pOutputDataBlockDesc->pSlots) { |
7322 | 0 | SSlotDescNode* pSD = (SSlotDescNode*)pSlotNode; |
7323 | 0 | if (pSD->slotId == projSlotId) { pSlotDesc = pSD; break; } |
7324 | 0 | } |
7325 | 0 | if (pSlotDesc == NULL) continue; |
7326 | | |
7327 | | // Create a column node referring to ExtWin's projSlotId. |
7328 | 0 | SColumnNode* pCol = NULL; |
7329 | 0 | code = nodesMakeNode(QUERY_NODE_COLUMN, (SNode**)&pCol); |
7330 | 0 | if (code != TSDB_CODE_SUCCESS) break; |
7331 | 0 | pCol->dataBlockId = pChildTupe->dataBlockId; |
7332 | 0 | pCol->slotId = projSlotId; |
7333 | 0 | pCol->colType = COLUMN_TYPE_COLUMN; |
7334 | 0 | pCol->node.resType = pSlotDesc->dataType; |
7335 | 0 | tstrncpy(pCol->colName, pSlotDesc->name, TSDB_COL_NAME_LEN); |
7336 | 0 | tstrncpy(pCol->node.aliasName, pSlotDesc->name, TSDB_COL_NAME_LEN); |
7337 | 0 | tstrncpy(pCol->node.userAlias, pSlotDesc->name, TSDB_COL_NAME_LEN); |
7338 | | |
7339 | | // Allocate a new slot in Sort's output block. |
7340 | 0 | int16_t nextSlot = (int16_t)LIST_LENGTH(pSort->node.pOutputDataBlockDesc->pSlots); |
7341 | 0 | code = nodesListStrictAppend(pSort->node.pOutputDataBlockDesc->pSlots, |
7342 | 0 | createSlotDesc(pCxt, pSlotDesc->name, (SNode*)pCol, nextSlot, true, false)); |
7343 | 0 | if (code != TSDB_CODE_SUCCESS) { nodesDestroyNode((SNode*)pCol); break; } |
7344 | 0 | SHashObj* pHash = taosArrayGetP(pCxt->pLocationHelper, pSort->node.pOutputDataBlockDesc->dataBlockId); |
7345 | 0 | int32_t nameLen = strlen(pSlotDesc->name); |
7346 | 0 | code = putSlotToHashImpl(pSort->node.pOutputDataBlockDesc->dataBlockId, nextSlot, |
7347 | 0 | pSlotDesc->name, nameLen, pHash); |
7348 | 0 | if (code != TSDB_CODE_SUCCESS) { nodesDestroyNode((SNode*)pCol); break; } |
7349 | 0 | pSort->node.pOutputDataBlockDesc->totalRowSize += pSlotDesc->dataType.bytes; |
7350 | 0 | pSort->node.pOutputDataBlockDesc->outputRowSize += pSlotDesc->dataType.bytes; |
7351 | | |
7352 | | // Create and append the STargetNode. |
7353 | 0 | SNode* pTarget = NULL; |
7354 | 0 | code = createTarget((SNode*)pCol, pSort->node.pOutputDataBlockDesc->dataBlockId, nextSlot, &pTarget); |
7355 | 0 | if (code != TSDB_CODE_SUCCESS) { nodesDestroyNode((SNode*)pCol); break; } |
7356 | 0 | code = nodesListMakeStrictAppend(&pSort->pTargets, pTarget); |
7357 | 0 | if (code != TSDB_CODE_SUCCESS) { nodesDestroyNode(pTarget); break; } |
7358 | 0 | } |
7359 | 0 | } |
7360 | 0 | } |
7361 | 0 | } |
7362 | |
|
7363 | 0 | if (TSDB_CODE_SUCCESS == code) { |
7364 | 0 | code = setConditionsSlotId(pCxt, (const SLogicNode*)pSortLogicNode, (SPhysiNode*)pSort); |
7365 | 0 | } |
7366 | |
|
7367 | 0 | if (TSDB_CODE_SUCCESS == code) { |
7368 | 0 | *pPhyNode = (SPhysiNode*)pSort; |
7369 | 0 | } else { |
7370 | 0 | nodesDestroyNode((SNode*)pSort); |
7371 | 0 | } |
7372 | |
|
7373 | 0 | nodesDestroyList(pPrecalcExprs); |
7374 | 0 | nodesDestroyList(pSortKeys); |
7375 | |
|
7376 | 0 | return code; |
7377 | 0 | } |
7378 | | |
7379 | | static int32_t createPartitionPhysiNodeImpl(SPhysiPlanContext* pCxt, SNodeList* pChildren, |
7380 | | SPartitionLogicNode* pPartLogicNode, ENodeType type, |
7381 | 0 | SPhysiNode** pPhyNode) { |
7382 | 0 | SPartitionPhysiNode* pPart = (SPartitionPhysiNode*)makePhysiNode(pCxt, (SLogicNode*)pPartLogicNode, type); |
7383 | 0 | if (NULL == pPart) { |
7384 | 0 | return terrno; |
7385 | 0 | } |
7386 | | |
7387 | 0 | SNodeList* pPrecalcExprs = NULL; |
7388 | 0 | SNodeList* pPartitionKeys = NULL; |
7389 | 0 | int32_t code = rewritePrecalcExprs(pCxt, pPartLogicNode->pPartitionKeys, &pPrecalcExprs, &pPartitionKeys); |
7390 | 0 | pPart->phasedMode = pPartLogicNode->phasedMode; |
7391 | 0 | pPart->needBlockOutputTsOrder = pPartLogicNode->needBlockOutputTsOrder; |
7392 | 0 | SDataBlockDescNode* pChildTupe = NULL; |
7393 | 0 | if (TSDB_CODE_SUCCESS == code) { |
7394 | 0 | code = getChildTuple(&pChildTupe, pChildren); |
7395 | 0 | } |
7396 | 0 | if (TSDB_CODE_SUCCESS == code) { |
7397 | 0 | code = setListSlotId(pCxt, pChildTupe->dataBlockId, -1, pPartLogicNode->node.pTargets, &pPart->pTargets); |
7398 | 0 | if (TSDB_CODE_SUCCESS == code) { |
7399 | 0 | code = addDataBlockSlots(pCxt, pPart->pTargets, pPart->node.pOutputDataBlockDesc); |
7400 | 0 | } |
7401 | 0 | } |
7402 | | // push down expression to pOutputDataBlockDesc of child node |
7403 | 0 | if (TSDB_CODE_SUCCESS == code && NULL != pPrecalcExprs) { |
7404 | 0 | code = setListSlotId(pCxt, pChildTupe->dataBlockId, -1, pPrecalcExprs, &pPart->pExprs); |
7405 | 0 | if (TSDB_CODE_SUCCESS == code) { |
7406 | 0 | code = pushdownDataBlockSlots(pCxt, pPart->pExprs, pChildTupe); |
7407 | 0 | } |
7408 | 0 | } |
7409 | | |
7410 | | // Convert pseudo-column functions (e.g. TBNAME) in partition keys to column |
7411 | | // nodes. doSetSlotId only resolves QUERY_NODE_COLUMN; a FUNCTION node passes |
7412 | | // through with an uninitialised slotId, and the executor's |
7413 | | // makeColumnArrayFromList then casts it to SColumnNode* => garbage slotId/type |
7414 | | // => buffer overflow in doHashPartition. Replacing with a COLUMN whose |
7415 | | // colName matches the slot added by addDataBlockSlots(pScanPseudoCols) lets |
7416 | | // doSetSlotId resolve the correct slotId. |
7417 | 0 | if (TSDB_CODE_SUCCESS == code) { |
7418 | 0 | SNode* pKeyNode = NULL; |
7419 | 0 | FOREACH(pKeyNode, pPartitionKeys) { |
7420 | 0 | if (QUERY_NODE_FUNCTION == nodeType(pKeyNode) && |
7421 | 0 | fmIsScanPseudoColumnFunc(((SFunctionNode*)pKeyNode)->funcId)) { |
7422 | 0 | SFunctionNode* pFunc = (SFunctionNode*)pKeyNode; |
7423 | 0 | SColumnNode* pCol = NULL; |
7424 | 0 | code = nodesMakeNode(QUERY_NODE_COLUMN, (SNode**)&pCol); |
7425 | 0 | if (TSDB_CODE_SUCCESS != code) break; |
7426 | 0 | pCol->node.resType = pFunc->node.resType; |
7427 | 0 | tstrncpy(pCol->colName, pFunc->node.aliasName, TSDB_COL_NAME_LEN); |
7428 | 0 | tstrncpy(pCol->node.aliasName, pFunc->node.aliasName, sizeof(pCol->node.aliasName)); |
7429 | 0 | tstrncpy(pCol->node.userAlias, pFunc->node.userAlias, sizeof(pCol->node.userAlias)); |
7430 | 0 | nodesDestroyNode(pKeyNode); |
7431 | 0 | REPLACE_NODE(pCol); |
7432 | 0 | } |
7433 | 0 | } |
7434 | 0 | } |
7435 | |
|
7436 | 0 | if (TSDB_CODE_SUCCESS == code) { |
7437 | 0 | code = setListSlotId(pCxt, pChildTupe->dataBlockId, -1, pPartitionKeys, &pPart->pPartitionKeys); |
7438 | 0 | } |
7439 | |
|
7440 | 0 | if (pPart->needBlockOutputTsOrder) { |
7441 | 0 | SNode* node; |
7442 | 0 | bool found = false; |
7443 | | // Iterate the PHYSICAL targets (pPart->pTargets) to get correct physical slot IDs. |
7444 | | // pPartLogicNode->node.pTargets has logical slotIds (often 0) which are wrong here. |
7445 | 0 | FOREACH(node, pPart->pTargets) { |
7446 | 0 | if (nodeType(node) == QUERY_NODE_TARGET) { |
7447 | 0 | STargetNode* pTgt = (STargetNode*)node; |
7448 | 0 | if (nodeType(pTgt->pExpr) == QUERY_NODE_COLUMN) { |
7449 | 0 | SColumnNode* pCol = (SColumnNode*)pTgt->pExpr; |
7450 | 0 | if (pCol->tableId == pPartLogicNode->pkTsColTbId && pCol->colId == pPartLogicNode->pkTsColId) { |
7451 | 0 | pPart->tsSlotId = pTgt->slotId; |
7452 | 0 | found = true; |
7453 | 0 | break; |
7454 | 0 | } |
7455 | 0 | } |
7456 | 0 | } |
7457 | 0 | } |
7458 | 0 | if (!found) code = TSDB_CODE_PLAN_INTERNAL_ERROR; |
7459 | 0 | } |
7460 | |
|
7461 | 0 | if (TSDB_CODE_SUCCESS == code) { |
7462 | 0 | code = setConditionsSlotId(pCxt, (const SLogicNode*)pPartLogicNode, (SPhysiNode*)pPart); |
7463 | 0 | } |
7464 | |
|
7465 | 0 | if (TSDB_CODE_SUCCESS == code) { |
7466 | 0 | *pPhyNode = (SPhysiNode*)pPart; |
7467 | 0 | } else { |
7468 | 0 | nodesDestroyNode((SNode*)pPart); |
7469 | 0 | } |
7470 | |
|
7471 | 0 | nodesDestroyList(pPrecalcExprs); |
7472 | 0 | nodesDestroyList(pPartitionKeys); |
7473 | |
|
7474 | 0 | return code; |
7475 | 0 | } |
7476 | | |
7477 | | static int32_t createPartitionPhysiNode(SPhysiPlanContext* pCxt, SNodeList* pChildren, |
7478 | 0 | SPartitionLogicNode* pPartLogicNode, SPhysiNode** pPhyNode) { |
7479 | 0 | return createPartitionPhysiNodeImpl(pCxt, pChildren, pPartLogicNode, QUERY_NODE_PHYSICAL_PLAN_PARTITION, pPhyNode); |
7480 | 0 | } |
7481 | | |
7482 | | static int32_t createFillPhysiNode(SPhysiPlanContext* pCxt, SNodeList* pChildren, SFillLogicNode* pFillNode, |
7483 | 0 | SPhysiNode** pPhyNode) { |
7484 | 0 | SFillPhysiNode* pFill = (SFillPhysiNode*)makePhysiNode( |
7485 | 0 | pCxt, (SLogicNode*)pFillNode, QUERY_NODE_PHYSICAL_PLAN_FILL); |
7486 | 0 | if (NULL == pFill) { |
7487 | 0 | return terrno; |
7488 | 0 | } |
7489 | | |
7490 | 0 | pFill->mode = pFillNode->mode; |
7491 | 0 | pFill->indefRowsMode = pFillNode->indefRowsMode; |
7492 | 0 | pFill->interval = pFillNode->interval; |
7493 | 0 | pFill->offset = pFillNode->offset; |
7494 | 0 | pFill->sliding = pFillNode->sliding; |
7495 | 0 | pFill->intervalUnit = pFillNode->intervalUnit; |
7496 | 0 | pFill->slidingUnit = pFillNode->slidingUnit; |
7497 | 0 | pFill->firstDayOfWeek = pFillNode->firstDayOfWeek; |
7498 | 0 | pFill->timezone = pFillNode->timezone; |
7499 | 0 | pFill->ownsTimezone = false; |
7500 | 0 | tstrncpy(pFill->timezoneName, pFillNode->timezoneName, sizeof(pFill->timezoneName)); |
7501 | 0 | pFill->timeRange = pFillNode->timeRange; |
7502 | 0 | TSWAP(pFill->pTimeRange, pFillNode->pTimeRange); |
7503 | 0 | pFill->node.inputTsOrder = pFillNode->node.inputTsOrder; |
7504 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
7505 | 0 | SDataBlockDescNode* pChildTupe = NULL; |
7506 | 0 | if (TSDB_CODE_SUCCESS == code) { |
7507 | 0 | code = getChildTuple(&pChildTupe, pChildren); |
7508 | 0 | } |
7509 | 0 | if (TSDB_CODE_SUCCESS == code) { |
7510 | 0 | code = setListSlotId(pCxt, pChildTupe->dataBlockId, -1, pFillNode->pFillExprs, &pFill->pFillExprs); |
7511 | 0 | } |
7512 | 0 | if (TSDB_CODE_SUCCESS == code) { |
7513 | 0 | code = addDataBlockSlots(pCxt, pFill->pFillExprs, pFill->node.pOutputDataBlockDesc); |
7514 | 0 | } |
7515 | 0 | if (TSDB_CODE_SUCCESS == code) { |
7516 | 0 | code = setListSlotId(pCxt, pChildTupe->dataBlockId, -1, pFillNode->pNotFillExprs, &pFill->pNotFillExprs); |
7517 | 0 | } |
7518 | 0 | if (TSDB_CODE_SUCCESS == code) { |
7519 | 0 | code = addDataBlockSlots(pCxt, pFill->pNotFillExprs, pFill->node.pOutputDataBlockDesc); |
7520 | 0 | } |
7521 | 0 | if (TSDB_CODE_SUCCESS == code && LIST_LENGTH(pFillNode->pFillNullExprs) > 0) { |
7522 | 0 | code = setListSlotId(pCxt, pChildTupe->dataBlockId, -1, pFillNode->pFillNullExprs, &pFill->pFillNullExprs); |
7523 | 0 | if (TSDB_CODE_SUCCESS == code) { |
7524 | 0 | code = addDataBlockSlots(pCxt, pFill->pFillNullExprs, pFill->node.pOutputDataBlockDesc); |
7525 | 0 | } |
7526 | 0 | } |
7527 | |
|
7528 | 0 | if (TSDB_CODE_SUCCESS == code) { |
7529 | 0 | code = setNodeSlotId(pCxt, pChildTupe->dataBlockId, -1, pFillNode->pWStartTs, &pFill->pWStartTs); |
7530 | 0 | } |
7531 | 0 | if (TSDB_CODE_SUCCESS == code) { |
7532 | 0 | code = addDataBlockSlot(pCxt, &pFill->pWStartTs, pFill->node.pOutputDataBlockDesc); |
7533 | 0 | } |
7534 | |
|
7535 | 0 | if (TSDB_CODE_SUCCESS == code && NULL != pFillNode->pValues) { |
7536 | 0 | code = nodesCloneNode(pFillNode->pValues, &pFill->pValues); |
7537 | 0 | } |
7538 | |
|
7539 | 0 | if (TSDB_CODE_SUCCESS == code && NULL != pFillNode->pSurroundingTime) { |
7540 | 0 | code = nodesCloneNode(pFillNode->pSurroundingTime, |
7541 | 0 | &pFill->pSurroundingTime); |
7542 | 0 | } |
7543 | |
|
7544 | 0 | if (TSDB_CODE_SUCCESS == code) { |
7545 | 0 | code = setConditionsSlotId(pCxt, (const SLogicNode*)pFillNode, (SPhysiNode*)pFill); |
7546 | 0 | } |
7547 | |
|
7548 | 0 | if (TSDB_CODE_SUCCESS == code) { |
7549 | 0 | *pPhyNode = (SPhysiNode*)pFill; |
7550 | 0 | } else { |
7551 | 0 | nodesDestroyNode((SNode*)pFill); |
7552 | 0 | } |
7553 | |
|
7554 | 0 | return code; |
7555 | 0 | } |
7556 | | |
7557 | 0 | static int32_t createExchangePhysiNodeByMerge(SMergePhysiNode* pMerge, int32_t idx, bool grpSingleChannel) { |
7558 | 0 | SExchangePhysiNode* pExchange = NULL; |
7559 | 0 | int32_t code = nodesMakeNode(QUERY_NODE_PHYSICAL_PLAN_EXCHANGE, (SNode**)&pExchange); |
7560 | 0 | if (NULL == pExchange) { |
7561 | 0 | return code; |
7562 | 0 | } |
7563 | 0 | pExchange->srcStartGroupId = pMerge->srcGroupId + idx; |
7564 | 0 | pExchange->srcEndGroupId = pMerge->srcGroupId + idx; |
7565 | 0 | pExchange->grpSingleChannel = grpSingleChannel; |
7566 | 0 | pExchange->singleSrc = true; |
7567 | 0 | pExchange->node.dynamicOp = pMerge->node.dynamicOp; |
7568 | 0 | pExchange->node.pParent = (SPhysiNode*)pMerge; |
7569 | 0 | pExchange->node.pOutputDataBlockDesc = NULL; |
7570 | 0 | code = nodesCloneNode((SNode*)pMerge->node.pOutputDataBlockDesc, (SNode**)&pExchange->node.pOutputDataBlockDesc); |
7571 | 0 | if (NULL == pExchange->node.pOutputDataBlockDesc) { |
7572 | 0 | nodesDestroyNode((SNode*)pExchange); |
7573 | 0 | return code; |
7574 | 0 | } |
7575 | 0 | SNode* pSlot = NULL; |
7576 | 0 | FOREACH(pSlot, pExchange->node.pOutputDataBlockDesc->pSlots) { ((SSlotDescNode*)pSlot)->output = true; } |
7577 | 0 | return nodesListMakeStrictAppend(&pMerge->node.pChildren, (SNode*)pExchange); |
7578 | 0 | } |
7579 | | |
7580 | | static int32_t createMergePhysiNode(SPhysiPlanContext* pCxt, SNodeList* pChildren, SMergeLogicNode* pMergeLogicNode, |
7581 | 0 | SPhysiNode** pPhyNode) { |
7582 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
7583 | 0 | SMergePhysiNode* pMerge = |
7584 | 0 | (SMergePhysiNode*)makePhysiNode(pCxt, (SLogicNode*)pMergeLogicNode, QUERY_NODE_PHYSICAL_PLAN_MERGE); |
7585 | 0 | if (NULL == pMerge) { |
7586 | 0 | return terrno; |
7587 | 0 | } |
7588 | | |
7589 | 0 | if (pMergeLogicNode->colsMerge) { |
7590 | 0 | pMerge->type = MERGE_TYPE_COLUMNS; |
7591 | 0 | } else if (pMergeLogicNode->needSort) { |
7592 | 0 | pMerge->type = MERGE_TYPE_SORT; |
7593 | 0 | } else { |
7594 | 0 | pMerge->type = MERGE_TYPE_NON_SORT; |
7595 | 0 | } |
7596 | |
|
7597 | 0 | pMerge->numOfChannels = pMergeLogicNode->numOfChannels; |
7598 | 0 | pMerge->srcGroupId = pMergeLogicNode->srcGroupId; |
7599 | 0 | pMerge->srcEndGroupId = pMergeLogicNode->srcEndGroupId; |
7600 | 0 | pMerge->groupSort = pMergeLogicNode->groupSort; |
7601 | 0 | pMerge->ignoreGroupId = pMergeLogicNode->ignoreGroupId; |
7602 | 0 | pMerge->inputWithGroupId = pMergeLogicNode->inputWithGroupId; |
7603 | 0 | pMerge->outerGroupPhaseMode = pMergeLogicNode->outerGroupPhaseMode; |
7604 | |
|
7605 | 0 | if (!pMergeLogicNode->colsMerge) { |
7606 | 0 | PLAN_ERR_JRET(addDataBlockSlots(pCxt, pMergeLogicNode->pInputs, pMerge->node.pOutputDataBlockDesc)); |
7607 | | |
7608 | 0 | for (int32_t j = 0; j < pMergeLogicNode->numOfSubplans; ++j) { |
7609 | 0 | for (int32_t i = 0; i < pMerge->numOfChannels; ++i) { |
7610 | 0 | PLAN_ERR_JRET(createExchangePhysiNodeByMerge(pMerge, j, pMerge->numOfChannels == 1)); |
7611 | 0 | } |
7612 | 0 | } |
7613 | | |
7614 | 0 | if (NULL != pMergeLogicNode->pMergeKeys) { |
7615 | 0 | PLAN_ERR_JRET(setListSlotId(pCxt, pMerge->node.pOutputDataBlockDesc->dataBlockId, -1, pMergeLogicNode->pMergeKeys, |
7616 | 0 | &pMerge->pMergeKeys)); |
7617 | 0 | } |
7618 | | |
7619 | 0 | PLAN_ERR_JRET(setListSlotId(pCxt, pMerge->node.pOutputDataBlockDesc->dataBlockId, -1, pMergeLogicNode->node.pTargets, |
7620 | 0 | &pMerge->pTargets)); |
7621 | 0 | PLAN_ERR_JRET(addDataBlockSlots(pCxt, pMerge->pTargets, pMerge->node.pOutputDataBlockDesc)); |
7622 | 0 | } else { |
7623 | 0 | PLAN_ERR_JRET(setMultiBlockSlotId(pCxt, pChildren, false, pMergeLogicNode->node.pTargets, &pMerge->pTargets)); |
7624 | 0 | PLAN_ERR_JRET(addDataBlockSlots(pCxt, pMerge->pTargets, pMerge->node.pOutputDataBlockDesc)); |
7625 | 0 | } |
7626 | | |
7627 | 0 | *pPhyNode = (SPhysiNode*)pMerge; |
7628 | 0 | return code; |
7629 | 0 | _return: |
7630 | 0 | nodesDestroyNode((SNode*)pMerge); |
7631 | 0 | return code; |
7632 | 0 | } |
7633 | | |
7634 | | static int32_t doCreatePhysiNode(SPhysiPlanContext* pCxt, SLogicNode* pLogicNode, SSubplan* pSubplan, |
7635 | 0 | SNodeList* pChildren, SPhysiNode** pPhyNode) { |
7636 | 0 | switch (nodeType(pLogicNode)) { |
7637 | 0 | case QUERY_NODE_LOGIC_PLAN_SCAN: |
7638 | 0 | return createScanPhysiNode(pCxt, pSubplan, (SScanLogicNode*)pLogicNode, pPhyNode); |
7639 | 0 | case QUERY_NODE_LOGIC_PLAN_JOIN: |
7640 | 0 | return createJoinPhysiNode(pCxt, pChildren, (SJoinLogicNode*)pLogicNode, pPhyNode); |
7641 | 0 | case QUERY_NODE_LOGIC_PLAN_AGG: |
7642 | 0 | return createAggPhysiNode(pCxt, pChildren, (SAggLogicNode*)pLogicNode, pPhyNode, pSubplan); |
7643 | 0 | case QUERY_NODE_LOGIC_PLAN_PROJECT: |
7644 | 0 | return createProjectPhysiNode(pCxt, pChildren, (SProjectLogicNode*)pLogicNode, pSubplan, pPhyNode); |
7645 | 0 | case QUERY_NODE_LOGIC_PLAN_EXCHANGE: |
7646 | 0 | return createExchangePhysiNode(pCxt, (SExchangeLogicNode*)pLogicNode, pPhyNode); |
7647 | 0 | case QUERY_NODE_LOGIC_PLAN_WINDOW: |
7648 | 0 | return createWindowPhysiNode(pCxt, pChildren, (SWindowLogicNode*)pLogicNode, pPhyNode); |
7649 | 0 | case QUERY_NODE_LOGIC_PLAN_SORT: |
7650 | 0 | return createSortPhysiNode(pCxt, pChildren, (SSortLogicNode*)pLogicNode, pPhyNode); |
7651 | 0 | case QUERY_NODE_LOGIC_PLAN_WINDOW_FUNC: |
7652 | 0 | return createWindowFuncPhysiNode(pCxt, pChildren, (SWindowFuncLogicNode*)pLogicNode, pPhyNode); |
7653 | 0 | case QUERY_NODE_LOGIC_PLAN_PARTITION: |
7654 | 0 | return createPartitionPhysiNode(pCxt, pChildren, (SPartitionLogicNode*)pLogicNode, pPhyNode); |
7655 | 0 | case QUERY_NODE_LOGIC_PLAN_FILL: |
7656 | 0 | return createFillPhysiNode(pCxt, pChildren, (SFillLogicNode*)pLogicNode, pPhyNode); |
7657 | 0 | case QUERY_NODE_LOGIC_PLAN_INDEF_ROWS_FUNC: |
7658 | 0 | return createIndefRowsFuncPhysiNode(pCxt, pChildren, (SIndefRowsFuncLogicNode*)pLogicNode, pPhyNode); |
7659 | 0 | case QUERY_NODE_LOGIC_PLAN_INTERP_FUNC: |
7660 | 0 | return createInterpFuncPhysiNode(pCxt, pChildren, (SInterpFuncLogicNode*)pLogicNode, pPhyNode); |
7661 | 0 | case QUERY_NODE_LOGIC_PLAN_ANALYSIS_FUNC: |
7662 | 0 | return createGenericAnalysisPhysiNode(pCxt, pChildren, (SGenericAnalysisLogicNode*)pLogicNode, pPhyNode); |
7663 | 0 | case QUERY_NODE_LOGIC_PLAN_FORECAST_FUNC: |
7664 | 0 | return createForecastFuncPhysiNode(pCxt, pChildren, (SForecastFuncLogicNode*)pLogicNode, pPhyNode); |
7665 | 0 | case QUERY_NODE_LOGIC_PLAN_ROWSET_SOURCE: |
7666 | 0 | return createRowsetSourcePhysiNode(pCxt, (SRowsetSourceLogicNode*)pLogicNode, pPhyNode); |
7667 | 0 | case QUERY_NODE_LOGIC_PLAN_MERGE: |
7668 | 0 | return createMergePhysiNode(pCxt, pChildren, (SMergeLogicNode*)pLogicNode, pPhyNode); |
7669 | 0 | case QUERY_NODE_LOGIC_PLAN_GROUP_CACHE: |
7670 | 0 | return createGroupCachePhysiNode(pCxt, pChildren, (SGroupCacheLogicNode*)pLogicNode, pPhyNode); |
7671 | 0 | case QUERY_NODE_LOGIC_PLAN_DYN_QUERY_CTRL: |
7672 | 0 | return createDynQueryCtrlPhysiNode(pCxt, pChildren, (SDynQueryCtrlLogicNode*)pLogicNode, pPhyNode, pSubplan); |
7673 | 0 | case QUERY_NODE_LOGIC_PLAN_VIRTUAL_TABLE_SCAN: |
7674 | 0 | return createVirtualTableScanPhysiNode(pCxt, pSubplan, pChildren, (SVirtualScanLogicNode*)pLogicNode, pPhyNode); |
7675 | 0 | case QUERY_NODE_LOGIC_PLAN_TAG_REF_SOURCE: |
7676 | 0 | return createTagRefSourcePhysiNode(pCxt, pSubplan, pChildren, (STagRefSourceLogicNode*)pLogicNode, pPhyNode); |
7677 | 0 | default: |
7678 | 0 | break; |
7679 | 0 | } |
7680 | | |
7681 | 0 | return TSDB_CODE_FAILED; |
7682 | 0 | } |
7683 | | |
7684 | | static int32_t createPhysiNode(SPhysiPlanContext* pCxt, SLogicNode* pLogicNode, SSubplan* pSubplan, |
7685 | 0 | SPhysiNode** pPhyNode) { |
7686 | 0 | SNodeList* pChildren = NULL; |
7687 | 0 | int32_t code = nodesMakeList(&pChildren); |
7688 | 0 | if (NULL == pChildren) { |
7689 | 0 | return code; |
7690 | 0 | } |
7691 | | |
7692 | 0 | SNode* pLogicChild; |
7693 | 0 | FOREACH(pLogicChild, pLogicNode->pChildren) { |
7694 | 0 | SPhysiNode* pChild = NULL; |
7695 | 0 | code = createPhysiNode(pCxt, (SLogicNode*)pLogicChild, pSubplan, &pChild); |
7696 | 0 | if (TSDB_CODE_SUCCESS == code) { |
7697 | 0 | code = nodesListStrictAppend(pChildren, (SNode*)pChild); |
7698 | 0 | } |
7699 | 0 | if (TSDB_CODE_SUCCESS != code) { |
7700 | 0 | break; |
7701 | 0 | } |
7702 | 0 | } |
7703 | |
|
7704 | 0 | if (TSDB_CODE_SUCCESS == code) { |
7705 | 0 | code = doCreatePhysiNode(pCxt, pLogicNode, pSubplan, pChildren, pPhyNode); |
7706 | 0 | } |
7707 | |
|
7708 | 0 | if (TSDB_CODE_SUCCESS == code) { |
7709 | 0 | if (LIST_LENGTH(pChildren) > 0) { |
7710 | 0 | (*pPhyNode)->pChildren = pChildren; |
7711 | 0 | SNode* pChild; |
7712 | 0 | FOREACH(pChild, (*pPhyNode)->pChildren) { ((SPhysiNode*)pChild)->pParent = (*pPhyNode); } |
7713 | 0 | } else { |
7714 | 0 | nodesDestroyList(pChildren); |
7715 | 0 | } |
7716 | 0 | } else { |
7717 | 0 | nodesDestroyList(pChildren); |
7718 | 0 | } |
7719 | |
|
7720 | 0 | return code; |
7721 | 0 | } |
7722 | | |
7723 | 0 | static int32_t createDataInserter(SPhysiPlanContext* pCxt, SVgDataBlocks* pBlocks, SDataSinkNode** pSink) { |
7724 | 0 | SDataInserterNode* pInserter = NULL; |
7725 | 0 | int32_t code = nodesMakeNode(QUERY_NODE_PHYSICAL_PLAN_INSERT, (SNode**)&pInserter); |
7726 | 0 | if (NULL == pInserter) { |
7727 | 0 | return code; |
7728 | 0 | } |
7729 | | |
7730 | 0 | pInserter->numOfTables = pBlocks->numOfTables; |
7731 | 0 | pInserter->size = pBlocks->size; |
7732 | 0 | pInserter->pData = pBlocks->pData; |
7733 | 0 | pBlocks->pData = NULL; |
7734 | |
|
7735 | 0 | *pSink = (SDataSinkNode*)pInserter; |
7736 | 0 | return TSDB_CODE_SUCCESS; |
7737 | 0 | } |
7738 | | |
7739 | | static int32_t createDataDispatcher(SPhysiPlanContext* pCxt, const SPhysiNode* pRoot, bool dynamicSchema, |
7740 | 0 | bool localBlockExchange, SDataSinkNode** pSink) { |
7741 | 0 | SDataDispatcherNode* pDispatcher = NULL; |
7742 | 0 | int32_t code = nodesMakeNode(QUERY_NODE_PHYSICAL_PLAN_DISPATCH, (SNode**)&pDispatcher); |
7743 | 0 | if (NULL == pDispatcher) { |
7744 | 0 | return code; |
7745 | 0 | } |
7746 | | |
7747 | 0 | pDispatcher->sink.pInputDataBlockDesc = NULL; |
7748 | 0 | code = nodesCloneNode((SNode*)pRoot->pOutputDataBlockDesc, (SNode**)&pDispatcher->sink.pInputDataBlockDesc); |
7749 | 0 | if (NULL == pDispatcher->sink.pInputDataBlockDesc) { |
7750 | 0 | nodesDestroyNode((SNode*)pDispatcher); |
7751 | 0 | return code; |
7752 | 0 | } |
7753 | 0 | pDispatcher->dynamicSchema = dynamicSchema; |
7754 | 0 | pDispatcher->localBlockExchange = localBlockExchange; |
7755 | |
|
7756 | 0 | *pSink = (SDataSinkNode*)pDispatcher; |
7757 | 0 | return TSDB_CODE_SUCCESS; |
7758 | 0 | } |
7759 | | |
7760 | 0 | static int32_t makeSubplan(SPhysiPlanContext* pCxt, SLogicSubplan* pLogicSubplan, SSubplan** ppSubplan) { |
7761 | 0 | SSubplan* pSubplan = NULL; |
7762 | 0 | int32_t code = nodesMakeNode(QUERY_NODE_PHYSICAL_SUBPLAN, (SNode**)&pSubplan); |
7763 | 0 | if (NULL == pSubplan) { |
7764 | 0 | return code; |
7765 | 0 | } |
7766 | 0 | pSubplan->id = pLogicSubplan->id; |
7767 | 0 | pSubplan->subplanType = pLogicSubplan->subplanType; |
7768 | 0 | pSubplan->level = pLogicSubplan->level; |
7769 | 0 | pSubplan->rowsThreshold = 4096; |
7770 | 0 | pSubplan->dynamicRowThreshold = false; |
7771 | 0 | pSubplan->isView = pCxt->pPlanCxt->isView; |
7772 | 0 | pSubplan->isAudit = pCxt->pPlanCxt->isAudit; |
7773 | 0 | pSubplan->userAppId = pCxt->pPlanCxt->userAppId; |
7774 | 0 | pSubplan->processOneBlock = pLogicSubplan->processOneBlock; |
7775 | 0 | pSubplan->dynTbname = pLogicSubplan->dynTbname; |
7776 | 0 | pSubplan->localBlockExchange = (pLogicSubplan->splitFlag & SUBPLAN_SPLIT_FLAG_LOCAL_BLOCK_EXCHANGE) != 0; |
7777 | 0 | pSubplan->execOnChildNode = pLogicSubplan->execOnChildNode; |
7778 | 0 | if (NULL != pCxt->pPlanCxt->pUser) { |
7779 | 0 | snprintf(pSubplan->user, sizeof(pSubplan->user), "%s", pCxt->pPlanCxt->pUser); |
7780 | 0 | } |
7781 | 0 | *ppSubplan = pSubplan; |
7782 | 0 | return code; |
7783 | 0 | } |
7784 | | |
7785 | 0 | static int32_t buildInsertValuesSubplan(SPhysiPlanContext* pCxt, SVnodeModifyLogicNode* pModify, SSubplan* pSubplan) { |
7786 | 0 | pSubplan->msgType = pModify->msgType; |
7787 | 0 | pSubplan->execNode.nodeId = pModify->pVgDataBlocks->vg.vgId; |
7788 | 0 | pSubplan->execNode.epSet = pModify->pVgDataBlocks->vg.epSet; |
7789 | 0 | return createDataInserter(pCxt, pModify->pVgDataBlocks, &pSubplan->pDataSink); |
7790 | 0 | } |
7791 | | |
7792 | | static int32_t createQueryInserter(SPhysiPlanContext* pCxt, SVnodeModifyLogicNode* pModify, SSubplan* pSubplan, |
7793 | 0 | SDataSinkNode** pSink) { |
7794 | 0 | SQueryInserterNode* pInserter = NULL; |
7795 | 0 | int32_t code = nodesMakeNode(QUERY_NODE_PHYSICAL_PLAN_QUERY_INSERT, (SNode**)&pInserter); |
7796 | 0 | if (NULL == pInserter) { |
7797 | 0 | return code; |
7798 | 0 | } |
7799 | | |
7800 | 0 | pInserter->tableId = pModify->tableId; |
7801 | 0 | pInserter->stableId = pModify->stableId; |
7802 | 0 | pInserter->tableType = pModify->tableType; |
7803 | 0 | tstrncpy(pInserter->tableName, pModify->tableName, TSDB_TABLE_NAME_LEN); |
7804 | 0 | pInserter->explain = (QUERY_NODE_EXPLAIN_STMT == nodeType(pCxt->pPlanCxt->pAstRoot) ? true : false); |
7805 | 0 | if (pModify->pVgroupList) { |
7806 | 0 | pInserter->vgId = pModify->pVgroupList->vgroups[0].vgId; |
7807 | 0 | pInserter->epSet = pModify->pVgroupList->vgroups[0].epSet; |
7808 | 0 | vgroupInfoToNodeAddr(pModify->pVgroupList->vgroups, &pSubplan->execNode); |
7809 | 0 | } |
7810 | 0 | code = setListSlotId(pCxt, pSubplan->pNode->pOutputDataBlockDesc->dataBlockId, -1, pModify->pInsertCols, |
7811 | 0 | &pInserter->pCols); |
7812 | 0 | if (TSDB_CODE_SUCCESS == code) { |
7813 | 0 | pInserter->sink.pInputDataBlockDesc = NULL; |
7814 | 0 | code = nodesCloneNode((SNode*)pSubplan->pNode->pOutputDataBlockDesc, (SNode**)&pInserter->sink.pInputDataBlockDesc); |
7815 | 0 | } |
7816 | |
|
7817 | 0 | if (TSDB_CODE_SUCCESS == code) { |
7818 | 0 | *pSink = (SDataSinkNode*)pInserter; |
7819 | 0 | } else { |
7820 | 0 | nodesDestroyNode((SNode*)pInserter); |
7821 | 0 | } |
7822 | |
|
7823 | 0 | return code; |
7824 | 0 | } |
7825 | | |
7826 | 0 | static int32_t buildInsertSelectSubplan(SPhysiPlanContext* pCxt, SVnodeModifyLogicNode* pModify, SSubplan* pSubplan) { |
7827 | 0 | int32_t code = |
7828 | 0 | createPhysiNode(pCxt, (SLogicNode*)nodesListGetNode(pModify->node.pChildren, 0), pSubplan, &pSubplan->pNode); |
7829 | 0 | if (TSDB_CODE_SUCCESS == code) { |
7830 | 0 | code = createQueryInserter(pCxt, pModify, pSubplan, &pSubplan->pDataSink); |
7831 | 0 | } |
7832 | 0 | pSubplan->msgType = TDMT_SCH_MERGE_QUERY; |
7833 | 0 | return code; |
7834 | 0 | } |
7835 | | |
7836 | 0 | static int32_t buildInsertSubplan(SPhysiPlanContext* pCxt, SVnodeModifyLogicNode* pModify, SSubplan* pSubplan) { |
7837 | 0 | if (NULL == pModify->node.pChildren) { |
7838 | 0 | return buildInsertValuesSubplan(pCxt, pModify, pSubplan); |
7839 | 0 | } |
7840 | 0 | return buildInsertSelectSubplan(pCxt, pModify, pSubplan); |
7841 | 0 | } |
7842 | | |
7843 | | static int32_t createDataDeleter(SPhysiPlanContext* pCxt, SVnodeModifyLogicNode* pModify, const SPhysiNode* pRoot, |
7844 | 0 | SDataSinkNode** pSink) { |
7845 | 0 | SDataDeleterNode* pDeleter = NULL; |
7846 | 0 | int32_t code = nodesMakeNode(QUERY_NODE_PHYSICAL_PLAN_DELETE, (SNode**)&pDeleter); |
7847 | 0 | if (NULL == pDeleter) { |
7848 | 0 | return code; |
7849 | 0 | } |
7850 | | |
7851 | 0 | pDeleter->tableId = pModify->tableId; |
7852 | 0 | pDeleter->tableType = pModify->tableType; |
7853 | 0 | tstrncpy(pDeleter->tableFName, pModify->tableName, TSDB_TABLE_NAME_LEN); |
7854 | 0 | tstrncpy(pDeleter->tsColName, pModify->tsColName, TSDB_COL_NAME_LEN); |
7855 | 0 | pDeleter->deleteTimeRange = pModify->deleteTimeRange; |
7856 | 0 | pDeleter->secureDelete = pModify->secureDelete; |
7857 | 0 | pDeleter->rangeMode = pModify->deleteRangeMode; |
7858 | 0 | pDeleter->tsSlotId = -1; |
7859 | |
|
7860 | 0 | if (pDeleter->rangeMode) { |
7861 | | // pStartTs carries the ts column here, not first(ts); resolve it against the scan output so the |
7862 | | // deleter can read the timestamps out of every incoming block. |
7863 | 0 | code = setNodeSlotId(pCxt, pRoot->pOutputDataBlockDesc->dataBlockId, -1, pModify->pStartTs, &pDeleter->pStartTs); |
7864 | 0 | if (TSDB_CODE_SUCCESS == code) { |
7865 | 0 | if (QUERY_NODE_COLUMN != nodeType(pDeleter->pStartTs)) { |
7866 | 0 | nodesDestroyNode((SNode*)pDeleter); |
7867 | 0 | return TSDB_CODE_PLAN_INTERNAL_ERROR; |
7868 | 0 | } |
7869 | 0 | pDeleter->tsSlotId = ((SColumnNode*)pDeleter->pStartTs)->slotId; |
7870 | 0 | } |
7871 | 0 | } else { |
7872 | 0 | code = setNodeSlotId(pCxt, pRoot->pOutputDataBlockDesc->dataBlockId, -1, pModify->pAffectedRows, |
7873 | 0 | &pDeleter->pAffectedRows); |
7874 | 0 | if (TSDB_CODE_SUCCESS == code) { |
7875 | 0 | code = setNodeSlotId(pCxt, pRoot->pOutputDataBlockDesc->dataBlockId, -1, pModify->pStartTs, &pDeleter->pStartTs); |
7876 | 0 | } |
7877 | 0 | if (TSDB_CODE_SUCCESS == code) { |
7878 | 0 | code = setNodeSlotId(pCxt, pRoot->pOutputDataBlockDesc->dataBlockId, -1, pModify->pEndTs, &pDeleter->pEndTs); |
7879 | 0 | } |
7880 | 0 | } |
7881 | | |
7882 | 0 | if (TSDB_CODE_SUCCESS == code) { |
7883 | 0 | pDeleter->sink.pInputDataBlockDesc = NULL; |
7884 | 0 | code = nodesCloneNode((SNode*)pRoot->pOutputDataBlockDesc, (SNode**)&pDeleter->sink.pInputDataBlockDesc); |
7885 | 0 | } |
7886 | |
|
7887 | 0 | if (TSDB_CODE_SUCCESS == code) { |
7888 | 0 | *pSink = (SDataSinkNode*)pDeleter; |
7889 | 0 | } else { |
7890 | 0 | nodesDestroyNode((SNode*)pDeleter); |
7891 | 0 | } |
7892 | |
|
7893 | 0 | return code; |
7894 | 0 | } |
7895 | | |
7896 | 0 | static int32_t buildDeleteSubplan(SPhysiPlanContext* pCxt, SVnodeModifyLogicNode* pModify, SSubplan* pSubplan) { |
7897 | 0 | int32_t code = |
7898 | 0 | createPhysiNode(pCxt, (SLogicNode*)nodesListGetNode(pModify->node.pChildren, 0), pSubplan, &pSubplan->pNode); |
7899 | 0 | if (TSDB_CODE_SUCCESS == code) { |
7900 | 0 | code = createDataDeleter(pCxt, pModify, pSubplan->pNode, &pSubplan->pDataSink); |
7901 | 0 | } |
7902 | 0 | pSubplan->msgType = TDMT_VND_DELETE; |
7903 | 0 | return code; |
7904 | 0 | } |
7905 | | |
7906 | 0 | static int32_t buildVnodeModifySubplan(SPhysiPlanContext* pCxt, SLogicSubplan* pLogicSubplan, SSubplan* pSubplan) { |
7907 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
7908 | 0 | SVnodeModifyLogicNode* pModify = (SVnodeModifyLogicNode*)pLogicSubplan->pNode; |
7909 | 0 | switch (pModify->modifyType) { |
7910 | 0 | case MODIFY_TABLE_TYPE_INSERT: |
7911 | 0 | code = buildInsertSubplan(pCxt, pModify, pSubplan); |
7912 | 0 | break; |
7913 | 0 | case MODIFY_TABLE_TYPE_DELETE: |
7914 | 0 | code = buildDeleteSubplan(pCxt, pModify, pSubplan); |
7915 | 0 | break; |
7916 | 0 | default: |
7917 | 0 | code = TSDB_CODE_FAILED; |
7918 | 0 | break; |
7919 | 0 | } |
7920 | 0 | return code; |
7921 | 0 | } |
7922 | | |
7923 | 0 | static int32_t createPhysiSubplan(SPhysiPlanContext* pCxt, SLogicSubplan* pLogicSubplan, SSubplan** pPhysiSubplan) { |
7924 | 0 | SSubplan* pSubplan = NULL; |
7925 | 0 | int32_t code = makeSubplan(pCxt, pLogicSubplan, &pSubplan); |
7926 | 0 | if (NULL == pSubplan) { |
7927 | 0 | return code; |
7928 | 0 | } |
7929 | | |
7930 | | // Set execNode from logic subplan's vgroup list |
7931 | | // After split phase, vgroup list is transferred from logic node to logic subplan via TSWAP |
7932 | | // We need to set execNode here before creating physical nodes |
7933 | 0 | if (pLogicSubplan->pVgroupList && pLogicSubplan->pVgroupList->numOfVgroups > 0) { |
7934 | 0 | vgroupInfoToNodeAddr(pLogicSubplan->pVgroupList->vgroups, &pSubplan->execNode); |
7935 | 0 | pSubplan->execNodeStat.tableNum = pLogicSubplan->pVgroupList->vgroups[0].numOfTable; |
7936 | 0 | } |
7937 | |
|
7938 | 0 | if (SUBPLAN_TYPE_MODIFY == pLogicSubplan->subplanType) { |
7939 | 0 | code = buildVnodeModifySubplan(pCxt, pLogicSubplan, pSubplan); |
7940 | 0 | } else { |
7941 | 0 | if (SUBPLAN_TYPE_SCAN == pSubplan->subplanType || SUBPLAN_TYPE_HSYSSCAN == pSubplan->subplanType) { |
7942 | 0 | pSubplan->msgType = TDMT_SCH_QUERY; |
7943 | 0 | } else { |
7944 | 0 | pSubplan->msgType = TDMT_SCH_MERGE_QUERY; |
7945 | 0 | } |
7946 | 0 | code = createPhysiNode(pCxt, pLogicSubplan->pNode, pSubplan, &pSubplan->pNode); |
7947 | 0 | if (TSDB_CODE_SUCCESS == code && |
7948 | 0 | (SUBPLAN_TYPE_SCAN == pSubplan->subplanType || SUBPLAN_TYPE_HSYSSCAN == pSubplan->subplanType) && |
7949 | 0 | QUERY_NODE_PHYSICAL_PLAN_HASH_INTERVAL == nodeType(pSubplan->pNode) && |
7950 | 0 | ((SIntervalPhysiNode*)pSubplan->pNode)->exInterval) { |
7951 | 0 | pSubplan->delayFreeTask = true; |
7952 | 0 | } |
7953 | 0 | if (TSDB_CODE_SUCCESS == code && pSubplan->localBlockExchange) { |
7954 | 0 | pSubplan->delayFreeTask = true; |
7955 | 0 | } |
7956 | 0 | if (TSDB_CODE_SUCCESS == code && !pCxt->pPlanCxt->topicQuery) { |
7957 | 0 | code = createDataDispatcher(pCxt, pSubplan->pNode, pSubplan->processOneBlock, |
7958 | 0 | pSubplan->localBlockExchange, &pSubplan->pDataSink); |
7959 | 0 | } |
7960 | 0 | } |
7961 | |
|
7962 | 0 | if (TSDB_CODE_SUCCESS == code) { |
7963 | 0 | *pPhysiSubplan = pSubplan; |
7964 | 0 | } else { |
7965 | 0 | nodesDestroyNode((SNode*)pSubplan); |
7966 | 0 | } |
7967 | |
|
7968 | 0 | return code; |
7969 | 0 | } |
7970 | | |
7971 | 0 | static int32_t makeQueryPhysiPlan(SPhysiPlanContext* pCxt, SQueryPlan** ppQueryPlan) { |
7972 | 0 | SQueryPlan* pPlan = NULL; |
7973 | 0 | int32_t code = nodesMakeNode(QUERY_NODE_PHYSICAL_PLAN, (SNode**)&pPlan); |
7974 | 0 | if (NULL == pPlan) { |
7975 | 0 | return code; |
7976 | 0 | } |
7977 | 0 | pPlan->pSubplans = NULL; |
7978 | 0 | code = nodesMakeList(&pPlan->pSubplans); |
7979 | 0 | if (NULL == pPlan->pSubplans) { |
7980 | 0 | nodesDestroyNode((SNode*)pPlan); |
7981 | 0 | return code; |
7982 | 0 | } |
7983 | 0 | pPlan->queryId = pCxt->pPlanCxt->queryId; |
7984 | 0 | *ppQueryPlan = pPlan; |
7985 | 0 | return code; |
7986 | 0 | } |
7987 | | |
7988 | 0 | static int32_t pushSubplan(SPhysiPlanContext* pCxt, SNode* pSubplan, int32_t level, SNodeList* pSubplans) { |
7989 | 0 | SNodeListNode* pGroup = NULL; |
7990 | 0 | if (level >= LIST_LENGTH(pSubplans)) { |
7991 | 0 | pGroup = NULL; |
7992 | 0 | int32_t code = nodesMakeNode(QUERY_NODE_NODE_LIST, (SNode**)&pGroup); |
7993 | 0 | if (NULL == pGroup) { |
7994 | 0 | return code; |
7995 | 0 | } |
7996 | 0 | if (TSDB_CODE_SUCCESS != nodesListStrictAppend(pSubplans, (SNode*)pGroup)) { |
7997 | 0 | return TSDB_CODE_OUT_OF_MEMORY; |
7998 | 0 | } |
7999 | 0 | } else { |
8000 | 0 | pGroup = (SNodeListNode*)nodesListGetNode(pSubplans, level); |
8001 | 0 | } |
8002 | 0 | if (NULL == pGroup->pNodeList) { |
8003 | 0 | int32_t code = nodesMakeList(&pGroup->pNodeList); |
8004 | 0 | if (NULL == pGroup->pNodeList) { |
8005 | 0 | return code; |
8006 | 0 | } |
8007 | 0 | } |
8008 | 0 | return nodesListAppend(pGroup->pNodeList, (SNode*)pSubplan); |
8009 | 0 | } |
8010 | | |
8011 | 0 | static bool physiNodeRoutesSubplanGroup(const SPhysiNode* pNode, int32_t groupId) { |
8012 | 0 | if (QUERY_NODE_PHYSICAL_PLAN_EXCHANGE == nodeType(pNode)) { |
8013 | 0 | const SExchangePhysiNode* pExchange = (const SExchangePhysiNode*)pNode; |
8014 | 0 | return groupId >= pExchange->srcStartGroupId && groupId <= pExchange->srcEndGroupId; |
8015 | 0 | } |
8016 | 0 | if (QUERY_NODE_PHYSICAL_PLAN_MERGE == nodeType(pNode)) { |
8017 | 0 | const SMergePhysiNode* pMerge = (const SMergePhysiNode*)pNode; |
8018 | 0 | return groupId >= pMerge->srcGroupId && groupId <= pMerge->srcEndGroupId; |
8019 | 0 | } |
8020 | 0 | return false; |
8021 | 0 | } |
8022 | | |
8023 | 0 | static bool physiSubplanEdgeInheritsMultiGroupJoin(const SPhysiNode* pNode, int32_t groupId, bool belowMultiGroupJoin) { |
8024 | 0 | if (NULL == pNode) { |
8025 | 0 | return false; |
8026 | 0 | } |
8027 | | |
8028 | 0 | if (physiNodeRoutesSubplanGroup(pNode, groupId)) { |
8029 | 0 | return belowMultiGroupJoin; |
8030 | 0 | } |
8031 | | |
8032 | 0 | bool childBelowMultiGroupJoin = belowMultiGroupJoin || (QUERY_NODE_PHYSICAL_PLAN_HASH_JOIN == nodeType(pNode) && |
8033 | 0 | ((const SHashJoinPhysiNode*)pNode)->multiGroupJoin); |
8034 | 0 | SNode* pChild = NULL; |
8035 | 0 | FOREACH(pChild, pNode->pChildren) { |
8036 | 0 | if (physiSubplanEdgeInheritsMultiGroupJoin((const SPhysiNode*)pChild, groupId, childBelowMultiGroupJoin)) { |
8037 | 0 | return true; |
8038 | 0 | } |
8039 | 0 | } |
8040 | 0 | return false; |
8041 | 0 | } |
8042 | | |
8043 | | static int32_t buildPhysiPlan(SPhysiPlanContext* pCxt, SLogicSubplan* pLogicSubplan, SSubplan* pParent, |
8044 | 0 | SQueryPlan* pQueryPlan, bool inheritedMultiGroupJoin) { |
8045 | 0 | SSubplan* pSubplan = NULL; |
8046 | 0 | int32_t code = createPhysiSubplan(pCxt, pLogicSubplan, &pSubplan); |
8047 | |
|
8048 | 0 | if (TSDB_CODE_SUCCESS == code) { |
8049 | 0 | pSubplan->inheritedMultiGroupJoin = inheritedMultiGroupJoin; |
8050 | 0 | } |
8051 | |
|
8052 | 0 | if (TSDB_CODE_SUCCESS == code) { |
8053 | 0 | code = pushSubplan(pCxt, (SNode*)pSubplan, pLogicSubplan->level, pQueryPlan->pSubplans); |
8054 | 0 | ++(pQueryPlan->numOfSubplans); |
8055 | 0 | } |
8056 | |
|
8057 | 0 | if (TSDB_CODE_SUCCESS != code) { |
8058 | 0 | nodesDestroyNode((SNode*)pSubplan); |
8059 | 0 | return code; |
8060 | 0 | } |
8061 | | |
8062 | 0 | if (TSDB_CODE_SUCCESS == code && NULL != pParent) { |
8063 | 0 | code = nodesListMakeAppend(&pParent->pChildren, (SNode*)pSubplan); |
8064 | 0 | if (TSDB_CODE_SUCCESS == code) { |
8065 | 0 | code = nodesListMakeAppend(&pSubplan->pParents, (SNode*)pParent); |
8066 | 0 | } |
8067 | 0 | } |
8068 | |
|
8069 | 0 | if (TSDB_CODE_SUCCESS == code) { |
8070 | 0 | SNode* pChild = NULL; |
8071 | 0 | FOREACH(pChild, pLogicSubplan->pChildren) { |
8072 | 0 | SLogicSubplan* pLogicChild = (SLogicSubplan*)pChild; |
8073 | 0 | bool childInheritedMultiGroupJoin = |
8074 | 0 | inheritedMultiGroupJoin || |
8075 | 0 | physiSubplanEdgeInheritsMultiGroupJoin(pSubplan->pNode, pLogicChild->id.groupId, false); |
8076 | 0 | code = buildPhysiPlan(pCxt, pLogicChild, pSubplan, pQueryPlan, childInheritedMultiGroupJoin); |
8077 | 0 | if (TSDB_CODE_SUCCESS != code) { |
8078 | 0 | break; |
8079 | 0 | } |
8080 | 0 | } |
8081 | 0 | } |
8082 | |
|
8083 | 0 | return code; |
8084 | 0 | } |
8085 | | |
8086 | 0 | static int32_t doCreatePhysiPlan(SPhysiPlanContext* pCxt, SQueryLogicPlan* pLogicPlan, SQueryPlan** pPhysiPlan) { |
8087 | 0 | SQueryPlan* pPlan = NULL; |
8088 | 0 | int32_t code = makeQueryPhysiPlan(pCxt, &pPlan); |
8089 | 0 | if (NULL == pPlan) { |
8090 | 0 | return code; |
8091 | 0 | } |
8092 | | |
8093 | 0 | SNode* pSubplan = NULL; |
8094 | 0 | FOREACH(pSubplan, pLogicPlan->pTopSubplans) { |
8095 | 0 | code = buildPhysiPlan(pCxt, (SLogicSubplan*)pSubplan, NULL, pPlan, false); |
8096 | 0 | if (TSDB_CODE_SUCCESS != code) { |
8097 | 0 | break; |
8098 | 0 | } |
8099 | 0 | } |
8100 | |
|
8101 | 0 | if (TSDB_CODE_SUCCESS == code) { |
8102 | | // * Propagate hasFederatedScan / hasScan flags to the plan output |
8103 | 0 | pPlan->hasFederatedScan = pCxt->hasFederatedScan; |
8104 | 0 | pPlan->hasScan = pCxt->pPlanCxt->hasScan; |
8105 | 0 | *pPhysiPlan = pPlan; |
8106 | 0 | } else { |
8107 | 0 | nodesDestroyNode((SNode*)pPlan); |
8108 | 0 | } |
8109 | |
|
8110 | 0 | return code; |
8111 | 0 | } |
8112 | | |
8113 | 0 | static void destoryLocationHash(void* p) { |
8114 | 0 | destroySlotIndexHash(*(SHashObj**)p); |
8115 | 0 | } |
8116 | | |
8117 | 0 | static void destoryPhysiPlanContext(SPhysiPlanContext* pCxt) { |
8118 | 0 | taosArrayDestroyEx(pCxt->pLocationHelper, destoryLocationHash); |
8119 | 0 | taosArrayDestroyEx(pCxt->pProjIdxLocHelper, destoryLocationHash); |
8120 | 0 | } |
8121 | | |
8122 | 0 | static void setExplainInfo(SPlanContext* pCxt, SQueryPlan* pPlan) { |
8123 | 0 | if (QUERY_NODE_EXPLAIN_STMT == nodeType(pCxt->pAstRoot)) { |
8124 | 0 | SExplainStmt* pStmt = (SExplainStmt*)pCxt->pAstRoot; |
8125 | 0 | pPlan->explainInfo.mode = pStmt->analyze ? EXPLAIN_MODE_ANALYZE : EXPLAIN_MODE_STATIC; |
8126 | 0 | pPlan->explainInfo.verbose = pStmt->pOptions->verbose; |
8127 | 0 | pPlan->explainInfo.ratio = pStmt->pOptions->ratio; |
8128 | 0 | pPlan->explainInfo.tz = pCxt->timezone; |
8129 | 0 | } else { |
8130 | 0 | pPlan->explainInfo.mode = EXPLAIN_MODE_DISABLE; |
8131 | 0 | } |
8132 | 0 | } |
8133 | | |
8134 | 0 | static int32_t setExecNodeList(SPhysiPlanContext* pCxt, SArray* pExecNodeList) { |
8135 | 0 | int32_t code = 0; |
8136 | 0 | if (NULL == pExecNodeList) { |
8137 | 0 | return code; |
8138 | 0 | } |
8139 | | |
8140 | 0 | if (IS_SYS_SCAN(pCxt->pPlanCxt->sysScanFlag) || !pCxt->pPlanCxt->hasScan) { |
8141 | 0 | SQueryNodeLoad node = {.addr = {.nodeId = MNODE_HANDLE, .epSet = pCxt->pPlanCxt->mgmtEpSet}, .load = 0}; |
8142 | 0 | if (NULL == taosArrayPush(pExecNodeList, &node)) code = terrno; |
8143 | 0 | } |
8144 | 0 | return code; |
8145 | 0 | } |
8146 | | |
8147 | 0 | int32_t createPhysiPlan(SPlanContext* pCxt, SQueryLogicPlan* pLogicPlan, SQueryPlan** pPlan, SArray* pExecNodeList) { |
8148 | 0 | SPhysiPlanContext cxt = {.pPlanCxt = pCxt, |
8149 | 0 | .errCode = TSDB_CODE_SUCCESS, |
8150 | 0 | .nextDataBlockId = 0, |
8151 | 0 | .pLocationHelper = taosArrayInit(32, POINTER_BYTES), |
8152 | 0 | .pProjIdxLocHelper = taosArrayInit(32, POINTER_BYTES), |
8153 | 0 | }; |
8154 | 0 | if (NULL == cxt.pLocationHelper || !cxt.pProjIdxLocHelper) { |
8155 | 0 | taosArrayDestroy(cxt.pLocationHelper); |
8156 | 0 | taosArrayDestroy(cxt.pProjIdxLocHelper); |
8157 | 0 | return terrno; |
8158 | 0 | } |
8159 | | |
8160 | 0 | int32_t code = doCreatePhysiPlan(&cxt, pLogicPlan, pPlan); |
8161 | 0 | if (TSDB_CODE_SUCCESS == code) { |
8162 | 0 | setExplainInfo(pCxt, *pPlan); |
8163 | 0 | code = setExecNodeList(&cxt, pExecNodeList); |
8164 | 0 | } |
8165 | |
|
8166 | 0 | destoryPhysiPlanContext(&cxt); |
8167 | 0 | return code; |
8168 | 0 | } |