Coverage Report

Created: 2025-11-05 06:27

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/tarantool/src/box/func_def.c
Line
Count
Source
1
/*
2
 * Copyright 2010-2019, Tarantool AUTHORS, please see AUTHORS file.
3
 *
4
 * Redistribution and use in source and binary forms, with or
5
 * without modification, are permitted provided that the following
6
 * conditions are met:
7
 *
8
 * 1. Redistributions of source code must retain the above
9
 *    copyright notice, this list of conditions and the
10
 *    following disclaimer.
11
 *
12
 * 2. Redistributions in binary form must reproduce the above
13
 *    copyright notice, this list of conditions and the following
14
 *    disclaimer in the documentation and/or other materials
15
 *    provided with the distribution.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21
 * <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
22
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
25
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
28
 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29
 * SUCH DAMAGE.
30
 */
31
#include "func_def.h"
32
#include "opt_def.h"
33
#include "string.h"
34
#include "diag.h"
35
#include "error.h"
36
#include "salad/grp_alloc.h"
37
#include "trivia/util.h"
38
39
#include <assert.h>
40
#include <stdint.h>
41
#include <stddef.h>
42
#include <stdlib.h>
43
44
const char *func_language_strs[] = {
45
  "LUA", "C", "SQL", "SQL_BUILTIN", "SQL_EXPR"
46
};
47
48
const char *func_aggregate_strs[] = {"none", "group"};
49
50
const struct func_opts func_opts_default = {
51
  /* .is_multikey = */ false,
52
  /* .takes_raw_args = */ false,
53
};
54
55
const struct opt_def func_opts_reg[] = {
56
  OPT_DEF("is_multikey", OPT_BOOL, struct func_opts, is_multikey),
57
  OPT_DEF("takes_raw_args", OPT_BOOL, struct func_opts, takes_raw_args),
58
  OPT_END,
59
};
60
61
struct func_def *
62
func_def_new(uint32_t fid, uint32_t uid, const char *name, uint32_t name_len,
63
       enum func_language language, const char *body, uint32_t body_len,
64
       const char *comment, uint32_t comment_len, const char *triggers)
