• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

taosdata / TDengine / #4788

14 Oct 2025 11:21AM UTC coverage: 60.992% (-2.3%) from 63.264%
#4788

push

travis-ci

web-flow
Merge 7ca9b50f9 into 19574fe21

154868 of 324306 branches covered (47.75%)

Branch coverage included in aggregate %.

207304 of 269498 relevant lines covered (76.92%)

125773493.22 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

64.05
/source/dnode/mnode/impl/src/mndFunc.c
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
#define _DEFAULT_SOURCE
17
#include "mndFunc.h"
18
#include "mndPrivilege.h"
19
#include "mndShow.h"
20
#include "mndSync.h"
21
#include "mndTrans.h"
22
#include "mndUser.h"
23

24
#define SDB_FUNC_VER          2
25
#define SDB_FUNC_RESERVE_SIZE 64
26

27
static SSdbRaw *mndFuncActionEncode(SFuncObj *pFunc);
28
static SSdbRow *mndFuncActionDecode(SSdbRaw *pRaw);
29
static int32_t  mndFuncActionInsert(SSdb *pSdb, SFuncObj *pFunc);
30
static int32_t  mndFuncActionDelete(SSdb *pSdb, SFuncObj *pFunc);
31
static int32_t  mndFuncActionUpdate(SSdb *pSdb, SFuncObj *pOld, SFuncObj *pNew);
32
static int32_t  mndCreateFunc(SMnode *pMnode, SRpcMsg *pReq, SCreateFuncReq *pCreate);
33
static int32_t  mndDropFunc(SMnode *pMnode, SRpcMsg *pReq, SFuncObj *pFunc);
34
static int32_t  mndProcessCreateFuncReq(SRpcMsg *pReq);
35
static int32_t  mndProcessDropFuncReq(SRpcMsg *pReq);
36
static int32_t  mndProcessRetrieveFuncReq(SRpcMsg *pReq);
37
static int32_t  mndRetrieveFuncs(SRpcMsg *pReq, SShowObj *pShow, SSDataBlock *pBlock, int32_t rows);
38
static void     mndCancelGetNextFunc(SMnode *pMnode, void *pIter);
39

40
int32_t mndInitFunc(SMnode *pMnode) {
549,564✔
41
  SSdbTable table = {
549,564✔
42
      .sdbType = SDB_FUNC,
43
      .keyType = SDB_KEY_BINARY,
44
      .encodeFp = (SdbEncodeFp)mndFuncActionEncode,
45
      .decodeFp = (SdbDecodeFp)mndFuncActionDecode,
46
      .insertFp = (SdbInsertFp)mndFuncActionInsert,
47
      .updateFp = (SdbUpdateFp)mndFuncActionUpdate,
48
      .deleteFp = (SdbDeleteFp)mndFuncActionDelete,
49
  };
50

51
  mndSetMsgHandle(pMnode, TDMT_MND_CREATE_FUNC, mndProcessCreateFuncReq);
549,564✔
52
  mndSetMsgHandle(pMnode, TDMT_MND_DROP_FUNC, mndProcessDropFuncReq);
549,564✔
53
  mndSetMsgHandle(pMnode, TDMT_MND_RETRIEVE_FUNC, mndProcessRetrieveFuncReq);
549,564✔
54

55
  mndAddShowRetrieveHandle(pMnode, TSDB_MGMT_TABLE_FUNC, mndRetrieveFuncs);
549,564✔
56
  mndAddShowFreeIterHandle(pMnode, TSDB_MGMT_TABLE_FUNC, mndCancelGetNextFunc);
549,564✔
57

58
  return sdbSetTable(pMnode->pSdb, table);
549,564✔
59
}
60

61
void mndCleanupFunc(SMnode *pMnode) {}
549,340✔
62

63
static SSdbRaw *mndFuncActionEncode(SFuncObj *pFunc) {
12,784✔
64
  int32_t code = 0;
12,784✔
65
  int32_t lino = 0;
12,784✔
66
  terrno = TSDB_CODE_OUT_OF_MEMORY;
12,784✔
67

68
  int32_t  size = pFunc->commentSize + pFunc->codeSize + sizeof(SFuncObj) + SDB_FUNC_RESERVE_SIZE;
12,784✔
69
  SSdbRaw *pRaw = sdbAllocRaw(SDB_FUNC, SDB_FUNC_VER, size);
12,784✔
70
  if (pRaw == NULL) goto _OVER;
12,784!
71

72
  int32_t dataPos = 0;
12,784✔
73
  SDB_SET_BINARY(pRaw, dataPos, pFunc->name, TSDB_FUNC_NAME_LEN, _OVER)
12,784!
74
  SDB_SET_INT64(pRaw, dataPos, pFunc->createdTime, _OVER)
12,784!
75
  SDB_SET_INT8(pRaw, dataPos, pFunc->funcType, _OVER)
12,784!
76
  SDB_SET_INT8(pRaw, dataPos, pFunc->scriptType, _OVER)
12,784!
77
  SDB_SET_INT8(pRaw, dataPos, pFunc->align, _OVER)
12,784!
78
  SDB_SET_INT8(pRaw, dataPos, pFunc->outputType, _OVER)
12,784!
79
  SDB_SET_INT32(pRaw, dataPos, pFunc->outputLen, _OVER)
12,784!
80
  SDB_SET_INT32(pRaw, dataPos, pFunc->bufSize, _OVER)
12,784!
81
  SDB_SET_INT64(pRaw, dataPos, pFunc->signature, _OVER)
12,784!
82
  SDB_SET_INT32(pRaw, dataPos, pFunc->commentSize, _OVER)
12,784!
83
  SDB_SET_INT32(pRaw, dataPos, pFunc->codeSize, _OVER)
12,784!
84
  if (pFunc->commentSize > 0) {
12,784✔
85
    SDB_SET_BINARY(pRaw, dataPos, pFunc->pComment, pFunc->commentSize, _OVER)
126!
86
  }
87
  SDB_SET_BINARY(pRaw, dataPos, pFunc->pCode, pFunc->codeSize, _OVER)
12,784!
88
  SDB_SET_INT32(pRaw, dataPos, pFunc->funcVersion, _OVER)
12,784!
89
  SDB_SET_RESERVE(pRaw, dataPos, SDB_FUNC_RESERVE_SIZE, _OVER)
12,784!
90
  SDB_SET_DATALEN(pRaw, dataPos, _OVER);
12,784!
91

92
  terrno = 0;
12,784✔
93

94
_OVER:
12,784✔
95
  if (terrno != 0) {
12,784!
96
    mError("func:%s, failed to encode to raw:%p since %s", pFunc->name, pRaw, terrstr());
×
97
    sdbFreeRaw(pRaw);
×
98
    return NULL;
×
99
  }
100

101
  mTrace("func:%s, encode to raw:%p, row:%p", pFunc->name, pRaw, pFunc);
12,784✔
102
  return pRaw;
12,784✔
103
}
104

