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

taosdata / TDengine / #3814

01 Apr 2025 05:36AM UTC coverage: 30.169% (-3.6%) from 33.798%
#3814

push

travis-ci

happyguoxy
test:add build cmake

129680 of 592945 branches covered (21.87%)

Branch coverage included in aggregate %.

196213 of 487270 relevant lines covered (40.27%)

555639.42 hits per line

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

65.28
/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) {
31✔
41
  SSdbTable table = {
31✔
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);
31✔
52
  mndSetMsgHandle(pMnode, TDMT_MND_DROP_FUNC, mndProcessDropFuncReq);
31✔
53
  mndSetMsgHandle(pMnode, TDMT_MND_RETRIEVE_FUNC, mndProcessRetrieveFuncReq);
31✔
54

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

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

61
void mndCleanupFunc(SMnode *pMnode) {}
28✔
62

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

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

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

92
  terrno = 0;
190✔
93

94
_OVER:
190✔
95
  if (terrno != 0) {
190!
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);
190✔
102
  return pRaw;
190✔
103
}
104

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

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

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

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

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

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

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

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

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

157
  SDB_GET_RESERVE(pRaw, dataPos, SDB_FUNC_RESERVE_SIZE, _OVER)
120!
158

159
  taosInitRWLatch(&pFunc->lock);
120✔
160

161
  terrno = 0;
120✔
162

163
_OVER:
120✔
164
  if (terrno != 0) {
120!
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);
120✔
171
  return pRow;
120✔
172
}
173

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

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

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

190
  taosWLockLatch(&pOld->lock);
60✔
191

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

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

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

232
  pOld->scriptType = pNew->scriptType;
60✔
233
  pOld->signature = pNew->signature;
60✔
234

235
  taosWUnLockLatch(&pOld->lock);
60✔
236

237
  return 0;
60✔
238
}
239

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

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

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

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

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

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

292
  pTrans = mndTransCreate(pMnode, TRN_POLICY_ROLLBACK, TRN_CONFLICT_NOTHING, pReq, "create-func");
35✔
293
  if (pTrans == NULL) {
35!
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);
35!
299

300
  SFuncObj *oldFunc = mndAcquireFunc(pMnode, pCreate->name);
35✔
301
  if (pCreate->orReplace == 1 && oldFunc != NULL) {
35!
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);
35✔
333
    if (pRedoRaw == NULL) {
35!
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);
35!
339
    TAOS_CHECK_GOTO(sdbSetRawStatus(pRedoRaw, SDB_STATUS_CREATING), NULL, _OVER);
35!
340

341
    SSdbRaw *pUndoRaw = mndFuncActionEncode(&func);
35✔
342
    if (pUndoRaw == NULL) {
35!
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);
35!
348
    TAOS_CHECK_GOTO(sdbSetRawStatus(pUndoRaw, SDB_STATUS_DROPPED), NULL, _OVER);
35!
349

350
    SSdbRaw *pCommitRaw = mndFuncActionEncode(&func);
35✔
351
    if (pCommitRaw == NULL) {
35!
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);
35!
357
    TAOS_CHECK_GOTO(sdbSetRawStatus(pCommitRaw, SDB_STATUS_READY), NULL, _OVER);
35!
358
  }
359

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

362
  code = 0;
35✔
363

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

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

375
static int32_t mndDropFunc(SMnode *pMnode, SRpcMsg *pReq, SFuncObj *pFunc) {
25✔
376
  int32_t code = -1;
25✔
377
  STrans *pTrans = mndTransCreate(pMnode, TRN_POLICY_ROLLBACK, TRN_CONFLICT_NOTHING, pReq, "drop-func");
25✔
378
  if (pTrans == NULL) {
25!
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);
25!
385

386
  SSdbRaw *pRedoRaw = mndFuncActionEncode(pFunc);
25✔
387
  if (pRedoRaw == NULL) {
25!
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);
25!
393
  TAOS_CHECK_GOTO(sdbSetRawStatus(pRedoRaw, SDB_STATUS_DROPPING), NULL, _OVER);
25!
394

395
  SSdbRaw *pUndoRaw = mndFuncActionEncode(pFunc);
25✔
396
  if (pUndoRaw == NULL) {
25!
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);
25!
402
  TAOS_CHECK_GOTO(sdbSetRawStatus(pUndoRaw, SDB_STATUS_READY), NULL, _OVER);
25!
403

404
  SSdbRaw *pCommitRaw = mndFuncActionEncode(pFunc);
25✔
405
  if (pCommitRaw == NULL) {
25!
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);
25!
411
  TAOS_CHECK_GOTO(sdbSetRawStatus(pCommitRaw, SDB_STATUS_DROPPED), NULL, _OVER);
25!
412

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

415
  code = 0;
25✔
416

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

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

428
  TAOS_CHECK_GOTO(tDeserializeSCreateFuncReq(pReq->pCont, pReq->contLen, &createReq), NULL, _OVER);
42!
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);
42!
435
  TAOS_CHECK_GOTO(mndCheckOperPrivilege(pMnode, pReq->info.conn.user, MND_OPER_CREATE_FUNC), NULL, _OVER);
42!
436

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

454
  if (createReq.name[0] == 0) {
40✔
455
    code = TSDB_CODE_MND_INVALID_FUNC_NAME;
1✔
456
    goto _OVER;
1✔
457
  }
458

459
  if (createReq.pCode == NULL) {
39✔
460
    code = TSDB_CODE_MND_INVALID_FUNC_CODE;
1✔
461
    goto _OVER;
1✔
462
  }
463

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

556
  for (int32_t i = 0; i < retrieveReq.numOfFuncs; ++i) {
1,056✔
557
    char *funcName = taosArrayGet(retrieveReq.pFuncNames, i);
530✔
558

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

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

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

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

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

621
  pReq->info.rsp = pRsp;
526✔
622
  pReq->info.rspLen = contLen;
526✔
623

624
  code = 0;
526✔
625

626
RETRIEVE_FUNC_OVER:
530✔
627
  tFreeSRetrieveFuncReq(&retrieveReq);
530✔
628
  tFreeSRetrieveFuncRsp(&retrieveRsp);
530✔
629

630
  TAOS_RETURN(code);
530✔
631
}
632

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

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

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

646
    return buf;
3✔
647
  }
648

649
  return tDataTypes[type].name;
28✔
650
}
651

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

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

665
    cols = 0;
31✔
666

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

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

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

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

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

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

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

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

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

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

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

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

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

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

757
  pShow->numOfRows += numOfRows;
27✔
758
  return numOfRows;
27✔
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