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 : /*
14 : * (author) M. Kersten 2015
15 : */
16 :
17 : #include "monetdb_config.h"
18 : #include "mal_instruction.h"
19 : #include "mal_function.h" /* for getPC() */
20 : #include "mal_utils.h"
21 : #include "mal_exception.h"
22 : #include "mal_listing.h"
23 :
24 : /*
25 : * Since MAL programs can be created on the fly by linked-in query
26 : * compilers, or transformed by optimizers, it becomes
27 : * mandatory to be able to produce textual correct MAL programs
28 : * from its internal representation for several purposes.
29 : *
30 : * Whenever there is an overriding property it is applied.
31 : *
32 : * The hiddenInstruction operator assumes a sufficiently large block
33 : * to leave information on the signature behind.
34 : *
35 : * The protection against overflow is not tight.
36 : */
37 : #define advance(X,B,L) while(*(X) && B+L>X)(X)++;
38 :
39 : /* Copy string in src to *dstp which has *lenp space available and
40 : * terminate with a NULL byte. *dstp and *lenp are adjusted for the
41 : * used space. If there is not enough space to copy all of src,
42 : * return false, otherwise return true. The resulting string is
43 : * always NULL-terminated. */
44 : static inline bool
45 3406049 : copystring(char **dstp, const char *src, size_t *lenp)
46 : {
47 3406049 : size_t len = *lenp;
48 3406049 : char *dst = *dstp;
49 :
50 3406049 : if (src == NULL)
51 : return true;
52 3406049 : if (len > 0) {
53 14501225 : while (*src && len > 1) {
54 11095169 : *dst++ = *src++;
55 11095169 : len--;
56 : }
57 3406056 : *dst = 0;
58 3406056 : *dstp = dst;
59 3406056 : *lenp = len;
60 : }
61 3406049 : return *src == 0;
62 : }
63 :
64 : static void
65 29675 : renderTerm(MalBlkPtr mb, MalStkPtr stk, InstrPtr p, int idx, int flg, char *buf, size_t max_len)
66 : {
67 29675 : char *bufend = buf;
68 29675 : int nameused = 0;
69 29675 : ValRecord *val = 0;
70 29675 : char *cv = 0;
71 29675 : str tpe;
72 29675 : int showtype = 0, closequote = 0;
73 29675 : int varid = getArg(p, idx);
74 :
75 : // show the name when required or is used
76 29675 : if ((flg & LIST_MAL_NAME) && !isVarConstant(mb, varid)
77 13397 : && !isVarTypedef(mb, varid)) {
78 13395 : (void) getVarNameIntoBuffer(mb, varid, bufend);
79 13396 : bufend += strlen(bufend);
80 13396 : nameused = 1;
81 : }
82 : // show the value when required or being a constant
83 29676 : if (((flg & LIST_MAL_VALUE) && stk != 0) || isVarConstant(mb, varid)) {
84 18051 : if (nameused)
85 1778 : bufend = stpcpy(bufend, "=");
86 : // locate value record
87 18051 : if (isVarConstant(mb, varid)) {
88 16273 : val = &getVarConstant(mb, varid);
89 16273 : showtype = getVarType(mb, varid) != TYPE_str
90 16273 : && getVarType(mb, varid) != TYPE_bit;
91 1778 : } else if (stk) {
92 1778 : val = &stk->stk[varid];
93 : }
94 18051 : cv = VALformat(val);
95 18052 : if (cv == NULL) {
96 0 : bufend = stpcpy(bufend, "<alloc failed...>");
97 18052 : } else if (!val->bat && strcmp(cv, "nil") == 0) {
98 200 : bufend = stpcpy(bufend, cv);
99 209 : showtype = showtype ||
100 9 : (getBatType(getVarType(mb, varid)) >= TYPE_date
101 9 : && getBatType(getVarType(mb, varid)) != TYPE_str) ||
102 208 : ((isVarTypedef(mb, varid)) && isVarConstant(mb, varid)) ||
103 8 : isaBatType(getVarType(mb, varid));
104 : } else {
105 17852 : if (!isaBatType(getVarType(mb, varid))
106 16016 : && getBatType(getVarType(mb, varid)) >= TYPE_date
107 7241 : && getBatType(getVarType(mb, varid)) != TYPE_str) {
108 280 : closequote = 1;
109 280 : bufend = stpcpy(bufend, "\"");
110 : }
111 17852 : size_t cv_len = strlen(cv);
112 17852 : if (cv_len > 100) {
113 25 : cv_len = 100;
114 25 : if (cv_len > (size_t) ((buf + max_len) - bufend))
115 0 : cv_len = (buf + max_len) - bufend - 1;
116 25 : strcpy_len(bufend, cv, cv_len + 1); /* 1 for null termination */
117 25 : bufend += cv_len;
118 25 : cv_len = strconcat_len(bufend, (buf + max_len) - bufend, "\" ..... ", NULL);
119 25 : bufend += cv_len;
120 : } else {
121 17827 : bufend = stpcpy(bufend, cv);
122 : }
123 17852 : if (closequote) {
124 280 : bufend = stpcpy(bufend, "\"");
125 : }
126 45413 : showtype = showtype || closequote > TYPE_str ||
127 9709 : ((isVarTypedef(mb, varid) ||
128 27561 : (flg & (LIST_MAL_REMOTE | LIST_MAL_TYPE))) && isVarConstant(mb, varid)) ||
129 1788 : (isaBatType(getVarType(mb, varid)) && idx < p->retc);
130 :
131 17852 : if (stk && isaBatType(getVarType(mb, varid))
132 1665 : && stk->stk[varid].val.bval) {
133 1663 : BAT *d = BBPquickdesc(stk->stk[varid].val.bval);
134 1663 : if (d)
135 1500 : bufend += snprintf(bufend, (buf + max_len) - bufend, "[" BUNFMT "]", BATcount(d));
136 : }
137 : }
138 18052 : GDKfree(cv);
139 : }
140 29677 : *bufend = 0;
141 : // show the type when required or frozen by the user
142 : // special care should be taken with constants, they may have been casted
143 29677 : if ((flg & LIST_MAL_TYPE) || (idx < p->retc) || isVarTypedef(mb, varid)
144 16 : || showtype) {
145 29661 : tpe = getTypeName(getVarType(mb, varid));
146 29658 : if (tpe) {
147 29658 : strconcat_len(bufend, (buf + max_len) - bufend, ":", tpe, NULL);
148 29657 : GDKfree(tpe);
149 : }
150 : }
151 29677 : }
152 :
153 : /*
154 : It receives the space to store the definition
155 : The MAL profiler dumps some performance data at the
156 : beginning of each line.
157 : */
158 :
159 : str
160 162427 : cfcnDefinition(Symbol s, str base, size_t len)
161 : {
162 162427 : unsigned int i;
163 162427 : str arg, tpe;
164 162427 : mel_func *f = s->func;
165 162427 : str t = base;
166 :
167 162427 : if (f->unsafe && !copystring(&t, "unsafe ", &len))
168 : return base;
169 324854 : if (!copystring(&t, operatorName(s->kind), &len) ||
170 324854 : !copystring(&t, " ", &len) ||
171 487281 : !copystring(&t, f->mod ? f->mod : userRef, &len) ||
172 324854 : !copystring(&t, ".", &len) ||
173 324854 : !copystring(&t, f->fcn, &len) || !copystring(&t, "(", &len))
174 0 : return base;
175 :
176 162427 : char var[16];
177 617542 : for (i = f->retc; i < f->argc; i++) {
178 455115 : if (snprintf(var, 16, "X_%d:", i-f->retc) >= 16 || !copystring(&t, var, &len))
179 0 : return base;
180 714011 : if ((f->args[i].isbat || (f->args[i].opt == 1)) && !copystring(&t, (f->args[i].opt == 1)?"bat?[:":"bat[:", &len))
181 : return base;
182 455115 : arg = f->args[i].type;
183 455115 : if (arg[0] && !copystring(&t, arg, &len))
184 : return base;
185 455115 : if (!arg[0]) {
186 17314 : if (f->args[i].nr) {
187 15904 : if (snprintf(var, 16, "any_%d", f->args[i].nr ) >= 16 || !copystring(&t, var, &len))
188 0 : return base;
189 1410 : } else if (!copystring(&t, "any", &len))
190 : return base;
191 : }
192 455115 : if ((f->args[i].isbat || f->args[i].opt == 1) && !copystring(&t, "]", &len))
193 : return base;
194 455115 : if (i+1 < f->argc && !copystring(&t, ", ", &len))
195 : return base;
196 : }
197 :
198 162427 : advance(t, base, len);
199 162427 : if (f->vargs && !copystring(&t, "...", &len))
200 : return base;
201 :
202 162427 : if (f->retc == 0) {
203 1586 : if (!copystring(&t, "):void", &len))
204 : return base;
205 160841 : } else if (f->retc == 1) {
206 157401 : if (!copystring(&t, "):", &len))
207 : return base;
208 265723 : if ((f->args[0].isbat || f->args[0].opt == 1) && !copystring(&t, (f->args[0].opt == 1)?"bat?[:":"bat[:", &len))
209 : return base;
210 157401 : tpe = f->args[0].type;
211 157401 : if (tpe[0] && !copystring(&t, tpe, &len))
212 : return base;
213 157401 : if (!tpe[0]) {
214 2633 : if (f->args[0].nr) {
215 2450 : if (snprintf(var, 16, "any_%d", f->args[0].nr ) >= 16 || !copystring(&t, var, &len))
216 0 : return base;
217 183 : } else if (!copystring(&t, "any", &len))
218 : return base;
219 : }
220 157401 : if ((f->args[0].isbat || f->args[0].opt == 1) && !copystring(&t, "]", &len))
221 : return base;
222 157401 : if (f->vrets && !copystring(&t, "...", &len))
223 : return base;
224 : } else {
225 3440 : if (!copystring(&t, ") (", &len))
226 : return base;
227 14000 : for (i = 0; i < f->retc; i++) {
228 10560 : if (snprintf(var, 16, "X_%d:", i+(f->argc-f->retc)) >= 16 || !copystring(&t, var, &len))
229 0 : return base;
230 19648 : if ((f->args[i].isbat || (f->args[i].opt == 1)) && !copystring(&t, (f->args[i].opt == 1)?"bat?[:":"bat[:", &len))
231 : return base;
232 10560 : arg = f->args[i].type;
233 10560 : if (arg[0] && !copystring(&t, arg, &len))
234 : return base;
235 10560 : if (!arg[0]) {
236 352 : if (f->args[i].nr) {
237 304 : if (snprintf(var, 16, "any_%d", f->args[i].nr ) >= 16 || !copystring(&t, var, &len))
238 0 : return base;
239 48 : } else if (!copystring(&t, "any", &len))
240 : return base;
241 : }
242 10560 : if ((f->args[i].isbat || f->args[i].opt == 1) && !copystring(&t, "]", &len))
243 : return base;
244 10560 : if (i+1 < f->retc && !copystring(&t, ", ", &len))
245 : return base;
246 : }
247 3440 : if (f->vrets && !copystring(&t, "...", &len))
248 : return base;
249 3440 : if (!copystring(&t, ")", &len))
250 : return base;
251 : }
252 :
253 : return base;
254 : }
255 :
256 : str
257 171 : fcnDefinition(MalBlkPtr mb, InstrPtr p, str t, int flg, str base, size_t len)
258 : {
259 171 : int i, j;
260 171 : char arg[256];
261 171 : str tpe;
262 :
263 171 : len -= t - base;
264 171 : if (!flg && !copystring(&t, "#", &len))
265 : return base;
266 171 : if (mb->inlineProp && !copystring(&t, "inline ", &len))
267 : return base;
268 171 : if (mb->unsafeProp && !copystring(&t, "unsafe ", &len))
269 : return base;
270 342 : if (!copystring(&t, operatorName(p->token), &len) ||
271 342 : !copystring(&t, " ", &len) ||
272 513 : !copystring(&t, getModuleId(p) ? getModuleId(p) : userRef, &len) ||
273 342 : !copystring(&t, ".", &len) ||
274 342 : !copystring(&t, getFunctionId(p), &len) || !copystring(&t, "(", &len))
275 0 : return base;
276 :
277 175 : for (i = p->retc; i < p->argc; i++) {
278 4 : renderTerm(mb, 0, p, i,
279 : (LIST_MAL_NAME | LIST_MAL_TYPE | LIST_MAL_PROPS),
280 : arg, sizeof(arg));
281 4 : if (!copystring(&t, arg, &len))
282 : return base;
283 4 : if (i < p->argc - 1 && !copystring(&t, ", ", &len))
284 : return base;
285 : }
286 :
287 171 : advance(t, base, len);
288 171 : if (p->varargs & VARARGS && !copystring(&t, "...", &len))
289 : return base;
290 :
291 171 : if (p->retc == 1) {
292 171 : if (!copystring(&t, "):", &len))
293 : return base;
294 171 : tpe = getTypeName(getVarType(mb, getArg(p, 0)));
295 171 : if (!copystring(&t, tpe, &len)) {
296 0 : GDKfree(tpe);
297 0 : return base;
298 : }
299 171 : GDKfree(tpe);
300 171 : if (p->varargs & VARRETS && !copystring(&t, "...", &len))
301 : return base;
302 : } else {
303 0 : if (!copystring(&t, ") (", &len))
304 : return base;
305 0 : for (i = 0; i < p->retc; i++) {
306 0 : renderTerm(mb, 0, p, i,
307 : (LIST_MAL_NAME | LIST_MAL_TYPE | LIST_MAL_PROPS),
308 : arg, sizeof(arg));
309 0 : if (!copystring(&t, arg, &len))
310 : return base;
311 0 : if (i < p->retc - 1 && !copystring(&t, ", ", &len))
312 : return base;
313 : }
314 0 : if (p->varargs & VARRETS && !copystring(&t, "...", &len))
315 : return base;
316 0 : if (!copystring(&t, ")", &len))
317 : return base;
318 : }
319 :
320 171 : if ((flg & LIST_MAL_NOCFUNC) == 0) {
321 155 : if (mb->binding[0]) {
322 0 : if (!copystring(&t, " address ", &len) ||
323 0 : !copystring(&t, mb->binding, &len))
324 0 : return base;
325 : }
326 155 : (void) copystring(&t, ";", &len);
327 : }
328 : /* add the extra properties for debugging */
329 171 : if (flg & LIST_MAL_PROPS) {
330 1 : char extra[256];
331 1 : if (p->token == REMsymbol) {
332 : } else {
333 0 : snprintf(extra, 256, "\t#[%d] (" BUNFMT ") %s ", getPC(mb, p),
334 1 : getRowCnt(mb, getArg(p, 0)),
335 1 : (p->blk ? p->blk->binding : ""));
336 1 : if (!copystring(&t, extra, &len))
337 0 : return base;
338 2 : for (j = 0; j < p->retc; j++) {
339 1 : snprintf(extra, 256, "%d ", getArg(p, j));
340 1 : if (!copystring(&t, extra, &len))
341 : return base;
342 : }
343 1 : if (p->argc - p->retc > 0) {
344 0 : if (!copystring(&t, "<- ", &len))
345 : return base;
346 : }
347 1 : for (; j < p->argc; j++) {
348 0 : snprintf(extra, 256, "%d ", getArg(p, j));
349 0 : if (!copystring(&t, extra, &len))
350 : return base;
351 : }
352 1 : if (!p->typeresolved) {
353 0 : if (!copystring(&t, " type check needed", &len))
354 : return base;
355 : }
356 : }
357 : }
358 : return base;
359 : }
360 :
361 : static str
362 3160 : fmtRemark(MalBlkPtr mb, MalStkPtr stk, InstrPtr pci, str t, int flg, str base,
363 : size_t len)
364 : {
365 3160 : char aux[128];
366 :
367 3160 : if (!copystring(&t, "# ", &len))
368 : return base;
369 :
370 3160 : if (pci->argc == 3) {
371 3156 : if (getFunctionId(pci)) {
372 3156 : char arg[256];
373 3156 : renderTerm(mb, stk, pci, 1, flg, arg, sizeof(arg));
374 3156 : int a1 = atoi(arg);
375 3156 : renderTerm(mb, stk, pci, 2, flg, arg, sizeof(arg));
376 3156 : long a2 = atol(arg);
377 3156 : const char *f = getFunctionId(pci);
378 3156 : if (strcmp(f, "total") == 0)
379 108 : snprintf(aux, 128, "%d optimizers %ld usecs", a1, a2);
380 : else
381 3048 : snprintf(aux, 128, "%-36s %d actions %ld usecs", f, a1, a2);
382 3156 : (void) copystring(&t, aux, &len);
383 : }
384 4 : } else if (pci->argc == 1) {
385 4 : if (getFunctionId(pci)) {
386 4 : if (!copystring(&t, getFunctionId(pci), &len))
387 : return base;
388 : }
389 0 : } else if (getVar(mb, getArg(pci, 0))->value.val.sval &&
390 0 : getVar(mb, getArg(pci, 0))->value.len > 0 &&
391 0 : !copystring(&t, getVar(mb, getArg(pci, 0))->value.val.sval,
392 : &len))
393 : return base;
394 :
395 : return base;
396 : }
397 :
398 : str
399 162707 : operatorName(int i)
400 : {
401 162707 : switch (i) {
402 : case ASSIGNsymbol:
403 : return ":=";
404 20 : case BARRIERsymbol:
405 20 : return "barrier";
406 0 : case REDOsymbol:
407 0 : return "redo";
408 0 : case LEAVEsymbol:
409 0 : return "leave";
410 12 : case EXITsymbol:
411 12 : return "exit";
412 0 : case RETURNsymbol:
413 0 : return "return";
414 0 : case CATCHsymbol:
415 0 : return "catch";
416 0 : case RAISEsymbol:
417 0 : return "raise";
418 36 : case ENDsymbol:
419 36 : return "end";
420 212 : case FUNCTIONsymbol:
421 212 : return "function";
422 25313 : case COMMANDsymbol:
423 25313 : return "command";
424 137114 : case PATTERNsymbol:
425 137114 : return "pattern";
426 :
427 : /* internal symbols */
428 : case FCNcall:
429 0 : assert(0);
430 : return "FCNcall";
431 : case CMDcall:
432 0 : assert(0);
433 : return "CMDcall";
434 : case PATcall:
435 0 : assert(0);
436 : return "PATcall";
437 : }
438 0 : return "";
439 : }
440 :
441 : str
442 8603 : instruction2str(MalBlkPtr mb, MalStkPtr stk, InstrPtr p, int flg)
443 : {
444 8603 : int i, j;
445 8603 : str base, t;
446 8603 : size_t len = 512 + (p->argc * 128); /* max realistic line length estimate */
447 :
448 8603 : t = base = GDKmalloc(len);
449 8606 : if (base == NULL)
450 : return NULL;
451 8606 : if (!flg) {
452 1 : *t++ = '#';
453 1 : len--;
454 1 : if (!p->typeresolved) {
455 0 : *t++ = '!'; /* error */
456 0 : len--;
457 : }
458 : }
459 8606 : *t = 0;
460 8606 : if (p->token == REMsymbol
461 3164 : && !(getModuleId(p) && strcmp(getModuleId(p), "querylog") == 0
462 0 : && getFunctionId(p) && strcmp(getFunctionId(p), "define") == 0)) {
463 : /* do nothing */
464 5442 : } else if (p->barrier) {
465 28 : if (p->barrier == LEAVEsymbol ||
466 28 : p->barrier == REDOsymbol ||
467 : p->barrier == RETURNsymbol || p->barrier == RAISEsymbol) {
468 0 : if (!copystring(&t, " ", &len))
469 : return base;
470 : }
471 28 : if (!copystring(&t, operatorName(p->barrier), &len) || !copystring(&t, " ", &len))
472 0 : return base;
473 5414 : } else if (functionStart(p) && flg != LIST_MAL_CALL) {
474 150 : return fcnDefinition(mb, p, t, flg, base, len + (t - base));
475 5264 : } else if (!functionExit(p) && flg != LIST_MAL_CALL) {
476 : // beautify with tabs
477 5110 : if (!copystring(&t, " ", &len))
478 : return base;
479 : }
480 8455 : switch (p->token < 0 ? -p->token : p->token) {
481 5138 : case FCNcall:
482 : case PATcall:
483 : case CMDcall:
484 : case ASSIGNsymbol:
485 : // is any variable explicit or used
486 : /* this code was meant to make it easy to detect functions whose
487 : * result variable was not used anywhere.
488 : * It is not essential
489 : for (i = 0; i < p->retc; i++)
490 : if ( !isTmpVar(mb,getArg(p,i)) || isVarUsed(mb, getArg(p, i)))
491 : break;
492 :
493 : if (i == p->retc)
494 : break;
495 : */
496 :
497 : /* display multi-assignment list */
498 5138 : if (p->retc > 1 && !copystring(&t, "(", &len))
499 : return base;
500 :
501 10387 : for (i = 0; i < p->retc; i++) {
502 5248 : char arg[256];
503 5248 : renderTerm(mb, stk, p, i, flg, arg, sizeof(arg));
504 5249 : if (!copystring(&t, arg, &len))
505 0 : return base;
506 5249 : if (i < p->retc - 1 && !copystring(&t, ", ", &len))
507 : return base;
508 : }
509 5139 : if (p->retc > 1 && !copystring(&t, ")", &len))
510 : return base;
511 :
512 5139 : if (p->argc > p->retc || getFunctionId(p)) {
513 5127 : if (!copystring(&t, " := ", &len))
514 : return base;
515 : }
516 : break;
517 149 : case ENDsymbol:
518 298 : if (!copystring(&t, "end ", &len) ||
519 298 : !copystring(&t, getModuleId(getInstrPtr(mb, 0)), &len) ||
520 298 : !copystring(&t, ".", &len) ||
521 149 : !copystring(&t, getFunctionId(getInstrPtr(mb, 0)), &len))
522 0 : return base;
523 : break;
524 5 : case COMMANDsymbol:
525 : case FUNCTIONsymbol:
526 : case PATTERNsymbol:
527 5 : if (flg & LIST_MAL_VALUE) {
528 10 : if (!copystring(&t, operatorName(p->token), &len) ||
529 5 : !copystring(&t, " ", &len))
530 0 : return base;
531 : }
532 5 : return fcnDefinition(mb, p, t, flg, base, len + (t - base));
533 3160 : case REMsymbol:
534 3160 : return fmtRemark(mb, stk, p, t, flg, base, len);
535 3 : default:
536 3 : i = snprintf(t, len, " unknown symbol ?%d? ", p->token);
537 3 : if (i < 0 || (size_t) i >= len)
538 : return base;
539 3 : len -= (size_t) i;
540 3 : t += i;
541 3 : break;
542 : }
543 :
544 5290 : if (getModuleId(p)) {
545 5127 : if (!copystring(&t, getModuleId(p), &len) || !copystring(&t, ".", &len))
546 0 : return base;
547 : }
548 5288 : if (getFunctionId(p)) {
549 10254 : if (!copystring(&t, getFunctionId(p), &len) ||
550 5127 : !copystring(&t, "(", &len))
551 0 : return base;
552 161 : } else if (p->argc > p->retc + 1) {
553 0 : if (!copystring(&t, "(", &len))
554 : return base;
555 : }
556 23400 : for (i = p->retc; i < p->argc; i++) {
557 18112 : char arg[256];
558 18112 : renderTerm(mb, stk, p, i, flg, arg, sizeof(arg));
559 18112 : if (!copystring(&t, arg, &len))
560 0 : return base;
561 18112 : if (i < p->argc - 1 && !copystring(&t, ", ", &len))
562 : return base;
563 : }
564 5288 : if (getFunctionId(p) || p->argc > p->retc + 1) {
565 5127 : if (!copystring(&t, ")", &len))
566 : return base;
567 : }
568 5288 : if (p->token != REMsymbol) {
569 5288 : if (!copystring(&t, ";", &len))
570 : return base;
571 : }
572 : /* add the extra properties for debugging */
573 5288 : if (flg & LIST_MAL_PROPS) {
574 2400 : char extra[256];
575 2400 : if (p->token == REMsymbol) {
576 : } else {
577 1 : snprintf(extra, 256, "\t#[%d] (" BUNFMT ") %s ", p->pc,
578 2400 : getRowCnt(mb, getArg(p, 0)),
579 2400 : (p->blk ? p->blk->binding : ""));
580 2400 : if (!copystring(&t, extra, &len))
581 0 : return base;
582 4834 : for (j = 0; j < p->retc; j++) {
583 2434 : snprintf(extra, 256, "%d ", getArg(p, j));
584 2434 : if (!copystring(&t, extra, &len))
585 : return base;
586 : }
587 2400 : if (p->argc - p->retc > 0) {
588 2397 : if (!copystring(&t, "<- ", &len))
589 : return base;
590 : }
591 12061 : for (; j < p->argc; j++) {
592 9661 : snprintf(extra, 256, "%d ", getArg(p, j));
593 9661 : if (!copystring(&t, extra, &len))
594 : return base;
595 : }
596 2400 : if (!p->typeresolved) {
597 0 : if (!copystring(&t, " type check needed", &len))
598 : return base;
599 : }
600 : }
601 : }
602 5288 : if (flg & LIST_MAL_ALGO) {
603 807 : const char *algo = MT_thread_getalgorithm();
604 807 : if (algo) {
605 122 : if (!copystring(&t, " # ", &len))
606 : return base;
607 122 : if (!copystring(&t, algo, &len))
608 : return base;
609 : }
610 : }
611 : return base;
612 : }
613 :
614 : /* the MAL beautifier is meant to simplify correlation of MAL variables and
615 : * the columns in the underlying database.
616 : * If the status is set, then we consider the instruction DONE and the result variables
617 : * should be shown as well.
618 : */
619 :
620 : /* Remote execution of MAL calls for more type/property information to be exchanged */
621 : str
622 0 : mal2str(MalBlkPtr mb, int first, int last)
623 : {
624 0 : str ps = NULL, *txt;
625 0 : int i, j;
626 0 : size_t *len, totlen = 0;
627 :
628 0 : txt = GDKmalloc(sizeof(str) * mb->stop);
629 0 : len = GDKmalloc(sizeof(size_t) * mb->stop);
630 :
631 0 : if (txt == NULL || len == NULL) {
632 0 : addMalException(mb, "mal2str: " MAL_MALLOC_FAIL);
633 0 : GDKfree(txt);
634 0 : GDKfree(len);
635 0 : return NULL;
636 : }
637 0 : for (i = first; i < last; i++) {
638 0 : if (i == 0)
639 0 : txt[i] = instruction2str(mb, 0, getInstrPtr(mb, i),
640 : LIST_MAL_NAME | LIST_MAL_TYPE |
641 : LIST_MAL_PROPS);
642 : else
643 0 : txt[i] = instruction2str(mb, 0, getInstrPtr(mb, i),
644 : LIST_MAL_CALL | LIST_MAL_PROPS |
645 : LIST_MAL_REMOTE);
646 :
647 0 : if (txt[i])
648 0 : totlen += len[i] = strlen(txt[i]);
649 : else {
650 0 : addMalException(mb, "mal2str: " MAL_MALLOC_FAIL);
651 0 : GDKfree(len);
652 0 : for (j = first; j < i; j++)
653 0 : GDKfree(txt[j]);
654 0 : GDKfree(txt);
655 0 : return NULL;
656 : }
657 : }
658 0 : ps = GDKmalloc(totlen + mb->stop + 1);
659 0 : if (ps == NULL) {
660 0 : addMalException(mb, "mal2str: " MAL_MALLOC_FAIL);
661 0 : GDKfree(len);
662 0 : for (i = first; i < last; i++)
663 0 : GDKfree(txt[i]);
664 0 : GDKfree(txt);
665 0 : return NULL;
666 : }
667 :
668 : totlen = 0;
669 0 : for (i = first; i < last; i++) {
670 0 : if (txt[i]) {
671 0 : strncpy(ps + totlen, txt[i], len[i]);
672 0 : ps[totlen + len[i]] = '\n';
673 0 : ps[totlen + len[i] + 1] = 0;
674 0 : totlen += len[i] + 1;
675 0 : GDKfree(txt[i]);
676 : }
677 : }
678 0 : GDKfree(len);
679 0 : GDKfree(txt);
680 0 : return ps;
681 : }
682 :
683 : void
684 2689 : printInstruction(stream *fd, MalBlkPtr mb, MalStkPtr stk, InstrPtr p, int flg)
685 : {
686 2689 : str ps;
687 :
688 2689 : if (fd == 0)
689 : return;
690 2689 : ps = instruction2str(mb, stk, p, flg);
691 : /* ps[strlen(ps)-1] = 0; remove '\n' */
692 2689 : if (ps) {
693 2729 : mnstr_printf(fd, "%s%s", (flg & LIST_MAL_MAPI ? "=" : ""), ps);
694 2689 : GDKfree(ps);
695 : } else {
696 0 : mnstr_printf(fd, "#failed instruction2str()");
697 : }
698 2689 : mnstr_printf(fd, "\n");
699 : }
700 :
701 : void
702 43899255 : traceInstruction(MalBlkPtr mb, MalStkPtr stk, InstrPtr p, int flg)
703 : {
704 43899255 : str ps;
705 43899255 : TRC_DEBUG_IF(MAL_OPTIMIZER) {
706 0 : ps = instruction2str(mb, stk, p, flg);
707 : /* ps[strlen(ps)-1] = 0; remove '\n' */
708 0 : if (ps) {
709 0 : TRC_DEBUG_ENDIF(MAL_OPTIMIZER, "%s%s\n",
710 : (flg & LIST_MAL_MAPI ? "=" : ""), ps);
711 0 : GDKfree(ps);
712 : } else {
713 0 : TRC_DEBUG_ENDIF(MAL_OPTIMIZER, "Failed instruction2str()\n");
714 : }
715 : }
716 43899255 : }
717 :
718 : void
719 0 : printSignature(stream *fd, Symbol s, int flg)
720 : {
721 0 : InstrPtr p;
722 0 : str txt;
723 :
724 0 : if (s->def == 0) {
725 0 : mnstr_printf(fd, "missing definition of %s\n", s->name);
726 0 : return;
727 : }
728 0 : txt = GDKzalloc(MAXLISTING); /* some slack for large blocks */
729 0 : if (txt) {
730 0 : p = getSignature(s);
731 0 : (void) fcnDefinition(s->def, p, txt, flg, txt, MAXLISTING);
732 0 : mnstr_printf(fd, "%s\n", txt);
733 0 : GDKfree(txt);
734 : } else
735 0 : mnstr_printf(fd, "printSignature: " MAL_MALLOC_FAIL);
736 : }
|