65
212
{
66
212
  struct func_def *def;
67
212
  struct grp_alloc all = grp_alloc_initializer();
68
212
  grp_alloc_reserve_data(&all, sizeof(*def));
69
212
  grp_alloc_reserve_str(&all, name_len);
70
212
  if (body_len != 0)
71
0
    grp_alloc_reserve_str(&all, body_len);
72
212
  if (comment_len != 0)
73
0
    grp_alloc_reserve_str(&all, comment_len);
74
212
  size_t triggers_len = 0;
75
212
  if (triggers != NULL) {
76
0
    const char *triggers_end = triggers;
77
0
    mp_next(&triggers_end);
78
0
    triggers_len = triggers_end - triggers;
79
0
    grp_alloc_reserve_data(&all, triggers_len);
80
0
  }
81
212
  grp_alloc_use(&all, xmalloc(grp_alloc_size(&all)));
82
212
  def = grp_alloc_create_data(&all, sizeof(*def));
83
212
  def->name = grp_alloc_create_str(&all, name, name_len);
84
212
  def->name_len = name_len;
85
212
  def->body = body_len == 0 ? NULL :
86
212
        grp_alloc_create_str(&all, body, body_len);
87
212
  def->comment = comment_len == 0 ? NULL :
88
212
           grp_alloc_create_str(&all, comment, comment_len);
89
212
  def->triggers = NULL;
90
212
  if (triggers != NULL) {
91
0
    def->triggers = grp_alloc_create_data(&all, triggers_len);
92
0
    memcpy(def->triggers, triggers, triggers_len);
93
0
  }
94
212
  assert(grp_alloc_size(&all) == 0);
95
212
  def->fid = fid;
96
212
  def->uid = uid;
97
212
  def->setuid = false;
98
212
  def->is_deterministic = false;
99
212
  def->is_sandboxed = false;
100
212
  def->param_count = 0;
101
212
  def->returns = FIELD_TYPE_ANY;
102
212
  def->aggregate = FUNC_AGGREGATE_NONE;
103
212
  def->language = language;
104
212
  def->exports.all = 0;
105
212
  func_opts_create(&def->opts);
106
212
  return def;
107
212
}
108
109
void
110
func_def_delete(struct func_def *def)
111
0
{
112
0
  free(def);
113
0
}
114
115
static int
116
func_opts_cmp(const struct func_opts *o1, const struct func_opts *o2)
117
0
{
118
0
  if (o1->is_multikey != o2->is_multikey)
119
0
    return o1->is_multikey - o2->is_multikey;
120
0
  if (o1->takes_raw_args != o2->takes_raw_args)
121
0
    return o1->takes_raw_args - o2->takes_raw_args;
122
0
  return 0;
123
0
}
124
125
int
126
func_def_cmp(const struct func_def *def1, const struct func_def *def2)
127
0
{
128
0
  if (def1->fid != def2->fid)
129
0
    return def1->fid - def2->fid;
130
0
  if (def1->uid != def2->uid)
131
0
    return def1->uid - def2->uid;
132
0
  if (def1->setuid != def2->setuid)
133
0
    return def1->setuid - def2->setuid;
134
0
  if (def1->language != def2->language)
135
0
    return def1->language - def2->language;
136
0
  if (def1->is_deterministic != def2->is_deterministic)
137
0
    return def1->is_deterministic - def2->is_deterministic;
138
0
  if (def1->is_sandboxed != def2->is_sandboxed)
139
0
    return def1->is_sandboxed - def2->is_sandboxed;
140
0
  if (strcmp(def1->name, def2->name) != 0)
141
0
    return strcmp(def1->name, def2->name);
142
0
  if ((def1->body != NULL) != (def2->body != NULL))
143
0
    return def1->body - def2->body;
144
0
  if (def1->body != NULL && strcmp(def1->body, def2->body) != 0)
145
0
    return strcmp(def1->body, def2->body);
146
0
  if (def1->returns != def2->returns)
147
0
    return def1->returns - def2->returns;
148
0
  if (def1->exports.all != def2->exports.all)
149
0
    return def1->exports.all - def2->exports.all;
150
0
  if (def1->aggregate != def2->aggregate)
151
0
    return def1->aggregate - def2->aggregate;
152
0
  if (def1->param_count != def2->param_count)
153
0
    return def1->param_count - def2->param_count;
154
0
  if ((def1->comment != NULL) != (def2->comment != NULL))
155
0
    return def1->comment - def2->comment;
156
0
  if (def1->comment != NULL && strcmp(def1->comment, def2->comment) != 0)
157
0
    return strcmp(def1->comment, def2->comment);
158
0
  if ((def1->triggers != NULL) != (def2->triggers != NULL))
159
0
    return def1->triggers - def2->triggers;
160
0
  if (def1->triggers != NULL) {
161
0
    const char *triggers1_end = def1->triggers;
162
0
    mp_next(&triggers1_end);
163
0
    const char *triggers2_end = def2->triggers;
164
0
    mp_next(&triggers2_end);
165
0
    size_t triggers1_len = triggers1_end - def1->triggers;
166
0
    size_t triggers2_len = triggers2_end - def2->triggers;
167
0
    if (triggers1_len != triggers2_len)
168
0
      return triggers1_len - triggers2_len;
169
0
    int cmp_res = memcmp(def1->triggers, def2->triggers,
170
0
             triggers1_len);
171
0
    if (cmp_res != 0)
172
0
      return cmp_res;
173
0
  }
174
0
  return func_opts_cmp(&def1->opts, &def2->opts);
175
0
}
176
177
struct func_def *
178
func_def_dup(const struct func_def *def)
179
0
{
180
0
  struct func_def *copy = func_def_new(
181
0
    def->fid, def->uid, def->name, def->name_len, def->language,
182
0
    def->body, def->body != NULL ? strlen(def->body) : 0,
183
0
    def->comment, def->comment != NULL ? strlen(def->comment) : 0,
184
0
    def->triggers);
185
0
  copy->setuid = def->setuid;
186
0
  copy->is_deterministic = def->is_deterministic;
187
0
  copy->is_sandboxed = def->is_sandboxed;
188
0
  copy->param_count = def->param_count;
189
0
  copy->returns = def->returns;
190
0
  copy->aggregate = def->aggregate;
191
0
  copy->exports.all = def->exports.all;
192
0
  copy->opts = def->opts;
193
0
  return copy;
194
0
}
195
196
/**
197
 * Check if a function definition is valid.
198
 * @retval  0 the definition is correct
199
 * @retval -1 the definition has incompatible options set,
200
 *            diagnostics message is provided
201
 */
202
int
203
func_def_check(const struct func_def *def)
204
0
{
205
0
  switch (def->language) {
206
0
  case FUNC_LANGUAGE_C:
207
0
    if (def->body != NULL || def->is_sandboxed) {
208
0
      diag_set(ClientError, ER_CREATE_FUNCTION, def->name,
209
0
         "body and is_sandboxed options are not compatible "
210
0
         "with C language");
211
0
      return -1;
212
0
    }
213
0
    break;
214
0
  case FUNC_LANGUAGE_LUA:
215
0
    if (def->is_sandboxed && def->body == NULL) {
216
0
      diag_set(ClientError, ER_CREATE_FUNCTION, def->name,
217
0
         "is_sandboxed option may be set only for a persistent "
218
0
         "Lua function (one with a non-empty body)");
219
0
      return -1;
220
0
    }
221
0
    break;
222
0
  default:
223
0
    break;
224
0
  }
225
0
  return 0;
226
0
}