Coverage Report

Created: 2026-10-18 06:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/tdengine/source/libs/nodes/src/nodesToSQLFuncs.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
3
 *
4
 * This program is free software: you can use, redistribute, and/or modify
5
 * it under the terms of the GNU Affero General Public License, version 3
6
 * or later ("AGPL"), as published by the Free Software Foundation.
7
 *
8
 * This program is distributed in the hope that it will be useful, but WITHOUT
9
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10
 * FITNESS FOR A PARTICULAR PURPOSE.
11
 *
12
 * You should have received a copy of the GNU Affero General Public License
13
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14
 */
15
16
#include "cmdnodes.h"
17
#include "nodesUtil.h"
18
#include "plannodes.h"
19
#include "querynodes.h"
20
#include "taos.h"
21
#include "taoserror.h"
22
#include "thash.h"
23
24
int32_t nodesNodeToSQLFormat(SNode *pNode, char *buf, int32_t bufSize, int32_t *len, bool longFormat);
25
26
0
const char *operatorTypeStr(EOperatorType type) {
27
0
  switch (type) {
28
0
    case OP_TYPE_ADD:
29
0
      return "+";
30
0
    case OP_TYPE_SUB:
31
0
      return "-";
32
0
    case OP_TYPE_MULTI:
33
0
      return "*";
34
0
    case OP_TYPE_DIV:
35
0
      return "/";
36
0
    case OP_TYPE_REM:
37
0
      return "%";
38
0
    case OP_TYPE_MINUS:
39
0
      return "-";
40
0
    case OP_TYPE_BIT_AND:
41
0
      return "&";
42
0
    case OP_TYPE_BIT_OR:
43
0
      return "|";
44
0
    case OP_TYPE_GREATER_THAN:
45
0
      return ">";
46
0
    case OP_TYPE_GREATER_EQUAL:
47
0
      return ">=";
48
0
    case OP_TYPE_LOWER_THAN:
49
0
      return "<";
50
0
    case OP_TYPE_LOWER_EQUAL:
51
0
      return "<=";
52
0
    case OP_TYPE_EQUAL:
53
0
      return "=";
54
0
    case OP_TYPE_NOT_EQUAL:
55
0
      return "<>";
56
0
    case OP_TYPE_IN:
57
0
      return "IN";
58
0
    case OP_TYPE_NOT_IN:
59
0
      return "NOT IN";
60
0
    case OP_TYPE_LIKE:
61
0
      return "LIKE";
62
0
    case OP_TYPE_NOT_LIKE:
63
0
      return "NOT LIKE";
64
0
    case OP_TYPE_MATCH:
65
0
      return "MATCH";
66
0
    case OP_TYPE_NMATCH:
67
0
      return "NMATCH";
68
0
    case OP_TYPE_IS_NULL:
69
0
      return "IS NULL";
70
0
    case OP_TYPE_IS_NOT_NULL:
71
0
      return "IS NOT NULL";
72
0
    case OP_TYPE_IS_TRUE:
73
0
      return "IS TRUE";
74
0
    case OP_TYPE_IS_FALSE:
75
0
      return "IS FALSE";
76
0
    case OP_TYPE_IS_UNKNOWN:
77
0
      return "IS UNKNOWN";
78
0
    case OP_TYPE_IS_NOT_TRUE:
79
0
      return "IS NOT TRUE";
80
0
    case OP_TYPE_IS_NOT_FALSE:
81
0
      return "IS NOT FALSE";
82
0
    case OP_TYPE_IS_NOT_UNKNOWN:
83
0
      return "IS NOT UNKNOWN";
84
0
    case OP_TYPE_EXISTS:
85
0
      return "EXISTS";
86
0
    case OP_TYPE_NOT_EXISTS:
87
0
      return "NOT EXISTS";
88
0
    case OP_TYPE_JSON_GET_VALUE:
89
0
      return "=>";
90
0
    case OP_TYPE_JSON_CONTAINS:
91
0
      return "CONTAINS";
92
0
    case OP_TYPE_ASSIGN:
93
0
      return "=";
94
0
    default:
95
0
      break;
96
0
  }
97
0
  return "UNKNOWN";
98
0
}
99
100
0
const char *operatorTypeStrEx(EOperatorType type, bool isNegative) {
101
0
  if (isNegative) {
102
0
    switch (type) {
103
0
      case OP_TYPE_IN:
104
0
        return "!= ANY";
105
0
      case OP_TYPE_NOT_IN:
106
0
        return "= ALL";
107
0
      default:
108
0
        break;
109
0
    }
110
0
    return "UNKNOWN";
111
0
  }
112
113
0
  return operatorTypeStr(type);
114
0
}
115
116
0
const char *logicConditionTypeStr(ELogicConditionType type) {
117
0
  switch (type) {
118
0
    case LOGIC_COND_TYPE_AND:
119
0
      return "AND";
120
0
    case LOGIC_COND_TYPE_OR:
121
0
      return "OR";
122
0
    case LOGIC_COND_TYPE_NOT:
123
0
      return "NOT";
124
0
    default:
125
0
      break;
126
0
  }
127
0
  return "UNKNOWN";
128
0
}
129
130
0
static int32_t sqlWindowBoundToSQL(SSqlWindowBound *pBound, char *buf, int32_t bufSize, int32_t *len) {
131
0
  switch (pBound->boundType) {
132
0
    case WINDOW_BOUND_UNBOUNDED_PRECEDING:
133
0
      *len += snprintf(buf + *len, bufSize - *len, "UNBOUNDED PRECEDING");
134
0
      return TSDB_CODE_SUCCESS;
135
0
    case WINDOW_BOUND_N_PRECEDING:
136
0
      if (NULL == pBound->pOffset) {
137
0
        return TSDB_CODE_FAILED;
138
0
      }
139
0
      NODES_ERR_RET(nodesNodeToSQLFormat(pBound->pOffset, buf, bufSize, len, true));
140
0
      *len += snprintf(buf + *len, bufSize - *len, " PRECEDING");
141
0
      return TSDB_CODE_SUCCESS;
142
0
    case WINDOW_BOUND_CURRENT_ROW:
143
0
      *len += snprintf(buf + *len, bufSize - *len, "CURRENT ROW");
144
0
      return TSDB_CODE_SUCCESS;
145
0
    case WINDOW_BOUND_N_FOLLOWING:
146
0
      if (NULL == pBound->pOffset) {
147
0
        return TSDB_CODE_FAILED;
148
0
      }
149
0
      NODES_ERR_RET(nodesNodeToSQLFormat(pBound->pOffset, buf, bufSize, len, true));
150
0
      *len += snprintf(buf + *len, bufSize - *len, " FOLLOWING");
151
0
      return TSDB_CODE_SUCCESS;
152
0
    case WINDOW_BOUND_UNBOUNDED_FOLLOWING:
153
0
      *len += snprintf(buf + *len, bufSize - *len, "UNBOUNDED FOLLOWING");
154
0
      return TSDB_CODE_SUCCESS;
155
0
    default:
156
0
      break;
157
0
  }
158
0
  return TSDB_CODE_FAILED;
159
0
}
160
161
0
int32_t nodesNodeToSQL(SNode *pNode, char *buf, int32_t bufSize, int32_t *len) {
162
0
  return nodesNodeToSQLFormat(pNode, buf, bufSize, len, false);
163
0
}
164
165
0
int32_t nodesNodeToSQLFormat(SNode *pNode, char *buf, int32_t bufSize, int32_t *len, bool longFormat) {
166
0
  switch (pNode->type) {
167
0
    case QUERY_NODE_COLUMN: {
168
0
      SColumnNode *colNode = (SColumnNode *)pNode;
169
0
      if (colNode->dbName[0]) {
170
0
        *len += snprintf(buf + *len, bufSize - *len, "`%s`.", colNode->dbName);
171
0
      }
172
173
0
      if (colNode->tableAlias[0]) {
174
0
        *len += snprintf(buf + *len, bufSize - *len, "`%s`.", colNode->tableAlias);
175
0
      } else if (colNode->tableName[0]) {
176
0
        *len += snprintf(buf + *len, bufSize - *len, "`%s`.", colNode->tableName);
177
0
      }
178
179
0
      if (colNode->node.userAlias[0]) {
180
0
        *len += snprintf(buf + *len, bufSize - *len, "`%s`", colNode->node.userAlias);
181
0
      } else {
182
0
        *len += snprintf(buf + *len, bufSize - *len, "`%s`", colNode->colName);
183
0
      }
184
185
0
      return TSDB_CODE_SUCCESS;
186
0
    }
187
0
    case QUERY_NODE_VALUE: {
188
0
      SValueNode *colNode = (SValueNode *)pNode;
189
0
      char       *t = nodesGetStrValueFromNode(colNode);
190
0
      if (NULL == t) {
191
        // NULL type value (e.g. ELSE NULL in CASE WHEN)
192
0
        *len += tsnprintf(buf + *len, bufSize - *len, "NULL");
193
0
        return TSDB_CODE_SUCCESS;
194
0
      }
195
196
0
      int32_t tlen = strlen(t);
197
0
      if (longFormat) {
198
0
        *len += snprintf(buf + *len, bufSize - *len, "%s", t);
199
0
      } else {
200
0
        if (tlen > 32) {
201
0
          *len += snprintf(buf + *len, bufSize - *len, "%.*s...%s", 32, t, t + tlen - 1);
202
0
        } else {
203
0
          *len += snprintf(buf + *len, bufSize - *len, "%s", t);
204
0
        }
205
0
      }
206
207
0
      taosMemoryFree(t);
208
209
0
      return TSDB_CODE_SUCCESS;
210
0
    }
211
0
    case QUERY_NODE_OPERATOR: {
212
0
      SOperatorNode *pOpNode = (SOperatorNode *)pNode;
213
0
      *len += snprintf(buf + *len, bufSize - *len, "(");
214
0
      if (pOpNode->pLeft) {
215
0
        NODES_ERR_RET(nodesNodeToSQLFormat(pOpNode->pLeft, buf, bufSize, len, true));
216
0
      }
217
218
0
      *len += tsnprintf(buf + *len, bufSize - *len, " %s ", operatorTypeStrEx(pOpNode->opType, pOpNode->flag & OPERATOR_FLAG_NEGATIVE_OP));
219
220
0
      if (pOpNode->pRight) {
221
0
        NODES_ERR_RET(nodesNodeToSQLFormat(pOpNode->pRight, buf, bufSize, len, true));
222
0
      }
223
224
0
      *len += snprintf(buf + *len, bufSize - *len, ")");
225
226
0
      return TSDB_CODE_SUCCESS;
227
0
    }
228
0
    case QUERY_NODE_SQL_WINDOW_SPEC: {
229
0
      SWindowSpecNode *pWin = (SWindowSpecNode *)pNode;
230
0
      SNode           *node = NULL;
231
0
      bool             first = true;
232
233
0
      if (pWin->refWindowName[0] != '\0' && NULL == pWin->pPartitionByList && NULL == pWin->pOrderByList &&
234
0
          NULL == pWin->pFrame) {
235
0
        *len += snprintf(buf + *len, bufSize - *len, "%s", pWin->refWindowName);
236
0
        return TSDB_CODE_SUCCESS;
237
0
      }
238
239
0
      *len += snprintf(buf + *len, bufSize - *len, "(");
240
0
      if (pWin->refWindowName[0] != '\0') {
241
0
        *len += snprintf(buf + *len, bufSize - *len, "%s", pWin->refWindowName);
242
0
        first = false;
243
0
      }
244
0
      if (NULL != pWin->pPartitionByList) {
245
0
        if (!first) {
246
0
          *len += snprintf(buf + *len, bufSize - *len, " ");
247
0
        }
248
0
        *len += snprintf(buf + *len, bufSize - *len, "PARTITION BY ");
249
0
        bool firstExpr = true;
250
0
        FOREACH(node, pWin->pPartitionByList) {
251
0
          if (!firstExpr) {
252
0
            *len += snprintf(buf + *len, bufSize - *len, ", ");
253
0
          }
254
0
          NODES_ERR_RET(nodesNodeToSQLFormat(node, buf, bufSize, len, true));
255
0
          firstExpr = false;
256
0
        }
257
0
        first = false;
258
0
      }
259
0
      if (NULL != pWin->pOrderByList) {
260
0
        if (!first) {
261
0
          *len += snprintf(buf + *len, bufSize - *len, " ");
262
0
        }
263
0
        *len += snprintf(buf + *len, bufSize - *len, "ORDER BY ");
264
0
        bool firstExpr = true;
265
0
        FOREACH(node, pWin->pOrderByList) {
266
0
          if (!firstExpr) {
267
0
            *len += snprintf(buf + *len, bufSize - *len, ", ");
268
0
          }
269
0
          NODES_ERR_RET(nodesNodeToSQLFormat(node, buf, bufSize, len, true));
270
0
          firstExpr = false;
271
0
        }
272
0
        first = false;
273
0
      }
274
0
      if (NULL != pWin->pFrame) {
275
0
        if (!first) {
276
0
          *len += snprintf(buf + *len, bufSize - *len, " ");
277
0
        }
278
0
        NODES_ERR_RET(nodesNodeToSQLFormat(pWin->pFrame, buf, bufSize, len, true));
279
0
      }
280
0
      *len += snprintf(buf + *len, bufSize - *len, ")");
281
0
      return TSDB_CODE_SUCCESS;
282
0
    }
283
0
    case QUERY_NODE_SQL_WINDOW_FRAME: {
284
0
      SWindowFrameNode *pFrame = (SWindowFrameNode *)pNode;
285
0
      *len += snprintf(buf + *len, bufSize - *len, "%s BETWEEN ",
286
0
                       WINDOW_FRAME_UNIT_RANGE == pFrame->frameUnit ? "RANGE" : "ROWS");
287
0
      NODES_ERR_RET(sqlWindowBoundToSQL(&pFrame->start, buf, bufSize, len));
288
0
      *len += snprintf(buf + *len, bufSize - *len, " AND ");
289
0
      NODES_ERR_RET(sqlWindowBoundToSQL(&pFrame->end, buf, bufSize, len));
290
0
      return TSDB_CODE_SUCCESS;
291
0
    }
292
0
    case QUERY_NODE_SQL_NAMED_WINDOW: {
293
0
      SNamedWindowNode *pWin = (SNamedWindowNode *)pNode;
294
0
      *len += snprintf(buf + *len, bufSize - *len, "%s AS ", pWin->windowName);
295
0
      NODES_ERR_RET(nodesNodeToSQLFormat(pWin->pSpec, buf, bufSize, len, true));
296
0
      return TSDB_CODE_SUCCESS;
297
0
    }
298
0
    case QUERY_NODE_LOGIC_CONDITION: {
299
0
      SLogicConditionNode *pLogicNode = (SLogicConditionNode *)pNode;
300
0
      SNode               *node = NULL;
301
0
      bool                 first = true;
302
303
0
      *len += snprintf(buf + *len, bufSize - *len, "(");
304
305
0
      FOREACH(node, pLogicNode->pParameterList) {
306
0
        if (!first) {
307
0
          *len += snprintf(buf + *len, bufSize - *len, " %s ", logicConditionTypeStr(pLogicNode->condType));
308
0
        }
309
0
        NODES_ERR_RET(nodesNodeToSQLFormat(node, buf, bufSize, len, true));
310
0
        first = false;
311
0
      }
312
313
0
      *len += snprintf(buf + *len, bufSize - *len, ")");
314
315
0
      return TSDB_CODE_SUCCESS;
316
0
    }
317
0
    case QUERY_NODE_FUNCTION: {
318
0
      SFunctionNode *pFuncNode = (SFunctionNode *)pNode;
319
0
      SNode         *node = NULL;
320
0
      bool           first = true;
321
322
0
      *len += snprintf(buf + *len, bufSize - *len, "%s(", pFuncNode->functionName);
323
324
0
      FOREACH(node, pFuncNode->pParameterList) {
325
0
        if (!first) {
326
0
          *len += snprintf(buf + *len, bufSize - *len, ", ");
327
0
        }
328
0
        NODES_ERR_RET(nodesNodeToSQLFormat(node, buf, bufSize, len, true));
329
0
        first = false;
330
0
      }
331
332
0
      *len += snprintf(buf + *len, bufSize - *len, ")");
333
0
      if (NULL != pFuncNode->pOver) {
334
0
        *len += snprintf(buf + *len, bufSize - *len, " OVER ");
335
0
        NODES_ERR_RET(nodesNodeToSQLFormat(pFuncNode->pOver, buf, bufSize, len, true));
336
0
      }
337
338
0
      return TSDB_CODE_SUCCESS;
339
0
    }
340
0
    case QUERY_NODE_NODE_LIST: {
341
0
      SNodeListNode *pListNode = (SNodeListNode *)pNode;
342
0
      SNode         *node = NULL;
343
0
      bool           first = true;
344
0
      int32_t        num = 0;
345
346
0
      *len += snprintf(buf + *len, bufSize - *len, "(");
347
348
0
      FOREACH(node, pListNode->pNodeList) {
349
0
        if (!first) {
350
0
          *len += snprintf(buf + *len, bufSize - *len, ", ");
351
0
          if (!longFormat) {
352
0
            if (++num >= 10) {
353
0
              *len += snprintf(buf + *len, bufSize - *len, "...");
354
0
              break;
355
0
            }
356
0
          }
357
0
        }
358
0
        NODES_ERR_RET(nodesNodeToSQLFormat(node, buf, bufSize, len, true));
359
0
        first = false;
360
0
      }
361
362
0
      *len += snprintf(buf + *len, bufSize - *len, ")");
363
364
0
      return TSDB_CODE_SUCCESS;
365
0
    }
366
0
    case QUERY_NODE_REMOTE_VALUE: {
367
0
      SRemoteValueNode* pRemote = (SRemoteValueNode*)pNode;
368
0
      *len += snprintf(buf + *len, bufSize - *len, "$(InitPlan %d)", pRemote->subQIdx + 1);
369
0
      return TSDB_CODE_SUCCESS;
370
0
    }
371
0
    case QUERY_NODE_REMOTE_VALUE_LIST: {
372
0
      SRemoteValueListNode* pRemote = (SRemoteValueListNode*)pNode;
373
0
      *len += tsnprintf(buf + *len, bufSize - *len, "$(InitPlan %d)", pRemote->subQIdx + 1);
374
0
      return TSDB_CODE_SUCCESS;
375
0
    }
376
0
    case QUERY_NODE_REMOTE_ROW: {
377
0
      SRemoteRowNode* pRemote = (SRemoteRowNode*)pNode;
378
0
      *len += tsnprintf(buf + *len, bufSize - *len, "$(InitPlan %d)", pRemote->subQIdx + 1);
379
0
      return TSDB_CODE_SUCCESS;
380
0
    }
381
0
    case QUERY_NODE_REMOTE_ZERO_ROWS: {
382
0
      SRemoteZeroRowsNode* pRemote = (SRemoteZeroRowsNode*)pNode;
383
0
      *len += tsnprintf(buf + *len, bufSize - *len, "$(InitPlan %d)", pRemote->subQIdx + 1);
384
0
      return TSDB_CODE_SUCCESS;
385
0
    }
386
0
    case QUERY_NODE_REMOTE_TABLE: {
387
0
      SRemoteTableNode* pRemote = (SRemoteTableNode*)pNode;
388
0
      *len += tsnprintf(buf + *len, bufSize - *len, "$(InitPlan %d)", pRemote->subQIdx + 1);
389
0
      return TSDB_CODE_SUCCESS;
390
0
    }
391
0
    case QUERY_NODE_WHEN_THEN: {
392
0
      SWhenThenNode *pWhenThen = (SWhenThenNode *)pNode;
393
0
      *len += tsnprintf(buf + *len, bufSize - *len, "WHEN ");
394
0
      NODES_ERR_RET(nodesNodeToSQLFormat(pWhenThen->pWhen, buf, bufSize, len, true));
395
0
      *len += tsnprintf(buf + *len, bufSize - *len, " THEN ");
396
0
      NODES_ERR_RET(nodesNodeToSQLFormat(pWhenThen->pThen, buf, bufSize, len, true));
397
0
      return TSDB_CODE_SUCCESS;
398
0
    }
399
0
    case QUERY_NODE_CASE_WHEN: {
400
0
      SCaseWhenNode *pCaseWhen = (SCaseWhenNode *)pNode;
401
0
      *len += tsnprintf(buf + *len, bufSize - *len, "CASE");
402
0
      if (pCaseWhen->pCase) {
403
0
        *len += tsnprintf(buf + *len, bufSize - *len, " ");
404
0
        NODES_ERR_RET(nodesNodeToSQLFormat(pCaseWhen->pCase, buf, bufSize, len, true));
405
0
      }
406
0
      SNode *pWhenThen = NULL;
407
0
      FOREACH(pWhenThen, pCaseWhen->pWhenThenList) {
408
0
        *len += tsnprintf(buf + *len, bufSize - *len, " ");
409
0
        NODES_ERR_RET(nodesNodeToSQLFormat(pWhenThen, buf, bufSize, len, true));
410
0
      }
411
0
      if (pCaseWhen->pElse) {
412
0
        *len += tsnprintf(buf + *len, bufSize - *len, " ELSE ");
413
0
        NODES_ERR_RET(nodesNodeToSQLFormat(pCaseWhen->pElse, buf, bufSize, len, true));
414
0
      }
415
0
      *len += tsnprintf(buf + *len, bufSize - *len, " END");
416
0
      return TSDB_CODE_SUCCESS;
417
0
    }
418
0
    default:
419
0
      break;
420
0
  }
421
422
0
  nodesError("nodesNodeToSQL unknown node = %s", nodesNodeName(pNode->type));
423
0
  NODES_RET(TSDB_CODE_APP_ERROR);
424
0
}