1/*
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 *
6 * Copyright 1997 - July 2008 CWI, August 2008 - 2019 MonetDB B.V.
7 */
8
9/*
10 * @f xml
11 * @a Sjoerd Mullender, Niels Nes, Martin Kersten
12 * @v 0.1
13 * @+ MAL support for XQL
14 * This module contains the primitives needed in the SQL
15 * front-end to support SQL/XML.
16 */
17#include "monetdb_config.h"
18#include "xml.h"
19#include "mal_interpreter.h"
20
21#ifdef HAVE_LIBXML
22#include <libxml/parser.h>
23#include <libxml/xmlmemory.h>
24
25/* The xml atom is used to represent XML data. It is implemented as a
26 subtype of str. The first character of the string representation
27 indicates the type of XML data. There are three possibilities:
28 * D - an XML document (possibly including <?xml?> and DOCTYPE);
29 * C - XML content, i.e. something that can occur inside an XML element;
30 * A - XML name/attribute pair.
31*/
32
33size_t
34XMLquotestring(const char *s, char *buf, size_t len)
35{
36 size_t i = 0;
37
38 assert(len > 0);
39 while (*s && i + 6 < len) {
40 if (*s == '&') {
41 buf[i++] = '&';
42 buf[i++] = 'a';
43 buf[i++] = 'm';
44 buf[i++] = 'p';
45 buf[i++] = ';';
46 } else if (*s == '<') {
47 buf[i++] = '&';
48 buf[i++] = 'l';
49 buf[i++] = 't';
50 buf[i++] = ';';
51 } else if (*s == '>') {
52 buf[i++] = '&';
53 buf[i++] = 'g';
54 buf[i++] = 't';
55 buf[i++] = ';';
56 } else if (*s == '"') {
57 buf[i++] = '&';
58 buf[i++] = 'q';
59 buf[i++] = 'u';
60 buf[i++] = 'o';
61 buf[i++] = 't';
62 buf[i++] = ';';
63 } else if (*s == '\'') {
64 buf[i++] = '&';
65 buf[i++] = 'a';
66 buf[i++] = 'p';
67 buf[i++] = 'o';
68 buf[i++] = 's';
69 buf[i++] = ';';
70 } else if ((*s & 0xFF) < 0x20) {
71 int n = snprintf(buf, len - i, "&#%d;", *s & 0xFF);
72
73 if (n < 0)
74 break;
75 i += n;
76 } else {
77 buf[i++] = *s;
78 }
79 s++;
80 }
81 if (i < len)
82 buf[i] = 0;
83 else
84 buf[len - 1] = 0;
85 return i;
86}
87
88size_t
89XMLunquotestring(const char **p, char q, char *buf)
90{
91 const char *s = *p;
92 size_t i = 0;
93
94 while (*s && *s != q) {
95 if (*s == '&') {
96 s++;
97 if (strncmp(s, "lt;", 3) == 0) {
98 buf[i++] = '<';
99 s += 3;
100 } else if (strncmp(s, "gt;", 3) == 0) {
101 buf[i++] = '>';
102 s += 3;
103 } else if (strncmp(s, "apos;", 5) == 0) {
104 buf[i++] = '\'';
105 s += 5;
106 } else if (strncmp(s, "quot;", 5) == 0) {
107 buf[i++] = '"';
108 s += 5;
109 } else if (strncmp(s, "amp;", 4) == 0) {
110 buf[i++] = '&';
111 s += 4;
112 } else if (*s == '#') {
113 char *e;
114 int base;
115 unsigned long n; /* type unsigned long returned by strtoul() */
116
117 s++;
118 if (*s == 'x' || *s == 'X') {
119 s++;
120 base = 16;
121 } else
122 base = 10;
123 n = strtoul(s, &e, base);
124 assert(e > s && *e == ';');
125 assert(n <= 0x7FFFFFFF);
126 s = e + 1;
127 if (n <= 0x7F)
128 buf[i++] = (char) n;
129 else if (n <= 0x7FF) {
130 buf[i++] = (char) (0xC0 | (n >> 6));
131 buf[i++] = (char) (0x80 | (n & 0x3F));
132 } else if (n <= 0xFFFF) {
133 buf[i++] = (char) (0xE0 | (n >> 12));
134 buf[i++] = (char) (0x80 | ((n >> 6) & 0x3F));
135 buf[i++] = (char) (0x80 | (n & 0x3F));
136 } else if (n <= 0x1FFFFF) {
137 buf[i++] = (char) (0xF0 | (n >> 18));
138 buf[i++] = (char) (0x80 | ((n >> 12) & 0x3F));
139 buf[i++] = (char) (0x80 | ((n >> 6) & 0x3F));
140 buf[i++] = (char) (0x80 | (n & 0x3F));
141 } else if (n <= 0x3FFFFFF) {
142 buf[i++] = (char) (0xF8 | (n >> 24));
143 buf[i++] = (char) (0x80 | ((n >> 18) & 0x3F));
144 buf[i++] = (char) (0x80 | ((n >> 12) & 0x3F));
145 buf[i++] = (char) (0x80 | ((n >> 6) & 0x3F));
146 buf[i++] = (char) (0x80 | (n & 0x3F));
147 } else if (n <= 0x7FFFFFFF) {
148 buf[i++] = (char) (0xFC | (n >> 30));
149 buf[i++] = (char) (0x80 | ((n >> 24) & 0x3F));
150 buf[i++] = (char) (0x80 | ((n >> 18) & 0x3F));
151 buf[i++] = (char) (0x80 | ((n >> 12) & 0x3F));
152 buf[i++] = (char) (0x80 | ((n >> 6) & 0x3F));
153 buf[i++] = (char) (0x80 | (n & 0x3F));
154 }
155 } else {
156 /* unrecognized entity: just leave it */
157 buf[i++] = '&';
158 }
159 } else
160 buf[i++] = *s++;
161 }
162 buf[i] = 0;
163 *p = s;
164 return i;
165}
166
167str
168XMLxml2str(str *s, xml *x)
169{
170 if (strNil(*x)) {
171 *s = GDKstrdup(str_nil);
172 return MAL_SUCCEED;
173 }
174 assert(**x == 'A' || **x == 'C' || **x == 'D');
175 *s = GDKstrdup(*x + 1);
176 return MAL_SUCCEED;
177}
178
179str
180XMLstr2xml(xml *x, const char **val)
181{
182 const char *t = *val;
183 str buf;
184 size_t len;
185
186 if (strNil(t)) {
187 *x = (xml) GDKstrdup(str_nil);
188 if (*x == NULL)
189 throw(MAL, "xml.xml", SQLSTATE(HY001) MAL_MALLOC_FAIL);
190 return MAL_SUCCEED;
191 }
192 len = 6 * strlen(t) + 1;
193 buf = GDKmalloc(len + 1);
194 if (buf == NULL)
195 throw(MAL, "xml.xml", SQLSTATE(HY001) MAL_MALLOC_FAIL);
196 buf[0] = 'C';
197 XMLquotestring(t, buf + 1, len);
198 *x = buf;
199 return MAL_SUCCEED;
200}
201
202str
203XMLxmltext(str *s, xml *x)
204{
205 xmlDocPtr doc;
206 xmlNodePtr elem;
207 str content = NULL;
208
209 if (strNil(*x)) {
210 *s = GDKstrdup(str_nil);
211 if (*s == NULL)
212 throw(MAL, "xml.text", SQLSTATE(HY001) MAL_MALLOC_FAIL);
213 return MAL_SUCCEED;
214 }
215 if (**x == 'D') {
216 doc = xmlParseMemory(*x + 1, (int) strlen(*x + 1));
217 elem = xmlDocGetRootElement(doc);
218 content = (str) xmlNodeGetContent(elem);
219 xmlFreeDoc(doc);
220 } else if (**x == 'C') {
221 doc = xmlParseMemory("<doc/>", 6);
222 xmlParseInNodeContext(xmlDocGetRootElement(doc), *x + 1, (int) strlen(*x + 1), 0, &elem);
223 content = (str) xmlNodeGetContent(elem);
224 xmlFreeNodeList(elem);
225 xmlFreeDoc(doc);
226 } else if (**x == 'A') {
227 const char *t = *x + 1;
228 str p;
229
230 p = content = GDKmalloc(strlen(*x) + 1);
231 if (p == NULL)
232 throw(MAL, "xml.text", SQLSTATE(HY001) MAL_MALLOC_FAIL);
233 while (*t) {
234 if (*t == '"' || *t == '\'') {
235 char q = *t++;
236
237 p += XMLunquotestring(&t, q, p);
238 }
239 t++;
240 }
241 *p = 0;
242 }
243 if (content == NULL) {
244 *s = GDKstrdup("");
245 if (*s == NULL)
246 throw(MAL, "xml.text", SQLSTATE(HY001) MAL_MALLOC_FAIL);
247 } else
248 *s = (str) content;
249 return MAL_SUCCEED;
250}
251
252str
253XMLxml2xml(xml *s, xml *x)
254{
255 *s = GDKstrdup(*x);
256 if (*s == NULL)
257 throw(MAL, "xml.xml", SQLSTATE(HY001) MAL_MALLOC_FAIL);
258 return MAL_SUCCEED;
259}
260
261str
262XMLdocument(xml *x, str *val)
263{
264 xmlDocPtr doc;
265
266 if (strNil(*val)) {
267 *x = (xml) GDKstrdup(str_nil);
268 if (*x == NULL)
269 throw(MAL, "xml.document", SQLSTATE(HY001) MAL_MALLOC_FAIL);
270 return MAL_SUCCEED;
271 }
272 /* call the libxml2 library to perform the test */
273 doc = xmlParseMemory(*val, (int) strlen(*val));
274 if (doc) {
275 int len;
276 xmlChar *buf;
277
278 xmlDocDumpMemory(doc, &buf, &len);
279 xmlFreeDoc(doc);
280 *x = GDKmalloc(len + 2);
281 if (*x == NULL)
282 throw(MAL, "xml.document", SQLSTATE(HY001) MAL_MALLOC_FAIL);
283 snprintf(*x, len + 2, "D%s", (char *) buf);
284 GDKfree(buf);
285 return MAL_SUCCEED;
286 }
287 throw(MAL, "xml.document", "Document parse error");
288}
289
290str
291XMLcontent(xml *x, str *val)
292{
293 xmlDocPtr doc;
294 xmlNodePtr elem;
295 xmlParserErrors err;
296 xmlBufferPtr buf;
297 const xmlChar *s;
298 size_t len;
299
300 if (strNil(*val)) {
301 *x = (xml) GDKstrdup(str_nil);
302 if (*x == NULL)
303 throw(MAL, "xml.content", SQLSTATE(HY001) MAL_MALLOC_FAIL);
304 return MAL_SUCCEED;
305 }
306 /* call the libxml2 library to perform the test */
307 doc = xmlParseMemory("<doc/>", 6);
308 err = xmlParseInNodeContext(xmlDocGetRootElement(doc), *val, (int) strlen(*val), 0, &elem);
309 if (err != XML_ERR_OK) {
310 xmlFreeDoc(doc);
311 throw(MAL, "xml.content", "Content parse error");
312 }
313 buf = xmlBufferCreate();
314 xmlNodeDump(buf, doc, elem, 0, 0);
315 s = xmlBufferContent(buf);
316 len = strlen((const char *) s) + 2;
317 *x = GDKmalloc(len);
318 if (*x == NULL)
319 throw(MAL, "xml.content", SQLSTATE(HY001) MAL_MALLOC_FAIL);
320 snprintf(*x, len, "C%s", (const char *) s);
321 xmlBufferFree(buf);
322 xmlFreeNodeList(elem);
323 xmlFreeDoc(doc);
324 return MAL_SUCCEED;
325}
326
327str
328XMLisdocument(bit *x, str *s)
329{
330 xmlDocPtr doc;
331
332 /* call the libxml2 library to perform the test */
333 if (strNil(*s))
334 *x = bit_nil;
335 else {
336 doc = xmlParseMemory(*s, (int) strlen(*s));
337 *x = doc != NULL;
338 if (doc)
339 xmlFreeDoc(doc);
340 }
341 return MAL_SUCCEED;
342}
343
344str
345XMLcomment(xml *x, str *s)
346{
347 size_t len;
348 str buf;
349
350 if (strNil(*s)) {
351 *x = (xml) GDKstrdup(str_nil);
352 if (*x == NULL)
353 throw(MAL, "xml.comment", SQLSTATE(HY001) MAL_MALLOC_FAIL);
354 return MAL_SUCCEED;
355 }
356 if (strstr(*s, "--") != NULL)
357 throw(MAL, "xml.comment", "comment may not contain `--'");
358 len = strlen(*s) + 9;
359 buf = (str) GDKmalloc(len);
360 if (buf == NULL)
361 throw(MAL, "xml.comment", SQLSTATE(HY001) MAL_MALLOC_FAIL);
362 snprintf(buf, len, "C<!--%s-->", *s);
363 *x = buf;
364 return MAL_SUCCEED;
365}
366
367str
368XMLparse(xml *x, str *doccont, str *val, str *option)
369{
370 (void) option;
371 if (strcmp(*doccont, "content") == 0)
372 return XMLcontent(x, val);
373 if (strcmp(*doccont, "document") == 0)
374 return XMLdocument(x, val);
375 throw(MAL, "xml.parse", "invalid parameter");
376}
377
378str
379XMLpi(str *ret, str *target, str *value)
380{
381 size_t len;
382 str buf;
383 str val = NULL;
384
385 if (strNil(*target)) {
386 *ret = GDKstrdup(str_nil);
387 if (*ret == NULL)
388 throw(MAL, "xml.attribute", SQLSTATE(HY001) MAL_MALLOC_FAIL);
389 return MAL_SUCCEED;
390 }
391 if (xmlValidateName((xmlChar *) *target, 0) != 0 || strcasecmp(*target, "xml") == 0)
392 throw(MAL, "xml.attribute", "invalid processing instruction target");
393 len = strlen(*target) + 6;
394 if (strNil(*value) || **value == 0) {
395 size_t n = 6 * strlen(*value) + 1;
396
397 val = GDKmalloc(n);
398 if (val == NULL)
399 throw(MAL, "xml.attribute", SQLSTATE(HY001) MAL_MALLOC_FAIL);
400 len += XMLquotestring(*value, val, n) + 1;
401 }
402 buf = GDKmalloc(len);
403 if (buf == NULL) {
404 if (val)
405 GDKfree(val);
406 throw(MAL, "xml.attribute", SQLSTATE(HY001) MAL_MALLOC_FAIL);
407 }
408 if (val == NULL) {
409 snprintf(buf, len, "C<?%s?>", *target);
410 } else {
411 snprintf(buf, len, "C<?%s %s?>", *target, val);
412 GDKfree(val);
413 }
414 *ret = buf;
415 return MAL_SUCCEED;
416}
417
418str
419XMLroot(xml *ret, xml *val, str *version, str *standalone)
420{
421 size_t len = 0, i = 0;
422 str buf;
423 bit isdoc = 0;
424
425 if (strNil(*val)) {
426 *ret = GDKstrdup(str_nil);
427 if (*ret == NULL)
428 throw(MAL, "xml.root", SQLSTATE(HY001) MAL_MALLOC_FAIL);
429 return MAL_SUCCEED;
430 }
431 if (**val != 'C')
432 throw(MAL, "xml.root", "value must be an XML node");
433 len = 8;
434 len = strlen(*val);
435 if (!strNil(*version) && **version) {
436 if (strcmp(*version, "1.0") != 0 && strcmp(*version, "1.1") != 0)
437 throw(MAL, "xml.root", "illegal XML version");
438 len += 11 + strlen(*version); /* strlen(" version=\"\"") */
439 }
440 if (!strNil(*standalone) && **standalone) {
441 if (strcmp(*standalone, "yes") != 0 && strcmp(*standalone, "no") != 0)
442 throw(MAL, "xml.root", "illegal XML standalone value");
443 len += 14 + strlen(*standalone); /* strlen(" standalone=\"\"") */
444 }
445 buf = GDKmalloc(len);
446 if (buf == NULL)
447 throw(MAL, "xml.root", SQLSTATE(HY001) MAL_MALLOC_FAIL);
448 strcpy(buf, "D<?xml");
449 i = strlen(buf);
450 if (!strNil(*version) && **version)
451 i += snprintf(buf + i, len - i, " version=\"%s\"", *version);
452 if (!strNil(*standalone) && **standalone)
453 i += snprintf(buf + i, len - i, " standalone=\"%s\"", *standalone);
454 snprintf(buf + i, len - i, "?>%s", *val + 1);
455 buf++;
456 XMLisdocument(&isdoc, &buf); /* check well-formedness */
457 buf--;
458 if (!isdoc) {
459 GDKfree(buf);
460 throw(MAL, "xml.root", "resulting document not well-formed");
461 }
462 *ret = buf;
463 return MAL_SUCCEED;
464}
465
466str
467XMLattribute(xml *x, str *name, str *val)
468{
469 str t = *val;
470 str buf;
471 size_t len;
472
473 if (strNil(t) || strNil(*name)) {
474 *x = (xml) GDKstrdup(str_nil);
475 if (*x == NULL)
476 throw(MAL, "xml.attribute", SQLSTATE(HY001) MAL_MALLOC_FAIL);
477 return MAL_SUCCEED;
478 }
479 if (xmlValidateName((xmlChar *) *name, 0) != 0)
480 throw(MAL, "xml.attribute", "invalid attribute name");
481 len = 6 * strlen(t) + 1;
482 buf = GDKmalloc(len);
483 if (buf == NULL)
484 throw(MAL, "xml.attribute", SQLSTATE(HY001) MAL_MALLOC_FAIL);
485 len = XMLquotestring(t, buf, len);
486 len += strlen(*name) + 5;
487 *x = GDKmalloc(len);
488 if (*x == NULL) {
489 GDKfree(buf);
490 throw(MAL, "xml.attribute", SQLSTATE(HY001) MAL_MALLOC_FAIL);
491 }
492 snprintf(*x, len, "A%s=\"%s\"", *name, buf);
493 GDKfree(buf);
494 return MAL_SUCCEED;
495}
496
497str
498XMLelement(xml *ret, str *name, xml *nspace, xml *attr, xml *val)
499{
500 size_t len, i, namelen;
501 str buf;
502
503 if (strNil(*name))
504 throw(MAL, "xml.element", "no element name specified");
505 if (xmlValidateName((xmlChar *) *name, 0) != 0)
506 throw(MAL, "xml.element", "invalid element name");
507 /* len is composed of several parts:
508 "C" + "<" + name + (nspace ? " " + nspace : "") + (attr ? " " + attr : "") + (val ? ">" + val + "</" + name + ">" : "/>")
509 */
510 namelen = strlen(*name);
511 len = namelen + 5; /* "C", "<", "/", ">", terminating NUL */
512 if (nspace && !strNil(*nspace)) {
513 if (**nspace != 'A')
514 throw(MAL, "xml.element", "illegal namespace");
515 len += strlen(*nspace); /* " " + nspace (nspace contains initial 'A' which is replaced by space) */
516 }
517 if (attr && !strNil(*attr)) {
518 if (**attr != 'A')
519 throw(MAL, "xml.element", "illegal attribute");
520 len += strlen(*attr); /* " " + attr (attr contains initial 'A' which is replaced by space) */
521 }
522 if (!strNil(*val) && **val != 0) {
523 if (**val != 'C')
524 throw(MAL, "xml.element", "illegal content");
525 len += strlen(*val + 1) + namelen + 2; /* extra "<", ">", and name ("/" already counted) */
526 }
527 buf = GDKmalloc(len);
528 if (buf == NULL)
529 throw(MAL, "xml.element", SQLSTATE(HY001) MAL_MALLOC_FAIL);
530 if (strNil(*val) && (!attr || strNil(*attr))) {
531 strcpy(buf, str_nil);
532 } else {
533 i = snprintf(buf, len, "C<%s", *name);
534 if (nspace && !strNil(*nspace))
535 i += snprintf(buf + i, len - i, " %s", *nspace + 1);
536 if (attr && !strNil(*attr))
537 i += snprintf(buf + i, len - i, " %s", *attr + 1);
538 if (!strNil(*val))
539 i += snprintf(buf + i, len - i, ">%s</%s>", *val + 1, *name);
540 else
541 i += snprintf(buf + i, len - i, "/>");
542 }
543 *ret = buf;
544 return MAL_SUCCEED;
545}
546
547str
548XMLelementSmall(xml *ret, str *name, xml *val)
549{
550 return XMLelement(ret, name, NULL, NULL, val);
551}
552
553str
554XMLconcat(xml *ret, xml *left, xml *right)
555{
556 size_t len;
557 str buf;
558
559 /* if either side is nil, return the other, otherwise concatenate */
560 if (strNil(*left))
561 buf = GDKstrdup(*right);
562 else if (strNil(*right))
563 buf = GDKstrdup(*left);
564 else if (**left != **right)
565 throw(MAL, "xml.concat", "arguments not compatible");
566 else if (**left == 'A') {
567 len = strlen(*left) + strlen(*right) + 1;
568 buf = GDKmalloc(len);
569 if (buf == NULL)
570 throw(MAL, "xml.concat", SQLSTATE(HY001) MAL_MALLOC_FAIL);
571 snprintf(buf, len, "A%s %s", *left + 1, *right + 1);
572 } else if (**left == 'C') {
573 len = strlen(*left) + strlen(*right) +2;
574 buf = GDKmalloc(len);
575 if (buf == NULL)
576 throw(MAL, "xml.concat", SQLSTATE(HY001) MAL_MALLOC_FAIL);
577 snprintf(buf, len, "C%s%s", *left + 1, *right + 1);
578 } else
579 throw(MAL, "xml.concat", "can only concatenate attributes and element content");
580 if (buf == NULL)
581 throw(MAL, "xml.concat", SQLSTATE(HY001) MAL_MALLOC_FAIL);
582 *ret = buf;
583 return MAL_SUCCEED;
584}
585
586str
587XMLforest(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
588{
589 xml *ret = getArgReference_TYPE(stk, p, 0, xml);
590 int i;
591 size_t len;
592 str buf;
593 xml x;
594
595 (void) cntxt;
596 (void) mb;
597
598 len = 2;
599 for (i = p->retc; i < p->argc; i++) {
600 x = *getArgReference_TYPE(stk, p, i, xml);
601 if (!strNil(x))
602 if (*x != 'C')
603 throw(MAL, "xml.forest", "arguments must be element content");
604 len += strlen(x + 1);
605 }
606 buf = (str) GDKmalloc(len);
607 if (buf == NULL)
608 throw(MAL, "xml.forest", SQLSTATE(HY001) MAL_MALLOC_FAIL);
609 *ret = buf;
610 *buf++ = 'C';
611 *buf = 0;
612
613 for (i = p->retc; i < p->argc; i++) {
614 x = *getArgReference_TYPE(stk, p, i, xml);
615 if (!strNil(x)) {
616 len = strlen(x + 1);
617 strcpy(buf, x + 1);
618 buf += len;
619 }
620 }
621 return MAL_SUCCEED;
622}
623
624int TYPE_xml;
625
626str
627XMLprelude(void *ret)
628{
629 (void) ret;
630 TYPE_xml = ATOMindex("xml");
631 xmlMemSetup(GDKfree, GDKmalloc, GDKrealloc, GDKstrdup);
632 xmlInitParser();
633 return MAL_SUCCEED;
634}
635
636ssize_t
637XMLfromString(const char *src, size_t *len, xml *x, bool external)
638{
639 if (*x){
640 GDKfree(*x);
641 *x = NULL;
642 }
643 if (external && strcmp(src, "nil") == 0) {
644 *x = GDKstrdup(str_nil);
645 if (*x == NULL)
646 return -1;
647 return 3;
648 } else if (GDK_STRNIL(src)) {
649 *x = GDKstrdup(str_nil);
650 if (*x == NULL)
651 return -1;
652 return 1;
653 } else {
654 char *err = XMLstr2xml(x, &src);
655 if (err != MAL_SUCCEED) {
656 GDKerror("%s", getExceptionMessageAndState(err));
657 freeException(err);
658 return -1;
659 }
660 }
661 *len = strlen(*x) + 1;
662 return (ssize_t) *len - 1;
663}
664
665ssize_t
666XMLtoString(str *s, size_t *len, const char *src, bool external)
667{
668 size_t l;
669
670 if (GDK_STRNIL(src))
671 src = external ? "nil" : str_nil;
672 else
673 src++;
674 l = strlen(src) + 1;
675 if (l >= *len || *s == NULL) {
676 GDKfree(*s);
677 *s = GDKmalloc(l);
678 if (*s == NULL)
679 return -1;
680 *len = l;
681 }
682 strcpy(*s, src);
683 return (ssize_t) l - 1;
684}
685
686#else
687
688#define NO_LIBXML_FATAL "xml: MonetDB was built without libxml, but what you are trying to do requires it."
689
690ssize_t XMLfromString(const char *src, size_t *len, xml *x, bool external) {
691 (void) src;
692 (void) len;
693 (void) x;
694 (void) external;
695 GDKerror("XMLfromString is not implemented\n");
696 return -1;
697}
698ssize_t XMLtoString(str *s, size_t *len, const char *src, bool external) {
699 (void) s;
700 (void) len;
701 (void) src;
702 (void) external;
703 GDKerror("XMLtoString is not implemented\n");
704 return -1;
705}
706str XMLxml2str(str *s, xml *x) {
707 (void) s;
708 (void) x;
709 return createException(MAL, "xml.xml2str", SQLSTATE(HY005) NO_LIBXML_FATAL);
710}
711str XMLstr2xml(xml *x, const char **s) {
712 (void) s;
713 (void) x;
714 return createException(MAL, "xml.xml2str", SQLSTATE(HY005) NO_LIBXML_FATAL);
715}
716str XMLxmltext(str *s, xml *x) {
717 (void) s;
718 (void) x;
719 return createException(MAL, "xml.xmltext", SQLSTATE(HY005) NO_LIBXML_FATAL);
720}
721str XMLxml2xml(xml *x, xml *s) {
722 (void) s;
723 (void) x;
724 return createException(MAL, "xml.xml2xml", SQLSTATE(HY005) NO_LIBXML_FATAL);
725}
726str XMLdocument(xml *x, str *s) {
727 (void) s;
728 (void) x;
729 return createException(MAL, "xml.document", SQLSTATE(HY005) NO_LIBXML_FATAL);
730}
731str XMLcontent(xml *x, str *s) {
732 (void) s;
733 (void) x;
734 return createException(MAL, "xml.content", SQLSTATE(HY005) NO_LIBXML_FATAL);
735}
736str XMLisdocument(bit *x, str *s) {
737 (void) s;
738 (void) x;
739 return createException(MAL, "xml.isdocument", SQLSTATE(HY005) NO_LIBXML_FATAL);
740}
741str XMLcomment(xml *x, str *s) {
742 (void) s;
743 (void) x;
744 return createException(MAL, "xml.comment", SQLSTATE(HY005) NO_LIBXML_FATAL);
745}
746str XMLpi(xml *x, str *target, str *s) {
747 (void) s;
748 (void) target;
749 (void) x;
750 return createException(MAL, "xml.pi", SQLSTATE(HY005) NO_LIBXML_FATAL);
751}
752str XMLroot(xml *x, xml *v, str *version, str *standalone) {
753 (void) x;
754 (void) v;
755 (void) version;
756 (void) standalone;
757 return createException(MAL, "xml.root", SQLSTATE(HY005) NO_LIBXML_FATAL);
758}
759str XMLparse(xml *x, str *doccont, str *s, str *option) {
760 (void) x;
761 (void) doccont;
762 (void) s;
763 (void) option;
764 return createException(MAL, "xml.parse", SQLSTATE(HY005) NO_LIBXML_FATAL);
765}
766str XMLattribute(xml *ret, str *name, str *val) {
767 (void) ret;
768 (void) name;
769 (void) val;
770 return createException(MAL, "xml.attribute", SQLSTATE(HY005) NO_LIBXML_FATAL);
771}
772str XMLelement(xml *ret, str *name, xml *nspace, xml *attr, xml *val) {
773 (void) ret;
774 (void) name;
775 (void) nspace;
776 (void) attr;
777 (void) val;
778 return createException(MAL, "xml.element", SQLSTATE(HY005) NO_LIBXML_FATAL);
779}
780str XMLelementSmall(xml *ret, str *name, xml *val) {
781 (void) ret;
782 (void) name;
783 (void) val;
784 return createException(MAL, "xml.elementSmall", SQLSTATE(HY005) NO_LIBXML_FATAL);
785}
786str XMLconcat(xml *ret, xml *left, xml *right) {
787 (void) ret;
788 (void) left;
789 (void) right;
790 return createException(MAL, "xml.concat", SQLSTATE(HY005) NO_LIBXML_FATAL);
791}
792str XMLforest(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p) {
793 (void) cntxt;
794 (void) mb;
795 (void) stk;
796 (void) p;
797 return createException(MAL, "xml.forest", SQLSTATE(HY005) NO_LIBXML_FATAL);
798}
799size_t XMLquotestring(const char *s, char *buf, size_t len) {
800 (void) s;
801 (void) buf;
802 (void) len;
803 return 0;
804}
805size_t XMLunquotestring(const char **p, char q, char *buf) {
806 (void) p;
807 (void) q;
808 (void) buf;
809 return 0;
810}
811str XMLprelude(void *ret) {
812 (void) ret;
813 return MAL_SUCCEED; /* to not break init */
814}
815
816#endif
817