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, 2025 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 357 : mal_startup(void)
43 : {
44 : /* clean up the MAL internal structures before restart */
45 357 : mel_modules_loaded = 0;
46 357 : 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 18890 : mal_module2(const char *name, mel_atom *atoms, mel_func *funcs,
57 : mel_init initfunc, const char *code)
58 : {
59 18890 : assert(mel_modules < MAX_MAL_MODULES);
60 18890 : mel_module[mel_modules].name = name;
61 18890 : mel_module[mel_modules].atoms = atoms;
62 18890 : mel_module[mel_modules].funcs = funcs;
63 18890 : mel_module[mel_modules].inits = initfunc;
64 18890 : mel_module[mel_modules].code = code;
65 18890 : mel_modules++;
66 18890 : }
67 :
68 : void
69 15733 : mal_module(const char *name, mel_atom *atoms, mel_func *funcs)
70 : {
71 15733 : mal_module2(name, atoms, funcs, NULL, NULL);
72 15733 : }
73 :
74 : static char *
75 16723 : initModule(Client c, const char *name, const char *initpasswd)
76 : {
77 16723 : char *msg = MAL_SUCCEED;
78 :
79 16723 : assert(getName(name) == name);
80 16723 : Module m = getModule(name);
81 16723 : if (m) { /* run prelude */
82 13510 : const char *prelude = putName("prelude");
83 13510 : if (prelude == NULL)
84 0 : throw(LOADER, __func__, SQLSTATE(HY013) MAL_MALLOC_FAIL);
85 13510 : Symbol s = findSymbolInModule(m, prelude);
86 :
87 13510 : if (s) {
88 1058 : if (s && s->kind == COMMANDsymbol && s->func && s->func->argc == 1) {
89 0 : int ret = 0;
90 :
91 0 : assert(s->func != NULL);
92 0 : msg = (*(str (*)(int *)) s->func->imp) (&ret);
93 0 : (void) ret;
94 1058 : } else if (s && s->kind == PATTERNsymbol) {
95 1058 : void *mb = NULL;
96 1058 : assert(s->func->fcn != NULL);
97 1058 : if (strcmp(name, "sql") == 0) {
98 : /* HACK ALERT: temporarily use sqlcontext to pass
99 : * the initial password to the prelude function */
100 357 : assert(c->sqlcontext == NULL);
101 357 : c->sqlcontext = (void *) initpasswd;
102 : /* HACK ALERT: use mb (MalBlkPtr) to pass revision
103 : * string in order to check that in the callee */
104 357 : mb = (void *) mercurial_revision();
105 : }
106 1058 : msg = (*(str (*)(Client, MalBlkPtr, MalStkPtr, InstrPtr)) s->func->pimp) (c, mb, NULL, NULL);
107 : }
108 : }
109 : }
110 : return msg;
111 : }
112 :
113 : /*
114 : * The statically description of the MAL structures call for a translation into
115 : * their underlying structure.
116 : */
117 : static str
118 2487 : addAtom(mel_atom *atoms)
119 : {
120 5676 : for (; atoms && atoms->name[0]; atoms++) {
121 3189 : int i = ATOMallocate(atoms->name);
122 3189 : if (is_int_nil(i))
123 0 : throw(TYPE, __func__, GDK_EXCEPTION);
124 3189 : if (atoms->basetype[0]) {
125 2487 : int tpe = ATOMindex(atoms->basetype);
126 2487 : if (tpe < 0)
127 0 : throw(TYPE, __func__, TYPE_NOT_SUPPORTED);
128 2487 : BATatoms[i] = BATatoms[tpe];
129 2487 : strcpy_len(BATatoms[i].name, atoms->name, sizeof(BATatoms[i].name));
130 2487 : BATatoms[i].storage = ATOMstorage(tpe);
131 : } else { /* cannot overload void atoms */
132 702 : BATatoms[i].storage = i;
133 702 : BATatoms[i].linear = false;
134 : }
135 3189 : if (atoms->del)
136 345 : BATatoms[i].atomDel = atoms->del;
137 3189 : if (atoms->cmp) {
138 1047 : BATatoms[i].atomCmp = atoms->cmp;
139 1047 : BATatoms[i].linear = true;
140 : }
141 3189 : if (atoms->fromstr)
142 2118 : BATatoms[i].atomFromStr = atoms->fromstr;
143 3189 : if (atoms->tostr)
144 2118 : BATatoms[i].atomToStr = atoms->tostr;
145 3189 : if (atoms->heap) {
146 345 : BATatoms[i].size = sizeof(var_t);
147 345 : assert_shift_width(ATOMelmshift(ATOMsize(i)), ATOMsize(i));
148 345 : BATatoms[i].atomHeap = atoms->heap;
149 : }
150 3189 : if (atoms->hash)
151 690 : BATatoms[i].atomHash = atoms->hash;
152 3189 : if (atoms->length)
153 345 : BATatoms[i].atomLen = atoms->length;
154 3189 : if (atoms->null) {
155 1047 : const void *atmnull = (*atoms->null) ();
156 :
157 1047 : BATatoms[i].atomNull = atmnull;
158 : }
159 3189 : if (atoms->nequal)
160 0 : BATatoms[i].atomCmp = atoms->nequal;
161 3189 : if (atoms->put)
162 345 : BATatoms[i].atomPut = atoms->put;
163 3189 : if (atoms->storage)
164 0 : BATatoms[i].storage = (*atoms->storage) ();
165 3189 : if (atoms->read)
166 690 : BATatoms[i].atomRead = atoms->read;
167 3189 : if (atoms->write)
168 690 : BATatoms[i].atomWrite = atoms->write;
169 : }
170 : return MAL_SUCCEED;
171 : }
172 :
173 : static malType
174 13886121 : makeMalType(mel_arg *a)
175 : {
176 13886121 : malType tpe = TYPE_any;
177 :
178 13886121 : if (!a->type[0]) {
179 452277 : a->typeid = tpe;
180 452277 : if (a->isbat)
181 356997 : tpe = newBatType(tpe);
182 452277 : if (a->nr > 0)
183 416258 : setTypeIndex(tpe, a->nr);
184 : } else {
185 13433844 : tpe = getAtomIndex(a->type, strlen(a->type), -1);
186 13433844 : a->typeid = tpe;
187 13433844 : if (a->isbat)
188 8033862 : tpe = newBatType(tpe);
189 : }
190 13886121 : if (a->opt == 1)
191 168504 : setOptBat(tpe);
192 13886121 : return tpe;
193 : }
194 :
195 : void
196 805354 : setPoly(mel_func *f, malType tpe)
197 : {
198 787554 : if (isAnyExpression(tpe) || tpe == TYPE_any || getOptBat(tpe)) {
199 599722 : unsigned int index = getTypeIndex(tpe);
200 581922 : if (index + 1 > f->poly)
201 332405 : f->poly = index + 1;
202 : }
203 787554 : }
204 :
205 : static str
206 19222 : addFunctions(mel_func *fcn)
207 : {
208 19222 : str msg = MAL_SUCCEED;
209 19222 : Module c;
210 19222 : Symbol s;
211 :
212 1861276 : for (; fcn && fcn->mod; fcn++) {
213 1842054 : const char *mod = putName(fcn->mod);
214 1842054 : if (mod == NULL)
215 0 : throw(LOADER, __func__, SQLSTATE(HY013) MAL_MALLOC_FAIL);
216 1842054 : c = getModule(mod);
217 1842054 : if (c == NULL && (c = globalModule(mod)) == NULL)
218 0 : throw(LOADER, __func__, "Module %s can not be created", mod);
219 :
220 3122409 : s = newSymbol(fcn->fcn, (fcn->command) ? COMMANDsymbol : PATTERNsymbol);
221 1842054 : if (s == NULL)
222 0 : throw(LOADER, __func__, "Can not create symbol for %s.%s missing", mod,
223 : fcn->fcn);
224 1842054 : s->def = NULL;
225 1842054 : s->func = fcn;
226 1842054 : s->allocated = false;
227 :
228 : /* add the return variables */
229 1842054 : unsigned int i;
230 3797408 : for (i = 0; i < fcn->retc; i++) {
231 1955354 : mel_arg *a = fcn->args + i;
232 1955354 : malType tpe = makeMalType(a);
233 1955354 : if (a->nr > 0 || a->opt)
234 61424 : setPoly(fcn, tpe);
235 1955354 : if (a->vargs) {
236 3380 : fcn->vrets = true;
237 3380 : setPoly(fcn, TYPE_any);
238 : }
239 1955354 : if (a->opt && fcn->command)
240 0 : throw(LOADER, __func__, "Can not have command symbol with dynamic types, ie bat vs scalar in %s.%s", mod, fcn->fcn);
241 : /*
242 : if (a->nr >= 2)
243 : printf("%s.%s\n", mod, fcn->fcn);
244 : */
245 : }
246 : /* add the arguments */
247 6644245 : for (i = fcn->retc; i < fcn->argc; i++) {
248 4802191 : mel_arg *a = fcn->args + i;
249 4802191 : malType tpe = makeMalType(a);
250 :
251 4802191 : if (a->nr > 0 || a->opt)
252 486210 : setPoly(fcn, tpe);
253 4802191 : if (a->vargs) {
254 14420 : fcn->vargs = true;
255 14420 : setPoly(fcn, TYPE_any);
256 : }
257 4802191 : if (a->opt && fcn->command)
258 0 : throw(LOADER, __func__, "Can not have command symbol with dynamic types, ie bat vs scalar in %s.%s", mod, fcn->fcn);
259 : /*
260 : if (a->nr >= 2)
261 : printf("%s.%s\n", mod, fcn->fcn);
262 : */
263 : }
264 1842054 : insertSymbol(c, s);
265 : }
266 : return msg;
267 : }
268 :
269 : static void
270 7128576 : argCopy( mel_arg *ap, mel_func_arg *a)
271 : {
272 7128576 : ap->typeid = a->type;
273 7128576 : ap->nr = a->nr;
274 7128576 : ap->isbat = a->isbat;
275 7128576 : ap->vargs = a->vargs;
276 7128576 : ap->opt = a->opt;
277 7128576 : if (a->type != TYPE_any)
278 7093590 : strcpy(ap->type, BATatoms[a->type].name);
279 : else
280 34986 : ap->type[0] = 0;
281 7128576 : }
282 :
283 : int
284 1777503 : melFunction(bool command, const char *mod, const char *fcn, MALfcn imp,
285 : const char *fname, bool unsafe, const char *comment, int retc,
286 : int argc, ...)
287 : {
288 1777503 : int i;
289 1777503 : Module c;
290 1777503 : Symbol s;
291 1777503 : mel_func *f = NULL;
292 1777503 : va_list va;
293 :
294 1777503 : assert(mod && fcn);
295 1777503 : mod = putName(mod);
296 1777503 : fcn = putName(fcn);
297 1777503 : c = getModule(mod);
298 1777503 : if (c == NULL && (c = globalModule(mod)) == NULL)
299 : return MEL_ERR;
300 :
301 3555006 : s = newSymbol(fcn, command ? COMMANDsymbol : PATTERNsymbol);
302 1777503 : if (s == NULL)
303 : return MEL_ERR;
304 1777503 : fcn = s->name;
305 1777503 : s->allocated = true;
306 :
307 1777503 : f = (mel_func*)GDKmalloc(sizeof(mel_func));
308 1777503 : mel_arg *args = (mel_arg*)GDKmalloc(sizeof(mel_arg)*argc);
309 1777503 : if (!f || !args) {
310 0 : GDKfree(f);
311 0 : GDKfree(args);
312 0 : freeSymbol(s);
313 0 : return MEL_ERR;
314 : }
315 3555006 : *f = (mel_func) {
316 : .mod = mod,
317 : .fcn = fcn,
318 : .command = command,
319 : .unsafe = unsafe,
320 : .vargs = 0,
321 : .vrets = 0,
322 : .poly = 0,
323 : .retc = retc,
324 : .argc = argc,
325 : .args = args,
326 : .imp = imp,
327 1777503 : .comment = comment ? GDKstrdup(comment) : NULL,
328 1777503 : .cname = fname ? GDKstrdup(fname) : NULL,
329 : };
330 1777503 : s->def = NULL;
331 1777503 : s->func = f;
332 :
333 1777503 : va_start(va, argc);
334 3565002 : for (i = 0; i < retc; i++) {
335 1787499 : mel_func_arg a = va_arg(va, mel_func_arg);
336 1787499 : mel_arg *ap = f->args+i;
337 1787499 : argCopy(ap, &a);
338 1787499 : malType tpe = makeMalType(ap);
339 1787499 : if (a.nr > 0 || a.opt)
340 0 : setPoly(f, tpe);
341 1787499 : if (a.vargs) {
342 0 : f->vrets = true;
343 0 : setPoly(f, TYPE_any);
344 : }
345 1787499 : if (a.opt && f->command) {
346 0 : va_end(va);
347 0 : freeSymbol(s); /* also frees f and args */
348 0 : return MEL_ERR;
349 : }
350 : /*
351 : if (a.nr >= 2)
352 : printf("%s.%s\n", f->mod, f->fcn);
353 : */
354 : }
355 : /* add the arguments */
356 7118580 : for (i = retc; i < argc; i++) {
357 5341077 : mel_func_arg a = va_arg(va, mel_func_arg);
358 5341077 : mel_arg *ap = f->args+i;
359 5341077 : argCopy(ap, &a);
360 5341077 : malType tpe = makeMalType(ap);
361 5341077 : if (a.nr > 0 || a.opt)
362 239904 : setPoly(f, tpe);
363 5341077 : if (a.vargs) {
364 0 : f->vargs = true;
365 0 : setPoly(f, TYPE_any);
366 : }
367 5341077 : if (a.opt && f->command) {
368 0 : va_end(va);
369 0 : freeSymbol(s); /* also frees f and args */
370 0 : return MEL_ERR;
371 : }
372 : /*
373 : if (a.nr >= 2)
374 : printf("%s.%s\n", f->mod, f->fcn);
375 : */
376 : }
377 1777503 : insertSymbol(c, s);
378 1777503 : va_end(va);
379 1777503 : return MEL_OK;
380 : }
381 :
382 : static str
383 357 : malPrelude(Client c, int listing, int *sql, int *mapi)
384 : {
385 357 : int i;
386 357 : str msg = MAL_SUCCEED;
387 :
388 357 : (void) listing;
389 : /* Add all atom definitions */
390 19579 : for (i = mel_modules_loaded; i < mel_modules; i++) {
391 19222 : if (mel_module[i].atoms) {
392 2487 : msg = addAtom(mel_module[i].atoms);
393 2487 : if (msg)
394 0 : return msg;
395 : }
396 : }
397 :
398 : /* Add the signatures, where we now have access to all atoms */
399 19579 : for (i = mel_modules_loaded; i < mel_modules; i++) {
400 19222 : const char *name = putName(mel_module[i].name);
401 19222 : if (name == NULL)
402 0 : throw(LOADER, __func__, MAL_MALLOC_FAIL);
403 19222 : if (!malLibraryEnabled(name))
404 0 : continue;
405 19222 : if (mel_module[i].funcs) {
406 19222 : msg = addFunctions(mel_module[i].funcs);
407 19222 : if (!msg && mel_module[i].code) /* some modules may also have some function definitions */
408 0 : msg = malIncludeString(c, name, (str) mel_module[i].code, listing, NULL);
409 19222 : if (msg)
410 0 : return msg;
411 :
412 : /* mapi should be last, and sql last before mapi */
413 19222 : if (name == sqlRef) {
414 357 : *sql = i;
415 357 : continue;
416 : }
417 18865 : if (name == mapiRef) {
418 357 : *mapi = i;
419 357 : continue;
420 : }
421 18508 : if (!mel_module[i].inits) {
422 16366 : msg = initModule(c, name, NULL);
423 16366 : if (msg)
424 0 : return msg;
425 : }
426 : }
427 18508 : if (mel_module[i].inits) {
428 : /* mapi should be last, and sql last before mapi */
429 2142 : if (name == sqlRef || name == mapiRef)
430 0 : continue;
431 2142 : msg = mel_module[i].inits();
432 2142 : if (msg)
433 0 : return msg;
434 : }
435 : }
436 357 : mel_modules_loaded = mel_modules;
437 357 : return MAL_SUCCEED;
438 : }
439 :
440 : str
441 357 : malIncludeModules(Client c, char *modules[], int listing, bool no_mapi_server,
442 : const char *initpasswd)
443 : {
444 357 : str msg;
445 357 : int sql = -1, mapi = -1;
446 :
447 4175 : for (int i = 0; modules[i]; i++) {
448 : /* load library */
449 3818 : if (!malLibraryEnabled(modules[i]))
450 1013 : continue;
451 2805 : if ((msg = loadLibrary(modules[i], listing)) != NULL)
452 0 : return msg;
453 : }
454 : /* load the mal code for these modules and execute preludes */
455 357 : if ((msg = malPrelude(c, listing, &sql, &mapi)) != NULL)
456 : return msg;
457 : /* mapi should be last, and sql last before mapi */
458 357 : if (sql >= 0) {
459 357 : if (mel_module[sql].inits)
460 0 : msg = mel_module[sql].inits();
461 : else
462 357 : msg = initModule(c, sqlRef, initpasswd);
463 356 : if (msg)
464 : return msg;
465 : }
466 356 : if (!no_mapi_server && mapi >= 0 && initpasswd == NULL) {
467 344 : if (mel_module[mapi].inits)
468 344 : msg = mel_module[mapi].inits();
469 : else
470 0 : msg = initModule(c, mapiRef, NULL);
471 344 : if (msg)
472 : return msg;
473 : }
474 : return MAL_SUCCEED;
475 : }
|