LCOV - code coverage report
Current view: top level - sql/server - rel_xml.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 117 181 64.6 %
Date: 2024-10-03 20:03:20 Functions: 5 9 55.6 %

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

Generated by: LCOV version 1.14