105
static SSdbRow *mndFuncActionDecode(SSdbRaw *pRaw) {
8,576✔
106
  int32_t code = 0;
8,576✔
107
  int32_t lino = 0;
8,576✔
108
  terrno = TSDB_CODE_OUT_OF_MEMORY;
8,576✔
109
  SSdbRow  *pRow = NULL;
8,576✔
110
  SFuncObj *pFunc = NULL;
8,576✔
111

112
  int8_t sver = 0;
8,576✔
113
  if (sdbGetRawSoftVer(pRaw, &sver) != 0) goto _OVER;
8,576!
114

115
  if (sver != 1 && sver != 2) {
8,576!
116
    terrno = TSDB_CODE_SDB_INVALID_DATA_VER;
×
117
    goto _OVER;
×
118
  }
119

120
  pRow = sdbAllocRow(sizeof(SFuncObj));
8,576✔
121
  if (pRow == NULL) goto _OVER;
8,576!
122

123
  pFunc = sdbGetRowObj(pRow);
8,576✔
124
  if (pFunc == NULL) goto _OVER;
8,576!
125

126
  int32_t dataPos = 0;
8,576✔
127
  SDB_GET_BINARY(pRaw, dataPos, pFunc->name, TSDB_FUNC_NAME_LEN, _OVER)
8,576!
128
  SDB_GET_INT64(pRaw, dataPos, &pFunc->createdTime, _OVER)
8,576!
129
  SDB_GET_INT8(pRaw, dataPos, &pFunc->funcType, _OVER)
8,576!
130
  SDB_GET_INT8(pRaw, dataPos, &pFunc->scriptType, _OVER)
8,576!
131
  SDB_GET_INT8(pRaw, dataPos, &pFunc->align, _OVER)
8,576!
132
  SDB_GET_INT8(pRaw, dataPos, &pFunc->outputType, _OVER)
8,576!
133
  SDB_GET_INT32(pRaw, dataPos, &pFunc->outputLen, _OVER)
8,576!
134
  SDB_GET_INT32(pRaw, dataPos, &pFunc->bufSize, _OVER)
8,576!
135
  SDB_GET_INT64(pRaw, dataPos, &pFunc->signature, _OVER)
8,576!
136
  SDB_GET_INT32(pRaw, dataPos, &pFunc->commentSize, _OVER)
8,576!
137
  SDB_GET_INT32(pRaw, dataPos, &pFunc->codeSize, _OVER)
8,576!
138

139
  if (pFunc->commentSize > 0) {
8,576✔
140
    pFunc->pComment = taosMemoryCalloc(1, pFunc->commentSize);
72!
141
    if (pFunc->pComment == NULL) {
72!
142
      goto _OVER;
×
143
    }
144
    SDB_GET_BINARY(pRaw, dataPos, pFunc->pComment, pFunc->commentSize, _OVER)
72!
145
  }
146

147
  pFunc->pCode = taosMemoryCalloc(1, pFunc->codeSize);
8,576!
148
  if (pFunc->pCode == NULL) {
8,576!
149
    goto _OVER;
×
150
  }
151
  SDB_GET_BINARY(pRaw, dataPos, pFunc->pCode, pFunc->codeSize, _OVER)
8,576!
152

153
  if (sver >= 2) {
8,576!
154
    SDB_GET_INT32(pRaw, dataPos, &pFunc->funcVersion, _OVER)
8,576!
155
  }
156

157
  SDB_GET_RESERVE(pRaw, dataPos, SDB_FUNC_RESERVE_SIZE, _OVER)
8,576!
158

159
  taosInitRWLatch(&pFunc->lock);
8,576✔
160

161
  terrno = 0;
8,576✔
162

163
_OVER:
8,576✔
164
  if (terrno != 0) {
8,576!
165
    mError("func:%s, failed to decode from raw:%p since %s", pFunc == NULL ? "null" : pFunc->name, pRaw, terrstr());
×
166
    taosMemoryFreeClear(pRow);
×
167
    return NULL;
×
168
  }
169

170
  mTrace("func:%s, decode from raw:%p, row:%p", pFunc->name, pRaw, pFunc);
8,576✔
171
  return pRow;
8,576✔
172
}
173

174
static int32_t mndFuncActionInsert(SSdb *pSdb, SFuncObj *pFunc) {
3,074✔
175
  mTrace("func:%s, perform insert action, row:%p", pFunc->name, pFunc);
3,074✔
176
  return 0;
3,074✔
177
}
178

179
static int32_t mndFuncActionDelete(SSdb *pSdb, SFuncObj *pFunc) {
8,576✔
180
  mTrace("func:%s, perform delete action, row:%p", pFunc->name, pFunc);
8,576✔
181
  taosMemoryFreeClear(pFunc->pCode);
8,576!
182
  taosMemoryFreeClear(pFunc->pComment);
8,576!
183
  return 0;
8,576✔
184
}
185

