LCOV - code coverage report
Current view: top level - sql/server - rel_xml.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 100 156 64.1 %
Date: 2021-10-13 02:24:04 Functions: 5 9 55.6 %

          Line data    Source code
       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 - 2021 MonetDB B.V.
       7             :  */
       8             : 
       9             : #include "monetdb_config.h"
      10             : #include "rel_xml.h"
      11             : #include "rel_exp.h"
      12             : #include "rel_select.h"
      13             : #include "sql_semantic.h"
      14             : #include "sql_parser.h"
      15             : 
      16             : static sql_exp *
      17          14 : rel_xmlelement(sql_query *query, sql_rel **rel, symbol *sym, int f, exp_kind knd)
      18             : {
      19          14 :         mvc *sql = query->sql;
      20          14 :         dnode *d = sym->data.lval->h;
      21          14 :         const char *tag = d->data.sval;
      22          14 :         dlist *ns_attrs_elms = d->next->data.lval;
      23             :         sql_exp *ns_st = NULL, *attr_st = NULL, *res = NULL;
      24             :         sql_type *t = NULL;
      25             :         sql_subtype xml_type;
      26             : 
      27          14 :         if ((t = mvc_bind_type(sql, "xml")) == NULL)
      28           0 :                 return sql_error(sql, 02, SQLSTATE(42000) "XML: xml type missing, probably the xml module wasn't added");
      29          14 :         sql_init_subtype(&xml_type, t, 0, 0);
      30          14 :         if (ns_attrs_elms) {
      31          14 :                 symbol *ns = ns_attrs_elms->h->data.sym;
      32          14 :                 symbol *attr = ns_attrs_elms->h->next->data.sym;
      33          14 :                 dlist *content = ns_attrs_elms->h->next->next->data.lval;
      34             : 
      35             :                 /* loop over the content, create recursive element  */
      36          14 :                 if (content) {
      37             :                         dnode *n;
      38          13 :                         dlist *cl = content->h->data.lval;
      39             : 
      40          29 :                         for (n=cl->h; n; n = n->next) {
      41          16 :                                 symbol *c = n->data.sym;
      42             :                                 sql_subtype *st;
      43          16 :                                 sql_exp *c_st = rel_value_exp(query, rel, c, f, knd);
      44             : 
      45          16 :                                 if (!c_st)
      46             :                                         return NULL;
      47             : 
      48          16 :                                 st = exp_subtype(c_st);
      49          16 :                                 assert(st);
      50          16 :                                 if (type_cmp(st->type, xml_type.type) != 0) {
      51             :                                         sql_subtype str_type;
      52             : 
      53           4 :                                         sql_find_subtype(&str_type, "clob", 0, 0);
      54             :                                         /* convert to string first */
      55           4 :                                         c_st = exp_check_type(sql, &str_type, rel ? *rel : NULL, c_st, type_equal);
      56             :                                         /* then to xml */
      57           4 :                                         if (!c_st || (c_st = exp_check_type(sql, &xml_type, rel ? *rel : NULL, c_st, type_equal)) == NULL)
      58           0 :                                                 return NULL;
      59             :                                 }
      60             : 
      61             :                                 /* lets glue the xml content together */
      62          16 :                                 if (res) {
      63           3 :                                         res = rel_binop_(sql, rel ? *rel : NULL, res, c_st, NULL, "concat", card_value);
      64             :                                 } else {
      65             :                                         res = c_st;
      66             :                                 }
      67             :                         }
      68             :                 }
      69          14 :                 if (ns) {
      70           0 :                         ns_st = rel_value_exp(query, rel, ns, f, knd);
      71           0 :                         if (!ns_st)
      72             :                                 return NULL;
      73             :                 }
      74          14 :                 if (attr) {
      75           5 :                         attr_st = rel_value_exp(query, rel, attr, f, knd);
      76           5 :                         if (!attr_st)
      77             :                                 return NULL;
      78             :                 }
      79             :         }
      80             : 
      81          14 :         if (!ns_st)
      82          14 :                 ns_st = exp_atom(sql->sa, atom_general(sql->sa, &xml_type, NULL));
      83          14 :         if (!attr_st)
      84           9 :                 attr_st = exp_atom(sql->sa, atom_general(sql->sa, &xml_type, NULL));
      85          14 :         if (!res)
      86           1 :                 res = exp_atom(sql->sa, atom_general(sql->sa, &xml_type, NULL));
      87             : 
      88          14 :         if (!ns_st || !attr_st || !res)
      89             :                 return NULL;
      90          14 :         return rel_nop_(query->sql, rel ? *rel : NULL, exp_atom_clob(sql->sa, tag), ns_st, attr_st, res, NULL, "element",
      91             :                                         card_value);
      92             : }
      93             : 
      94             : static sql_exp *
      95           5 : rel_xmlforest(sql_query *query, sql_rel **rel, symbol *sym, int f, exp_kind knd)
      96             : {
      97           5 :         mvc *sql = query->sql;
      98           5 :         dnode *d = sym->data.lval->h;
      99           5 :         symbol *ns = d->data.sym;
     100           5 :         dlist *elms = d->next->data.lval;
     101             :         sql_exp *ns_st, *attr_st, *res = NULL;
     102             :         sql_type *t = NULL;
     103             :         sql_subtype xml_type;
     104             : 
     105           5 :         if ((t = mvc_bind_type(sql, "xml")) == NULL)
     106           0 :                 return sql_error(sql, 02, SQLSTATE(42000) "XML: xml type missing, probably the xml module wasn't added");
     107           5 :         sql_init_subtype(&xml_type, t, 0, 0);
     108           5 :         if (ns) {
     109           0 :                 ns_st = rel_value_exp(query, rel, ns, f, knd);
     110             :         } else {
     111           5 :                 ns_st = exp_atom(sql->sa, atom_general(sql->sa, &xml_type, NULL));
     112             :         }
     113           5 :         if (!ns_st)
     114             :                 return NULL;
     115           5 :         attr_st = exp_atom(sql->sa, atom_general(sql->sa, &xml_type, NULL));
     116           5 :         if (elms) {
     117             :                 dnode *e;
     118             : 
     119          19 :                 for (e = elms->h; e; e = e->next) {
     120          14 :                         dnode *cc = e->data.lval->h;
     121          14 :                         symbol *c = cc->data.sym;
     122          14 :                         const char *tag = cc->next->data.sval;
     123             : 
     124          14 :                         sql_exp *c_st = rel_value_exp(query, rel, c, f, knd);
     125             :                         sql_subtype *st;
     126          14 :                         if (!c_st)
     127             :                                 return NULL;
     128             : 
     129          14 :                         st = exp_subtype(c_st);
     130          14 :                         assert(st);
     131          14 :                         if (type_cmp(st->type, xml_type.type) != 0) {
     132             :                                 sql_subtype str_type;
     133             : 
     134          14 :                                 sql_find_subtype(&str_type, "clob", 0, 0);
     135             :                                 /* convert to string first */
     136          14 :                                 c_st = exp_check_type(sql, &str_type, rel ? *rel : NULL, c_st, type_equal);
     137             :                                 /* then to xml */
     138          14 :                                 if (!c_st || (c_st = exp_check_type(sql, &xml_type, rel ? *rel : NULL, c_st, type_equal)) == NULL)
     139           0 :                                         return NULL;
     140             :                         }
     141             : 
     142          14 :                         if (!tag) {
     143           6 :                                 tag = exp_name(c_st);
     144           6 :                                 if (!tag)
     145             :                                         tag = "single_value";
     146             :                         }
     147          14 :                         c_st = rel_nop_(sql, rel ? *rel : NULL, exp_atom_clob(sql->sa, tag), ns_st, attr_st, c_st, NULL,
     148             :                                                         "element", card_value);
     149             :                         /* lets glue the xml content together */
     150          14 :                         if (res) {
     151           9 :                                 res = rel_binop_(sql, rel ? *rel : NULL, res, c_st, NULL, "concat", card_value);
     152             :                         } else {
     153             :                                 res = c_st;
     154             :                         }
     155             :                 }
     156             :         }
     157             :         return res;
     158             : }
     159             : 
     160             : static sql_exp *
     161           1 : rel_xmlcomment(sql_query *query, sql_rel **rel, symbol *sym, int f, exp_kind knd)
     162             : {
     163           1 :         dnode *d = sym->data.lval->h;
     164           1 :         symbol *comment = d->data.sym;
     165             :         sql_exp *comment_st;
     166             : 
     167           1 :         comment_st = rel_value_exp(query, rel, comment, f, knd);
     168           1 :         if (!comment_st)
     169             :                 return NULL;
     170           1 :         return rel_unop_(query->sql, rel ? *rel : NULL, comment_st, NULL, "comment", card_value);
     171             : }
     172             : 
     173             : static sql_exp *
     174           5 : rel_xmlattribute(sql_query *query, sql_rel **rel, symbol *sym, int f, exp_kind knd)
     175             : {
     176           5 :         dnode *d = sym->data.lval->h;
     177           5 :         const char *attr_name = d->data.sval;
     178           5 :         symbol *attr = d->next->data.sym;
     179             :         sql_exp *attr_st, *attr_name_st = NULL;
     180             : 
     181           5 :         attr_st = rel_value_exp(query, rel, attr, f, knd);
     182           5 :         if (!attr_st)
     183             :                 return NULL;
     184           5 :         if (!attr_name) {
     185             :                 /*TODO:convert simple column names into valid attribute names */
     186           1 :                 attr_name = exp_name(attr_st);
     187           1 :                 if (!attr_name)
     188             :                         attr_name = "single_value";
     189             :         }
     190             :         sql_subtype str_type;
     191             : 
     192           5 :         sql_find_subtype(&str_type, "clob", 0, 0);
     193           5 :         attr_name_st = exp_atom_str(query->sql->sa, attr_name, &str_type);
     194           5 :         return rel_binop_(query->sql, rel ? *rel : NULL, attr_name_st, attr_st, NULL, "attribute", card_value);
     195             : }
     196             : 
     197             : static sql_exp *
     198           0 : rel_xmlconcat(sql_query *query, sql_rel **rel, symbol *sym, int f, exp_kind knd)
     199             : {
     200           0 :         dnode *d = sym->data.lval->h;
     201           0 :         dnode *en = d->data.lval->h;
     202             :         sql_exp *concat_st, *res = NULL;
     203             : 
     204           0 :         for (; en; en = en->next) {
     205           0 :                 symbol *c = en->data.sym;
     206           0 :                 concat_st = rel_value_exp(query, rel, c, f, knd);
     207           0 :                 if (!concat_st)
     208             :                         return NULL;
     209           0 :                 if (res)
     210           0 :                         res = rel_binop_(query->sql, rel ? *rel : NULL, res, concat_st, NULL, "concat", card_value);
     211             :                 else
     212             :                         res = concat_st;
     213             :         }
     214             :         return res;
     215             : }
     216             : 
     217             : static sql_exp *
     218           0 : rel_xmldocument(sql_query *query, sql_rel **rel, symbol *sym, int f, exp_kind knd)
     219             : {
     220           0 :         dnode *d = sym->data.lval->h;
     221           0 :         symbol *val = d->data.sym;
     222             :         sql_exp *val_st;
     223             : 
     224           0 :         val_st = rel_value_exp(query, rel, val, f, knd);
     225           0 :         if (!val_st)
     226             :                 return NULL;
     227           0 :         return rel_unop_(query->sql, rel ? *rel : NULL, val_st, NULL, "document", card_value);
     228             : }
     229             : 
     230             : static sql_exp *
     231           0 : rel_xmlpi(sql_query *query, sql_rel **rel, symbol *sym, int f, exp_kind knd)
     232             : {
     233           0 :         dnode *d = sym->data.lval->h;
     234           0 :         char *target = d->data.sval;
     235           0 :         symbol *val = d->next->data.sym;
     236             :         sql_exp *target_st, *val_st;
     237             :         sql_subtype str_type;
     238             : 
     239           0 :         sql_find_subtype(&str_type, "clob", 0, 0);
     240           0 :         target_st = exp_atom_str(query->sql->sa, target, &str_type);
     241           0 :         if (!val)
     242           0 :                 val_st = rel_value_exp(query, rel, val, f, knd);
     243             :         else
     244           0 :                 val_st = exp_atom(query->sql->sa, atom_general(query->sql->sa, &str_type, NULL));
     245           0 :         if (!val_st)
     246             :                 return NULL;
     247           0 :         return rel_binop_(query->sql, rel ? *rel : NULL, target_st, val_st, NULL, "pi", card_value);
     248             : }
     249             : 
     250             : /* cast string to xml */
     251             : static sql_exp *
     252           0 : rel_xmltext(sql_query *query, sql_rel **rel, symbol *sym, int f, exp_kind knd)
     253             : {
     254           0 :         dnode *d = sym->data.lval->h;
     255           0 :         symbol *text = d->data.sym;
     256             :         sql_exp *text_st;
     257             :         sql_type *t = NULL;
     258             :         sql_subtype xml_type;
     259             : 
     260           0 :         if ((t = mvc_bind_type(query->sql, "xml")) == NULL)
     261           0 :                 return sql_error(query->sql, 02, SQLSTATE(42000) "XML: xml type missing, probably the xml module wasn't added");
     262           0 :         sql_init_subtype(&xml_type, t, 0, 0);
     263           0 :         text_st = rel_value_exp(query, rel, text, f, knd);
     264           0 :         if (!text_st || (text_st = exp_check_type(query->sql, &xml_type, rel ? *rel : NULL, text_st, type_equal)) == NULL)
     265           0 :                 return NULL;
     266             :         return text_st;
     267             : }
     268             : 
     269             : sql_exp *
     270          25 : rel_xml(sql_query *query, sql_rel **rel, symbol *s, int f, exp_kind knd)
     271             : {
     272          25 :         mvc *sql = query->sql;
     273             :         sql_exp *ret = NULL;
     274             : 
     275          25 :         switch (s->token) {
     276          14 :         case SQL_XMLELEMENT:
     277          14 :                 ret = rel_xmlelement(query, rel, s, f, knd);
     278          14 :                 break;
     279           5 :         case SQL_XMLFOREST:
     280           5 :                 ret = rel_xmlforest(query, rel, s, f, knd);
     281           5 :                 break;
     282           1 :         case SQL_XMLCOMMENT:
     283           1 :                 ret = rel_xmlcomment(query, rel, s, f, knd);
     284           1 :                 break;
     285           5 :         case SQL_XMLATTRIBUTE:
     286           5 :                 ret = rel_xmlattribute(query, rel, s, f, knd);
     287           5 :                 break;
     288           0 :         case SQL_XMLCONCAT:
     289           0 :                 ret = rel_xmlconcat(query, rel, s, f, knd);
     290           0 :                 break;
     291           0 :         case SQL_XMLDOCUMENT:
     292           0 :                 ret = rel_xmldocument(query, rel, s, f, knd);
     293           0 :                 break;
     294           0 :         case SQL_XMLPI:
     295           0 :                 ret = rel_xmlpi(query, rel, s, f, knd);
     296           0 :                 break;
     297           0 :         case SQL_XMLTEXT:
     298           0 :                 ret = rel_xmltext(query, rel, s, f, knd);
     299           0 :                 break;
     300           0 :         default:
     301           0 :                 return sql_error(sql, 01, SQLSTATE(42000) "XML statement unknown symbol(%p)->token = %s", s, token2string(s->token));
     302             :         }
     303             :         return ret;
     304             : }

Generated by: LCOV version 1.14