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 : * M.L. Kersten
15 : * XML multiplexes
16 : * SQL/XML requires a handful of instructions.
17 : * The collection of routines provided here are map operations
18 : * for the atom xml primitives.
19 : *
20 : * In line with the batcalc module, we assume that if two bat operands
21 : * are provided that they are aligned.
22 : *
23 : * The implementation is focussed on functionality. At a later stage
24 : * we may postpone string contstruction until it is really needed.
25 : */
26 :
27 :
28 :
29 : #include "monetdb_config.h"
30 : #include "gdk.h"
31 : #include <ctype.h>
32 : #include <string.h>
33 : #ifdef HAVE_LIBXML
34 : #include <libxml/parser.h>
35 : #endif
36 : #include "mal_interpreter.h"
37 : #include "mal_function.h"
38 : #include "xml.h"
39 :
40 : #include "mel.h"
41 :
42 : #ifdef HAVE_LIBXML
43 :
44 : #define prepareResult(X,Y,tpe,Z,free) \
45 : do { \
46 : (X) = COLnew((Y)->hseqbase, (tpe), BATcount(Y), TRANSIENT); \
47 : if ((X) == NULL) { \
48 : BBPunfix((Y)->batCacheid); \
49 : free; \
50 : throw(MAL, "xml." Z, SQLSTATE(HY013) MAL_MALLOC_FAIL); \
51 : } \
52 : (X)->tsorted = false; \
53 : (X)->trevsorted = false; \
54 : (X)->tnonil = true; \
55 : (X)->tkey = false; \
56 : } while (0)
57 :
58 : #define finalizeResult(X,Y,Z) \
59 : do { \
60 : BATsetcount((Y), (Y)->batCount); \
61 : *(X) = (Y)->batCacheid; \
62 : BBPkeepref(Y); \
63 : BBPunfix((Z)->batCacheid); \
64 : } while (0)
65 :
66 : static str
67 12 : BATXMLxml2str(bat *ret, const bat *bid)
68 : {
69 12 : BAT *b, *bn;
70 12 : BUN p, q;
71 12 : BATiter bi;
72 :
73 12 : if ((b = BATdescriptor(*bid)) == NULL)
74 0 : throw(MAL, "xml.str", INTERNAL_BAT_ACCESS);
75 12 : prepareResult(bn, b, TYPE_str, "str", (void) 0);
76 12 : bi = bat_iterator(b);
77 36 : BATloop(b, p, q) {
78 24 : const char *t = (const char *) BUNtvar(bi, p);
79 :
80 24 : if (strNil(t)) {
81 0 : if (bunfastapp_nocheckVAR(bn, t) != GDK_SUCCEED)
82 0 : goto bunins_failed;
83 0 : bn->tnonil = false;
84 : } else {
85 24 : assert(*t == 'A' || *t == 'C' || *t == 'D');
86 24 : if (bunfastapp_nocheckVAR(bn, t + 1) != GDK_SUCCEED)
87 0 : goto bunins_failed;
88 : }
89 : }
90 12 : bat_iterator_end(&bi);
91 12 : finalizeResult(ret, bn, b);
92 12 : return MAL_SUCCEED;
93 0 : bunins_failed:
94 0 : bat_iterator_end(&bi);
95 0 : BBPunfix(b->batCacheid);
96 0 : BBPunfix(bn->batCacheid);
97 0 : throw(MAL, "xml.str", OPERATION_FAILED " during bulk coercion");
98 : }
99 :
100 : static str
101 0 : BATXMLxmltext(bat *ret, const bat *bid)
102 : {
103 0 : BAT *b, *bn;
104 0 : BUN p, q;
105 0 : BATiter bi;
106 0 : size_t size = 0;
107 0 : str buf = NULL;
108 0 : xmlDocPtr doc = NULL;
109 0 : xmlNodePtr elem;
110 0 : str content = NULL;
111 0 : const char *err = OPERATION_FAILED;
112 :
113 0 : if ((b = BATdescriptor(*bid)) == NULL)
114 0 : throw(MAL, "xml.text", INTERNAL_BAT_ACCESS);
115 0 : prepareResult(bn, b, TYPE_str, "text", (void) 0);
116 0 : bi = bat_iterator(b);
117 0 : BATloop(b, p, q) {
118 0 : const char *t = (const char *) BUNtvar(bi, p);
119 0 : size_t len;
120 :
121 0 : if (strNil(t)) {
122 0 : if (bunfastapp_nocheckVAR(bn, t) != GDK_SUCCEED)
123 0 : goto bunins_failed;
124 0 : bn->tnonil = false;
125 0 : continue;
126 : }
127 0 : len = strlen(t);
128 0 : switch (*t) {
129 0 : case 'D':{
130 0 : xmlDocPtr d = xmlParseMemory(t + 1, (int) (len - 1));
131 0 : elem = xmlDocGetRootElement(d);
132 0 : content = (str) xmlNodeGetContent(elem);
133 0 : xmlFreeDoc(d);
134 0 : if (content == NULL) {
135 0 : err = SQLSTATE(HY013) MAL_MALLOC_FAIL;
136 0 : goto bunins_failed;
137 : }
138 : break;
139 : }
140 0 : case 'C':
141 0 : if (doc == NULL)
142 0 : doc = xmlParseMemory("<doc/>", 6);
143 0 : xmlParseInNodeContext(xmlDocGetRootElement(doc), t + 1,
144 0 : (int) (len - 1), 0, &elem);
145 0 : content = (str) xmlNodeGetContent(elem);
146 0 : xmlFreeNodeList(elem);
147 0 : if (content == NULL) {
148 0 : err = SQLSTATE(HY013) MAL_MALLOC_FAIL;
149 0 : goto bunins_failed;
150 : }
151 : break;
152 0 : case 'A':{
153 0 : str s;
154 :
155 0 : if (buf == NULL || size < len) {
156 0 : size = len + 128;
157 0 : if (buf != NULL)
158 0 : GDKfree(buf);
159 0 : buf = GDKmalloc(size);
160 0 : if (buf == NULL) {
161 0 : err = SQLSTATE(HY013) MAL_MALLOC_FAIL;
162 0 : goto bunins_failed;
163 : }
164 : }
165 0 : s = buf;
166 0 : t++;
167 0 : while (*t) {
168 0 : if (*t == '"' || *t == '\'') {
169 0 : char q = *t++;
170 :
171 0 : s += XMLunquotestring(&t, q, s);
172 : }
173 0 : t++;
174 : }
175 0 : *s = 0;
176 0 : break;
177 : }
178 : default:
179 0 : assert(*t == 'A' || *t == 'C' || *t == 'D');
180 : if (bunfastapp_nocheckVAR(bn, str_nil) != GDK_SUCCEED)
181 : goto bunins_failed;
182 : bn->tnonil = false;
183 : continue;
184 : }
185 0 : assert(content != NULL || buf != NULL);
186 0 : if (bunfastapp_nocheckVAR(bn, content != NULL ? content : buf) != GDK_SUCCEED)
187 0 : goto bunins_failed;
188 0 : if (content != NULL)
189 0 : GDKfree(content);
190 0 : content = NULL;
191 : }
192 0 : bat_iterator_end(&bi);
193 0 : finalizeResult(ret, bn, b);
194 0 : if (buf != NULL)
195 0 : GDKfree(buf);
196 0 : if (doc != NULL)
197 0 : xmlFreeDoc(doc);
198 : return MAL_SUCCEED;
199 0 : bunins_failed:
200 0 : bat_iterator_end(&bi);
201 0 : BBPunfix(b->batCacheid);
202 0 : BBPunfix(bn->batCacheid);
203 0 : if (buf != NULL)
204 0 : GDKfree(buf);
205 0 : if (doc != NULL)
206 0 : xmlFreeDoc(doc);
207 0 : if (content != NULL)
208 0 : GDKfree(content);
209 0 : throw(MAL, "xml.text", "%s", err);
210 : }
211 :
212 : /*
213 : * The core of the activity is str2xml, where the actual strings
214 : * are constructed.
215 : * To avoid repetitive copying we make sure that the garbage
216 : * collector does not remove the xml intermediates.
217 : * This way, we know that as long as the xml-variables are not
218 : * reused, the complete structure of the xml document(s) are available.
219 : * We merely have to collect the pieces.
220 : * [FOR LATER, FIRST GO FOR THE EASY IMPLEMENTATION]
221 : * XML values are represented by strings already.
222 : */
223 : static str
224 56 : BATXMLstr2xml(bat *ret, const bat *bid)
225 : {
226 56 : BAT *b, *bn;
227 56 : BUN p, q;
228 56 : size_t size = BUFSIZ;
229 56 : str buf;
230 56 : const char *err = OPERATION_FAILED;
231 56 : BATiter bi;
232 :
233 56 : buf = GDKmalloc(size);
234 56 : if (buf == NULL)
235 0 : throw(MAL, "xml.str2xml", SQLSTATE(HY013) MAL_MALLOC_FAIL);
236 56 : if ((b = BATdescriptor(*bid)) == NULL) {
237 0 : GDKfree(buf);
238 0 : throw(MAL, "xml.xml", INTERNAL_BAT_ACCESS);
239 : }
240 56 : prepareResult(bn, b, TYPE_xml, "xml", GDKfree(buf));
241 56 : bi = bat_iterator(b);
242 148 : BATloop(b, p, q) {
243 92 : const char *t = (const char *) BUNtvar(bi, p);
244 92 : size_t len;
245 :
246 92 : if (strNil(t)) {
247 0 : if (bunfastapp_nocheckVAR(bn, str_nil) != GDK_SUCCEED)
248 0 : goto bunins_failed;
249 0 : bn->tnonil = false;
250 0 : continue;
251 : }
252 :
253 92 : len = strlen(t) * 6 + 1;
254 92 : if (size < len) {
255 0 : size = len + 128;
256 0 : GDKfree(buf);
257 0 : buf = GDKmalloc(size);
258 0 : if (buf == NULL) {
259 0 : err = SQLSTATE(HY013) MAL_MALLOC_FAIL;
260 0 : goto bunins_failed;
261 : }
262 : }
263 92 : buf[0] = 'C';
264 92 : XMLquotestring(t, buf + 1, size - 1);
265 91 : if (bunfastapp_nocheckVAR(bn, buf) != GDK_SUCCEED)
266 0 : goto bunins_failed;
267 : }
268 56 : bat_iterator_end(&bi);
269 56 : GDKfree(buf);
270 56 : finalizeResult(ret, bn, b);
271 56 : return MAL_SUCCEED;
272 0 : bunins_failed:
273 0 : bat_iterator_end(&bi);
274 0 : BBPunfix(b->batCacheid);
275 0 : BBPunfix(bn->batCacheid);
276 0 : if (buf != NULL)
277 0 : GDKfree(buf);
278 0 : throw(MAL, "xml.xml", "%s", err);
279 : }
280 :
281 : static str
282 0 : BATXMLdocument(bat *ret, const bat *bid)
283 : {
284 0 : BAT *b, *bn;
285 0 : BUN p, q;
286 0 : BATiter bi;
287 0 : size_t size = BUFSIZ;
288 0 : str buf = GDKmalloc(size);
289 0 : const char *err = OPERATION_FAILED;
290 :
291 0 : if (buf == NULL)
292 0 : throw(MAL, "xml.document", SQLSTATE(HY013) MAL_MALLOC_FAIL);
293 0 : if ((b = BATdescriptor(*bid)) == NULL) {
294 0 : GDKfree(buf);
295 0 : throw(MAL, "xml.document", INTERNAL_BAT_ACCESS);
296 : }
297 0 : prepareResult(bn, b, TYPE_xml, "document", GDKfree(buf));
298 0 : bi = bat_iterator(b);
299 0 : BATloop(b, p, q) {
300 0 : const char *t = (const char *) BUNtvar(bi, p);
301 0 : xmlDocPtr doc;
302 0 : int len;
303 0 : xmlChar *s;
304 :
305 0 : if (strNil(t)) {
306 0 : if (bunfastapp_nocheckVAR(bn, str_nil) != GDK_SUCCEED)
307 0 : goto bunins_failed;
308 0 : bn->tnonil = false;
309 0 : continue;
310 : }
311 0 : len = (int) strlen(t);
312 0 : doc = xmlParseMemory(t, len);
313 0 : if (doc == NULL) {
314 0 : err = OPERATION_FAILED XML_PARSE_ERROR;
315 0 : goto bunins_failed;
316 : }
317 0 : xmlDocDumpMemory(doc, &s, &len);
318 0 : xmlFreeDoc(doc);
319 0 : if ((size_t) len + 2 >= size) {
320 0 : GDKfree(buf);
321 0 : size = (size_t) len + 128;
322 0 : buf = GDKmalloc(size);
323 0 : if (buf == NULL) {
324 0 : err = MAL_MALLOC_FAIL;
325 0 : goto bunins_failed;
326 : }
327 : }
328 0 : buf[0] = 'D';
329 0 : strcpy(buf + 1, (char *) s);
330 0 : if (bunfastapp_nocheckVAR(bn, buf) != GDK_SUCCEED)
331 0 : goto bunins_failed;
332 : }
333 0 : bat_iterator_end(&bi);
334 0 : GDKfree(buf);
335 0 : finalizeResult(ret, bn, b);
336 0 : return MAL_SUCCEED;
337 0 : bunins_failed:
338 0 : bat_iterator_end(&bi);
339 0 : GDKfree(buf);
340 0 : BBPunfix(b->batCacheid);
341 0 : BBPunfix(bn->batCacheid);
342 0 : throw(MAL, "xml.document", "%s", err);
343 : }
344 :
345 : static str
346 0 : BATXMLcontent(bat *ret, const bat *bid)
347 : {
348 0 : BAT *b, *bn;
349 0 : BUN p, q;
350 0 : BATiter bi;
351 0 : xmlDocPtr doc;
352 0 : xmlNodePtr root;
353 0 : size_t size = BUFSIZ;
354 0 : str buf = GDKmalloc(size);
355 0 : const char *err = OPERATION_FAILED;
356 0 : xmlBufferPtr xbuf;
357 :
358 0 : if (buf == NULL)
359 0 : throw(MAL, "xml.content", SQLSTATE(HY013) MAL_MALLOC_FAIL);
360 0 : if ((b = BATdescriptor(*bid)) == NULL) {
361 0 : GDKfree(buf);
362 0 : throw(MAL, "xml.content", INTERNAL_BAT_ACCESS);
363 : }
364 0 : doc = xmlParseMemory("<doc/>", 6);
365 0 : root = xmlDocGetRootElement(doc);
366 0 : prepareResult(bn, b, TYPE_xml, "content", GDKfree(buf));
367 0 : bi = bat_iterator(b);
368 0 : xbuf = xmlBufferCreate();
369 0 : BATloop(b, p, q) {
370 0 : const char *t = (const char *) BUNtvar(bi, p);
371 0 : size_t len;
372 0 : xmlNodePtr elem;
373 0 : xmlParserErrors xerr;
374 0 : const xmlChar *s;
375 :
376 0 : if (strNil(t)) {
377 0 : if (bunfastapp_nocheckVAR(bn, str_nil) != GDK_SUCCEED)
378 0 : goto bunins_failed;
379 0 : bn->tnonil = false;
380 0 : continue;
381 : }
382 0 : len = strlen(t);
383 0 : xerr = xmlParseInNodeContext(root, t, (int) len, 0, &elem);
384 0 : if (xerr != XML_ERR_OK) {
385 0 : err = XML_PARSE_ERROR;
386 0 : goto bunins_failed;
387 : }
388 0 : xmlNodeDump(xbuf, doc, elem, 0, 0);
389 0 : s = xmlBufferContent(xbuf);
390 0 : len = strlen((const char *) s);
391 0 : if (len + 2 >= size) {
392 0 : GDKfree(buf);
393 0 : size = len + 128;
394 0 : buf = GDKmalloc(size);
395 0 : if (buf == NULL) {
396 0 : err = SQLSTATE(HY013) MAL_MALLOC_FAIL;
397 0 : goto bunins_failed;
398 : }
399 : }
400 0 : buf[0] = 'C';
401 0 : strcpy(buf + 1, (const char *) s);
402 0 : if (bunfastapp_nocheckVAR(bn, buf) != GDK_SUCCEED)
403 0 : goto bunins_failed;
404 0 : xmlBufferEmpty(xbuf);
405 0 : xmlFreeNodeList(elem);
406 : }
407 0 : bat_iterator_end(&bi);
408 0 : xmlBufferFree(xbuf);
409 0 : xmlFreeDoc(doc);
410 0 : GDKfree(buf);
411 0 : finalizeResult(ret, bn, b);
412 0 : return MAL_SUCCEED;
413 0 : bunins_failed:
414 0 : bat_iterator_end(&bi);
415 0 : xmlBufferFree(xbuf);
416 0 : xmlFreeDoc(doc);
417 0 : if (buf != NULL)
418 0 : GDKfree(buf);
419 0 : BBPunfix(b->batCacheid);
420 0 : BBPunfix(bn->batCacheid);
421 0 : throw(MAL, "xml.document", "%s", err);
422 : }
423 :
424 : static str
425 0 : BATXMLisdocument(bat *ret, const bat *bid)
426 : {
427 0 : BAT *b, *bn;
428 0 : BUN p, q;
429 0 : BATiter bi;
430 :
431 0 : if ((b = BATdescriptor(*bid)) == NULL)
432 0 : throw(MAL, "xml.isdocument", INTERNAL_BAT_ACCESS);
433 0 : prepareResult(bn, b, TYPE_bit, "isdocument", (void) 0);
434 0 : bi = bat_iterator(b);
435 0 : BATloop(b, p, q) {
436 0 : const char *t = (const char *) BUNtvar(bi, p);
437 0 : xmlDocPtr doc;
438 0 : bit val;
439 :
440 0 : if (strNil(t)) {
441 0 : val = bit_nil;
442 0 : bn->tnonil = false;
443 : } else {
444 0 : doc = xmlParseMemory(t, (int) strlen(t));
445 0 : if (doc == NULL) {
446 : val = 0;
447 : } else {
448 0 : xmlFreeDoc(doc);
449 0 : val = 1;
450 : }
451 : }
452 0 : if (bunfastappTYPE(bit, bn, &val) != GDK_SUCCEED) {
453 0 : bat_iterator_end(&bi);
454 0 : BBPunfix(b->batCacheid);
455 0 : BBPunfix(bn->batCacheid);
456 0 : throw(MAL, "xml.isdocument",
457 : OPERATION_FAILED " During bulk processing");
458 : }
459 : }
460 0 : bat_iterator_end(&bi);
461 0 : finalizeResult(ret, bn, b);
462 0 : return MAL_SUCCEED;
463 : }
464 :
465 : /*
466 : * The standard supports specific mappings for
467 : * NULL values,i.e. {null,absent,empty,nil,niloncontent)
468 : * in the context of an element and forest construction.
469 : * The standard should be studied in more detail, because
470 : * the syntax(rules) seem ambiguous.
471 : * It applies to all components of an element or their
472 : * concatenation.
473 : *
474 : * For the time being, the variaton on XMLtag seems the
475 : * most reasonable interpretation.
476 : */
477 : static str
478 0 : BATXMLoptions(bat *ret, const char *const *name, const char *const *options,
479 : const bat *bid)
480 : {
481 0 : BAT *b, *bn;
482 0 : BUN p, q;
483 0 : str buf = GDKmalloc(BUFSIZ);
484 0 : str val = GDKmalloc(BUFSIZ);
485 0 : size_t size = BUFSIZ, len = strlen(*name);
486 0 : BATiter bi = (BATiter) {.b = NULL };
487 0 : const char *err = OPERATION_FAILED " During bulk options analysis";
488 :
489 0 : if (val == NULL || buf == NULL) {
490 0 : if (val != NULL)
491 0 : GDKfree(val);
492 0 : if (buf != NULL)
493 0 : GDKfree(buf);
494 0 : throw(MAL, "batxml.options", SQLSTATE(HY013) MAL_MALLOC_FAIL);
495 : }
496 0 : if ((b = BATdescriptor(*bid)) == NULL) {
497 0 : GDKfree(val);
498 0 : GDKfree(buf);
499 0 : throw(MAL, "xml.options", INTERNAL_BAT_ACCESS);
500 : }
501 0 : prepareResult(bn, b, TYPE_xml, "options", GDKfree(val);
502 : GDKfree(buf));
503 :
504 0 : if (strcmp(*options, "absent") == 0)
505 0 : buf[0] = 0;
506 0 : else if (strcmp(*options, "empty") == 0)
507 0 : snprintf(buf, size, "<%s></%s>", *name, *name);
508 0 : else if (strcmp(*options, "null") == 0)
509 0 : snprintf(buf, size, "null");
510 0 : else if (strcmp(*options, "nil") == 0)
511 0 : snprintf(buf, size, "nil");
512 : else {
513 : /*if(strcmp(*options,"niloncontent")==0) */
514 0 : err = SQLSTATE(0 A000) PROGRAM_NYI;
515 0 : goto bunins_failed;
516 : }
517 :
518 0 : snprintf(val, size, "<%s>", *name);
519 0 : bi = bat_iterator(b);
520 0 : BATloop(b, p, q) {
521 0 : const char *t = (const char *) BUNtvar(bi, p);
522 :
523 0 : if (strNil(t)) {
524 0 : if (bunfastapp_nocheckVAR(bn, buf) != GDK_SUCCEED)
525 0 : goto bunins_failed1;
526 : } else {
527 0 : if (strlen(t) > size - 2 * len - 6) {
528 0 : char *tmp;
529 0 : size += strlen(t);
530 0 : tmp = (char *) GDKrealloc(val, size + strlen(t));
531 0 : if (tmp == NULL) {
532 0 : err = SQLSTATE(HY013) MAL_MALLOC_FAIL;
533 0 : goto bunins_failed1;
534 : }
535 : val = tmp;
536 : }
537 0 : snprintf(val + len + 2, size - len, "%s</%s>", t, *name);
538 0 : if (bunfastapp_nocheckVAR(bn, val) != GDK_SUCCEED)
539 0 : goto bunins_failed1;
540 : }
541 : }
542 0 : bat_iterator_end(&bi);
543 0 : GDKfree(val);
544 0 : GDKfree(buf);
545 0 : finalizeResult(ret, bn, b);
546 0 : return MAL_SUCCEED;
547 0 : bunins_failed1:
548 0 : bat_iterator_end(&bi);
549 0 : bunins_failed:
550 0 : BBPunfix(b->batCacheid);
551 0 : BBPunfix(bn->batCacheid);
552 0 : if (buf != NULL)
553 0 : GDKfree(buf);
554 0 : if (val != NULL)
555 0 : GDKfree(val);
556 0 : throw(MAL, "batxml.options", "%s", err);
557 : }
558 :
559 : static str
560 1 : BATXMLcomment(bat *ret, const bat *bid)
561 : {
562 1 : BAT *b, *bn;
563 1 : BUN p, q;
564 1 : size_t size = BUFSIZ;
565 1 : str buf = GDKmalloc(size);
566 1 : BATiter bi;
567 1 : const char *err = OPERATION_FAILED;
568 :
569 1 : if (buf == NULL)
570 0 : throw(MAL, "xml.comment", SQLSTATE(HY013) MAL_MALLOC_FAIL);
571 1 : if ((b = BATdescriptor(*bid)) == NULL) {
572 0 : GDKfree(buf);
573 0 : throw(MAL, "xml.comment", INTERNAL_BAT_ACCESS);
574 : }
575 1 : prepareResult(bn, b, TYPE_xml, "comment", GDKfree(buf));
576 1 : bi = bat_iterator(b);
577 3 : BATloop(b, p, q) {
578 2 : const char *t = (const char *) BUNtvar(bi, p);
579 2 : size_t len;
580 :
581 2 : if (strNil(t)) {
582 0 : if (bunfastapp_nocheckVAR(bn, str_nil) != GDK_SUCCEED)
583 0 : goto bunins_failed;
584 0 : bn->tnonil = false;
585 0 : continue;
586 : }
587 2 : if (strstr(t, "--") != NULL) {
588 0 : err = XML_COMMENT_ERROR;
589 0 : goto bunins_failed;
590 : }
591 2 : len = strlen(t);
592 2 : if (len + 9 >= size) {
593 : /* make sure there is enough space */
594 0 : size = len + 128;
595 : /* free/malloc so we don't copy */
596 0 : GDKfree(buf);
597 0 : buf = GDKmalloc(size);
598 0 : if (buf == NULL) {
599 0 : err = SQLSTATE(HY013) MAL_MALLOC_FAIL;
600 0 : goto bunins_failed;
601 : }
602 : }
603 2 : snprintf(buf, size, "C<!--%s-->", t);
604 2 : if (bunfastapp_nocheckVAR(bn, buf) != GDK_SUCCEED)
605 0 : goto bunins_failed;
606 : }
607 1 : bat_iterator_end(&bi);
608 1 : GDKfree(buf);
609 1 : finalizeResult(ret, bn, b);
610 1 : return MAL_SUCCEED;
611 0 : bunins_failed:
612 0 : bat_iterator_end(&bi);
613 0 : BBPunfix(b->batCacheid);
614 0 : BBPunfix(bn->batCacheid);
615 0 : if (buf != NULL)
616 0 : GDKfree(buf);
617 0 : throw(MAL, "xml.comment", "%s", err);
618 : }
619 :
620 : static str
621 0 : BATXMLparse(bat *ret, const char *const *doccont, const bat *bid,
622 : const char *const *option)
623 : {
624 0 : (void) option;
625 0 : if (strcmp(*doccont, "content") == 0)
626 0 : return BATXMLcontent(ret, bid);
627 0 : if (strcmp(*doccont, "document") == 0)
628 0 : return BATXMLdocument(ret, bid);
629 0 : throw(MAL, "xml.parse",
630 : ILLEGAL_ARGUMENT " <document> or <content> expected");
631 : }
632 :
633 : static str
634 0 : BATXMLpi(bat *ret, const char *const *target, const bat *bid)
635 : {
636 0 : BAT *b, *bn;
637 0 : BUN p, q;
638 0 : size_t size = BUFSIZ;
639 0 : str buf;
640 0 : BATiter bi;
641 0 : size_t tgtlen;
642 0 : const char *err = OPERATION_FAILED;
643 :
644 0 : if (strNil(*target))
645 0 : throw(MAL, "xml.pi", XML_PI_ERROR);
646 0 : buf = GDKmalloc(size);
647 0 : if (buf == NULL)
648 0 : throw(MAL, "xml.pi", SQLSTATE(HY013) MAL_MALLOC_FAIL);
649 :
650 0 : tgtlen = strlen(*target) + 6;
651 0 : if ((b = BATdescriptor(*bid)) == NULL) {
652 0 : GDKfree(buf);
653 0 : throw(MAL, "xml.pi", INTERNAL_BAT_ACCESS);
654 : }
655 0 : prepareResult(bn, b, TYPE_xml, "pi", GDKfree(buf));
656 0 : bi = bat_iterator(b);
657 0 : BATloop(b, p, q) {
658 0 : const char *t = (const char *) BUNtvar(bi, p);
659 0 : size_t len;
660 :
661 0 : len = tgtlen;
662 0 : if (!strNil(t))
663 0 : len += strlen(t) * 6 + 1;
664 0 : if (len >= size) {
665 : /* make sure there is enough space */
666 0 : size = len + 128;
667 : /* free/malloc so we don't copy */
668 0 : GDKfree(buf);
669 0 : buf = GDKmalloc(size);
670 0 : if (buf == NULL) {
671 0 : err = SQLSTATE(HY013) MAL_MALLOC_FAIL;
672 0 : goto bunins_failed;
673 : }
674 : }
675 0 : if (strNil(t))
676 0 : snprintf(buf, size, "C<?%s?>", *target);
677 : else {
678 0 : int n = snprintf(buf, size, "C<?%s ", *target);
679 0 : size_t m = XMLquotestring(t, buf + n, size - n);
680 0 : strcpy(buf + n + m, "?>");
681 : }
682 0 : if (bunfastapp_nocheckVAR(bn, buf) != GDK_SUCCEED)
683 0 : goto bunins_failed;
684 : }
685 0 : bat_iterator_end(&bi);
686 0 : GDKfree(buf);
687 0 : finalizeResult(ret, bn, b);
688 0 : return MAL_SUCCEED;
689 0 : bunins_failed:
690 0 : bat_iterator_end(&bi);
691 0 : BBPunfix(b->batCacheid);
692 0 : BBPunfix(bn->batCacheid);
693 0 : if (buf != NULL)
694 0 : GDKfree(buf);
695 0 : throw(MAL, "xml.pi", "%s", err);
696 : }
697 :
698 : static str
699 1 : BATXMLroot(bat *ret, const bat *bid, const char *const *version,
700 : const char *const *standalone)
701 : {
702 1 : BAT *b, *bn;
703 1 : BUN p, q;
704 1 : size_t size = BUFSIZ;
705 1 : str buf;
706 1 : BATiter bi;
707 1 : size_t hdrlen;
708 1 : const char *err = OPERATION_FAILED;
709 :
710 1 : hdrlen = 8;
711 2 : if (!strNil(*version) && **version) {
712 1 : if (strcmp(*version, "1.0") != 0 && strcmp(*version, "1.1") != 0)
713 0 : throw(MAL, "xml.root", XML_VERSION_ERROR);
714 1 : hdrlen += 11 + strlen(*version); /* strlen(" version=\"\"") */
715 : }
716 2 : if (!strNil(*standalone) && **standalone) {
717 1 : if (strcmp(*standalone, "yes") != 0 && strcmp(*standalone, "no") != 0)
718 0 : throw(MAL, "xml.root",
719 : XML_STANDALONE_ERROR "illegal XML standalone value");
720 1 : hdrlen += 14 + strlen(*standalone); /* strlen(" standalone=\"\"") */
721 : }
722 1 : buf = GDKmalloc(size);
723 1 : if (buf == NULL)
724 0 : throw(MAL, "xml.root", SQLSTATE(HY013) MAL_MALLOC_FAIL);
725 1 : if ((b = BATdescriptor(*bid)) == NULL) {
726 0 : GDKfree(buf);
727 0 : throw(MAL, "xml.pi", INTERNAL_BAT_ACCESS);
728 : }
729 1 : prepareResult(bn, b, TYPE_xml, "pi", GDKfree(buf));
730 1 : bi = bat_iterator(b);
731 3 : BATloop(b, p, q) {
732 2 : const char *t = (const char *) BUNtvar(bi, p);
733 2 : size_t len, i;
734 2 : bit isdoc;
735 :
736 2 : len = hdrlen;
737 4 : if (!strNil(t))
738 2 : len += strlen(t);
739 2 : if (len >= size) {
740 : /* make sure there is enough space */
741 0 : size = len + 128;
742 : /* free/malloc so we don't copy */
743 0 : GDKfree(buf);
744 0 : buf = GDKmalloc(size);
745 0 : if (buf == NULL) {
746 0 : err = SQLSTATE(HY013) MAL_MALLOC_FAIL;
747 0 : goto bunins_failed;
748 : }
749 : }
750 2 : if (strNil(t)) {
751 0 : strcpy(buf, str_nil);
752 0 : bn->tnonil = false;
753 : } else {
754 2 : strcpy(buf, "D<?xml");
755 2 : i = strlen(buf);
756 4 : if (!strNil(*version) && **version)
757 2 : i += snprintf(buf + i, len - i, " version=\"%s\"", *version);
758 4 : if (!strNil(*standalone) && **standalone)
759 2 : i += snprintf(buf + i, len - i, " standalone=\"%s\"",
760 : *standalone);
761 2 : snprintf(buf + i, len - i, "?>%s", t + 1);
762 2 : buf++;
763 2 : XMLisdocument(&isdoc, &buf); /* check well-formedness */
764 2 : buf--;
765 2 : if (!isdoc) {
766 0 : err = XML_NOT_WELL_FORMED;
767 0 : goto bunins_failed;
768 : }
769 : }
770 2 : if (bunfastapp_nocheckVAR(bn, buf) != GDK_SUCCEED)
771 0 : goto bunins_failed;
772 : }
773 1 : bat_iterator_end(&bi);
774 1 : GDKfree(buf);
775 1 : finalizeResult(ret, bn, b);
776 1 : return MAL_SUCCEED;
777 0 : bunins_failed:
778 0 : bat_iterator_end(&bi);
779 0 : BBPunfix(b->batCacheid);
780 0 : BBPunfix(bn->batCacheid);
781 0 : if (buf != NULL)
782 0 : GDKfree(buf);
783 0 : throw(MAL, "xml.root", "%s", err);
784 : }
785 :
786 : static str
787 11 : BATXMLattribute(bat *ret, const char *const *name, const bat *bid)
788 : {
789 11 : BAT *b, *bn;
790 11 : BUN p, q;
791 11 : size_t size = BUFSIZ;
792 11 : str buf;
793 11 : BATiter bi;
794 11 : size_t attrlen;
795 11 : const char *err = OPERATION_FAILED;
796 :
797 11 : if (strNil(*name))
798 0 : throw(MAL, "xml.attribute", XML_ATTRIBUTE_ERROR);
799 11 : if (xmlValidateName((xmlChar *) *name, 0) != 0)
800 0 : throw(MAL, "xml.attribute", XML_ATTRIBUTE_INVALID);
801 11 : attrlen = strlen(*name) + 5;
802 11 : buf = GDKmalloc(size);
803 11 : if (buf == NULL)
804 0 : throw(MAL, "xml.attribute", SQLSTATE(HY013) MAL_MALLOC_FAIL);
805 11 : if ((b = BATdescriptor(*bid)) == NULL) {
806 0 : GDKfree(buf);
807 0 : throw(MAL, "xml.attribute", INTERNAL_BAT_ACCESS);
808 : }
809 11 : prepareResult(bn, b, TYPE_xml, "attribute", GDKfree(buf));
810 11 : bi = bat_iterator(b);
811 35 : BATloop(b, p, q) {
812 24 : const char *t = (const char *) BUNtvar(bi, p);
813 24 : size_t len;
814 :
815 24 : len = attrlen;
816 48 : if (!strNil(t))
817 24 : len += strlen(t) * 6 + 1;
818 24 : if (len >= size) {
819 : /* make sure there is enough space */
820 0 : size = len + 128;
821 : /* free/malloc so we don't copy */
822 0 : GDKfree(buf);
823 0 : buf = GDKmalloc(size);
824 0 : if (buf == NULL) {
825 0 : err = SQLSTATE(HY013) MAL_MALLOC_FAIL;
826 0 : goto bunins_failed;
827 : }
828 : }
829 24 : if (strNil(t)) {
830 0 : strcpy(buf, str_nil);
831 0 : bn->tnonil = false;
832 : } else {
833 24 : int n = snprintf(buf, size, "A%s = \"", *name);
834 24 : size_t m = XMLquotestring(t, buf + n, size - n);
835 24 : strcpy(buf + n + m, "\"");
836 : }
837 24 : if (bunfastapp_nocheckVAR(bn, buf) != GDK_SUCCEED)
838 0 : goto bunins_failed;
839 : }
840 11 : bat_iterator_end(&bi);
841 11 : GDKfree(buf);
842 11 : finalizeResult(ret, bn, b);
843 11 : return MAL_SUCCEED;
844 0 : bunins_failed:
845 0 : bat_iterator_end(&bi);
846 0 : BBPunfix(b->batCacheid);
847 0 : BBPunfix(bn->batCacheid);
848 0 : if (buf != NULL)
849 0 : GDKfree(buf);
850 0 : throw(MAL, "xml.attribute", "%s", err);
851 : }
852 :
853 : static str
854 66 : BATXMLelement(bat *ret, const char *const *name, xml *nspace, xml *attr,
855 : const bat *bid)
856 : {
857 66 : BAT *b, *bn;
858 66 : BUN p, q;
859 66 : size_t size = BUFSIZ;
860 66 : str buf;
861 66 : BATiter bi;
862 66 : size_t elemlen, namelen;
863 66 : const char *err = OPERATION_FAILED;
864 :
865 66 : if (strNil(*name))
866 0 : throw(MAL, "xml.element", XML_NO_ELEMENT);
867 66 : if (xmlValidateName((xmlChar *) *name, 0) != 0)
868 0 : throw(MAL, "xml.element", XML_ATTRIBUTE_INVALID);
869 124 : if (nspace && !strNil(*nspace) && **nspace)
870 0 : throw(MAL, "xml.element", XML_NO_NAMESPACE);
871 66 : namelen = strlen(*name);
872 66 : elemlen = namelen + 5;
873 124 : if (nspace && !strNil(*nspace)) {
874 0 : if (**nspace != 'A')
875 0 : throw(MAL, "xml.element", XML_ILLEGAL_NAMESPACE);
876 0 : elemlen += strlen(*nspace); /* " " + nspace (nspace contains initial 'A' which is replaced by space) */
877 : }
878 124 : if (attr && !strNil(*attr)) {
879 0 : if (**attr != 'A')
880 0 : throw(MAL, "xml.element", XML_ILLEGAL_ATTRIBUTE);
881 0 : elemlen += strlen(*attr); /* " " + attr (attr contains initial 'A' which is replaced by space) */
882 : }
883 66 : buf = GDKmalloc(size);
884 66 : if (buf == NULL)
885 0 : throw(MAL, "xml.attribute", SQLSTATE(HY013) MAL_MALLOC_FAIL);
886 66 : if ((b = BATdescriptor(*bid)) == NULL) {
887 0 : GDKfree(buf);
888 0 : throw(MAL, "xml.element", INTERNAL_BAT_ACCESS);
889 : }
890 66 : prepareResult(bn, b, TYPE_xml, "element", GDKfree(buf));
891 66 : bi = bat_iterator(b);
892 179 : BATloop(b, p, q) {
893 114 : const char *t = (const char *) BUNtvar(bi, p);
894 113 : size_t len;
895 :
896 113 : len = elemlen;
897 226 : if (!strNil(t)) {
898 111 : if (*t != 'C') {
899 0 : err = XML_ILLEGAL_CONTENT;
900 0 : goto bunins_failed;
901 : }
902 111 : len += strlen(t + 1) + namelen + 2; /* extra "<", ">", and name ("/" already counted) */
903 : }
904 113 : if (len >= size) {
905 : /* make sure there is enough space */
906 0 : size = len + 128;
907 : /* free/malloc so we don't copy */
908 0 : GDKfree(buf);
909 0 : buf = GDKmalloc(size);
910 0 : if (buf == NULL) {
911 0 : err = SQLSTATE(HY013) MAL_MALLOC_FAIL;
912 0 : goto bunins_failed;
913 : }
914 : }
915 115 : if (strNil(t) && (!attr || strNil(*attr))) {
916 2 : strcpy(buf, str_nil);
917 2 : bn->tnonil = false;
918 : } else {
919 111 : int i = snprintf(buf, size, "C<%s", *name);
920 204 : if (nspace && !strNil(*nspace))
921 0 : i += snprintf(buf + i, size - i, " %s", *nspace + 1);
922 204 : if (attr && !strNil(*attr))
923 0 : i += snprintf(buf + i, size - i, " %s", *attr + 1);
924 222 : if (!strNil(t))
925 111 : i += snprintf(buf + i, size - i, ">%s</%s>", t + 1, *name);
926 : else
927 0 : i += snprintf(buf + i, size - i, "/>");
928 : }
929 113 : if (bunfastapp_nocheckVAR(bn, buf) != GDK_SUCCEED)
930 0 : goto bunins_failed;
931 : }
932 65 : bat_iterator_end(&bi);
933 66 : GDKfree(buf);
934 66 : finalizeResult(ret, bn, b);
935 66 : return MAL_SUCCEED;
936 0 : bunins_failed:
937 0 : bat_iterator_end(&bi);
938 0 : BBPunfix(b->batCacheid);
939 0 : BBPunfix(bn->batCacheid);
940 0 : if (buf != NULL)
941 0 : GDKfree(buf);
942 0 : throw(MAL, "xml.element", "%s", err);
943 : }
944 :
945 : static str
946 8 : BATXMLelementSmall(bat *ret, const char *const *name, const bat *bid)
947 : {
948 8 : return BATXMLelement(ret, name, NULL, NULL, bid);
949 : }
950 :
951 : static str
952 1 : BATXMLforest(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
953 : {
954 1 : bat *ret = getArgReference_bat(stk, pci, 0);
955 1 : BAT *bn;
956 1 : BATiter *bi;
957 1 : BUN *p, *q;
958 1 : str buf;
959 1 : int i;
960 1 : size_t offset, len, size = BUFSIZ;
961 1 : const char *err = OPERATION_FAILED;
962 :
963 1 : (void) mb;
964 1 : (void) cntxt;
965 1 : buf = GDKmalloc(size);
966 1 : bi = GDKmalloc(sizeof(BATiter) * pci->argc);
967 1 : p = GDKmalloc(sizeof(BUN) * pci->argc);
968 1 : q = GDKmalloc(sizeof(BUN) * pci->argc);
969 1 : if (buf == NULL || bi == NULL || p == NULL || q == NULL) {
970 0 : if (buf)
971 0 : GDKfree(buf);
972 0 : if (bi)
973 0 : GDKfree(bi);
974 0 : if (p)
975 0 : GDKfree(p);
976 0 : if (q)
977 0 : GDKfree(q);
978 0 : throw(MAL, "xml.forest", SQLSTATE(HY013) MAL_MALLOC_FAIL);
979 : }
980 :
981 : /* collect the admin for the xml elements */
982 3 : for (i = pci->retc; i < pci->argc; i++) {
983 2 : BAT *b = BATdescriptor(*getArgReference_bat(stk, pci, i));
984 2 : if (b == NULL) {
985 0 : while (i > pci->retc) {
986 0 : i--;
987 0 : b = bi[i].b;
988 0 : bat_iterator_end(&bi[i]);
989 0 : BBPunfix(b->batCacheid);
990 : }
991 0 : GDKfree(bi);
992 0 : GDKfree(p);
993 0 : GDKfree(q);
994 0 : GDKfree(buf);
995 0 : throw(MAL, "xml.forest", INTERNAL_BAT_ACCESS);
996 : }
997 2 : bi[i] = bat_iterator(b);
998 2 : p[i] = 0;
999 2 : q[i] = BATcount(bi[i].b);
1000 : }
1001 :
1002 1 : prepareResult(bn, bi[pci->retc].b, TYPE_xml, "forest",
1003 : for (i = pci->retc; i < pci->argc; i++) {
1004 : BAT *b = bi[i].b; bat_iterator_end(&bi[i]);
1005 : BBPunfix(b->batCacheid);}
1006 : GDKfree(bi); GDKfree(p); GDKfree(q); GDKfree(buf)) ;
1007 :
1008 3 : while (p[pci->retc] < q[pci->retc]) {
1009 2 : const char *t;
1010 :
1011 : /* fetch the elements */
1012 2 : offset = 0;
1013 2 : strcpy(buf, str_nil);
1014 6 : for (i = pci->retc; i < pci->argc; i++) {
1015 4 : int n;
1016 :
1017 4 : t = (const char *) BUNtvar(bi[i], p[i]);
1018 4 : if (strNil(t))
1019 0 : continue;
1020 :
1021 4 : if ((len = strlen(t)) >= size - offset) {
1022 0 : char *tmp;
1023 0 : size += len + 128;
1024 0 : tmp = GDKrealloc(buf, size);
1025 0 : if (tmp == NULL) {
1026 0 : err = SQLSTATE(HY013) MAL_MALLOC_FAIL;
1027 0 : goto bunins_failed;
1028 : }
1029 : buf = tmp;
1030 : }
1031 4 : if (offset == 0)
1032 2 : n = snprintf(buf, size, "%s", t);
1033 2 : else if (buf[0] != *t) {
1034 0 : err = "incompatible values in forest";
1035 0 : goto bunins_failed;
1036 2 : } else if (buf[0] == 'A')
1037 0 : n = snprintf(buf + offset, size - offset, " %s", t + 1);
1038 2 : else if (buf[0] == 'C')
1039 2 : n = snprintf(buf + offset, size - offset, "%s", t + 1);
1040 : else {
1041 0 : err = "can only combine attributes and element content";
1042 0 : goto bunins_failed;
1043 : }
1044 4 : offset += n;
1045 : }
1046 2 : if (bunfastapp_nocheckVAR(bn, buf) != GDK_SUCCEED)
1047 0 : goto bunins_failed;
1048 2 : if (offset == 0)
1049 0 : bn->tnonil = false;
1050 :
1051 6 : for (i = pci->retc; i < pci->argc; i++)
1052 4 : if (bi[i].b)
1053 4 : p[i]++;
1054 : }
1055 1 : GDKfree(buf);
1056 1 : BATsetcount(bn, bn->batCount);
1057 1 : *ret = bn->batCacheid;
1058 1 : BBPkeepref(bn);
1059 3 : for (i = pci->retc; i < pci->argc; i++) {
1060 2 : BAT *b = bi[i].b;
1061 2 : if (b) {
1062 2 : bat_iterator_end(&bi[i]);
1063 2 : BBPunfix(b->batCacheid);
1064 : }
1065 : }
1066 1 : GDKfree(bi);
1067 1 : GDKfree(p);
1068 1 : GDKfree(q);
1069 1 : return MAL_SUCCEED;
1070 0 : bunins_failed:
1071 0 : for (i = pci->retc; i < pci->argc; i++) {
1072 0 : BAT *b = bi[i].b;
1073 0 : if (b) {
1074 0 : bat_iterator_end(&bi[i]);
1075 0 : BBPunfix(b->batCacheid);
1076 : }
1077 : }
1078 0 : BBPunfix(bn->batCacheid);
1079 0 : if (buf != NULL)
1080 0 : GDKfree(buf);
1081 0 : GDKfree(bi);
1082 0 : GDKfree(p);
1083 0 : GDKfree(q);
1084 0 : throw(MAL, "xml.forest", "%s", err);
1085 : }
1086 :
1087 : static str
1088 39 : BATXMLconcat(bat *ret, const bat *bid, const bat *rid)
1089 : {
1090 39 : BAT *b, *r = 0, *bn;
1091 39 : BUN p, q, rp = 0;
1092 39 : size_t len, size = BUFSIZ;
1093 39 : str buf = GDKmalloc(size);
1094 39 : BATiter bi, ri;
1095 39 : const char *err = OPERATION_FAILED;
1096 :
1097 39 : if (buf == NULL)
1098 0 : throw(MAL, "xml.concat", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1099 39 : b = BATdescriptor(*bid);
1100 39 : r = BATdescriptor(*rid);
1101 38 : if (b == NULL || r == NULL) {
1102 0 : GDKfree(buf);
1103 0 : BBPreclaim(b);
1104 0 : BBPreclaim(r);
1105 0 : throw(MAL, "xml.concat", INTERNAL_BAT_ACCESS);
1106 : }
1107 38 : p = 0;
1108 38 : q = BATcount(b);
1109 38 : rp = 0;
1110 :
1111 38 : prepareResult(bn, b, TYPE_xml, "concat", GDKfree(buf);
1112 : BBPunfix(r->batCacheid));
1113 :
1114 39 : bi = bat_iterator(b);
1115 38 : ri = bat_iterator(r);
1116 99 : while (p < q) {
1117 60 : const char *t = (const char *) BUNtvar(bi, p);
1118 61 : const char *v = (const char *) BUNtvar(ri, rp);
1119 :
1120 61 : len = strlen(t) + strlen(v) + 1;
1121 :
1122 61 : if (len >= size) {
1123 0 : GDKfree(buf);
1124 0 : size = len + 128;
1125 0 : buf = GDKmalloc(size);
1126 0 : if (buf == NULL) {
1127 0 : err = MAL_MALLOC_FAIL;
1128 0 : goto bunins_failed;
1129 : }
1130 : }
1131 61 : if (strNil(t)) {
1132 0 : if (strNil(v)) {
1133 0 : strcpy(buf, str_nil);
1134 0 : bn->tnonil = false;
1135 : } else
1136 0 : strcpy(buf, v);
1137 : } else {
1138 61 : if (strNil(v))
1139 2 : strcpy(buf, t);
1140 59 : else if (*t != *v) {
1141 0 : err = "arguments not compatible";
1142 0 : goto bunins_failed;
1143 59 : } else if (*t == 'A')
1144 2 : snprintf(buf, size, "A%s %s", t + 1, v + 1);
1145 57 : else if (*t == 'C')
1146 57 : snprintf(buf, size, "C%s%s", t + 1, v + 1);
1147 : else {
1148 0 : err = "can only concatenate attributes and element content";
1149 0 : goto bunins_failed;
1150 : }
1151 : }
1152 61 : if (bunfastapp_nocheckVAR(bn, buf) != GDK_SUCCEED)
1153 0 : goto bunins_failed;
1154 61 : rp++;
1155 61 : p++;
1156 : }
1157 39 : bat_iterator_end(&bi);
1158 39 : bat_iterator_end(&ri);
1159 39 : GDKfree(buf);
1160 39 : finalizeResult(ret, bn, b);
1161 39 : BBPunfix(r->batCacheid);
1162 39 : return MAL_SUCCEED;
1163 0 : bunins_failed:
1164 0 : bat_iterator_end(&bi);
1165 0 : bat_iterator_end(&ri);
1166 0 : BBPunfix(r->batCacheid);
1167 0 : BBPunfix(b->batCacheid);
1168 0 : BBPunfix(bn->batCacheid);
1169 0 : if (buf != NULL)
1170 0 : GDKfree(buf);
1171 0 : throw(MAL, "xml.concat", "%s", err);
1172 : }
1173 :
1174 : static str
1175 2 : BATXMLgroup(xml *ret, const bat *bid)
1176 : {
1177 2 : BAT *b;
1178 2 : BUN p, q;
1179 2 : const char *t;
1180 2 : size_t len, size = BUFSIZ, offset;
1181 2 : str buf = GDKmalloc(size);
1182 2 : BATiter bi;
1183 2 : const char *err = NULL;
1184 :
1185 2 : if (buf == NULL)
1186 0 : throw(MAL, "xml.aggr", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1187 2 : if ((b = BATdescriptor(*bid)) == NULL) {
1188 0 : GDKfree(buf);
1189 0 : throw(MAL, "xml.aggr", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
1190 : }
1191 :
1192 2 : strcpy(buf, str_nil);
1193 2 : offset = 0;
1194 2 : bi = bat_iterator(b);
1195 5 : BATloop(b, p, q) {
1196 3 : int n;
1197 :
1198 3 : t = (const char *) BUNtvar(bi, p);
1199 :
1200 3 : if (strNil(t))
1201 0 : continue;
1202 3 : len = strlen(t) + 1;
1203 3 : if (len >= size - offset) {
1204 0 : char *tmp;
1205 0 : size += len + 128;
1206 0 : tmp = GDKrealloc(buf, size);
1207 0 : if (tmp == NULL) {
1208 0 : err = MAL_MALLOC_FAIL;
1209 0 : goto failed;
1210 : }
1211 : buf = tmp;
1212 : }
1213 3 : if (offset == 0)
1214 1 : n = snprintf(buf, size, "%s", t);
1215 2 : else if (buf[0] != *t) {
1216 0 : err = "incompatible values in group";
1217 0 : goto failed;
1218 2 : } else if (buf[0] == 'A')
1219 0 : n = snprintf(buf + offset, size - offset, " %s", t + 1);
1220 2 : else if (buf[0] == 'C')
1221 2 : n = snprintf(buf + offset, size - offset, "%s", t + 1);
1222 : else {
1223 0 : err = "can only group attributes and element content";
1224 0 : goto failed;
1225 : }
1226 3 : offset += n;
1227 : }
1228 2 : bat_iterator_end(&bi);
1229 2 : BBPunfix(b->batCacheid);
1230 2 : *ret = buf;
1231 2 : return MAL_SUCCEED;
1232 0 : failed:
1233 0 : bat_iterator_end(&bi);
1234 0 : BBPunfix(b->batCacheid);
1235 0 : if (buf != NULL)
1236 0 : GDKfree(buf);
1237 0 : throw(MAL, "xml.aggr", "%s", err);
1238 : }
1239 :
1240 : static const char *
1241 2 : BATxmlaggr(BAT **bnp, BAT *b, BAT *g, BAT *e, BAT *s, int skip_nils)
1242 : {
1243 2 : BAT *bn = NULL, *t1, *t2 = NULL;
1244 2 : BATiter bi = (BATiter) {.b = NULL };
1245 2 : oid min, max;
1246 2 : BUN ngrp;
1247 2 : BUN nils = 0;
1248 2 : struct canditer ci;
1249 2 : int isnil;
1250 2 : const char *v;
1251 2 : const oid *grps, *map;
1252 2 : oid mapoff = 0;
1253 2 : oid prev;
1254 2 : BUN p, q;
1255 2 : int freeb = 0, freeg = 0;
1256 2 : char *buf = NULL;
1257 2 : size_t buflen, maxlen, len;
1258 2 : const char *err;
1259 2 : char *tmp;
1260 :
1261 2 : if ((err = BATgroupaggrinit(b, g, e, s, &min, &max, &ngrp, &ci)) !=NULL) {
1262 : return err;
1263 : }
1264 2 : assert(b->ttype == TYPE_xml);
1265 2 : if (BATcount(b) == 0 || ngrp == 0) {
1266 0 : bn = BATconstant(ngrp == 0 ? 0 : min, TYPE_xml, ATOMnilptr(TYPE_xml),
1267 : ngrp, TRANSIENT);
1268 0 : if (bn == NULL)
1269 : return MAL_MALLOC_FAIL;
1270 0 : *bnp = bn;
1271 0 : return NULL;
1272 : }
1273 2 : if (s) {
1274 0 : b = BATproject(s, b);
1275 0 : if (b == NULL) {
1276 0 : err = "internal project failed";
1277 0 : goto out;
1278 : }
1279 0 : freeb = 1;
1280 0 : if (g) {
1281 0 : g = BATproject(s, g);
1282 0 : if (g == NULL) {
1283 0 : err = "internal project failed";
1284 0 : goto out;
1285 : }
1286 : freeg = 1;
1287 : }
1288 : }
1289 2 : if (g && BATtdense(g)) {
1290 : /* singleton groups: return group ID's (g's tail) and original
1291 : * values from b */
1292 0 : bn = VIEWcreate(g->tseqbase, b, 0, BUN_MAX);
1293 0 : if (bn == NULL)
1294 0 : err = GDK_EXCEPTION;
1295 0 : goto out;
1296 : }
1297 :
1298 2 : maxlen = BUFSIZ;
1299 2 : if ((buf = GDKmalloc(maxlen)) == NULL) {
1300 0 : err = SQLSTATE(HY013) MAL_MALLOC_FAIL;
1301 0 : goto out;
1302 : }
1303 2 : buflen = 0;
1304 2 : bn = COLnew(min, TYPE_xml, ngrp, TRANSIENT);
1305 2 : if (bn == NULL) {
1306 0 : err = SQLSTATE(HY013) MAL_MALLOC_FAIL;
1307 0 : goto out;
1308 : }
1309 2 : bi = bat_iterator(b);
1310 2 : if (g) {
1311 : /* stable sort g */
1312 2 : if (BATsort(&t1, &t2, NULL, g, NULL, NULL, false, false, true) != GDK_SUCCEED) {
1313 0 : BBPreclaim(bn);
1314 0 : bn = NULL;
1315 0 : err = GDK_EXCEPTION;
1316 0 : goto out1;
1317 : }
1318 2 : if (freeg)
1319 0 : BBPunfix(g->batCacheid);
1320 2 : g = t1;
1321 2 : freeg = 1;
1322 2 : if (t2->ttype == TYPE_void) {
1323 2 : map = NULL;
1324 2 : mapoff = b->tseqbase;
1325 : } else {
1326 0 : map = (const oid *) Tloc(t2, 0);
1327 : }
1328 2 : grps = (const oid *) Tloc(g, 0);
1329 2 : prev = grps[0];
1330 2 : isnil = 0;
1331 9 : for (p = 0, q = BATcount(g); p <= q; p++) {
1332 9 : if (p == q || grps[p] != prev) {
1333 5 : while (BATcount(bn) < prev - min) {
1334 0 : if (bunfastapp_nocheckVAR(bn, str_nil) != GDK_SUCCEED)
1335 0 : goto bunins_failed;
1336 0 : nils++;
1337 : }
1338 5 : if (bunfastapp_nocheckVAR(bn, buf) != GDK_SUCCEED)
1339 0 : goto bunins_failed;
1340 5 : nils += strNil(buf);
1341 5 : strncpy(buf, str_nil, maxlen);
1342 5 : buflen = 0;
1343 5 : if (p == q)
1344 : break;
1345 3 : prev = grps[p];
1346 3 : isnil = 0;
1347 : }
1348 7 : if (isnil)
1349 0 : continue;
1350 7 : v = (const char *) BUNtvar(bi, (map ? (BUN) map[p] : p + mapoff));
1351 7 : if (strNil(v)) {
1352 0 : if (skip_nils)
1353 0 : continue;
1354 0 : strncpy(buf, str_nil, buflen);
1355 0 : isnil = 1;
1356 : } else {
1357 7 : len = strlen(v);
1358 7 : if (len >= maxlen - buflen) {
1359 0 : maxlen += len + BUFSIZ;
1360 0 : tmp = GDKrealloc(buf, maxlen);
1361 0 : if (tmp == NULL) {
1362 0 : err = SQLSTATE(HY013) MAL_MALLOC_FAIL;
1363 0 : goto bunins_failed;
1364 : }
1365 : buf = tmp;
1366 : }
1367 7 : if (buflen == 0) {
1368 5 : strncpy(buf, v, maxlen);
1369 5 : buflen += len;
1370 2 : } else if (buf[0] != v[0]) {
1371 0 : err = "incompatible values in group";
1372 0 : goto bunins_failed;
1373 2 : } else if (buf[0] == 'A') {
1374 0 : snprintf(buf + buflen, maxlen - buflen, " %s", v + 1);
1375 0 : buflen += len;
1376 2 : } else if (buf[0] == 'C') {
1377 2 : snprintf(buf + buflen, maxlen - buflen, "%s", v + 1);
1378 2 : buflen += len - 1;
1379 : } else {
1380 0 : err = "can only group attributes and element content";
1381 0 : goto bunins_failed;
1382 : }
1383 : }
1384 : }
1385 2 : BBPunfix(t2->batCacheid);
1386 2 : t2 = NULL;
1387 : } else {
1388 0 : for (p = 0, q = p + BATcount(b); p < q; p++) {
1389 0 : v = (const char *) BUNtvar(bi, p);
1390 0 : if (strNil(v)) {
1391 0 : if (skip_nils)
1392 0 : continue;
1393 0 : strncpy(buf, str_nil, buflen);
1394 0 : nils++;
1395 0 : break;
1396 : }
1397 0 : len = strlen(v);
1398 0 : if (len >= maxlen - buflen) {
1399 0 : maxlen += len + BUFSIZ;
1400 0 : tmp = GDKrealloc(buf, maxlen);
1401 0 : if (tmp == NULL) {
1402 0 : err = SQLSTATE(HY013) MAL_MALLOC_FAIL;
1403 0 : goto bunins_failed;
1404 : }
1405 : buf = tmp;
1406 : }
1407 0 : if (buflen == 0) {
1408 0 : strncpy(buf, v, maxlen);
1409 0 : buflen += len;
1410 0 : } else if (buf[0] != v[0]) {
1411 0 : err = "incompatible values in group";
1412 0 : goto bunins_failed;
1413 0 : } else if (buf[0] == 'A') {
1414 0 : snprintf(buf + buflen, maxlen - buflen, " %s", v + 1);
1415 0 : buflen += len;
1416 0 : } else if (buf[0] == 'C') {
1417 0 : snprintf(buf + buflen, maxlen - buflen, "%s", v + 1);
1418 0 : buflen += len - 1;
1419 : } else {
1420 0 : err = "can only group attributes and element content";
1421 0 : goto bunins_failed;
1422 : }
1423 : }
1424 0 : if (bunfastapp_nocheckVAR(bn, buf) != GDK_SUCCEED)
1425 0 : goto bunins_failed;
1426 : }
1427 2 : bn->theap->dirty = true;
1428 2 : bn->tnil = nils != 0;
1429 2 : bn->tnonil = nils == 0;
1430 2 : bn->tsorted = BATcount(bn) <= 1;
1431 2 : bn->trevsorted = BATcount(bn) <= 1;
1432 2 : bn->tkey = BATcount(bn) <= 1;
1433 :
1434 2 : out1:
1435 2 : bat_iterator_end(&bi);
1436 2 : out:
1437 2 : BBPreclaim(t2);
1438 2 : if (freeb && b)
1439 0 : BBPunfix(b->batCacheid);
1440 2 : if (freeg && g)
1441 2 : BBPunfix(g->batCacheid);
1442 2 : if (buf)
1443 2 : GDKfree(buf);
1444 2 : *bnp = bn;
1445 2 : return err;
1446 :
1447 0 : bunins_failed:
1448 0 : bat_iterator_end(&bi);
1449 0 : BBPreclaim(bn);
1450 0 : bn = NULL;
1451 0 : if (err == NULL)
1452 0 : err = SQLSTATE(HY013) MAL_MALLOC_FAIL; /* insertion into result BAT failed */
1453 0 : goto out;
1454 : }
1455 :
1456 : static str
1457 2 : AGGRsubxmlcand(bat *retval, const bat *bid, const bat *gid, const bat *eid,
1458 : const bat *sid, const bit *skip_nils)
1459 : {
1460 2 : BAT *b, *g, *e, *s, *bn = NULL;
1461 2 : const char *err;
1462 :
1463 2 : b = BATdescriptor(*bid);
1464 2 : g = gid ? BATdescriptor(*gid) : NULL;
1465 2 : e = eid ? BATdescriptor(*eid) : NULL;
1466 2 : if (b == NULL || (gid != NULL && g == NULL) || (eid != NULL && e == NULL)) {
1467 0 : BBPreclaim(b);
1468 0 : BBPreclaim(g);
1469 0 : BBPreclaim(e);
1470 0 : throw(MAL, "aggr.subxml", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
1471 : }
1472 2 : if (sid && !is_bat_nil(*sid)) {
1473 0 : s = BATdescriptor(*sid);
1474 0 : if (s == NULL) {
1475 0 : BBPunfix(b->batCacheid);
1476 0 : BBPreclaim(g);
1477 0 : BBPreclaim(e);
1478 0 : throw(MAL, "aggr.subxml", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
1479 : }
1480 : } else {
1481 : s = NULL;
1482 : }
1483 2 : err = BATxmlaggr(&bn, b, g, e, s, *skip_nils);
1484 2 : BBPunfix(b->batCacheid);
1485 2 : BBPreclaim(g);
1486 2 : BBPreclaim(e);
1487 2 : BBPreclaim(s);
1488 2 : if (err !=NULL)
1489 0 : throw(MAL, "aggr.subxml", "%s", err);
1490 :
1491 2 : *retval = bn->batCacheid;
1492 2 : BBPkeepref(bn);
1493 2 : return MAL_SUCCEED;
1494 : }
1495 :
1496 : static str
1497 2 : AGGRsubxml(bat *retval, const bat *bid, const bat *gid, const bat *eid,
1498 : const bit *skip_nils)
1499 : {
1500 2 : return AGGRsubxmlcand(retval, bid, gid, eid, NULL, skip_nils);
1501 : }
1502 :
1503 : static str
1504 0 : BATXMLxquery(bat *ret, const bat *bid, const char *const *expr)
1505 : {
1506 0 : (void) ret;
1507 0 : (void) bid;
1508 0 : (void) expr;
1509 : /* use external library to solve this */
1510 0 : throw(MAL, "xml.xquery", SQLSTATE(0 A000) PROGRAM_NYI);
1511 : }
1512 :
1513 : #else
1514 :
1515 : #define NO_LIBXML_FATAL "batxml: MonetDB was built without libxml, but what you are trying to do requires it."
1516 :
1517 : static str
1518 : BATXMLxml2str(bat *ret, const bat *bid)
1519 : {
1520 : (void) ret;
1521 : (void) bid;
1522 : return createException(MAL, "batxml.xml2str",
1523 : SQLSTATE(HY005) NO_LIBXML_FATAL);
1524 : }
1525 :
1526 : static str
1527 : BATXMLxmltext(bat *ret, const bat *bid)
1528 : {
1529 : (void) ret;
1530 : (void) bid;
1531 : return createException(MAL, "batxml.xmltext",
1532 : SQLSTATE(HY005) NO_LIBXML_FATAL);
1533 : }
1534 :
1535 : static str
1536 : BATXMLstr2xml(bat *ret, const bat *bid)
1537 : {
1538 : (void) ret;
1539 : (void) bid;
1540 : return createException(MAL, "batxml.str2xml",
1541 : SQLSTATE(HY005) NO_LIBXML_FATAL);
1542 : }
1543 :
1544 : static str
1545 : BATXMLdocument(bat *ret, const bat *bid)
1546 : {
1547 : (void) ret;
1548 : (void) bid;
1549 : return createException(MAL, "batxml.document",
1550 : SQLSTATE(HY005) NO_LIBXML_FATAL);
1551 : }
1552 :
1553 : static str
1554 : BATXMLcontent(bat *ret, const bat *bid)
1555 : {
1556 : (void) ret;
1557 : (void) bid;
1558 : return createException(MAL, "batxml.content",
1559 : SQLSTATE(HY005) NO_LIBXML_FATAL);
1560 : }
1561 :
1562 : static str
1563 : BATXMLisdocument(bat *ret, const bat *bid)
1564 : {
1565 : (void) ret;
1566 : (void) bid;
1567 : return createException(MAL, "batxml.isdocument",
1568 : SQLSTATE(HY005) NO_LIBXML_FATAL);
1569 : }
1570 :
1571 : static str
1572 : BATXMLelementSmall(bat *ret, const char *const *name, const bat *bid)
1573 : {
1574 : (void) ret;
1575 : (void) name;
1576 : (void) bid;
1577 : return createException(MAL, "batxml.elementSmall",
1578 : SQLSTATE(HY005) NO_LIBXML_FATAL);
1579 : }
1580 :
1581 : static str
1582 : BATXMLoptions(bat *ret, const char *const *name, const char *const *options,
1583 : const bat *bid)
1584 : {
1585 : (void) ret;
1586 : (void) name;
1587 : (void) options;
1588 : (void) bid;
1589 : return createException(MAL, "batxml.options",
1590 : SQLSTATE(HY005) NO_LIBXML_FATAL);
1591 : }
1592 :
1593 : static str
1594 : BATXMLcomment(bat *ret, const bat *bid)
1595 : {
1596 : (void) ret;
1597 : (void) bid;
1598 : return createException(MAL, "batxml.comment",
1599 : SQLSTATE(HY005) NO_LIBXML_FATAL);
1600 : }
1601 :
1602 : static str
1603 : BATXMLparse(bat *ret, const char *const *doccont, const bat *bid,
1604 : const char *const *option)
1605 : {
1606 : (void) ret;
1607 : (void) doccont;
1608 : (void) bid;
1609 : (void) option;
1610 : return createException(MAL, "batxml.parse",
1611 : SQLSTATE(HY005) NO_LIBXML_FATAL);
1612 : }
1613 :
1614 : static str
1615 : BATXMLxquery(bat *ret, const bat *bid, const char *const *expr)
1616 : {
1617 : (void) ret;
1618 : (void) bid;
1619 : (void) expr;
1620 : return createException(MAL, "batxml.xquery",
1621 : SQLSTATE(HY005) NO_LIBXML_FATAL);
1622 : }
1623 :
1624 : static str
1625 : BATXMLpi(bat *ret, const char *const *tgt, const bat *bid)
1626 : {
1627 : (void) ret;
1628 : (void) tgt;
1629 : (void) bid;
1630 : return createException(MAL, "batxml.pi", SQLSTATE(HY005) NO_LIBXML_FATAL);
1631 : }
1632 :
1633 : static str
1634 : BATXMLroot(bat *ret, const bat *bid, const char *const *version,
1635 : const char *const *standalone)
1636 : {
1637 : (void) ret;
1638 : (void) bid;
1639 : (void) version;
1640 : (void) standalone;
1641 : return createException(MAL, "batxml.root", SQLSTATE(HY005) NO_LIBXML_FATAL);
1642 : }
1643 :
1644 : static str
1645 : BATXMLattribute(bat *ret, const char *const *name, const bat *bid)
1646 : {
1647 : (void) ret;
1648 : (void) name;
1649 : (void) bid;
1650 : return createException(MAL, "batxml.attribute",
1651 : SQLSTATE(HY005) NO_LIBXML_FATAL);
1652 : }
1653 :
1654 : static str
1655 : BATXMLelement(bat *ret, const char *const *name, xml *ns, xml *attr,
1656 : const bat *bid)
1657 : {
1658 : (void) ret;
1659 : (void) name;
1660 : (void) ns;
1661 : (void) attr;
1662 : (void) bid;
1663 : return createException(MAL, "batxml.element",
1664 : SQLSTATE(HY005) NO_LIBXML_FATAL);
1665 : }
1666 :
1667 : static str
1668 : BATXMLconcat(bat *ret, const bat *bid, const bat *rid)
1669 : {
1670 : (void) ret;
1671 : (void) bid;
1672 : (void) rid;
1673 : return createException(MAL, "batxml.concat",
1674 : SQLSTATE(HY005) NO_LIBXML_FATAL);
1675 : }
1676 :
1677 : static str
1678 : BATXMLforest(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
1679 : {
1680 : (void) cntxt;
1681 : (void) mb;
1682 : (void) stk;
1683 : (void) p;
1684 : return createException(MAL, "batxml.forest",
1685 : SQLSTATE(HY005) NO_LIBXML_FATAL);
1686 : }
1687 :
1688 : static str
1689 : BATXMLgroup(xml *ret, const bat *bid)
1690 : {
1691 : (void) ret;
1692 : (void) bid;
1693 : return createException(MAL, "batxml.group",
1694 : SQLSTATE(HY005) NO_LIBXML_FATAL);
1695 : }
1696 :
1697 : static str
1698 : AGGRsubxmlcand(bat *retval, const bat *bid, const bat *gid, const bat *eid,
1699 : const bat *sid, const bit *skip_nils)
1700 : {
1701 : (void) retval;
1702 : (void) bid;
1703 : (void) gid;
1704 : (void) eid;
1705 : (void) sid;
1706 : (void) skip_nils;
1707 : return createException(MAL, "batxml.subxmlcand",
1708 : SQLSTATE(HY005) NO_LIBXML_FATAL);
1709 : }
1710 :
1711 : static str
1712 : AGGRsubxml(bat *retval, const bat *bid, const bat *gid, const bat *eid,
1713 : const bit *skip_nils)
1714 : {
1715 : (void) retval;
1716 : (void) bid;
1717 : (void) gid;
1718 : (void) eid;
1719 : (void) skip_nils;
1720 : return createException(MAL, "batxml.subxml",
1721 : SQLSTATE(HY005) NO_LIBXML_FATAL);
1722 : }
1723 :
1724 : #endif /* HAVE_LIBXML */
1725 :
1726 : #include "mel.h"
1727 : mel_func batxml_init_funcs[] = {
1728 : command("batxml", "xml", BATXMLstr2xml, false, "Cast the string to an xml compliant string.", args(1,2, batarg("",xml),batarg("src",str))),
1729 : command("batxml", "str", BATXMLxml2str, false, "Cast the xml to a string.", args(1,2, batarg("",str),batarg("src",xml))),
1730 : command("batxml", "document", BATXMLdocument, false, "Parse the string as an XML document.", args(1,2, batarg("",xml),batarg("src",str))),
1731 : command("batxml", "content", BATXMLcontent, false, "Parse the string as XML element content.", args(1,2, batarg("",xml),batarg("src",str))),
1732 : command("batxml", "comment", BATXMLcomment, false, "Create an XML comment element.", args(1,2, batarg("",xml),batarg("val",str))),
1733 : command("batxml", "parse", BATXMLparse, false, "Parse the XML document or element string values.", args(1,4, batarg("",xml),arg("doccont",str),batarg("val",str),arg("option",str))),
1734 : command("batxml", "serialize", BATXMLxml2str, false, "Serialize the XML object to a string.", args(1,2, batarg("",str),batarg("val",xml))),
1735 : command("batxml", "text", BATXMLxmltext, false, "Serialize the XML object to a string.", args(1,2, batarg("",str),batarg("val",xml))),
1736 : command("batxml", "xquery", BATXMLxquery, false, "Execute the XQuery against the elements.", args(1,3, batarg("",xml),batarg("val",str),arg("expr",str))),
1737 : command("batxml", "pi", BATXMLpi, false, "Construct a processing instruction.", args(1,3, batarg("",xml),arg("target",str),batarg("val",xml))),
1738 : command("batxml", "attribute", BATXMLattribute, false, "Construct an attribute value pair.", args(1,3, batarg("",xml),arg("name",str),batarg("val",str))),
1739 : command("batxml", "element", BATXMLelementSmall, false, "The basic building block for XML elements are namespaces, attributes and a sequence of XML elements. The name space and the attributes may be left unspecified.", args(1,3, batarg("",xml),arg("name",str),batarg("s",xml))),
1740 : command("batxml", "options", BATXMLoptions, false, "Create the components including NULL conversions.", args(1,4, batarg("",xml),arg("tag",str),arg("option",str),batarg("left",xml))),
1741 : command("batxml", "element", BATXMLelement, false, "The basic building block for XML elements are namespaces, attributes and a sequence of XML elements. The name space and the attributes may be left unspecified(=nil).", args(1,5, batarg("",xml),arg("name",str),arg("ns",xml),arg("attr",xml),batarg("s",xml))),
1742 : command("batxml", "concat", BATXMLconcat, false, "Concatenate the XML values.", args(1,3, batarg("",xml),batarg("left",xml),batarg("right",xml))),
1743 : pattern("batxml", "forest", BATXMLforest, false, "Construct an element list.", args(1,2, batarg("",xml),batvararg("val",xml))),
1744 : command("batxml", "root", BATXMLroot, false, "Contruct the root nodes.", args(1,4, batarg("",xml),batarg("val",xml),arg("version",str),arg("standalone",str))),
1745 : command("batxml", "isdocument", BATXMLisdocument, false, "Validate the string as a XML document.", args(1,2, batarg("",bit),batarg("val",str))),
1746 : command("xml", "aggr", BATXMLgroup, false, "Aggregate the XML values.", args(1,2, arg("",xml),batarg("val",xml))),
1747 : command("xml", "subaggr", AGGRsubxml, false, "Grouped aggregation of XML values.", args(1,5, batarg("",xml),batarg("val",xml),batarg("g",oid),batargany("e",1),arg("skip_nils",bit))),
1748 : command("xml", "subaggr", AGGRsubxmlcand, false, "Grouped aggregation of XML values with candidates list.", args(1,6, batarg("",xml),batarg("val",xml),batarg("g",oid),batargany("e",1),batarg("s",oid),arg("skip_nils",bit))),
1749 : command("batcalc", "xml", BATXMLstr2xml, false, "", args(1,2, batarg("",xml),batarg("src",str))),
1750 : { .imp=NULL }
1751 : };
1752 : #include "mal_import.h"
1753 : #ifdef _MSC_VER
1754 : #undef read
1755 : #pragma section(".CRT$XCU",read)
1756 : #endif
1757 334 : LIB_STARTUP_FUNC(init_batxml_mal)
1758 334 : { mal_module("batxml", NULL, batxml_init_funcs); }
|