186
static int32_t mndFuncActionUpdate(SSdb *pSdb, SFuncObj *pOld, SFuncObj *pNew) {
3,803✔
187
  int32_t code = 0;
3,803✔
188
  mTrace("func:%s, perform update action, old row:%p new row:%p", pOld->name, pOld, pNew);
3,803✔
189

190
  taosWLockLatch(&pOld->lock);
3,803✔
191

192
  pOld->align = pNew->align;
3,803✔
193
  pOld->bufSize = pNew->bufSize;
3,803✔
194
  pOld->codeSize = pNew->codeSize;
3,803✔
195
  pOld->commentSize = pNew->commentSize;
3,803✔
196
  pOld->createdTime = pNew->createdTime;
3,803✔
197
  pOld->funcType = pNew->funcType;
3,803✔
198
  pOld->funcVersion = pNew->funcVersion;
3,803✔
199
  pOld->outputLen = pNew->outputLen;
3,803✔
200
  pOld->outputType = pNew->outputType;
3,803✔
201

202
  if (pOld->pComment != NULL) {
3,803✔
203
    taosMemoryFree(pOld->pComment);
36!
204
    pOld->pComment = NULL;
36✔
205
  }
206
  if (pNew->commentSize > 0 && pNew->pComment != NULL) {
3,803!
207
    pOld->commentSize = pNew->commentSize;
36✔
208
    pOld->pComment = taosMemoryMalloc(pOld->commentSize);
36!
209
    if (pOld->pComment == NULL) {
36!
210
      code = terrno;
×
211
      taosWUnLockLatch(&pOld->lock);
×
212
      return code;
×
213
    }
214
    (void)memcpy(pOld->pComment, pNew->pComment, pOld->commentSize);
36!
215
  }
216

217
  if (pOld->pCode != NULL) {
3,803!
218
    taosMemoryFree(pOld->pCode);
3,803!
219
    pOld->pCode = NULL;
3,803✔
220
  }
221
  if (pNew->codeSize > 0 && pNew->pCode != NULL) {
3,803!
222
    pOld->codeSize = pNew->codeSize;
3,803✔
223
    pOld->pCode = taosMemoryMalloc(pOld->codeSize);
3,803!
224
    if (pOld->pCode == NULL) {
3,803!
225
      code = terrno;
×
226
      taosWUnLockLatch(&pOld->lock);
×
227
      return code;
×
228
    }
229
    (void)memcpy(pOld->pCode, pNew->pCode, pOld->codeSize);
3,803!
230
  }
231

232
  pOld->scriptType = pNew->scriptType;
3,803✔
233
  pOld->signature = pNew->signature;
3,803✔
234

235
  taosWUnLockLatch(&pOld->lock);
3,803✔
236

237
  return 0;
3,803✔
238
}
239

240
static SFuncObj *mndAcquireFunc(SMnode *pMnode, char *funcName) {
42,376✔
241
  terrno = 0;
42,376✔
242
  SSdb     *pSdb = pMnode->pSdb;
42,376✔
243
  SFuncObj *pFunc = sdbAcquire(pSdb, SDB_FUNC, funcName);
42,376✔
244
  if (pFunc == NULL && terrno == TSDB_CODE_SDB_OBJ_NOT_THERE) {
42,376!
245
    terrno = TSDB_CODE_MND_FUNC_NOT_EXIST;
7,308✔
246
  }
247
  return pFunc;
42,376✔
248
}
249

250
static void mndReleaseFunc(SMnode *pMnode, SFuncObj *pFunc) {
37,244✔
251
  SSdb *pSdb = pMnode->pSdb;
37,244✔
252
  sdbRelease(pSdb, pFunc);
37,244✔
253
}
37,244✔
254

