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;
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 0 : mal_startup(void)
43 : {
44 : /* clean up the MAL internal structures before restart */
45 0 : return 0;
46 : }
47 :
48 : /* all MAL related functions register themselves
49 : * the order in which these registrations happen is significant
50 : * because there may be dependencies among the definitions.
51 : * For example, you better know the atoms before you use them
52 : */
53 :
54 : void
55 3296 : mal_module2(const char *name, mel_atom *atoms, mel_func *funcs,
56 : mel_init initfunc, const char *code)
57 : {
58 3296 : assert(mel_modules < MAX_MAL_MODULES);
59 3296 : mel_module[mel_modules].name = name;
60 3296 : mel_module[mel_modules].atoms = atoms;
61 3296 : mel_module[mel_modules].funcs = funcs;
62 3296 : mel_module[mel_modules].inits = initfunc;
63 3296 : mel_module[mel_modules].code = code;
64 3296 : mel_modules++;
65 3296 : }
66 :
67 : void
68 15121 : mal_module(const char *name, mel_atom *atoms, mel_func *funcs)
69 : {
70 15121 : assert(mel_modules < MAX_MAL_MODULES);
71 15121 : mel_module[mel_modules].name = name;
72 15121 : mel_module[mel_modules].atoms = atoms;
73 15121 : mel_module[mel_modules].funcs = funcs;
74 15121 : mel_module[mel_modules].inits = NULL;
75 15121 : mel_module[mel_modules].code = NULL;
76 15121 : mel_modules++;
77 15121 : }
78 :
79 : static char *
80 15411 : initModule(Client c, const char *name, const char *initpasswd)
81 : {
82 15411 : char *msg = MAL_SUCCEED;
83 :
84 15411 : if (!getName(name))
85 : return msg;
86 15411 : if ((name = putName(name)) == NULL)
87 0 : throw(LOADER, __func__, SQLSTATE(HY013) MAL_MALLOC_FAIL);
88 15411 : Module m = getModule(name);
89 15411 : if (m) { /* run prelude */
90 12387 : const char *prelude = putName("prelude");
91 12387 : if (prelude == NULL)
92 0 : throw(LOADER, __func__, SQLSTATE(HY013) MAL_MALLOC_FAIL);
93 12387 : Symbol s = findSymbolInModule(m, prelude);
94 :
95 12387 : if (s) {
96 670 : InstrPtr pci = getInstrPtr(s->def, 0);
97 :
98 670 : if (pci && pci->token == COMMANDsymbol && pci->argc == 1) {
99 0 : int ret = 0;
100 :
101 0 : assert(pci->fcn != NULL);
102 0 : msg = (*(str (*)(int *)) pci->fcn) (&ret);
103 0 : (void) ret;
104 670 : } else if (pci && pci->token == PATTERNsymbol) {
105 670 : void *mb = NULL;
106 670 : assert(pci->fcn != NULL);
107 670 : if (strcmp(name, "sql") == 0) {
108 : /* HACK ALERT: temporarily use sqlcontext to pass
109 : * the initial password to the prelude function */
110 336 : assert(c->sqlcontext == NULL);
111 336 : c->sqlcontext = (void *) initpasswd;
112 : /* HACK ALERT: use mb (MalBlkPtr) to pass revision
113 : * string in order to check that in the callee */
114 336 : mb = (void *) mercurial_revision();
115 : }
116 670 : msg = (*(str (*)(Client, MalBlkPtr, MalStkPtr, InstrPtr)) pci->
117 : fcn) (c, mb, NULL, NULL);
118 : }
119 : }
120 : }
121 : return msg;
122 : }
123 :
124 : /*
125 : * The statically description of the MAL structures call for a translation into
126 : * their underlying structure.
127 : */
128 : static str
129 3012 : addAtom(mel_atom *atoms)
130 : {
131 7008 : for (; atoms && atoms->name[0]; atoms++) {
132 3996 : int i = ATOMallocate(atoms->name);
133 3996 : if (is_int_nil(i))
134 0 : throw(TYPE, __func__, GDK_EXCEPTION);
135 3996 : if (atoms->basetype[0]) {
136 3012 : int tpe = ATOMindex(atoms->basetype);
137 3012 : if (tpe < 0)
138 0 : throw(TYPE, __func__, TYPE_NOT_SUPPORTED);
139 3012 : BATatoms[i] = BATatoms[tpe];
140 3012 : strcpy_len(BATatoms[i].name, atoms->name, sizeof(BATatoms[i].name));
141 3012 : BATatoms[i].storage = ATOMstorage(tpe);
142 : } else { /* cannot overload void atoms */
143 984 : BATatoms[i].storage = i;
144 984 : BATatoms[i].linear = false;
145 : }
146 3996 : if (atoms->del)
147 648 : BATatoms[i].atomDel = atoms->del;
148 3996 : if (atoms->cmp) {
149 1308 : BATatoms[i].atomCmp = atoms->cmp;
150 1308 : BATatoms[i].linear = true;
151 : }
152 3996 : if (atoms->fromstr)
153 2988 : BATatoms[i].atomFromStr = atoms->fromstr;
154 3996 : if (atoms->tostr)
155 2988 : BATatoms[i].atomToStr = atoms->tostr;
156 3996 : if (atoms->fix)
157 0 : BATatoms[i].atomFix = atoms->fix;
158 3996 : if (atoms->unfix)
159 0 : BATatoms[i].atomUnfix = atoms->unfix;
160 3996 : if (atoms->heap) {
161 648 : BATatoms[i].size = sizeof(var_t);
162 648 : assert_shift_width(ATOMelmshift(ATOMsize(i)), ATOMsize(i));
163 648 : BATatoms[i].atomHeap = atoms->heap;
164 : }
165 3996 : if (atoms->hash)
166 972 : BATatoms[i].atomHash = atoms->hash;
167 3996 : if (atoms->length)
168 648 : BATatoms[i].atomLen = atoms->length;
169 3996 : if (atoms->null) {
170 1308 : const void *atmnull = (*atoms->null) ();
171 :
172 1308 : BATatoms[i].atomNull = atmnull;
173 : }
174 3996 : if (atoms->nequal)
175 0 : BATatoms[i].atomCmp = atoms->nequal;
176 3996 : if (atoms->put)
177 648 : BATatoms[i].atomPut = atoms->put;
178 3996 : if (atoms->storage)
179 0 : BATatoms[i].storage = (*atoms->storage) ();
180 3996 : if (atoms->read)
181 972 : BATatoms[i].atomRead = atoms->read;
182 3996 : if (atoms->write)
183 972 : BATatoms[i].atomWrite = atoms->write;
184 : }
185 : return MAL_SUCCEED;
186 : }
187 :
188 : static str
189 6513546 : makeArgument(MalBlkPtr mb, const mel_arg *a, int *idx)
190 : {
191 6513546 : int tpe = TYPE_any; //, l;
192 :
193 6513546 : if (
194 : #ifdef MEL_STR
195 6513546 : !a->type[0]
196 : #else
197 : a->type == TYPE_any
198 : #endif
199 : ) {
200 630305 : if (a->isbat)
201 339356 : tpe = newBatType(tpe);
202 630305 : if (a->nr > 0)
203 402860 : setTypeIndex(tpe, a->nr);
204 : } else {
205 5883241 : int mask = 0;
206 : #ifdef MEL_STR
207 5883241 : tpe = getAtomIndex(a->type, strlen(a->type), -1);
208 : #else
209 : tpe = a->type;
210 : #endif
211 5883241 : if (a->isbat)
212 2102295 : tpe = newBatType(tpe) | mask;
213 : }
214 : /*
215 : if (a->name) {
216 : *idx = findVariableLength(mb, a->name, l = strlen(a->name));
217 : if (*idx != -1)
218 : throw(LOADER, __func__, "Duplicate argument name %s", a->name);
219 : *idx = newVariable(mb, a->name, l, tpe);
220 : } else
221 : */
222 6513546 : *idx = newTmpVariable(mb, tpe);
223 6513546 : if (*idx < 0) {
224 0 : char *msg = mb->errors;
225 0 : mb->errors = NULL;
226 0 : if (msg)
227 : return msg;
228 0 : throw(LOADER, __func__, SQLSTATE(HY013) MAL_MALLOC_FAIL);
229 : }
230 : return MAL_SUCCEED;
231 : }
232 :
233 : static str
234 18770 : addFunctions(mel_func *fcn)
235 : {
236 18770 : str msg = MAL_SUCCEED;
237 18770 : const char *mod;
238 18770 : int idx;
239 18770 : Module c;
240 18770 : Symbol s;
241 18770 : MalBlkPtr mb;
242 18770 : InstrPtr sig;
243 :
244 1781901 : for (; fcn && fcn->mod[0]; fcn++) {
245 1763131 : assert(fcn->mod);
246 1763131 : mod = putName(fcn->mod);
247 1763131 : if (mod == NULL)
248 0 : throw(LOADER, __func__, SQLSTATE(HY013) MAL_MALLOC_FAIL);
249 1763131 : c = getModule(mod);
250 1763131 : if (c == NULL && (c = globalModule(mod)) == NULL)
251 0 : throw(LOADER, __func__, "Module %s can not be created", fcn->mod);
252 :
253 2981994 : s = newSymbol(fcn->fcn, fcn->command ? COMMANDsymbol : PATTERNsymbol);
254 1763131 : if (s == NULL)
255 0 : throw(LOADER, __func__,
256 : "Can not create symbol for %s.%s missing", fcn->mod,
257 : fcn->fcn);
258 1763131 : mb = s->def;
259 1763131 : assert(mb); /* if this is NULL, s should have been NULL */
260 :
261 1763131 : if (fcn->cname && fcn->cname[0])
262 1763131 : strcpy_len(mb->binding, fcn->cname, sizeof(mb->binding));
263 : /* keep the comment around, setting the static avoids freeing
264 : * the string accidentally, saving on duplicate documentation in
265 : * the code. */
266 1763131 : mb->statichelp = mb->help = fcn->comment;
267 :
268 1763131 : sig = newInstructionArgs(mb, mod, putName(fcn->fcn),
269 1763131 : fcn->argc + (fcn->retc == 0));
270 1763131 : if (sig == NULL) {
271 0 : freeSymbol(s);
272 0 : throw(LOADER, __func__, SQLSTATE(HY013) MAL_MALLOC_FAIL);
273 : }
274 1763131 : sig->retc = 0;
275 1763131 : sig->argc = 0;
276 1763131 : sig->token = fcn->command ? COMMANDsymbol : PATTERNsymbol;
277 1763131 : sig->fcn = fcn->imp;
278 1763131 : if (fcn->unsafe)
279 49092 : mb->unsafeProp = 1;
280 :
281 : /* add the return variables */
282 1763131 : if (fcn->retc == 0) {
283 31916 : int idx = newTmpVariable(mb, TYPE_void);
284 31916 : if (idx < 0) {
285 0 : freeInstruction(sig);
286 0 : freeSymbol(s);
287 0 : throw(LOADER, __func__, MAL_MALLOC_FAIL);
288 : }
289 31916 : sig = pushReturn(mb, sig, idx);
290 : }
291 : int i;
292 3631518 : for (i = 0; i < fcn->retc; i++) {
293 1868387 : const mel_arg *a = fcn->args + i;
294 1868387 : msg = makeArgument(mb, a, &idx);
295 1868387 : if (msg) {
296 0 : freeInstruction(sig);
297 0 : freeSymbol(s);
298 0 : return msg;
299 : }
300 1868387 : sig = pushReturn(mb, sig, idx);
301 1868387 : int tpe = TYPE_any;
302 1868387 : if (a->nr > 0) {
303 64868 : if (a->isbat)
304 53770 : tpe = newBatType(tpe);
305 64868 : setPolymorphic(sig, tpe, TRUE);
306 : }
307 1868387 : if (a->vargs) {
308 3186 : sig->varargs |= VARRETS;
309 3186 : setPolymorphic(sig, TYPE_any, TRUE);
310 : }
311 : }
312 : /* add the arguments */
313 6408290 : for (i = fcn->retc; i < fcn->argc; i++) {
314 4645159 : const mel_arg *a = fcn->args + i;
315 4645159 : msg = makeArgument(mb, a, &idx);
316 4645159 : if (msg) {
317 0 : freeInstruction(sig);
318 0 : freeSymbol(s);
319 0 : return msg;
320 : }
321 4645159 : sig = pushArgument(mb, sig, idx);
322 4645159 : int tpe = TYPE_any;
323 4645159 : if (a->nr > 0) {
324 337992 : if (a->isbat)
325 264408 : tpe = newBatType(tpe);
326 337992 : setPolymorphic(sig, tpe, TRUE);
327 : }
328 4645159 : if (a->vargs) {
329 11896 : sig->varargs |= VARARGS;
330 11896 : setPolymorphic(sig, TYPE_any, TRUE);
331 : }
332 : }
333 1763131 : if (mb->errors) {
334 0 : freeInstruction(sig);
335 0 : freeSymbol(s);
336 0 : msg = mb->errors;
337 0 : mb->errors = NULL;
338 0 : return msg;
339 : }
340 1763131 : assert(sig->retc > 0);
341 1763131 : pushInstruction(mb, sig);
342 1763131 : if (mb->errors) {
343 0 : freeSymbol(s);
344 0 : msg = mb->errors;
345 0 : mb->errors = NULL;
346 0 : return msg;
347 : }
348 1763131 : insertSymbol(c, s);
349 : }
350 : return msg;
351 : }
352 :
353 : static int
354 6709248 : makeFuncArgument(MalBlkPtr mb, mel_func_arg *a)
355 : {
356 6709248 : int tpe = TYPE_any;
357 :
358 6709248 : if (a->type == TYPE_any) {
359 32928 : if (a->isbat)
360 22176 : tpe = newBatType(tpe);
361 32928 : if (a->nr > 0)
362 32256 : setTypeIndex(tpe, a->nr);
363 : } else {
364 6676320 : tpe = a->type;
365 6676320 : if (a->isbat)
366 5500992 : tpe = newBatType(tpe);
367 : }
368 6709248 : return newTmpVariable(mb, tpe);
369 : }
370 :
371 : int
372 1672944 : melFunction(bool command, const char *mod, const char *fcn, MALfcn imp,
373 : const char *fname, bool unsafe, const char *comment, int retc,
374 : int argc, ...)
375 : {
376 1672944 : int i, idx;
377 1672944 : Module c;
378 1672944 : Symbol s;
379 1672944 : MalBlkPtr mb;
380 1672944 : InstrPtr sig;
381 1672944 : va_list va;
382 :
383 1672944 : assert(mod);
384 1672944 : mod = putName(mod);
385 1672944 : c = getModule(mod);
386 1672944 : if (c == NULL && (c = globalModule(mod)) == NULL)
387 : return MEL_ERR;
388 :
389 3345888 : s = newSymbol(fcn, command ? COMMANDsymbol : PATTERNsymbol);
390 1672944 : if (s == NULL)
391 : return MEL_ERR;
392 1672944 : fcn = s->name;
393 1672944 : mb = s->def;
394 1672944 : (void) comment;
395 1672944 : if (fname)
396 1672944 : strcpy_len(mb->binding, fname, sizeof(mb->binding));
397 1672944 : if (mb == NULL) {
398 0 : freeSymbol(s);
399 0 : return MEL_ERR;
400 : }
401 1672944 : sig = newInstructionArgs(mb, mod, fcn, argc + (retc == 0));
402 1672944 : if (sig == NULL) {
403 0 : freeSymbol(s);
404 0 : return MEL_ERR;
405 : }
406 1672944 : sig->retc = 0;
407 1672944 : sig->argc = 0;
408 1672944 : sig->token = command ? COMMANDsymbol : PATTERNsymbol;
409 1672944 : sig->fcn = imp;
410 1672944 : if (unsafe)
411 0 : mb->unsafeProp = 1;
412 : /* add the return variables */
413 1672944 : if (retc == 0) {
414 0 : idx = newTmpVariable(mb, TYPE_void);
415 0 : if (idx < 0) {
416 0 : freeInstruction(sig);
417 0 : freeSymbol(s);
418 0 : return MEL_ERR;
419 : }
420 0 : sig = pushReturn(mb, sig, idx);
421 : }
422 :
423 1672944 : va_start(va, argc);
424 3355296 : for (i = 0; i < retc; i++) {
425 1682352 : mel_func_arg a = va_arg(va, mel_func_arg);
426 1682352 : idx = makeFuncArgument(mb, &a);
427 1682352 : if (idx < 0) {
428 0 : freeInstruction(sig);
429 0 : freeSymbol(s);
430 0 : va_end(va);
431 0 : return MEL_ERR;
432 : }
433 1682352 : sig = pushReturn(mb, sig, idx);
434 1682352 : int tpe = TYPE_any;
435 1682352 : if (a.nr > 0) {
436 0 : if (a.isbat)
437 0 : tpe = newBatType(tpe);
438 0 : setPolymorphic(sig, tpe, TRUE);
439 : }
440 1682352 : if (a.vargs) {
441 0 : sig->varargs |= VARRETS;
442 0 : setPolymorphic(sig, TYPE_any, TRUE);
443 : }
444 : }
445 : /* add the arguments */
446 6699840 : for (i = retc; i < argc; i++) {
447 5026896 : mel_func_arg a = va_arg(va, mel_func_arg);
448 5026896 : idx = makeFuncArgument(mb, &a);
449 5026896 : if (idx < 0) {
450 0 : freeInstruction(sig);
451 0 : freeSymbol(s);
452 0 : va_end(va);
453 0 : return MEL_ERR;
454 : }
455 5026896 : sig = pushArgument(mb, sig, idx);
456 5026896 : int tpe = TYPE_any;
457 5026896 : if (a.nr > 0) {
458 225792 : if (a.isbat)
459 150528 : tpe = newBatType(tpe);
460 225792 : setPolymorphic(sig, tpe, TRUE);
461 : }
462 5026896 : if (a.vargs) {
463 0 : sig->varargs |= VARARGS;
464 0 : setPolymorphic(sig, TYPE_any, TRUE);
465 : }
466 : }
467 1672944 : assert(sig->retc > 0);
468 1672944 : pushInstruction(mb, sig);
469 1672944 : insertSymbol(c, s);
470 1672944 : va_end(va);
471 1672944 : return MEL_OK;
472 : }
473 :
474 : static str
475 336 : malPrelude(Client c, int listing, int *sql, int *mapi)
476 : {
477 336 : int i;
478 336 : str msg = MAL_SUCCEED;
479 :
480 336 : (void) listing;
481 : /* Add all atom definitions */
482 19106 : for (i = 0; i < mel_modules; i++) {
483 18770 : if (mel_module[i].atoms) {
484 3012 : msg = addAtom(mel_module[i].atoms);
485 3012 : if (msg)
486 0 : return msg;
487 : }
488 : }
489 :
490 : /* Add the signatures, where we now have access to all atoms */
491 19106 : for (i = 0; i < mel_modules; i++) {
492 18770 : const char *name = putName(mel_module[i].name);
493 18770 : if (!malLibraryEnabled(name))
494 0 : continue;
495 18770 : if (mel_module[i].funcs) {
496 18770 : msg = addFunctions(mel_module[i].funcs);
497 18770 : if (!msg && mel_module[i].code) /* some modules may also have some function definitions */
498 0 : msg = malIncludeString(c, name, (str) mel_module[i].code, listing, NULL);
499 18770 : if (msg)
500 0 : return msg;
501 :
502 : /* mapi should be last, and sql last before mapi */
503 18770 : if (strcmp(name, "sql") == 0) {
504 336 : *sql = i;
505 336 : continue;
506 : }
507 18434 : if (strcmp(name, "mapi") == 0) {
508 336 : *mapi = i;
509 336 : continue;
510 : }
511 18098 : if (!mel_module[i].inits) {
512 15075 : msg = initModule(c, name, NULL);
513 15075 : if (msg)
514 0 : return msg;
515 : }
516 : }
517 18098 : if (mel_module[i].inits) {
518 : /* mapi should be last, and sql last before mapi */
519 3023 : if (strcmp(name, "sql") == 0 || strcmp(name, "mapi") == 0)
520 0 : continue;
521 3023 : msg = mel_module[i].inits();
522 3023 : if (msg)
523 0 : return msg;
524 : }
525 : }
526 : return MAL_SUCCEED;
527 : }
528 :
529 : str
530 336 : malIncludeModules(Client c, char *modules[], int listing, bool no_mapi_server,
531 : const char *initpasswd)
532 : {
533 336 : str msg;
534 336 : int sql = -1, mapi = -1;
535 :
536 3597 : for (int i = 0; modules[i]; i++) {
537 : /* load library */
538 3261 : if (!malLibraryEnabled(modules[i]))
539 951 : continue;
540 2310 : if ((msg = loadLibrary(modules[i], listing)) != NULL)
541 0 : return msg;
542 : }
543 : /* load the mal code for these modules and execute preludes */
544 336 : if ((msg = malPrelude(c, listing, &sql, &mapi)) != NULL)
545 : return msg;
546 : /* mapi should be last, and sql last before mapi */
547 336 : if (sql >= 0) {
548 336 : if (mel_module[sql].inits)
549 0 : msg = mel_module[sql].inits();
550 : else
551 336 : msg = initModule(c, "sql", initpasswd);
552 335 : if (msg)
553 : return msg;
554 : }
555 335 : if (!no_mapi_server && mapi >= 0 && initpasswd == NULL) {
556 323 : if (mel_module[mapi].inits)
557 323 : msg = mel_module[mapi].inits();
558 : else
559 0 : msg = initModule(c, "mapi", NULL);
560 323 : if (msg)
561 : return msg;
562 : }
563 : return MAL_SUCCEED;
564 : }
|