Line data Source code
1 : /*
2 : * SPDX-License-Identifier: MPL-2.0
3 : *
4 : * This Source Code Form is subject to the terms of the Mozilla Public
5 : * License, v. 2.0. If a copy of the MPL was not distributed with this
6 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 : *
8 : * Copyright 2024 MonetDB Foundation;
9 : * Copyright August 2008 - 2023 MonetDB B.V.;
10 : * Copyright 1997 - July 2008 CWI.
11 : */
12 :
13 : /* Author(s) M.L. Kersten, N. Nes
14 : * This module takes the statically defined modules, atoms, commands and patterns
15 : * and populate the internal structures.
16 : *
17 : */
18 :
19 : #include "monetdb_config.h"
20 : #include "mal_import.h"
21 : #include "mal_interpreter.h" /* for showErrors() */
22 : #include "mal_linker.h" /* for loadModuleLibrary() */
23 : #include "mal_scenario.h"
24 : #include "mal_parser.h"
25 : #include "mal_authorize.h"
26 : #include "mal_private.h"
27 : #include "mutils.h"
28 :
29 : #include "mal_prelude.h"
30 :
31 : #define MAX_MAL_MODULES 128
32 : static int mel_modules = 0, mel_modules_loaded = 0;
33 : static struct mel_module {
34 : const char *name;
35 : mel_atom *atoms;
36 : mel_func *funcs;
37 : mel_init inits;
38 : const char *code;
39 : } mel_module[MAX_MAL_MODULES];
40 :
41 : int
42 330 : mal_startup(void)
43 : {
44 : /* clean up the MAL internal structures before restart */
45 330 : mel_modules_loaded = 0;
46 330 : return 0;
47 : }
48 :
49 : /* all MAL related functions register themselves
50 : * the order in which these registrations happen is significant
51 : * because there may be dependencies among the definitions.
52 : * For example, you better know the atoms before you use them
53 : */
54 :
55 : void
56 3237 : mal_module2(const char *name, mel_atom *atoms, mel_func *funcs,
57 : mel_init initfunc, const char *code)
58 : {
59 3237 : assert(mel_modules < MAX_MAL_MODULES);
60 3237 : mel_module[mel_modules].name = name;
61 3237 : mel_module[mel_modules].atoms = atoms;
62 3237 : mel_module[mel_modules].funcs = funcs;
63 3237 : mel_module[mel_modules].inits = initfunc;
64 3237 : mel_module[mel_modules].code = code;
65 3237 : mel_modules++;
66 3237 : }
67 :
68 : void
69 14845 : mal_module(const char *name, mel_atom *atoms, mel_func *funcs)
70 : {
71 14845 : assert(mel_modules < MAX_MAL_MODULES);
72 14845 : mel_module[mel_modules].name = name;
73 14845 : mel_module[mel_modules].atoms = atoms;
74 14845 : mel_module[mel_modules].funcs = funcs;
75 14845 : mel_module[mel_modules].inits = NULL;
76 14845 : mel_module[mel_modules].code = NULL;
77 14845 : mel_modules++;
78 14845 : }
79 :
80 : static char *
81 15465 : initModule(Client c, const char *name, const char *initpasswd)
82 : {
83 15465 : char *msg = MAL_SUCCEED;
84 :
85 15465 : if (!getName(name))
86 : return msg;
87 15465 : if ((name = putName(name)) == NULL)
88 0 : throw(LOADER, __func__, SQLSTATE(HY013) MAL_MALLOC_FAIL);
89 15465 : Module m = getModule(name);
90 15465 : if (m) { /* run prelude */
91 12495 : const char *prelude = putName("prelude");
92 12495 : if (prelude == NULL)
93 0 : throw(LOADER, __func__, SQLSTATE(HY013) MAL_MALLOC_FAIL);
94 12495 : Symbol s = findSymbolInModule(m, prelude);
95 :
96 12495 : if (s) {
97 658 : if (s && s->kind == COMMANDsymbol && s->func && s->func->argc == 1) {
98 0 : int ret = 0;
99 :
100 0 : assert(s->func != NULL);
101 0 : msg = (*(str (*)(int *)) s->func->imp) (&ret);
102 0 : (void) ret;
103 658 : } else if (s && s->kind == PATTERNsymbol) {
104 658 : void *mb = NULL;
105 658 : assert(s->func->fcn != NULL);
106 658 : if (strcmp(name, "sql") == 0) {
107 : /* HACK ALERT: temporarily use sqlcontext to pass
108 : * the initial password to the prelude function */
109 330 : assert(c->sqlcontext == NULL);
110 330 : c->sqlcontext = (void *) initpasswd;
111 : /* HACK ALERT: use mb (MalBlkPtr) to pass revision
112 : * string in order to check that in the callee */
113 330 : mb = (void *) mercurial_revision();
114 : }
115 658 : msg = (*(str (*)(Client, MalBlkPtr, MalStkPtr, InstrPtr)) s->func->pimp) (c, mb, NULL, NULL);
116 : }
117 : }
118 : }
119 : return msg;
120 : }
121 :
122 : /*
123 : * The statically description of the MAL structures call for a translation into
124 : * their underlying structure.
125 : */
126 : static str
127 2958 : addAtom(mel_atom *atoms)
128 : {
129 6882 : for (; atoms && atoms->name[0]; atoms++) {
130 3924 : int i = ATOMallocate(atoms->name);
131 3924 : if (is_int_nil(i))
132 0 : throw(TYPE, __func__, GDK_EXCEPTION);
133 3924 : if (atoms->basetype[0]) {
134 2958 : int tpe = ATOMindex(atoms->basetype);
135 2958 : if (tpe < 0)
136 0 : throw(TYPE, __func__, TYPE_NOT_SUPPORTED);
137 2958 : BATatoms[i] = BATatoms[tpe];
138 2958 : strcpy_len(BATatoms[i].name, atoms->name, sizeof(BATatoms[i].name));
139 2958 : BATatoms[i].storage = ATOMstorage(tpe);
140 : } else { /* cannot overload void atoms */
141 966 : BATatoms[i].storage = i;
142 966 : BATatoms[i].linear = false;
143 : }
144 3924 : if (atoms->del)
145 636 : BATatoms[i].atomDel = atoms->del;
146 3924 : if (atoms->cmp) {
147 1284 : BATatoms[i].atomCmp = atoms->cmp;
148 1284 : BATatoms[i].linear = true;
149 : }
150 3924 : if (atoms->fromstr)
151 2934 : BATatoms[i].atomFromStr = atoms->fromstr;
152 3924 : if (atoms->tostr)
153 2934 : BATatoms[i].atomToStr = atoms->tostr;
154 3924 : if (atoms->heap) {
155 636 : BATatoms[i].size = sizeof(var_t);
156 636 : assert_shift_width(ATOMelmshift(ATOMsize(i)), ATOMsize(i));
157 636 : BATatoms[i].atomHeap = atoms->heap;
158 : }
159 3924 : if (atoms->hash)
160 954 : BATatoms[i].atomHash = atoms->hash;
161 3924 : if (atoms->length)
162 636 : BATatoms[i].atomLen = atoms->length;
163 3924 : if (atoms->null) {
164 1284 : const void *atmnull = (*atoms->null) ();
165 :
166 1284 : BATatoms[i].atomNull = atmnull;
167 : }
168 3924 : if (atoms->nequal)
169 0 : BATatoms[i].atomCmp = atoms->nequal;
170 3924 : if (atoms->put)
171 636 : BATatoms[i].atomPut = atoms->put;
172 3924 : if (atoms->storage)
173 0 : BATatoms[i].storage = (*atoms->storage) ();
174 3924 : if (atoms->read)
175 954 : BATatoms[i].atomRead = atoms->read;
176 3924 : if (atoms->write)
177 954 : BATatoms[i].atomWrite = atoms->write;
178 : }
179 : return MAL_SUCCEED;
180 : }
181 :
182 : static malType
183 12861222 : makeMalType(mel_arg *a)
184 : {
185 12861222 : malType tpe = TYPE_any;
186 :
187 12861222 : if (!a->type[0]) {
188 418094 : a->typeid = tpe;
189 418094 : if (a->isbat)
190 330326 : tpe = newBatType(tpe);
191 418094 : if (a->nr > 0)
192 385106 : setTypeIndex(tpe, a->nr);
193 : } else {
194 12443128 : tpe = getAtomIndex(a->type, strlen(a->type), -1);
195 12443128 : a->typeid = tpe;
196 12443128 : if (a->isbat)
197 7438059 : tpe = newBatType(tpe);
198 : }
199 12861222 : if (a->opt == 1)
200 155760 : setOptBat(tpe);
201 12861222 : return tpe;
202 : }
203 :
204 : void
205 743148 : setPoly(mel_func *f, malType tpe)
206 : {
207 728322 : int any = isAnyExpression(tpe) || tpe == TYPE_any || getOptBat(tpe);
208 1281390 : unsigned int index = 0;
209 : if (!any)
210 : return;
211 553068 : if (getTypeIndex(tpe) > 0)
212 : index = getTypeIndex(tpe);
213 538242 : if (any && (index + 1) > f->poly)
214 306592 : f->poly = index + 1;
215 : }
216 :
217 : static str
218 18435 : addFunctions(mel_func *fcn)
219 : {
220 18435 : str msg = MAL_SUCCEED;
221 18435 : Module c;
222 18435 : Symbol s;
223 :
224 1731771 : for (; fcn && fcn->mod; fcn++) {
225 1713336 : const char *mod = fcn->mod = putName(fcn->mod);
226 1713336 : fcn->fcn = putName(fcn->fcn);
227 1713336 : if (mod == NULL)
228 0 : throw(LOADER, __func__, SQLSTATE(HY013) MAL_MALLOC_FAIL);
229 1713336 : c = getModule(mod);
230 1713336 : if (c == NULL && (c = globalModule(mod)) == NULL)
231 0 : throw(LOADER, __func__, "Module %s can not be created", fcn->mod);
232 :
233 2895808 : s = newSymbol(fcn->fcn, (fcn->command) ? COMMANDsymbol : PATTERNsymbol);
234 1713336 : if (s == NULL)
235 0 : throw(LOADER, __func__, "Can not create symbol for %s.%s missing", fcn->mod,
236 : fcn->fcn);
237 1713336 : s->def = NULL;
238 1713336 : s->func = fcn;
239 1713336 : s->allocated = false;
240 :
241 : /* add the return variables */
242 1713336 : unsigned int i;
243 3532024 : for (i = 0; i < fcn->retc; i++) {
244 1818688 : mel_arg *a = fcn->args + i;
245 1818688 : malType tpe = makeMalType(a);
246 1818688 : if (a->nr > 0 || a->opt)
247 57110 : setPoly(fcn, tpe);
248 1818688 : if (a->vargs) {
249 3136 : fcn->vrets = true;
250 3136 : setPoly(fcn, TYPE_any);
251 : }
252 1818688 : if (a->opt && fcn->command)
253 0 : throw(LOADER, __func__, "Can not have command symbol with dynamic types, ie bat vs scalar in %s.%s", fcn->mod, fcn->fcn);
254 : /*
255 : if (a->nr >= 2)
256 : printf("%s.%s\n", fcn->mod, fcn->fcn);
257 : */
258 : }
259 : /* add the arguments */
260 6166430 : for (i = fcn->retc; i < fcn->argc; i++) {
261 4453094 : mel_arg *a = fcn->args + i;
262 4453094 : malType tpe = makeMalType(a);
263 :
264 4453094 : if (a->nr > 0 || a->opt)
265 449436 : setPoly(fcn, tpe);
266 4453094 : if (a->vargs) {
267 11690 : fcn->vargs = true;
268 11690 : setPoly(fcn, TYPE_any);
269 : }
270 4453094 : if (a->opt && fcn->command)
271 0 : throw(LOADER, __func__, "Can not have command symbol with dynamic types, ie bat vs scalar in %s.%s", fcn->mod, fcn->fcn);
272 : /*
273 : if (a->nr >= 2)
274 : printf("%s.%s\n", fcn->mod, fcn->fcn);
275 : */
276 : }
277 1713336 : insertSymbol(c, s);
278 : }
279 : return msg;
280 : }
281 :
282 : static void
283 6589440 : argCopy( mel_arg *ap, mel_func_arg *a)
284 : {
285 6589440 : ap->typeid = a->type;
286 6589440 : ap->nr = a->nr;
287 6589440 : ap->isbat = a->isbat;
288 6589440 : ap->vargs = a->vargs;
289 6589440 : ap->opt = a->opt;
290 6589440 : if (a->type != TYPE_any)
291 6557100 : strcpy(ap->type, BATatoms[a->type].name);
292 : else
293 32340 : ap->type[0] = 0;
294 6589440 : }
295 :
296 : int
297 1643070 : melFunction(bool command, const char *mod, const char *fcn, MALfcn imp,
298 : const char *fname, bool unsafe, const char *comment, int retc,
299 : int argc, ...)
300 : {
301 1643070 : int i;
302 1643070 : Module c;
303 1643070 : Symbol s;
304 1643070 : mel_func *f = NULL;
305 1643070 : va_list va;
306 :
307 1643070 : assert(mod && fcn);
308 1643070 : mod = putName(mod);
309 1643070 : fcn = putName(fcn);
310 1643070 : c = getModule(mod);
311 1643070 : if (c == NULL && (c = globalModule(mod)) == NULL)
312 : return MEL_ERR;
313 :
314 3286140 : s = newSymbol(fcn, command ? COMMANDsymbol : PATTERNsymbol);
315 1643070 : if (s == NULL)
316 : return MEL_ERR;
317 1643070 : fcn = s->name;
318 1643070 : s->allocated = true;
319 :
320 1643070 : f = (mel_func*)GDKmalloc(sizeof(mel_func));
321 1643070 : mel_arg *args = (mel_arg*)GDKmalloc(sizeof(mel_arg)*argc);
322 1643070 : if (!f || !args) {
323 0 : if(!f) GDKfree(f);
324 0 : freeSymbol(s);
325 0 : return MEL_ERR;
326 : }
327 1643070 : f->mod = mod;
328 1643070 : f->fcn = fcn;
329 1643070 : f->command = command;
330 1643070 : f->unsafe = unsafe;
331 1643070 : f->vargs = 0;
332 1643070 : f->vrets = 0;
333 1643070 : f->poly = 0;
334 1643070 : f->retc = retc;
335 1643070 : f->argc = argc;
336 1643070 : f->args = args;
337 1643070 : f->imp = imp;
338 1643070 : f->comment = comment?GDKstrdup(comment):NULL;
339 1643070 : f->cname = fname?GDKstrdup(fname):NULL;
340 1643070 : s->def = NULL;
341 1643070 : s->func = f;
342 :
343 1643070 : va_start(va, argc);
344 3295380 : for (i = 0; i < retc; i++) {
345 1652310 : mel_func_arg a = va_arg(va, mel_func_arg);
346 1652310 : mel_arg *ap = f->args+i;
347 1652310 : argCopy(ap, &a);
348 1652310 : malType tpe = makeMalType(ap);
349 1652310 : if (a.nr > 0 || a.opt)
350 0 : setPoly(f, tpe);
351 1652310 : if (a.vargs) {
352 0 : f->vrets = true;
353 0 : setPoly(f, TYPE_any);
354 : }
355 1652310 : if (a.opt && f->command)
356 0 : return MEL_ERR;
357 : /*
358 : if (a.nr >= 2)
359 : printf("%s.%s\n", f->mod, f->fcn);
360 : */
361 : }
362 : /* add the arguments */
363 6580200 : for (i = retc; i < argc; i++) {
364 4937130 : mel_func_arg a = va_arg(va, mel_func_arg);
365 4937130 : mel_arg *ap = f->args+i;
366 4937130 : argCopy(ap, &a);
367 4937130 : malType tpe = makeMalType(ap);
368 4937130 : if (a.nr > 0 || a.opt)
369 221760 : setPoly(f, tpe);
370 4937130 : if (a.vargs) {
371 0 : f->vargs = true;
372 0 : setPoly(f, TYPE_any);
373 : }
374 4937130 : if (a.opt && f->command)
375 0 : return MEL_ERR;
376 : /*
377 : if (a.nr >= 2)
378 : printf("%s.%s\n", f->mod, f->fcn);
379 : */
380 : }
381 1643070 : insertSymbol(c, s);
382 1643070 : va_end(va);
383 1643070 : return MEL_OK;
384 : }
385 :
386 : static str
387 330 : malPrelude(Client c, int listing, int *sql, int *mapi)
388 : {
389 330 : int i;
390 330 : str msg = MAL_SUCCEED;
391 :
392 330 : (void) listing;
393 : /* Add all atom definitions */
394 18765 : for (i = mel_modules_loaded; i < mel_modules; i++) {
395 18435 : if (mel_module[i].atoms) {
396 2958 : msg = addAtom(mel_module[i].atoms);
397 2958 : if (msg)
398 0 : return msg;
399 : }
400 : }
401 :
402 : /* Add the signatures, where we now have access to all atoms */
403 18765 : for (i = mel_modules_loaded; i < mel_modules; i++) {
404 18435 : const char *name = putName(mel_module[i].name);
405 18435 : if (!malLibraryEnabled(name))
406 0 : continue;
407 18435 : if (mel_module[i].funcs) {
408 18435 : msg = addFunctions(mel_module[i].funcs);
409 18435 : if (!msg && mel_module[i].code) /* some modules may also have some function definitions */
410 0 : msg = malIncludeString(c, name, (str) mel_module[i].code, listing, NULL);
411 18435 : if (msg)
412 0 : return msg;
413 :
414 : /* mapi should be last, and sql last before mapi */
415 18435 : if (strcmp(name, "sql") == 0) {
416 330 : *sql = i;
417 330 : continue;
418 : }
419 18105 : if (strcmp(name, "mapi") == 0) {
420 330 : *mapi = i;
421 330 : continue;
422 : }
423 17775 : if (!mel_module[i].inits) {
424 15135 : msg = initModule(c, name, NULL);
425 15135 : if (msg)
426 0 : return msg;
427 : }
428 : }
429 17775 : if (mel_module[i].inits) {
430 : /* mapi should be last, and sql last before mapi */
431 2640 : if (strcmp(name, "sql") == 0 || strcmp(name, "mapi") == 0)
432 0 : continue;
433 2640 : msg = mel_module[i].inits();
434 2640 : if (msg)
435 0 : return msg;
436 : }
437 : }
438 330 : mel_modules_loaded = mel_modules;
439 330 : return MAL_SUCCEED;
440 : }
441 :
442 : str
443 330 : malIncludeModules(Client c, char *modules[], int listing, bool no_mapi_server,
444 : const char *initpasswd)
445 : {
446 330 : str msg;
447 330 : int sql = -1, mapi = -1;
448 :
449 3531 : for (int i = 0; modules[i]; i++) {
450 : /* load library */
451 3201 : if (!malLibraryEnabled(modules[i]))
452 932 : continue;
453 2269 : if ((msg = loadLibrary(modules[i], listing)) != NULL)
454 0 : return msg;
455 : }
456 : /* load the mal code for these modules and execute preludes */
457 330 : if ((msg = malPrelude(c, listing, &sql, &mapi)) != NULL)
458 : return msg;
459 : /* mapi should be last, and sql last before mapi */
460 330 : if (sql >= 0) {
461 330 : if (mel_module[sql].inits)
462 0 : msg = mel_module[sql].inits();
463 : else
464 330 : msg = initModule(c, "sql", initpasswd);
465 329 : if (msg)
466 : return msg;
467 : }
468 329 : if (!no_mapi_server && mapi >= 0 && initpasswd == NULL) {
469 317 : if (mel_module[mapi].inits)
470 317 : msg = mel_module[mapi].inits();
471 : else
472 0 : msg = initModule(c, "mapi", NULL);
473 317 : if (msg)
474 : return msg;
475 : }
476 : return MAL_SUCCEED;
477 : }
|