255
static int32_t mndCreateFunc(SMnode *pMnode, SRpcMsg *pReq, SCreateFuncReq *pCreate) {
2,104✔
256
  int32_t code = -1;
2,104✔
257
  STrans *pTrans = NULL;
2,104✔
258

259
  if ((code = grantCheck(TSDB_GRANT_USER)) < 0) {
2,104!
260
    return code;
×
261
  }
262

263
  SFuncObj func = {0};
2,104✔
264
  (void)memcpy(func.name, pCreate->name, TSDB_FUNC_NAME_LEN);
2,104✔
265
  func.createdTime = taosGetTimestampMs();
2,104✔
266
  func.funcType = pCreate->funcType;
2,104✔
267
  func.scriptType = pCreate->scriptType;
2,104✔
268
  func.outputType = pCreate->outputType;
2,104✔
269
  func.outputLen = pCreate->outputLen;
2,104✔
270
  func.bufSize = pCreate->bufSize;
2,104✔
271
  func.signature = pCreate->signature;
2,104✔
272
  if (NULL != pCreate->pComment) {
2,104✔
273
    func.commentSize = strlen(pCreate->pComment) + 1;
27!
274
    func.pComment = taosMemoryMalloc(func.commentSize);
27!
275
    if (func.pComment == NULL) {
27!
276
      code = terrno;
×
277
      goto _OVER;
×
278
    }
279
  }
280
  func.codeSize = pCreate->codeLen;
2,104✔
281
  func.pCode = taosMemoryMalloc(func.codeSize);
2,104!
282
  if (func.pCode == NULL || func.pCode == NULL) {
2,104!
283
    code = terrno;
×
284
    goto _OVER;
×
285
  }
286

287
  if (func.commentSize > 0) {
2,104✔
288
    (void)memcpy(func.pComment, pCreate->pComment, func.commentSize);
27!
289
  }
290
  (void)memcpy(func.pCode, pCreate->pCode, func.codeSize);
2,104!
291

292
  pTrans = mndTransCreate(pMnode, TRN_POLICY_ROLLBACK, TRN_CONFLICT_NOTHING, pReq, "create-func");
2,104✔
293
  if (pTrans == NULL) {
2,104!
294
    code = TSDB_CODE_MND_RETURN_VALUE_NULL;
×
295
    if (terrno != 0) code = terrno;
×
296
    goto _OVER;
×
297
  }
298
  mInfo("trans:%d, used to create func:%s", pTrans->id, pCreate->name);
2,104!
299

300
  SFuncObj *oldFunc = mndAcquireFunc(pMnode, pCreate->name);
2,104✔
301
  if (pCreate->orReplace == 1 && oldFunc != NULL) {
2,104!
302
    func.funcVersion = oldFunc->funcVersion + 1;
×
303
    func.createdTime = oldFunc->createdTime;
×
304

305
    SSdbRaw *pRedoRaw = mndFuncActionEncode(oldFunc);
×
306
    if (pRedoRaw == NULL) {
×
307
      code = TSDB_CODE_MND_RETURN_VALUE_NULL;
×
308
      if (terrno != 0) code = terrno;
×
309
      goto _OVER;
×
310
    }
311
    TAOS_CHECK_GOTO(mndTransAppendRedolog(pTrans, pRedoRaw), NULL, _OVER);
×
312
    TAOS_CHECK_GOTO(sdbSetRawStatus(pRedoRaw, SDB_STATUS_READY), NULL, _OVER);
×
313

314
    SSdbRaw *pUndoRaw = mndFuncActionEncode(oldFunc);
×
315
    if (pUndoRaw == NULL) {
×
316
      code = TSDB_CODE_MND_RETURN_VALUE_NULL;
×
317
      if (terrno != 0) code = terrno;
×
318
      goto _OVER;
×
319
    }
320
    TAOS_CHECK_GOTO(mndTransAppendUndolog(pTrans, pUndoRaw), NULL, _OVER);
×
321
    TAOS_CHECK_GOTO(sdbSetRawStatus(pUndoRaw, SDB_STATUS_READY), NULL, _OVER);
×
322

323
    SSdbRaw *pCommitRaw = mndFuncActionEncode(&func);
×
324
    if (pCommitRaw == NULL) {
×
325
      code = TSDB_CODE_MND_RETURN_VALUE_NULL;
×
326
      if (terrno != 0) code = terrno;
×
327
      goto _OVER;
×
328
    }
329
    TAOS_CHECK_GOTO(mndTransAppendCommitlog(pTrans, pCommitRaw), NULL, _OVER);
×
330
    TAOS_CHECK_GOTO(sdbSetRawStatus(pCommitRaw, SDB_STATUS_READY), NULL, _OVER);
×
331
  } else {
332
    SSdbRaw *pRedoRaw = mndFuncActionEncode(&func);
2,104✔
333
    if (pRedoRaw == NULL) {
2,104!
334
      code = TSDB_CODE_MND_RETURN_VALUE_NULL;
×
335
      if (terrno != 0) code = terrno;
×
336
      goto _OVER;
×
337
    }
338
    TAOS_CHECK_GOTO(mndTransAppendRedolog(pTrans, pRedoRaw), NULL, _OVER);
2,104!
339
    TAOS_CHECK_GOTO(sdbSetRawStatus(pRedoRaw, SDB_STATUS_CREATING), NULL, _OVER);
2,104!
340

341
    SSdbRaw *pUndoRaw = mndFuncActionEncode(&func);
2,104✔
342
    if (pUndoRaw == NULL) {
2,104!
343
      code = TSDB_CODE_MND_RETURN_VALUE_NULL;
×
344
      if (terrno != 0) code = terrno;
×
345
      goto _OVER;
×
346
    }
347
    TAOS_CHECK_GOTO(mndTransAppendUndolog(pTrans, pUndoRaw), NULL, _OVER);
2,104!
348
    TAOS_CHECK_GOTO(sdbSetRawStatus(pUndoRaw, SDB_STATUS_DROPPED), NULL, _OVER);
2,104!
349

350
    SSdbRaw *pCommitRaw = mndFuncActionEncode(&func);
2,104✔
351
    if (pCommitRaw == NULL) {
2,104!
352
      code = TSDB_CODE_MND_RETURN_VALUE_NULL;
×
353
      if (terrno != 0) code = terrno;
×
354
      goto _OVER;
×
355
    }
356
    TAOS_CHECK_GOTO(mndTransAppendCommitlog(pTrans, pCommitRaw), NULL, _OVER);
2,104!
357
    TAOS_CHECK_GOTO(sdbSetRawStatus(pCommitRaw, SDB_STATUS_READY), NULL, _OVER);
2,104!
358
  }
359

360
  TAOS_CHECK_GOTO(mndTransPrepare(pMnode, pTrans), NULL, _OVER);
2,104!
361

362
  code = 0;
2,104✔
363

364
_OVER:
2,104✔
365
  if (oldFunc != NULL) {
2,104!
366
    mndReleaseFunc(pMnode, oldFunc);
×
367
  }
368

369
  taosMemoryFree(func.pCode);
2,104!
370
  taosMemoryFree(func.pComment);
2,104!
371
  mndTransDrop(pTrans);
2,104✔
372
  TAOS_RETURN(code);
2,104✔
373
}
374

