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