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