375
static int32_t mndDropFunc(SMnode *pMnode, SRpcMsg *pReq, SFuncObj *pFunc) {
1,699✔
376
  int32_t code = -1;
1,699✔
377
  STrans *pTrans = mndTransCreate(pMnode, TRN_POLICY_ROLLBACK, TRN_CONFLICT_NOTHING, pReq, "drop-func");
1,699✔
378
  if (pTrans == NULL) {
1,699!
379
    code = TSDB_CODE_MND_RETURN_VALUE_NULL;
×
380
    if (terrno != 0) code = terrno;
×
381
    goto _OVER;
×
382
  }
383

384
  mInfo("trans:%d, used to drop user:%s", pTrans->id, pFunc->name);
1,699!
385

386
  SSdbRaw *pRedoRaw = mndFuncActionEncode(pFunc);
1,699✔
387
  if (pRedoRaw == NULL) {
1,699!
388
    code = TSDB_CODE_MND_RETURN_VALUE_NULL;
×
389
    if (terrno != 0) code = terrno;
×
390
    goto _OVER;
×
391
  }
392
  TAOS_CHECK_GOTO(mndTransAppendRedolog(pTrans, pRedoRaw), NULL, _OVER);
1,699!
393
  TAOS_CHECK_GOTO(sdbSetRawStatus(pRedoRaw, SDB_STATUS_DROPPING), NULL, _OVER);
1,699!
394

395
  SSdbRaw *pUndoRaw = mndFuncActionEncode(pFunc);
1,699✔
396
  if (pUndoRaw == NULL) {
1,699!
397
    code = TSDB_CODE_MND_RETURN_VALUE_NULL;
×
398
    if (terrno != 0) code = terrno;
×
399
    goto _OVER;
×
400
  }
401
  TAOS_CHECK_GOTO(mndTransAppendUndolog(pTrans, pUndoRaw), NULL, _OVER);
1,699!
402
  TAOS_CHECK_GOTO(sdbSetRawStatus(pUndoRaw, SDB_STATUS_READY), NULL, _OVER);
1,699!
403

404
  SSdbRaw *pCommitRaw = mndFuncActionEncode(pFunc);
1,699✔
405
  if (pCommitRaw == NULL) {
1,699!
406
    code = TSDB_CODE_MND_RETURN_VALUE_NULL;
×
407
    if (terrno != 0) code = terrno;
×
408
    goto _OVER;
×
409
  }
410
  TAOS_CHECK_GOTO(mndTransAppendCommitlog(pTrans, pCommitRaw), NULL, _OVER);
1,699!
411
  TAOS_CHECK_GOTO(sdbSetRawStatus(pCommitRaw, SDB_STATUS_DROPPED), NULL, _OVER);
1,699!
412

413
  TAOS_CHECK_GOTO(mndTransPrepare(pMnode, pTrans), NULL, _OVER);
1,699!
414

415
  code = 0;
1,699✔
416

417
_OVER:
1,699✔
418
  mndTransDrop(pTrans);
1,699✔
419
  return code;
1,699✔
420
}
421

422
static int32_t mndProcessCreateFuncReq(SRpcMsg *pReq) {
2,167✔
423
  SMnode        *pMnode = pReq->info.node;
2,167✔
424
  int32_t        code = -1;
2,167✔
425
  SFuncObj      *pFunc = NULL;
2,167✔
426
  SCreateFuncReq createReq = {0};
2,167✔
427

428
  TAOS_CHECK_GOTO(tDeserializeSCreateFuncReq(pReq->pCont, pReq->contLen, &createReq), NULL, _OVER);
2,167!
429

430
#ifdef WINDOWS
431
  code = TSDB_CODE_MND_INVALID_PLATFORM;
432
  goto _OVER;
433
#endif
434
  mInfo("func:%s, start to create, size:%d", createReq.name, createReq.codeLen);
2,167!
435
  TAOS_CHECK_GOTO(mndCheckOperPrivilege(pMnode, pReq->info.conn.user, MND_OPER_CREATE_FUNC), NULL, _OVER);
2,167!
436

437
  pFunc = mndAcquireFunc(pMnode, createReq.name);
2,167✔
438
  if (pFunc != NULL) {
2,167✔
439
    if (createReq.igExists) {
18✔
440
      mInfo("func:%s, already exist, ignore exist is set", createReq.name);
9!
441
      code = 0;
9✔
442
      goto _OVER;
9✔
443
    } else if (createReq.orReplace) {
9!
444
      mInfo("func:%s, replace function is set", createReq.name);
×
445
      code = 0;
×
446
    } else {
447
      code = TSDB_CODE_MND_FUNC_ALREADY_EXIST;
9✔
448
      goto _OVER;
9✔
449
    }
450
  } else if (terrno == TSDB_CODE_MND_FUNC_ALREADY_EXIST) {
2,149!
451
    goto _OVER;
×
452
  }
453

454
  if (createReq.name[0] == 0) {
2,149✔
455
    code = TSDB_CODE_MND_INVALID_FUNC_NAME;
9✔
456
    goto _OVER;
9✔
457
  }
458

459
  if (createReq.pCode == NULL) {
2,140✔
460
    code = TSDB_CODE_MND_INVALID_FUNC_CODE;
9✔
461
    goto _OVER;
9✔
462
  }
463

464
  if (createReq.codeLen <= 1) {
2,131✔
465
    code = TSDB_CODE_MND_INVALID_FUNC_CODE;
9✔
466
    goto _OVER;
9✔
467
  }
468

469
  if (createReq.bufSize < 0 || createReq.bufSize > TSDB_FUNC_BUF_SIZE) {
2,122✔
470
    code = TSDB_CODE_MND_INVALID_FUNC_BUFSIZE;
18✔
471
    goto _OVER;
18✔
472
  }
473

474
  code = mndCreateFunc(pMnode, pReq, &createReq);
2,104✔
475
  if (code == 0) code = TSDB_CODE_ACTION_IN_PROGRESS;
2,104!
476

477
_OVER:
2,077✔
478
  if (code != 0 && code != TSDB_CODE_ACTION_IN_PROGRESS) {
2,167✔
479
    mError("func:%s, failed to create since %s", createReq.name, tstrerror(code));
54!
480
  }
481

482
  mndReleaseFunc(pMnode, pFunc);
2,167✔
483
  tFreeSCreateFuncReq(&createReq);
2,167✔
484
  TAOS_RETURN(code);
2,167✔
485
}
486

