LCOV - code coverage report
Current view: top level - sql/backends/monet5 - rel_tvtree.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 175 182 96.2 %
Date: 2025-03-25 21:27:32 Functions: 11 11 100.0 %

          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 - 2025 MonetDB Foundation;
       9             :  * Copyright August 2008 - 2023 MonetDB B.V.;
      10             :  * Copyright 1997 - July 2008 CWI.
      11             :  */
      12             : 
      13             : #include "monetdb_config.h"
      14             : 
      15             : #include "rel_tvtree.h"
      16             : #include "rel_exp.h"
      17             : #include "rel_bin.h"
      18             : #include "sql_statement.h"
      19             : 
      20             : static tv_type
      21      139541 : tv_get_type(sql_subtype *st)
      22             : {
      23      139541 :         if (st->multiset) {
      24          30 :                 if (st->multiset == MS_ARRAY)
      25             :                         return TV_MSET;
      26           0 :                 if (st->multiset == MS_SETOF)
      27           0 :                         return TV_SETOF;
      28      139511 :         } else if (st->type->composite)
      29          18 :                 return TV_COMP;
      30             : 
      31             :         return TV_BASIC;
      32             : }
      33             : 
      34             : static tv_tree*
      35      139512 : tv_node(allocator *sa, sql_subtype *st, tv_type tvt)
      36             : {
      37      139512 :         tv_tree *n = (sa)?SA_NEW(sa, tv_tree):MNEW(tv_tree);
      38      139415 :         if (n == NULL)
      39             :                 return NULL;
      40      139415 :         n->st = st;
      41      139415 :         n->tvt = tvt;
      42      139415 :         n->rid_idx = 0;
      43      139415 :         n->ctl = n->rid = n->msid = n->msnr = n->vals = NULL;
      44             : 
      45             :         /* allocate only the lists that we need based on the tv-tree type */
      46      139415 :         switch (n->tvt) {
      47      139351 :                 case TV_BASIC:
      48      139351 :                         n->vals = sa_list(sa);
      49      139359 :                 return n;
      50          34 :         case TV_COMP:
      51          34 :                         n->ctl = sa_list(sa);
      52         102 :                         for (node *sf = st->type->d.fields->h; sf; sf = sf->next) {
      53          68 :                                 sql_arg *sfa = sf->data;
      54          68 :                                 append(n->ctl, tv_node(sa, &sfa->type, tv_get_type(&sfa->type)));
      55             :                         }
      56             :                 return n;
      57          30 :         case TV_MSET:
      58          30 :                         n->msnr = sa_list(sa);
      59             :                         /* fall through */
      60          30 :         case TV_SETOF:
      61          30 :                 n->rid = sa_list(sa);
      62          30 :                 n->msid = sa_list(sa);
      63          30 :                         n->ctl = sa_list(sa);
      64             : 
      65             :                         /* For MSET/SETOF we make a new child node for the values
      66             :                          * NOTE: the ->st of the child is the same as this node so
      67             :                          * we need to **EXPLICITLY** specify the tv_type */
      68          30 :                         tv_tree *sn;
      69          30 :                         if (st->type->composite)
      70          16 :                                 sn = tv_node(sa, st, TV_COMP);
      71             :                         else
      72          14 :                                 sn = tv_node(sa, st, TV_BASIC);
      73          30 :                         sn->st = st;
      74             : 
      75          30 :                         append(n->ctl, sn);
      76             : 
      77          30 :                         return n;
      78             :                 default:
      79           0 :                         assert(0);
      80             :                         break;
      81             :         }
      82             : 
      83             :         return NULL;
      84             : }
      85             : 
      86             : tv_tree *
      87      139451 : tv_create(backend *be, sql_subtype *st)
      88             : {
      89             :         /* there is some ambiguity with the types-value tree construction:
      90             :          * nodes which are mset/setof have their underlying type (composite/basic)
      91             :          * in the same subtype->type struct. That's why we have to be careful
      92             :          * with how we generate the nodes. Read carefully tv_node */
      93      139451 :         return tv_node(be->mvc->sa, st, tv_get_type(st));
      94             : }
      95             : 
      96             : static bool
      97             : tv_parse_values_(backend *be, tv_tree *t, sql_exp *value, stmt *left, stmt *sel);
      98             : 
      99             : static int
     100          62 : append_values_from_varchar(backend *be, tv_tree *t, stmt *sl, stmt *left, stmt *sel)
     101             : {
     102          62 :     node *n, *m;
     103          62 :     int sid = 0;
     104             : 
     105          62 :         switch(t->tvt) {
     106          30 :                 case TV_BASIC:
     107          30 :                         assert(sl->type == st_result || sl->type == st_list);
     108             : 
     109          30 :                         if (sl->type == st_result)
     110          20 :                                 list_append(t->vals, sl);
     111          10 :                         else if (sl->type == st_list) {
     112          10 :                                 stmt *sa = sl->op4.lval->h->data;
     113          10 :                                 list_append(t->vals, sa->op1);
     114             :                         }
     115             :                         return 1;
     116          14 :                 case TV_COMP:
     117          42 :                         for (n = t->ctl->h, m = sl->op4.lval->h; n; n = n->next, m = m->next) {
     118          28 :                             stmt *ts = m->data;
     119          28 :                             assert(ts->type == st_alias);
     120          28 :                                 append_values_from_varchar(be, n->data, ts->op1, left, sel);
     121             :                         }
     122          14 :                         return list_length(t->ctl);
     123          18 :                 case TV_MSET:
     124             :                 case TV_SETOF:
     125          18 :                         assert(list_length(t->ctl) == 1);
     126             : 
     127          18 :                         sid = append_values_from_varchar(be, t->ctl->h->data, sl, left, sel);
     128             : 
     129          18 :                         list_append(t->msid, list_fetch(sl->op4.lval, sid++));
     130          18 :                         if (t->tvt == TV_MSET)
     131          18 :                                 list_append(t->msnr, list_fetch(sl->op4.lval, sid++));
     132          18 :                         list_append(t->rid, list_fetch(sl->op4.lval, sid++));
     133             : 
     134          18 :                         assert(list_length(sl->op4.lval) == sid);
     135             : 
     136             :                         return sid;
     137             :                 default:
     138           0 :                         assert(0);
     139             :                         break;
     140             :         }
     141             :         return 0;
     142             : }
     143             : 
     144             : static bool
     145          43 : mset_value_from_array_constructor(backend *be, tv_tree *t, sql_exp *values, stmt *left, stmt *sel)
     146             : {
     147             :     /* rowid */
     148          43 :     stmt *rid = stmt_atom_int(be, t->rid_idx);
     149          43 :     if (!rid)
     150             :         return false;
     151          43 :     assert(t->rid);
     152          43 :     list_append(t->rid, rid);
     153             : 
     154             :     /* per value insert actual data, msid(=rowid), msnr(for MSET only) */
     155          43 :     int msnr_idx = 1;  /* NOTE: in mset-value values are 1-offset indexed */
     156          43 :     list *ms_vals = values->f;
     157         124 :     for (node *n = ms_vals->h; n; n = n->next, msnr_idx++) {
     158             : 
     159             :                 /* vals (in the child tree) */
     160          81 :                 assert(list_length(t->ctl) == 1);
     161          81 :                 tv_tree *ct = t->ctl->h->data;
     162          81 :                 tv_parse_values_(be, ct, n->data, left, sel);
     163             : 
     164             :                 /* msid */
     165          81 :         stmt *msid = stmt_atom_int(be, t->rid_idx);
     166          81 :         if (!msid)
     167             :             return false;
     168          81 :         list_append(t->msid, msid);
     169             : 
     170             :                 /* msnr */
     171          81 :         if (t->tvt == TV_MSET) {
     172          81 :             stmt *msnr = stmt_atom_int(be, msnr_idx);
     173          81 :             if (!msnr)
     174             :                 return false;
     175          81 :             list_append(t->msnr, msnr);
     176             :         }
     177             :     }
     178             : 
     179             :     /* we inserted all the mset-value's subvalues so now
     180             :      * increment this tv_tree node's (mset) rowid index */
     181          43 :     t->rid_idx++;
     182             : 
     183          43 :     return true;
     184             : }
     185             : 
     186             : static bool
     187          10 : mset_value_from_literal(backend *be, tv_tree *t, sql_exp *values, stmt *left, stmt *sel)
     188             : {
     189             :     /* per entry-value in the literal the call to exp_bin() will generate an
     190             :      * `sql.from_varchar()` instruction. This instructions for a given returns
     191             :      * either 3 or 4 bat results corresponding to rowid, value, msid and optionally
     192             :      * msnr (multiset vs setof). Those return values will be in an st_list stmt
     193             :      * so we have to retrieve them (from stmt_list's op4) and append them to the
     194             :      * tv_tree list of stmts */
     195          10 :     assert(t->tvt == TV_SETOF || t->tvt == TV_MSET);
     196          10 :         assert(!t->vals && t->ctl);
     197             : 
     198          10 :         stmt *i = exp_bin(be, values, left, NULL, NULL, NULL, NULL, sel, 0, 0, 0);
     199          10 :         if (!i)
     200             :                 return false;
     201             : 
     202          10 :         assert(i->type == st_list);
     203             : 
     204          10 :         append_values_from_varchar(be, t, i, left, sel);
     205             : 
     206          10 :     return true;
     207             : }
     208             : 
     209             : static bool
     210          68 : comp_value_from_parenthesis(backend *be, tv_tree *t, sql_exp *values, stmt *left, stmt *sel)
     211             : {
     212          68 :         assert(values->f);
     213          68 :         list *ct_vals = values->f;
     214             : 
     215          68 :         int cnt = 0;
     216         204 :         for (node *n = ct_vals->h; n; cnt++, n = n->next)
     217         136 :                 if (false == tv_parse_values_(be, list_fetch(t->ctl, cnt), n->data, left, sel))
     218             :                         return false;
     219             : 
     220             :         return true;
     221             : }
     222             : 
     223             : static bool
     224           6 : comp_value_from_literal(backend *be, tv_tree *t, sql_exp *values, stmt *left, stmt *sel)
     225             : {
     226           6 :     assert(t->tvt == TV_COMP);
     227           6 :         assert(!t->vals && t->ctl);
     228             : 
     229           6 :         stmt *i = exp_bin(be, values, left, NULL, NULL, NULL, NULL, sel, 0, 0, 0);
     230           6 :         if (!i)
     231             :                 return false;
     232             : 
     233           6 :         append_values_from_varchar(be, t, i, left, sel);
     234             : 
     235           6 :         return true;
     236             : }
     237             : 
     238             : static bool
     239      749352 : tv_parse_values_(backend *be, tv_tree *t, sql_exp *value, stmt *left, stmt *sel)
     240             : {
     241      749352 :         stmt *i;
     242      749352 :         sql_exp* uc;
     243             : 
     244      749352 :         switch (t->tvt) {
     245      749225 :                 case TV_BASIC:
     246      749225 :                         i = exp_bin(be, value, left, NULL, NULL, NULL, NULL, sel, 0, 0, 0);
     247      750444 :                         if (!i)
     248             :                                 return false;
     249      750444 :                         assert(t->vals);
     250      750444 :                         list_append(t->vals, i);
     251      750444 :                         break;
     252          53 :                 case TV_MSET:
     253             :                 case TV_SETOF:
     254             :                         //assert(is_convert(value->type));
     255          53 :                         assert(value->f);
     256          53 :                         uc = value;
     257          53 :                         if (is_convert(value->type))
     258          50 :                                 uc = value->l;
     259          53 :                         if (!uc->f)
     260             :                 /* VALUES ('{1, 2, 3}') */
     261          10 :                 return mset_value_from_literal(be, t, value, left, sel);
     262             :             else
     263             :                 /* VALUES (array[1, 2, 3]) */
     264          43 :                 return mset_value_from_array_constructor(be, t, uc, left, sel);
     265          74 :             break;
     266          74 :                 case TV_COMP:
     267          74 :                         if (is_convert(value->type))
     268             :                                 /* VALUES ('(1,"alice")') */
     269           6 :                                 return comp_value_from_literal(be, t, value, left, sel);
     270             :                         else
     271             :                                 /* VALUES ((1,'alice')) */
     272          68 :                                 return comp_value_from_parenthesis(be, t, value, left, sel);
     273           0 :                         break;
     274             :                 default:
     275           0 :                         assert(0);
     276             :                         break;
     277             :         }
     278             : 
     279      750444 :         return true;
     280             : }
     281             : 
     282             : static inline sql_exp *
     283           8 : tv_exp_wrap_list(backend *be, tv_tree *t, list *l)
     284             : {
     285          16 :         sql_exp *e = exp_null(be->mvc->sa, t->st);
     286           8 :         e->l = e->f = 0;
     287           8 :         e->f = l;
     288           8 :         return e;
     289             : }
     290             : 
     291             : bool
     292      137413 : tv_parse_values(backend *be, tv_tree *t, sql_exp *col_vals, stmt *left, stmt *sel)
     293             : {
     294      137413 :         list *vals = exp_get_values(col_vals);
     295             :         /* vals is a list with values that correspond to a column whose
     296             :          * (possibly "complex") type is represented by the tv_tree. NOTE:
     297             :          * in this case vals might be either
     298             :          *   1. a list of many values or
     299             :          *   2. a single value of composite or mset/setof with composite/basic type.
     300             :          * that's why we need to check for
     301             :          *       a. ->row in the first entry of col_vals exp
     302             :          *       b. for mset/setof the first ->row in the first entry of vals
     303             :          * If it is set it means that we are dealing with a single row insert and we
     304             :          * need a dummy expression de (to put vals at its e->f) so parsing the values
     305             :          * stays similar with the general case
     306             :          */
     307      137597 :         bool single_row_val = false;
     308      137597 :         single_row_val |= col_vals->row;
     309      137597 :         if ((t->tvt == TV_MSET) || (t->tvt == TV_SETOF)) {
     310             :                 // single value MSET/SETOF of basic type
     311          14 :                 single_row_val |= !((sql_exp*)vals->h->data)->f;
     312             :                 // single value MSET/SETOF of composite type
     313          14 :                 single_row_val |= ((sql_exp*)vals->h->data)->row;
     314             :         }
     315             : 
     316      137597 :     if (single_row_val) {
     317             :                 /* we need to create a dummy expression to single row vals
     318             :                  * to adhere to the rest of the api */
     319           8 :                 sql_exp *de = tv_exp_wrap_list(be, t, vals);
     320           8 :                 if (false == tv_parse_values_(be, t, de, left, sel))
     321             :                         return false;
     322             :         } else {
     323      887070 :                 for (node *n = vals->h; n; n = n->next) {
     324      749440 :                         sql_exp *e = n->data;
     325      749440 :                         if (false == tv_parse_values_(be, t, e, left, sel))
     326             :                                 return false;
     327             :                 }
     328             :         }
     329             :         return true;
     330             : }
     331             : 
     332             : stmt *
     333      137656 : tv_generate_stmts(backend *be, tv_tree *t)
     334             : {
     335      137656 :         stmt *ap, *tmp, *s;
     336      137656 :         list *sl;
     337             : 
     338      137656 :         switch (t->tvt) {
     339      137592 :                 case TV_BASIC:
     340      137592 :                         return stmt_append_bulk(be, stmt_temp(be, t->st), t->vals);
     341          30 :                 case TV_MSET:
     342             :                 case TV_SETOF:
     343             :                         /* vals (in the child tree) */
     344          30 :                         assert(list_length(t->ctl) == 1);
     345          30 :                         tv_tree *ct = t->ctl->h->data;
     346          30 :                         tmp = tv_generate_stmts(be, ct);
     347             : 
     348             :                         /* if the lower tv node does NOT returns a list (e.g. because
     349             :                          * it is basic type) we need to create it explicitly */
     350          30 :                         if (tmp->type == st_list) {
     351             :                                 s = tmp;
     352             :                         } else {
     353          14 :                                 s = stmt_list(be, sa_list(be->mvc->sa));
     354          14 :                                 list_append(s->op4.lval, tmp);
     355             :                         }
     356             : 
     357             :                         /* msid */
     358          30 :                         tmp = stmt_temp(be, tail_type(t->msid->h->data));
     359          30 :                         ap = stmt_append_bulk(be, tmp, t->msid);
     360          30 :                         append(s->op4.lval, ap);
     361             : 
     362             :                         /* msnr */
     363          30 :                         if (t->tvt == TV_MSET) {
     364          30 :                                 tmp = stmt_temp(be, tail_type(t->msnr->h->data));
     365          30 :                                 ap = stmt_append_bulk(be, tmp, t->msnr);
     366          30 :                                 append(s->op4.lval, ap);
     367             :                         }
     368             : 
     369             :                         /* rid */
     370          30 :                         tmp = stmt_temp(be, tail_type(t->rid->h->data));
     371          30 :                         ap = stmt_append_bulk(be, tmp, t->rid);
     372          30 :                         append(s->op4.lval, ap);
     373             : 
     374             :                         /* we've appended in the stmt_list so update nrcols */
     375          30 :                         stmt_set_nrcols(s);
     376          30 :                         s->subtype = *t->st;
     377          30 :                         return s;
     378          34 :                 case TV_COMP:
     379          34 :                         sl = sa_list(be->mvc->sa);
     380             :                         /* gather all the composite (sub)field's statements */
     381         102 :                         for (node *n = t->ctl->h; n; n = n->next)
     382          68 :                                 list_append(sl, tv_generate_stmts(be, n->data));
     383          34 :                         return stmt_list(be, sl);
     384             :                 default:
     385           0 :                         assert(0);
     386             :                         return NULL;
     387             :         }
     388             :         return s;
     389             : }

Generated by: LCOV version 1.14