487
static int32_t mndProcessDropFuncReq(SRpcMsg *pReq) {
1,726✔
488
  SMnode      *pMnode = pReq->info.node;
1,726✔
489
  int32_t      code = -1;
1,726✔
490
  SFuncObj    *pFunc = NULL;
1,726✔
491
  SDropFuncReq dropReq = {0};
1,726✔
492

493
  TAOS_CHECK_GOTO(tDeserializeSDropFuncReq(pReq->pCont, pReq->contLen, &dropReq), NULL, _OVER);
1,726!
494

495
  mInfo("func:%s, start to drop", dropReq.name);
1,726!
496
  TAOS_CHECK_GOTO(mndCheckOperPrivilege(pMnode, pReq->info.conn.user, MND_OPER_DROP_FUNC), NULL, _OVER);
1,726!
497

498
  if (dropReq.name[0] == 0) {
1,726✔
499
    code = TSDB_CODE_MND_INVALID_FUNC_NAME;
9✔
500
    goto _OVER;
9✔
501
  }
502

503
  pFunc = mndAcquireFunc(pMnode, dropReq.name);
1,717✔
504
  if (pFunc == NULL) {
1,717✔
505
    if (dropReq.igNotExists) {
18✔
506
      mInfo("func:%s, not exist, ignore not exist is set", dropReq.name);
9!
507
      code = 0;
9✔
508
      goto _OVER;
9✔
509
    } else {
510
      code = TSDB_CODE_MND_FUNC_NOT_EXIST;
9✔
511
      goto _OVER;
9✔
512
    }
513
  }
514

515
  code = mndDropFunc(pMnode, pReq, pFunc);
1,699✔
516
  if (code == 0) code = TSDB_CODE_ACTION_IN_PROGRESS;
1,699!
517

518
_OVER:
1,690✔
519
  if (code != 0 && code != TSDB_CODE_ACTION_IN_PROGRESS) {
1,726✔
520
    mError("func:%s, failed to drop since %s", dropReq.name, tstrerror(code));
18!
521
  }
522

523
  mndReleaseFunc(pMnode, pFunc);
1,726✔
524
  TAOS_RETURN(code);
1,726✔
525
}
526

527
static int32_t mndProcessRetrieveFuncReq(SRpcMsg *pReq) {
36,388✔
528
  SMnode          *pMnode = pReq->info.node;
36,388✔
529
  int32_t          code = -1;
36,388✔
530
  SRetrieveFuncReq retrieveReq = {0};
36,388✔
531
  SRetrieveFuncRsp retrieveRsp = {0};
36,388✔
532

533
  if (tDeserializeSRetrieveFuncReq(pReq->pCont, pReq->contLen, &retrieveReq) != 0) {
36,388!
534
    code = TSDB_CODE_INVALID_MSG;
×
535
    goto RETRIEVE_FUNC_OVER;
×
536
  }
537

538
  if (retrieveReq.numOfFuncs <= 0 || retrieveReq.numOfFuncs > TSDB_FUNC_MAX_RETRIEVE) {
36,388✔
539
    code = TSDB_CODE_MND_INVALID_FUNC_RETRIEVE;
18✔
540
    goto RETRIEVE_FUNC_OVER;
18✔
541
  }
542

543
  retrieveRsp.numOfFuncs = retrieveReq.numOfFuncs;
36,370✔
544
  retrieveRsp.pFuncInfos = taosArrayInit(retrieveReq.numOfFuncs, sizeof(SFuncInfo));
36,370✔
545
  if (retrieveRsp.pFuncInfos == NULL) {
36,370!
546
    code = terrno;
×
547
    goto RETRIEVE_FUNC_OVER;
×
548
  }
549

550
  retrieveRsp.pFuncExtraInfos = taosArrayInit(retrieveReq.numOfFuncs, sizeof(SFuncExtraInfo));
36,370✔
551
  if (retrieveRsp.pFuncExtraInfos == NULL) {
36,370!
552
    code = terrno;
×
553
    goto RETRIEVE_FUNC_OVER;
×
554
  }
555

556
  for (int32_t i = 0; i < retrieveReq.numOfFuncs; ++i) {
69,721✔
557
    char *funcName = taosArrayGet(retrieveReq.pFuncNames, i);
36,388✔
558

559
    SFuncObj *pFunc = mndAcquireFunc(pMnode, funcName);
36,388✔
560
    if (pFunc == NULL) {
36,388✔
561
      if (terrno != 0) code = terrno;
3,037!
562
      goto RETRIEVE_FUNC_OVER;
3,037✔
563
    }
564

565
    SFuncInfo funcInfo = {0};
33,351✔
566
    (void)memcpy(funcInfo.name, pFunc->name, TSDB_FUNC_NAME_LEN);
33,351✔
567
    funcInfo.funcType = pFunc->funcType;
33,351✔
568
    funcInfo.scriptType = pFunc->scriptType;
33,351✔
569
    funcInfo.outputType = pFunc->outputType;
33,351✔
570
    funcInfo.outputLen = pFunc->outputLen;
33,351✔
571
    funcInfo.bufSize = pFunc->bufSize;
33,351✔
572
    funcInfo.signature = pFunc->signature;
33,351✔
573
    if (retrieveReq.ignoreCodeComment) {
33,351!
574
      funcInfo.commentSize = 0;
28,712✔
575
      funcInfo.codeSize = 0;
28,712✔
576
    } else {
577
      funcInfo.commentSize = pFunc->commentSize;
4,639✔
578
      funcInfo.codeSize = pFunc->codeSize;
4,639✔
579
      funcInfo.pCode = taosMemoryCalloc(1, funcInfo.codeSize);
4,639!
580
      if (funcInfo.pCode == NULL) {
4,639!
581
        terrno = terrno;
×
582
        goto RETRIEVE_FUNC_OVER;
×
583
      }
584
      (void)memcpy(funcInfo.pCode, pFunc->pCode, pFunc->codeSize);
4,639!
585
      if (funcInfo.commentSize > 0) {
4,639✔
586
        funcInfo.pComment = taosMemoryCalloc(1, funcInfo.commentSize);
54!
587
        if (funcInfo.pComment == NULL) {
54!
588
          terrno = terrno;
×
589
          goto RETRIEVE_FUNC_OVER;
×
590
        }
591
        (void)memcpy(funcInfo.pComment, pFunc->pComment, pFunc->commentSize);
54!
592
      }
593
    }
594
    if (taosArrayPush(retrieveRsp.pFuncInfos, &funcInfo) == NULL) {
66,702!
595
      terrno = terrno;
×
596
      goto RETRIEVE_FUNC_OVER;
×
597
    }
598
    SFuncExtraInfo extraInfo = {0};
33,351✔
599
    extraInfo.funcVersion = pFunc->funcVersion;
33,351✔
600
    extraInfo.funcCreatedTime = pFunc->createdTime;
33,351✔
601
    if (taosArrayPush(retrieveRsp.pFuncExtraInfos, &extraInfo) == NULL) {
66,702!
602
      terrno = terrno;
×
603
      goto RETRIEVE_FUNC_OVER;
×
604
    }
605

606
    mndReleaseFunc(pMnode, pFunc);
33,351✔
607
  }
608

609
  int32_t contLen = tSerializeSRetrieveFuncRsp(NULL, 0, &retrieveRsp);
33,333✔
610
  void   *pRsp = rpcMallocCont(contLen);
33,333✔
611
  if (pRsp == NULL) {
33,333!
612
    code = terrno;
×
613
    goto RETRIEVE_FUNC_OVER;
×
614
  }
615

616
  if ((contLen = tSerializeSRetrieveFuncRsp(pRsp, contLen, &retrieveRsp)) <= 0) {
33,333!
617
    code = contLen;
×
618
    goto RETRIEVE_FUNC_OVER;
×
619
  }
620

621
  pReq->info.rsp = pRsp;
33,333✔
622
  pReq->info.rspLen = contLen;
33,333✔
623

624
  code = 0;
33,333✔
625

626
RETRIEVE_FUNC_OVER:
36,388✔
627
  tFreeSRetrieveFuncReq(&retrieveReq);
36,388✔
628
  tFreeSRetrieveFuncRsp(&retrieveRsp);
36,388✔
629

630
  TAOS_RETURN(code);
36,388✔
631
}
632

633
static void *mnodeGenTypeStr(char *buf, int32_t buflen, uint8_t type, int32_t len) {
2,122✔
634
  char *msg = "unknown";
2,122✔
635
  if (type >= sizeof(tDataTypes) / sizeof(tDataTypes[0])) {
2,122!
636
    return msg;
×
637
  }
638

639
  if (type == TSDB_DATA_TYPE_NCHAR || type == TSDB_DATA_TYPE_VARBINARY || type == TSDB_DATA_TYPE_BINARY ||
2,122!
640
      type == TSDB_DATA_TYPE_GEOMETRY) {
641
    int32_t bytes = len > 0 ? (int32_t)(len - VARSTR_HEADER_SIZE) : len;
27!
642

643
    (void)snprintf(buf, buflen - 1, "%s(%d)", tDataTypes[type].name, type == TSDB_DATA_TYPE_NCHAR ? bytes / 4 : bytes);
27!
644
    buf[buflen - 1] = 0;
27✔
645

646
    return buf;
27✔
647
  }
648

649
  return tDataTypes[type].name;
2,095✔
650
}
651

652
static int32_t mndRetrieveFuncs(SRpcMsg *pReq, SShowObj *pShow, SSDataBlock *pBlock, int32_t rows) {
11,277✔
653
  SMnode   *pMnode = pReq->info.node;
11,277✔
654
  SSdb     *pSdb = pMnode->pSdb;
11,277✔
655
  int32_t   numOfRows = 0;
11,277✔
656
  SFuncObj *pFunc = NULL;
11,277✔
657
  int32_t   cols = 0;
11,277✔
658
  int32_t   code = 0;
11,277✔
659
  char      buf[TSDB_TYPE_STR_MAX_LEN];
11,232✔
660

661
  while (numOfRows < rows) {
13,399!
662
    pShow->pIter = sdbFetch(pSdb, SDB_FUNC, pShow->pIter, (void **)&pFunc);
13,399✔
663
    if (pShow->pIter == NULL) break;
13,399✔
664

665
    cols = 0;
2,122✔
666

667
    char b1[tListLen(pFunc->name) + VARSTR_HEADER_SIZE] = {0};
2,122✔
668
    STR_WITH_MAXSIZE_TO_VARSTR(b1, pFunc->name, pShow->pMeta->pSchemas[cols].bytes);
2,122!
669

670
    SColumnInfoData *pColInfo = taosArrayGet(pBlock->pDataBlock, cols++);
2,122✔
671
    TAOS_CHECK_RETURN_WITH_RELEASE(colDataSetVal(pColInfo, numOfRows, (const char *)b1, false), pSdb, pFunc);
2,122!
672

673
    if (pFunc->pComment) {
2,122✔
674
      char *b2 = taosMemoryCalloc(1, pShow->pMeta->pSchemas[cols].bytes);
45!
675
      STR_WITH_MAXSIZE_TO_VARSTR(b2, pFunc->pComment, pShow->pMeta->pSchemas[cols].bytes);
45!
676

677
      pColInfo = taosArrayGet(pBlock->pDataBlock, cols++);
45✔
678
      code = colDataSetVal(pColInfo, numOfRows, (const char *)b2, false);
45✔
679
      if (code != 0) {
45!
680
        sdbRelease(pSdb, pFunc);
×
681
        taosMemoryFree(b2);
×
682
        TAOS_RETURN(code);
×
683
      }
684
      taosMemoryFree(b2);
45!
685
    } else {
686
      pColInfo = taosArrayGet(pBlock->pDataBlock, cols++);
2,077✔
687
      TAOS_CHECK_RETURN_WITH_RELEASE(colDataSetVal(pColInfo, numOfRows, NULL, true), pSdb, pFunc);
2,077!
688
      if (code != 0) {
2,077!
689
        sdbRelease(pSdb, pFunc);
×
690
        TAOS_RETURN(code);
×
691
      }
692
    }
693

694
    int32_t isAgg = (pFunc->funcType == TSDB_FUNC_TYPE_AGGREGATE) ? 1 : 0;
2,122✔
695

696
    pColInfo = taosArrayGet(pBlock->pDataBlock, cols++);
2,122✔
697
    TAOS_CHECK_RETURN_WITH_RELEASE(colDataSetVal(pColInfo, numOfRows, (const char *)&isAgg, false), pSdb, pFunc);
2,122!
698
    char b3[TSDB_TYPE_STR_MAX_LEN + 1] = {0};
2,122✔
699
    STR_WITH_MAXSIZE_TO_VARSTR(b3, mnodeGenTypeStr(buf, TSDB_TYPE_STR_MAX_LEN, pFunc->outputType, pFunc->outputLen),
2,122!
700
                               pShow->pMeta->pSchemas[cols].bytes);
701

702
    pColInfo = taosArrayGet(pBlock->pDataBlock, cols++);
2,122✔
703
    TAOS_CHECK_RETURN_WITH_RELEASE(colDataSetVal(pColInfo, numOfRows, (const char *)b3, false), pSdb, pFunc);
2,122!
704

705
    pColInfo = taosArrayGet(pBlock->pDataBlock, cols++);
2,122✔
706
    TAOS_CHECK_RETURN_WITH_RELEASE(colDataSetVal(pColInfo, numOfRows, (const char *)&pFunc->createdTime, false), pSdb,
2,122!
707
                                   pFunc);
708

709
    pColInfo = taosArrayGet(pBlock->pDataBlock, cols++);
2,122✔
710
    TAOS_CHECK_RETURN_WITH_RELEASE(colDataSetVal(pColInfo, numOfRows, (const char *)&pFunc->codeSize, false), pSdb,
2,122!
711
                                   pFunc);
712

713
    pColInfo = taosArrayGet(pBlock->pDataBlock, cols++);
2,122✔
714
    TAOS_CHECK_RETURN_WITH_RELEASE(colDataSetVal(pColInfo, numOfRows, (const char *)&pFunc->bufSize, false), pSdb,
2,122!
715
                                   pFunc);
716

717
    pColInfo = taosArrayGet(pBlock->pDataBlock, cols++);
2,122✔
718
    char *language = "";
2,122✔
719
    if (pFunc->scriptType == TSDB_FUNC_SCRIPT_BIN_LIB) {
2,122✔
720
      language = "C";
2,077✔
721
    } else if (pFunc->scriptType == TSDB_FUNC_SCRIPT_PYTHON) {
45!
722
      language = "Python";
×
723
    }
724
    char varLang[TSDB_TYPE_STR_MAX_LEN + 1] = {0};
2,122✔
725
    varDataSetLen(varLang, strlen(language));
2,122!
726
    tstrncpy(varDataVal(varLang), language, sizeof(varLang) - VARSTR_HEADER_SIZE);
2,122!
727
    TAOS_CHECK_RETURN_WITH_RELEASE(colDataSetVal(pColInfo, numOfRows, (const char *)varLang, false), pSdb, pFunc);
2,122!
728

729
    pColInfo = taosArrayGet(pBlock->pDataBlock, cols++);
2,122✔
730
    int32_t varCodeLen = (pFunc->codeSize + VARSTR_HEADER_SIZE) > TSDB_MAX_BINARY_LEN
2,122✔
731
                             ? TSDB_MAX_BINARY_LEN
732
                             : pFunc->codeSize + VARSTR_HEADER_SIZE;
2,122✔
733
    char   *b4 = taosMemoryMalloc(varCodeLen);
2,122!
734
    if (b4 == NULL) {
2,122!
735
      code = terrno;
×
736
      sdbRelease(pSdb, pFunc);
×
737
      TAOS_RETURN(code);
×
738
    }
739
    (void)memcpy(varDataVal(b4), pFunc->pCode, varCodeLen - VARSTR_HEADER_SIZE);
2,122!
740
    varDataSetLen(b4, varCodeLen - VARSTR_HEADER_SIZE);
2,122✔
741
    code = colDataSetVal(pColInfo, numOfRows, (const char *)b4, false);
2,122✔
742
    if (code < 0) {
2,122!
743
      sdbRelease(pSdb, pFunc);
×
744
      taosMemoryFree(b4);
×
745
      TAOS_RETURN(code);
×
746
    }
747
    taosMemoryFree(b4);
2,122!
748

749
    pColInfo = taosArrayGet(pBlock->pDataBlock, cols++);
2,122✔
750
    TAOS_CHECK_RETURN_WITH_RELEASE(colDataSetVal(pColInfo, numOfRows, (const char *)&pFunc->funcVersion, false), pSdb,
2,122!
751
                                   pFunc);
752

753
    numOfRows++;
2,122✔
754
    sdbRelease(pSdb, pFunc);
2,122✔
755
  }
756

757
  pShow->numOfRows += numOfRows;
11,277✔
758
  return numOfRows;
11,277✔
759
}
760

761
static void mndCancelGetNextFunc(SMnode *pMnode, void *pIter) {
×
762
  SSdb *pSdb = pMnode->pSdb;
×
763
  sdbCancelFetchByType(pSdb, pIter, SDB_FUNC);
×
764
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc