LCOV - code coverage report
Current view: top level - sql/server - rel_basetable.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 513 633 81.0 %
Date: 2025-03-24 21:28:01 Functions: 28 34 82.4 %

          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             : #include "rel_rel.h"
      15             : #include "rel_exp.h"
      16             : #include "rel_prop.h"
      17             : #include "rel_basetable.h"
      18             : #include "rel_remote.h"
      19             : #include "rel_statistics.h"
      20             : #include "rel_rewriter.h"
      21             : #include "sql_privileges.h"
      22             : #include "sql_storage.h"
      23             : 
      24             : #define USED_LEN(nr) ((nr+31)/32)
      25             : #define rel_base_set_used(b,nr) b->used[(nr)/32] |= (1U<<((nr)%32))
      26             : #define rel_base_is_used(b,nr) ((b->used[(nr)/32]&(1U<<((nr)%32))) != 0)
      27             : 
      28             : typedef struct rel_base_t {
      29             :         sql_table *mt;
      30             :         sql_alias *name;
      31             :         int disallowed; /* ie check per column */
      32             :         int basenr;
      33             :         uint32_t used[];
      34             : } rel_base_t;
      35             : 
      36             : void
      37          72 : rel_base_disallow(sql_rel *r)
      38             : {
      39          72 :         rel_base_t *ba = r->r;
      40          72 :         ba->disallowed = 1;
      41          72 : }
      42             : 
      43             : sql_alias *
      44      213873 : rel_base_name(sql_rel *r)
      45             : {
      46      213873 :         rel_base_t *ba = r->r;
      47      213873 :         if (ba->name)
      48             :                 return ba->name;
      49             :         return NULL;
      50             : }
      51             : 
      52             : sql_alias *
      53           0 : rel_base_rename(sql_rel *r, sql_alias *name)
      54             : {
      55           0 :         rel_base_t *ba = r->r;
      56           0 :         assert(ba->name);
      57           0 :         ba->name->name = name->name;
      58           0 :         ba->name->parent = name->parent;
      59           0 :         return name;
      60             : }
      61             : 
      62             : int
      63        1050 : rel_base_idx_nid(sql_rel *r, sql_idx *i)
      64             : {
      65        1050 :         rel_base_t *ba = r->r;
      66        1050 :         sql_table *b = r->l;
      67        1050 :         if (i) {
      68        1050 :                 int j = ba->basenr + ol_length(b->columns) + 1;
      69        1120 :                 for (node *in = ol_first_node(i->t->idxs); in; in = in->next, j++) {
      70        1120 :                         if (i == in->data)
      71        1050 :                                 return -(ba->basenr + j);
      72             :                 }
      73             :         }
      74             :         return 0;
      75             : }
      76             : 
      77             : sql_column*
      78      307735 : rel_base_find_column(sql_rel *r, int nid)
      79             : {
      80      307735 :         rel_base_t *ba = r->r;
      81      307735 :         sql_table *b = r->l;
      82      307735 :         nid = -nid;
      83      307735 :         if ((nid - ba->basenr) >= ol_length(b->columns))
      84             :                 return NULL;
      85      209788 :         return ol_fetch(b->columns, nid - ba->basenr);
      86             : }
      87             : 
      88             : int
      89       34973 : rel_base_nid(sql_rel *r, sql_column *c)
      90             : {
      91       34973 :         rel_base_t *ba = r->r;
      92       34973 :         sql_table *b = r->l;
      93       34973 :         if (c)
      94       24102 :                 return -(ba->basenr + c->colnr);
      95       10871 :         return -(ba->basenr + ol_length(b->columns));
      96             : }
      97             : 
      98             : bool
      99     1917858 : rel_base_has_nid(sql_rel *r, int nid)
     100             : {
     101     1917858 :         rel_base_t *ba = r->r;
     102     1917858 :         sql_table *b = r->l;
     103             : 
     104     1917858 :         nid = -nid;
     105     1917858 :         return (nid >= ba->basenr && nid <= ba->basenr + ol_length(b->columns));
     106             : }
     107             : 
     108             : int
     109     1780763 : rel_base_use( mvc *sql, sql_rel *rt, int nr)
     110             : {
     111     1780763 :         assert(is_basetable(rt->op));
     112     1780763 :         sql_table *t = rt->l;
     113     1780763 :         rel_base_t *ba = rt->r;
     114             : 
     115     1780763 :         if (ba->disallowed && nr < ol_length(t->columns)) {
     116          34 :                 sql_column *c = ol_fetch(t->columns, nr);
     117          34 :                 if (!column_privs(sql, c, PRIV_SELECT))
     118             :                         return -1;
     119             :         }
     120     1780746 :         rel_base_set_used(ba, nr);
     121     1780746 :         return 0;
     122             : }
     123             : 
     124             : void
     125        8034 : rel_base_use_tid( mvc *sql, sql_rel *rt)
     126             : {
     127        8034 :         sql_table *t = rt->l;
     128        8034 :         rel_base_use(sql, rt, ol_length(t->columns));
     129        8034 : }
     130             : 
     131             : void
     132      398591 : rel_base_use_all( mvc *sql, sql_rel *rel)
     133             : {
     134      398591 :         sql_table *t = rel->l;
     135      398591 :         rel_base_t *ba = rel->r;
     136             : 
     137      398591 :         if (ba->disallowed) {
     138          10 :                 int i = 0;
     139          33 :                 for (node *cn = ol_first_node(t->columns); cn; cn = cn->next, i++) {
     140          23 :                         sql_column *c = cn->data;
     141          23 :                         if (!column_privs(sql, c, PRIV_SELECT))
     142          12 :                                 continue;
     143          11 :                         rel_base_set_used(ba, i);
     144             :                 }
     145             :         } else {
     146      398581 :                 int len = USED_LEN(ol_length(t->columns) + 1 + ol_length(t->idxs));
     147      801672 :                 for (int i = 0; i < len; i++)
     148      402749 :                         ba->used[i] = ~0U;
     149             :         }
     150      398933 : }
     151             : 
     152             : static rel_base_t* rel_nested_basetable_add_cols(mvc *sql, rel_base_t *pba, char *colname, sql_table *t, list *exps);
     153             : 
     154             : static node *
     155          66 : rel_nested_basetable_add_ccols(mvc *sql, rel_base_t *ba, sql_column *c, node *cn, list *exps)
     156             : {
     157          66 :         sql_alias *atname = a_create(sql->sa, c->base.name);
     158          66 :         atname->parent = ba->name;
     159          66 :         int i = sql->nid;
     160          66 :         prop *p = NULL;
     161          66 :         sql_exp *e = NULL;
     162             : 
     163          66 :         sql->nid += list_length(c->type.type->d.fields);
     164         245 :         for (node *n = c->type.type->d.fields->h; n && cn; n = n->next, i++) {
     165         179 :                 sql_column *c = cn->data;
     166         179 :                 if (!column_privs(sql, c, PRIV_SELECT))
     167           0 :                         continue;
     168         179 :                 if (c->type.multiset) {
     169          24 :                         e = exp_alias(sql, atname, c->base.name, atname, c->base.name, &c->type, CARD_MULTI, c->null, is_column_unique(c), 1);
     170          24 :                         prop *p = p = prop_create(sql->sa, PROP_NESTED, e->p);
     171          24 :                         p->value.pval = c;
     172          24 :                         e->p = p;
     173          24 :                         if (e)
     174          24 :                                 e->f = sa_list(sql->sa);
     175          24 :                         if (!e || !e->f)
     176             :                                 return NULL;
     177          24 :                         sql_table *t = mvc_bind_table(sql, c->t->s, c->storage_type);
     178          24 :                         if (rel_nested_basetable_add_cols(sql, ba, c->base.name, t, e->f) == NULL)
     179           0 :                                 e = NULL;
     180          24 :                         cn = cn->next;
     181         155 :                 } else if (c->type.type->composite) {
     182          12 :                         e = exp_alias(sql, atname, c->base.name, atname, c->base.name, &c->type, CARD_MULTI, c->null, is_column_unique(c), 0);
     183          12 :                         if (e)
     184          12 :                                 e->f = sa_list(sql->sa);
     185          12 :                         if (!e || !e->f)
     186           0 :                                 return NULL;
     187          12 :                         cn = rel_nested_basetable_add_ccols(sql, ba, c, cn->next, e->f);
     188             :                 } else {
     189         143 :                         e = exp_alias(sql, atname, c->base.name, atname, c->base.name, &c->type, CARD_MULTI, c->null, is_column_unique(c), 1);
     190         143 :                         cn = cn->next;
     191             :                 }
     192         179 :                 if (e == NULL)
     193             :                         return NULL;
     194         179 :                 e->nid = -(i);
     195         179 :                 e->alias.label = e->nid;
     196         179 :                 if (c->t->pkey && ((sql_kc*)c->t->pkey->k.columns->h->data)->c == c) {
     197           0 :                         p = e->p = prop_create(sql->sa, PROP_HASHCOL, e->p);
     198           0 :                         p->value.pval = c->t->pkey;
     199         179 :                 } else if (c->unique == 2) {
     200           0 :                         p = e->p = prop_create(sql->sa, PROP_HASHCOL, e->p);
     201           0 :                         p->value.pval = NULL;
     202             :                 }
     203         179 :                 set_intern(e);
     204         179 :                 set_basecol(e);
     205         179 :                 sql_column_get_statistics(sql, c, e);
     206         179 :                 append(exps, e);
     207             :         }
     208             :         return cn;
     209             : }
     210             : 
     211             : static rel_base_t*
     212          62 : rel_nested_basetable_add_cols(mvc *sql, rel_base_t *pba, char *colname, sql_table *t, list *exps)
     213             : {
     214          62 :         allocator *sa = sql->sa;
     215          62 :         int nrcols = ol_length(t->columns), end = nrcols + 1 + ol_length(t->idxs);
     216          62 :         rel_base_t *ba = (rel_base_t*)sa_zalloc(sa, sizeof(rel_base_t) + sizeof(int)*USED_LEN(end));
     217             : 
     218          62 :         ba->basenr = sql->nid;
     219          62 :         sql->nid += end;
     220             : 
     221          62 :         if (!ba)
     222             :                 return NULL;
     223             : 
     224          62 :         sql_alias *atname = a_create(sa, colname);
     225          62 :         atname->parent = ba->name;
     226          62 :         int i = 0;
     227          62 :         prop *p = NULL;
     228          62 :         sql_exp *e = NULL;
     229         267 :         for (node *cn = ol_first_node(t->columns); cn; i++) {
     230         205 :                 sql_column *c = cn->data;
     231         205 :                 if (!column_privs(sql, c, PRIV_SELECT))
     232           0 :                         continue;
     233         205 :                 if (c->type.multiset) {
     234           8 :                         e = exp_alias(sql, atname, c->base.name, atname, c->base.name, &c->type, CARD_MULTI, c->null, is_column_unique(c), 1);
     235           8 :                         prop *p = p = prop_create(sql->sa, PROP_NESTED, e->p);
     236           8 :                         p->value.pval = c;
     237           8 :                         e->p = p;
     238           8 :                         if (e)
     239           8 :                                 e->f = sa_list(sql->sa);
     240           8 :                         if (!e || !e->f)
     241             :                                 return NULL;
     242           8 :                         sql_table *t = mvc_bind_table(sql, c->t->s, c->storage_type);
     243           8 :                         if (rel_nested_basetable_add_cols(sql, pba, c->base.name, t, e->f) == NULL)
     244           0 :                                 e = NULL;
     245           8 :                         cn = cn->next;
     246         197 :                 } else if (c->type.type->composite) {
     247          10 :                         e = exp_alias(sql, atname, c->base.name, atname, c->base.name, &c->type, CARD_MULTI, c->null, is_column_unique(c), 0);
     248          10 :                         if (e)
     249          10 :                                 e->f = sa_list(sql->sa);
     250          10 :                         if (!e || !e->f)
     251           0 :                                 return NULL;
     252          10 :                         cn = rel_nested_basetable_add_ccols(sql, ba, c, cn->next, e->f);
     253             :                 } else {
     254         187 :                         e = exp_alias(sql, atname, c->base.name, atname, c->base.name, &c->type, CARD_MULTI, c->null, is_column_unique(c), 1);
     255         187 :                         cn = cn->next;
     256             :                 }
     257         205 :                 if (e == NULL)
     258             :                         return NULL;
     259         205 :                 e->nid = -(ba->basenr + i);
     260         205 :                 e->alias.label = e->nid;
     261         205 :                 if (c->t->pkey && ((sql_kc*)c->t->pkey->k.columns->h->data)->c == c) {
     262           0 :                         p = e->p = prop_create(sa, PROP_HASHCOL, e->p);
     263           0 :                         p->value.pval = c->t->pkey;
     264         205 :                 } else if (c->unique == 2) {
     265           0 :                         p = e->p = prop_create(sa, PROP_HASHCOL, e->p);
     266           0 :                         p->value.pval = NULL;
     267             :                 }
     268         205 :                 set_intern(e);
     269         205 :                 set_basecol(e);
     270         205 :                 sql_column_get_statistics(sql, c, e);
     271         205 :                 append(exps, e);
     272             :         }
     273             :         return ba;
     274             : }
     275             : 
     276             : static sql_rel *
     277          74 : rel_nested_basetable(mvc *sql, sql_table *t, sql_alias *atname)
     278             : {
     279          74 :         allocator *sa = sql->sa;
     280          74 :         sql_rel *rel = rel_create(sa);
     281             :         /* keep all column exp's as one large list in the result already */
     282             : 
     283          74 :         int nrcols = ol_length(t->columns), end = nrcols + 1 + ol_length(t->idxs);
     284          74 :         rel_base_t *ba = (rel_base_t*)sa_zalloc(sa, sizeof(rel_base_t) + sizeof(int)*USED_LEN(end));
     285          74 :         sqlstore *store = sql->session->tr->store;
     286             : 
     287          74 :         if(!rel || !ba)
     288             :                 return NULL;
     289             : 
     290          74 :         ba->basenr = sql->nid;
     291          74 :         sql->nid += end;
     292          74 :         if (isTable(t) && t->s && !isDeclaredTable(t)) /* count active rows only */
     293          74 :                 set_count_prop(sql->sa, rel, (BUN)store->storage_api.count_del(sql->session->tr, t, CNT_ACTIVE));
     294          74 :         assert(atname);
     295          74 :         if (!a_cmp_obj_name(atname, t->base.name))
     296           8 :                 ba->name = atname;
     297             :         else
     298          66 :                 ba->name = table_alias(sql->sa, t, schema_alias(sql->sa, t->s));
     299          74 :         int i = 0;
     300          74 :         prop *p = NULL;
     301          74 :         rel->exps = new_exp_list(sa);
     302          74 :         sql_exp *e = NULL;
     303         182 :         for (node *cn = ol_first_node(t->columns); cn; i++) {
     304         108 :                 sql_column *c = cn->data;
     305         108 :                 if (!column_privs(sql, c, PRIV_SELECT))
     306           0 :                         continue;
     307         108 :                 if (c->type.multiset) {
     308          30 :                         e = exp_alias(sql, atname, c->base.name, atname, c->base.name, &c->type, CARD_MULTI, c->null, is_column_unique(c), 0);
     309          30 :                         prop *p = p = prop_create(sql->sa, PROP_NESTED, e->p);
     310          30 :                         p->value.pval = c;
     311          30 :                         e->p = p;
     312          30 :                         if (e)
     313          30 :                                 e->f = sa_list(sql->sa);
     314          30 :                         if (!e || !e->f)
     315             :                                 return NULL;
     316          30 :                         sql_table *t = mvc_bind_table(sql, c->t->s, c->storage_type);
     317          30 :                         if (rel_nested_basetable_add_cols(sql, ba, c->base.name, t, e->f) == NULL)
     318           0 :                                 e = NULL;
     319          30 :                         cn = cn->next;
     320          78 :                 } else if (c->type.type->composite) {
     321          44 :                         e = exp_alias(sql, atname, c->base.name, atname, c->base.name, &c->type, CARD_MULTI, c->null, is_column_unique(c), 0);
     322          44 :                         if (e)
     323          44 :                                 e->f = sa_list(sql->sa);
     324          44 :                         if (!e || !e->f)
     325           0 :                                 return NULL;
     326          44 :                         cn = rel_nested_basetable_add_ccols(sql, ba, c, cn->next, e->f);
     327             :                 } else {
     328          34 :                         e = exp_alias(sql, atname, c->base.name, atname, c->base.name, &c->type, CARD_MULTI, c->null, is_column_unique(c), 0);
     329          34 :                         cn = cn->next;
     330             :                 }
     331         108 :                 if (e == NULL) {
     332           0 :                         rel_destroy(rel);
     333           0 :                         return NULL;
     334             :                 }
     335         108 :                 e->nid = -(ba->basenr + i);
     336         108 :                 e->alias.label = e->nid;
     337         108 :                 if (c->t->pkey && ((sql_kc*)c->t->pkey->k.columns->h->data)->c == c) {
     338           0 :                         p = e->p = prop_create(sa, PROP_HASHCOL, e->p);
     339           0 :                         p->value.pval = c->t->pkey;
     340         108 :                 } else if (c->unique == 2) {
     341           0 :                         p = e->p = prop_create(sa, PROP_HASHCOL, e->p);
     342           0 :                         p->value.pval = NULL;
     343             :                 }
     344         108 :                 set_basecol(e);
     345         108 :                 sql_column_get_statistics(sql, c, e);
     346         108 :                 append(rel->exps, e);
     347             :         }
     348          74 :         e = exp_alias(sql, atname, TID, atname, TID, sql_bind_localtype("oid"), CARD_MULTI, 0, 1, 1);
     349          74 :         if (e == NULL) {
     350           0 :                 rel_destroy(rel);
     351           0 :                 return NULL;
     352             :         }
     353          74 :         e->nid = -(ba->basenr + i);
     354          74 :         e->alias.label = e->nid;
     355          74 :         append(rel->exps, e);
     356          74 :         i++;
     357             :         /* todo add idx's */
     358             : 
     359          74 :         rel->l = t;
     360          74 :         rel->r = ba;
     361          74 :         rel->op = op_basetable;
     362          74 :         rel->card = CARD_MULTI;
     363          74 :         rel->nrcols = nrcols;
     364          74 :         return rel;
     365             : }
     366             : 
     367             : sql_rel *
     368      634115 : rel_basetable(mvc *sql, sql_table *t, sql_alias *atname)
     369             : {
     370      634115 :         if (t->multiset || t->composite)
     371          74 :                 return rel_nested_basetable(sql, t, atname);
     372      634041 :         allocator *sa = sql->sa;
     373      634041 :         sql_rel *rel = rel_create(sa);
     374      634268 :         int nrcols = ol_length(t->columns), end = nrcols + 1 + ol_length(t->idxs);
     375      634340 :         rel_base_t *ba = (rel_base_t*)sa_zalloc(sa, sizeof(rel_base_t) + sizeof(int)*USED_LEN(end));
     376      634462 :         sqlstore *store = sql->session->tr->store;
     377             : 
     378      634462 :         if(!rel || !ba)
     379             :                 return NULL;
     380             : 
     381      634462 :         ba->basenr = sql->nid;
     382      634462 :         sql->nid += end;
     383      634462 :         if (isTable(t) && t->s && !isDeclaredTable(t)) /* count active rows only */
     384      573368 :                 set_count_prop(sql->sa, rel, (BUN)store->storage_api.count_del(sql->session->tr, t, CNT_ACTIVE));
     385      634302 :         assert(atname);
     386      634302 :         if (!a_cmp_obj_name(atname, t->base.name))
     387      255265 :                 ba->name = atname;
     388             :         else
     389      378974 :                 ba->name = table_alias(sql->sa, t, schema_alias(sql->sa, t->s));
     390     1424372 :         for(int i = nrcols; i<end; i++)
     391      790075 :                 rel_base_set_used(ba, i);
     392      634297 :         rel->l = t;
     393      634297 :         rel->r = ba;
     394      634297 :         rel->op = op_basetable;
     395      634297 :         rel->card = CARD_MULTI;
     396      634297 :         rel->nrcols = nrcols;
     397      634297 :         return rel;
     398             : }
     399             : 
     400             : void
     401          55 : rel_base_copy(mvc *sql, sql_rel *in, sql_rel *out)
     402             : {
     403          55 :         allocator *sa = sql->sa;
     404          55 :         sql_table *t = in->l;
     405          55 :         rel_base_t *ba = in->r;
     406             : 
     407          55 :         assert(is_basetable(in->op) && is_basetable(out->op));
     408          55 :         int nrcols = ol_length(t->columns), end = nrcols + 1 + ol_length(t->idxs);
     409          55 :         size_t bsize = sizeof(rel_base_t) + sizeof(uint32_t)*USED_LEN(end);
     410          55 :         rel_base_t *nba = (rel_base_t*)sa_alloc(sa, bsize);
     411             : 
     412          55 :         memcpy(nba, ba, bsize);
     413          55 :         if (ba->name)
     414          55 :                 nba->name = a_create(sa, sa_strdup(sa, ba->name->name));
     415             : 
     416          55 :         out->l = t;
     417          55 :         out->r = nba;
     418          55 : }
     419             : 
     420             : sql_rel *
     421           0 : rel_base_bind_column_( sql_rel *rel, const char *cname)
     422             : {
     423           0 :         sql_table *t = rel->l;
     424           0 :         node *n = ol_find_name(t->columns, cname);
     425           0 :         if (n)
     426           0 :                 return rel;
     427             :         return NULL;
     428             : }
     429             : 
     430             : static sql_exp *
     431     2379719 : bind_col_exp(mvc *sql, rel_base_t *ba, sql_alias *name, sql_column *c)
     432             : {
     433     2379719 :         prop *p = NULL;
     434     2379719 :         sql_exp *e = exp_column(sql->sa, name, c->base.name, &c->type, CARD_MULTI, c->null, is_column_unique(c), 0);
     435             : 
     436     2379723 :         if (e) {
     437     2379723 :                 e->nid = -(ba->basenr + c->colnr);
     438     2379723 :                 e->alias.label = e->nid;
     439             :         }
     440     2379723 :         if (c->type.type->composite && !c->type.multiset)
     441           0 :                 e->virt = 1;
     442     2379723 :         if (c->t->pkey && ((sql_kc*)c->t->pkey->k.columns->h->data)->c == c) {
     443       85329 :                 p = e->p = prop_create(sql->sa, PROP_HASHCOL, e->p);
     444       85329 :                 p->value.pval = c->t->pkey;
     445     2294394 :         } else if (c->unique == 2) {
     446       23236 :                 p = e->p = prop_create(sql->sa, PROP_HASHCOL, e->p);
     447       23236 :                 p->value.pval = NULL;
     448             :         }
     449     2379723 :         set_basecol(e);
     450     2379723 :         sql_column_get_statistics(sql, c, e);
     451     2379729 :         return e;
     452             : }
     453             : 
     454             : static sql_exp *
     455     1698126 : bind_col(mvc *sql, sql_rel *rel, sql_alias *name, sql_column *c )
     456             : {
     457     1698126 :         if (!c || rel_base_use(sql, rel, c->colnr)) {
     458             :                 /* error */
     459          12 :                 return NULL;
     460             :         }
     461     1698114 :         return bind_col_exp(sql, rel->r, name, c);
     462             : }
     463             : 
     464             : sql_exp *
     465         240 : rel_base_bind_colnr( mvc *sql, sql_rel *rel, int nr)
     466             : {
     467         240 :         sql_table *t = rel->l;
     468         240 :         rel_base_t *ba = rel->r;
     469         240 :         return bind_col(sql, rel, ba->name, ol_fetch(t->columns, nr));
     470             : }
     471             : 
     472             : sql_exp *
     473           0 : rel_base_find_label( mvc *sql, sql_rel *rel, int label)
     474             : {
     475           0 :         sql_table *t = rel->l;
     476           0 :         rel_base_t *ba = rel->r;
     477             : 
     478           0 :         label = -label;
     479           0 :         int colnr = label - ba->basenr;
     480           0 :         if (colnr > ol_length(t->columns))
     481             :                 return NULL;
     482           0 :         return rel_base_bind_colnr(sql, rel, colnr);
     483             : }
     484             : 
     485             : sql_exp *
     486     4089338 : rel_base_bind_column( mvc *sql, sql_rel *rel, const char *cname, int no_tname)
     487             : {
     488     4089338 :         sql_table *t = rel->l;
     489     4089338 :         rel_base_t *ba = rel->r;
     490     4089338 :         (void)no_tname;
     491     4089338 :         node *n = t ? ol_find_name(t->columns, cname) : NULL;
     492     4089338 :         if (!n)
     493     3246515 :                 return NULL;
     494      842823 :         return bind_col(sql, rel, ba->name, n->data);
     495             : }
     496             : 
     497             : sql_rel *
     498           0 : rel_base_bind_column2_( sql_rel *rel, const char *tname, const char *cname)
     499             : {
     500           0 :         sql_table *t = rel->l;
     501           0 :         rel_base_t *ba = rel->r;
     502             : 
     503           0 :         assert(ba);
     504           0 :         if (ba->name && !a_cmp_obj_name(ba->name, tname))
     505             :                 return NULL;
     506           0 :         node *n = ol_find_name(t->columns, cname);
     507           0 :         if (!n)
     508             :                 return NULL;
     509             :         return rel;
     510             : }
     511             : 
     512             : sql_exp *
     513     1403837 : rel_base_bind_column2( mvc *sql, sql_rel *rel, sql_alias *tname, const char *cname)
     514             : {
     515     1403837 :         sql_table *t = rel->l;
     516     1403837 :         rel_base_t *ba = rel->r;
     517             : 
     518     1403837 :         assert(ba);
     519     1403837 :         if (ba->name && !a_match_obj(ba->name, tname)) { /* TODO handle more levels */
     520      717519 :                 node *n = ol_find_name(t->columns, tname->name);
     521      717519 :                 if (n) {
     522          28 :                         sql_column *c = n->data;
     523          28 :                         if (c->type.type->composite) {
     524           0 :                                 n = n->next;
     525           0 :                                 for(node *m = c->type.type->d.fields->h; m; m = m->next, n = n->next) {
     526           0 :                                         sql_arg *a = m->data;
     527           0 :                                         if (strcmp(a->name, cname) == 0) {
     528           0 :                                                 c = n->data;
     529           0 :                                                 return bind_col(sql, rel, ba->name, c);
     530             :                                         }
     531             :                                 }
     532             :                         }
     533             :                 }
     534             :                 return NULL;
     535             :         }
     536      686318 :         node *n = ol_find_name(t->columns, cname);
     537      686318 :         if (!n)
     538             :                 return NULL;
     539      686313 :         sql_column *c = n->data;
     540      686313 :         return bind_col(sql, rel, ba->name, c);
     541             : }
     542             : 
     543             : sql_exp *
     544           0 : rel_base_bind_column3( mvc *sql, sql_rel *rel, sql_alias *tname, const char *cname)
     545             : {
     546           0 :         sql_alias *name = rel_base_name(rel);
     547           0 :         if (!a_match(name, tname))
     548             :                 return NULL;
     549           0 :         return rel_base_bind_column(sql, rel, cname, 0);
     550             : }
     551             : 
     552             : list *
     553      105228 : rel_base_projection( mvc *sql, sql_rel *rel, int intern)
     554             : {
     555      105228 :         int i = 0;
     556      105228 :         sql_table *t = rel->l;
     557      105228 :         rel_base_t *ba = rel->r;
     558      105228 :         sql_alias *name = ba->name;
     559      105228 :         list *exps = new_exp_list(sql->sa);
     560      105231 :         prop *p;
     561             : 
     562      786946 :         for (node *cn = ol_first_node(t->columns); cn; cn = cn->next, i++) {
     563      681711 :                 if (rel_base_is_used(ba, i)) {
     564      681601 :                         sql_exp *e = bind_col_exp(sql, ba, name, cn->data);
     565      681613 :                         append(exps, e);
     566             :                 }
     567             :         }
     568      105235 :         if ((intern && rel_base_is_used(ba, i)) || list_empty(exps)) { /* Add TID column if no column is used */
     569       80066 :                 sql_exp *e = exp_column(sql->sa, name, TID, sql_bind_localtype("oid"), CARD_MULTI, 0, 1, 1);
     570       80066 :                 e->nid = -(ba->basenr + i);
     571       80066 :                 e->alias.label = e->nid;
     572       80066 :                 append(exps, e);
     573             :         }
     574      105235 :         i++;
     575      105235 :         if (intern) {
     576       80066 :                 int j = i;
     577      112002 :                 for (node *in = ol_first_node(t->idxs); in; in = in->next, j++) {
     578       31936 :                         if (rel_base_is_used(ba, j)) {
     579       31936 :                                 sql_idx *i = in->data;
     580       31936 :                                 sql_subtype *t = sql_bind_localtype("lng"); /* hash "lng" */
     581       31936 :                                 int has_nils = 0, unique;
     582             : 
     583       31936 :                                 if ((hash_index(i->type) && list_length(i->columns) <= 1) || !idx_has_column(i->type))
     584       31023 :                                         continue;
     585             : 
     586         913 :                                 if (i->type == join_idx)
     587         767 :                                         t = sql_bind_localtype("oid");
     588             : 
     589         913 :                                 char *iname = sa_strconcat( sql->sa, "%", i->base.name);
     590        1970 :                                 for (node *n = i->columns->h ; n && !has_nils; n = n->next) { /* check for NULL values */
     591        1057 :                                         sql_kc *kc = n->data;
     592             : 
     593        1057 :                                         if (kc->c->null)
     594         725 :                                                 has_nils = 1;
     595             :                                 }
     596         913 :                                 unique = list_length(i->columns) == 1 && is_column_unique(((sql_kc*)i->columns->h->data)->c);
     597         913 :                                 sql_exp *e = exp_column(sql->sa, name, iname, t, CARD_MULTI, has_nils, unique, 1);
     598         913 :                                 e->nid = -(ba->basenr + j);
     599         913 :                                 e->alias.label = e->nid;
     600         913 :                                 if (hash_index(i->type)) {
     601         146 :                                         p = e->p = prop_create(sql->sa, PROP_HASHIDX, e->p);
     602         146 :                                         p->value.pval = i;
     603             :                                 }
     604         913 :                                 if (i->type == join_idx) {
     605         767 :                                         p = e->p = prop_create(sql->sa, PROP_JOINIDX, e->p);
     606         767 :                                         p->value.pval = i;
     607             :                                 }
     608         913 :                                 append(exps, e);
     609             :                         }
     610             :                 }
     611             :         }
     612      105235 :         return exps;
     613             : }
     614             : 
     615             : list *
     616       14215 : rel_base_project_all( mvc *sql, sql_rel *rel, char *tname)
     617             : {
     618       14215 :         sql_table *t = rel->l;
     619       14215 :         rel_base_t *ba = rel->r;
     620       14215 :         sql_alias *name = ba->name;
     621       14215 :         list *exps = new_exp_list(sql->sa);
     622             : 
     623       14215 :         if (!exps || !a_cmp_obj_name(name, tname))
     624          46 :                 return NULL;
     625             : 
     626      182919 :         for (node *cn = ol_first_node(t->columns); cn; cn = cn->next)
     627      168750 :                 append(exps, bind_col( sql, rel, name, cn->data));
     628             :         return exps;
     629             : }
     630             : 
     631             : sql_rel *
     632         517 : rel_base_add_columns( mvc *sql, sql_rel *r)
     633             : {
     634         517 :         sql_table *t = r->l;
     635         517 :         rel_base_t *ba = r->r;
     636             : 
     637         517 :         r->exps = new_exp_list(sql->sa);
     638         517 :         if(!r->exps) {
     639           0 :                 rel_destroy(r);
     640           0 :                 return NULL;
     641             :         }
     642             : 
     643         517 :         int i = 0;
     644         517 :         prop *p = NULL;
     645         517 :         node *cn;
     646         517 :         sql_alias *ta = table_alias(sql->sa, t, NULL);
     647         517 :         sql_alias *atname = ba->name;
     648             : 
     649        1547 :         for (cn = ol_first_node(t->columns); cn; cn = cn->next, i++) {
     650        1030 :                 sql_column *c = cn->data;
     651        1030 :                 sql_exp *e = exp_alias(sql, atname, c->base.name, ta, c->base.name, &c->type, CARD_MULTI, c->null, is_column_unique(c), 0);
     652             : 
     653        1030 :                 if (e == NULL) {
     654           0 :                         rel_destroy(r);
     655           0 :                         return NULL;
     656             :                 }
     657        1030 :                 e->nid = -(ba->basenr + i);
     658        1030 :                 e->alias.label = e->nid;
     659        1030 :                 if (c->t->pkey && ((sql_kc*)c->t->pkey->k.columns->h->data)->c == c) {
     660           0 :                         p = e->p = prop_create(sql->sa, PROP_HASHCOL, e->p);
     661           0 :                         p->value.pval = c->t->pkey;
     662        1030 :                 } else if (c->unique == 2) {
     663           0 :                         p = e->p = prop_create(sql->sa, PROP_HASHCOL, e->p);
     664           0 :                         p->value.pval = NULL;
     665             :                 }
     666        1030 :                 set_basecol(e);
     667        1030 :                 sql_column_get_statistics(sql, c, e);
     668        1030 :                 append(r->exps, e);
     669             :         }
     670             :         return r;
     671             : }
     672             : 
     673             : sql_rel *
     674     2184234 : rewrite_basetable(mvc *sql, sql_rel *rel)
     675             : {
     676     2184234 :         if (is_basetable(rel->op) && !rel->exps) {
     677      458374 :                 allocator *sa = sql->sa;
     678      458374 :                 sql_table *t = rel->l;
     679      458374 :                 rel_base_t *ba = rel->r;
     680             : 
     681      458374 :                 rel->exps = new_exp_list(sa);
     682      458474 :                 if(!rel->exps) {
     683           0 :                         rel_destroy(rel);
     684           0 :                         return NULL;
     685             :                 }
     686             : 
     687      458474 :                 int i = 0;
     688      458474 :                 prop *p = NULL;
     689      458474 :                 node *cn;
     690      458474 :                 const char *tname = t->base.name;
     691      458474 :                 sql_alias *atname = ba->name;
     692             : 
     693      458474 :                 if (isRemote(t))
     694         287 :                         tname = mapiuri_table(t->query, sql->sa, tname);
     695      458474 :                 sql_alias *ta = a_create(sql->sa, tname);
     696     3305225 :                 for (cn = ol_first_node(t->columns); cn; cn = cn->next, i++) {
     697     2846660 :                         if (!rel_base_is_used(ba, i))
     698     1062509 :                                 continue;
     699             : 
     700     1784151 :                         sql_column *c = cn->data;
     701     1784151 :                         sql_exp *e = exp_alias(sql, atname, c->base.name, ta, c->base.name, &c->type, CARD_MULTI, c->null, is_column_unique(c), c->column_type == 16);
     702             : 
     703     1784245 :                         if (e == NULL) {
     704           0 :                                 rel_destroy(rel);
     705           0 :                                 return NULL;
     706             :                         }
     707     1784245 :                         e->nid = -(ba->basenr + i);
     708     1784245 :                         e->alias.label = e->nid;
     709     1784245 :                         if (c->t->pkey && ((sql_kc*)c->t->pkey->k.columns->h->data)->c == c) {
     710       58325 :                                 p = e->p = prop_create(sa, PROP_HASHCOL, e->p);
     711       58326 :                                 p->value.pval = c->t->pkey;
     712     1725920 :                         } else if (c->unique == 2) {
     713       12164 :                                 p = e->p = prop_create(sa, PROP_HASHCOL, e->p);
     714       12164 :                                 p->value.pval = NULL;
     715             :                         }
     716     1784246 :                         set_basecol(e);
     717     1784246 :                         sql_column_get_statistics(sql, c, e);
     718     1784733 :                         append(rel->exps, e);
     719             :                 }
     720      458565 :                 if (rel_base_is_used(ba, i) || list_empty(rel->exps)) { /* Add TID column if no column is used */
     721      458565 :                         sql_exp *e = exp_alias(sql, atname, TID, ta, TID, sql_bind_localtype("oid"), CARD_MULTI, 0, 1, 1);
     722      458541 :                         if (e == NULL) {
     723           0 :                                 rel_destroy(rel);
     724           0 :                                 return NULL;
     725             :                         }
     726      458541 :                         e->nid = -(ba->basenr + i);
     727      458541 :                         e->alias.label = e->nid;
     728      458541 :                         append(rel->exps, e);
     729             :                 }
     730      458641 :                 i++;
     731      458641 :                 int j = i;
     732      581741 :                 for (cn = ol_first_node(t->idxs); cn; cn = cn->next, j++) {
     733      123261 :                         if (!rel_base_is_used(ba, j))
     734           0 :                                 continue;
     735             : 
     736      123261 :                         sql_exp *e;
     737      123261 :                         sql_idx *i = cn->data;
     738      123261 :                         sql_subtype *t;
     739      123261 :                         char *iname = NULL;
     740      123261 :                         int has_nils = 0, unique;
     741             : 
     742             :                         /* do not include empty indices in the plan */
     743      123261 :                         if ((hash_index(i->type) && list_length(i->columns) <= 1) || !idx_has_column(i->type))
     744      105217 :                                 continue;
     745             : 
     746       18045 :                         t = (i->type == join_idx) ? sql_bind_localtype("oid") : sql_bind_localtype("lng");
     747       18045 :                         iname = sa_strconcat( sa, "%", i->base.name);
     748       39791 :                         for (node *n = i->columns->h ; n && !has_nils; n = n->next) { /* check for NULL values */
     749       21746 :                                 sql_kc *kc = n->data;
     750             : 
     751       21746 :                                 if (kc->c->null)
     752       13227 :                                         has_nils = 1;
     753             :                         }
     754       18045 :                         unique = list_length(i->columns) == 1 && is_column_unique(((sql_kc*)i->columns->h->data)->c);
     755       18045 :                         e = exp_alias(sql, atname, iname, ta, iname, t, CARD_MULTI, has_nils, unique, 1);
     756       18045 :                         if (e == NULL) {
     757           0 :                                 rel_destroy(rel);
     758           0 :                                 return NULL;
     759             :                         }
     760             :                         /* index names are prefixed, to make them independent */
     761       18045 :                         if (hash_index(i->type)) {
     762       10067 :                                 p = e->p = prop_create(sa, PROP_HASHIDX, e->p);
     763       10067 :                                 p->value.pval = i;
     764             :                         }
     765       18045 :                         if (i->type == join_idx) {
     766        7978 :                                 p = e->p = prop_create(sa, PROP_JOINIDX, e->p);
     767        7978 :                                 p->value.pval = i;
     768             :                         }
     769       18045 :                         e->nid = -(ba->basenr + j);
     770       18045 :                         e->alias.label = e->nid;
     771       18045 :                         append(rel->exps, e);
     772             :                 }
     773             :         }
     774             :         return rel;
     775             : }
     776             : 
     777             : sql_exp *
     778        1039 : basetable_get_tid_or_add_it(mvc *sql, sql_rel *rel)
     779             : {
     780        1039 :         sql_exp *res = NULL;
     781             : 
     782        1039 :         if (is_basetable(rel->op)) {
     783        1039 :                 sql_table *t = rel->l;
     784        1039 :                 rel_base_t *ba = rel->r;
     785        1039 :                 const char *tname = t->base.name;
     786        1039 :                 sql_alias *atname = ba->name;
     787             : 
     788        1039 :                 if (isRemote(t))
     789           0 :                         tname = mapiuri_table(t->query, sql->sa, tname);
     790        1039 :                 sql_alias *ta = a_create(sql->sa, tname);
     791        1039 :                 if (!rel->exps) { /* no exps yet, just set TID */
     792        1012 :                         rel_base_use_tid(sql, rel);
     793        1012 :                         res = exp_alias(sql, atname, TID, ta, TID, sql_bind_localtype("oid"), CARD_MULTI, 0, 1, 1);
     794        1012 :                         res->nid = -(ba->basenr + ol_length(t->columns));
     795        1012 :                         res->alias.label = res->nid;
     796          27 :                 } else if (!rel_base_is_used(ba, ol_length(t->columns)) ||  /* exps set, but no TID, add it */
     797          27 :                                    !(res = exps_bind_column2(rel->exps, atname, TID, NULL))) { /* exps set with TID, but maybe rel_dce removed it */
     798           0 :                         node *n = NULL;
     799           0 :                         rel_base_use_tid(sql, rel);
     800           0 :                         res = exp_alias(sql, atname, TID, ta, TID, sql_bind_localtype("oid"), CARD_MULTI, 0, 1, 1);
     801           0 :                         res->nid = -(ba->basenr + ol_length(t->columns));
     802           0 :                         res->alias.label = res->nid;
     803             : 
     804             :                         /* search for indexes */
     805           0 :                         for (node *cn = rel->exps->h; cn && !n; cn = cn->next) {
     806           0 :                                 sql_exp *e = cn->data;
     807             : 
     808           0 :                                 if (is_intern(e))
     809           0 :                                         n = cn;
     810             :                         }
     811           0 :                         if (n) { /* has indexes, insert TID before them */
     812           0 :                                 list_append_before(rel->exps, n, res);
     813             :                         } else {
     814           0 :                                 list_append(rel->exps, res);
     815             :                         }
     816             :                 }
     817             :         }
     818        1039 :         return res;
     819             : }
     820             : 
     821             : sql_rel *
     822         550 : rel_rename_part(mvc *sql, sql_rel *p, sql_rel *mt_rel, sql_alias *mtalias)
     823             : {
     824         550 :         sql_exp *ne = NULL;
     825         550 :         sql_table *mt = rel_base_table(mt_rel), *t = rel_base_table(p);
     826         550 :         rel_base_t *mt_ba = mt_rel->r, *p_ba = p->r;
     827         550 :         p_ba->basenr = mt_ba->basenr;
     828             : 
     829         550 :         assert(!p->exps);
     830         550 :         p->exps = sa_list(sql->sa);
     831         550 :         const char *pname = t->base.name;
     832         550 :         if (isRemote(t))
     833          37 :                 pname = mapiuri_table(t->query, sql->sa, pname);
     834         550 :         sql_alias *pa = a_create(sql->sa, pname);
     835        1482 :         for (node *n = mt_rel->exps->h; n; n = n->next) {
     836         932 :                 sql_exp *e = n->data;
     837         932 :                 node *cn = NULL, *ci = NULL;
     838         932 :                 const char *nname = e->r;
     839             : 
     840         932 :                 if (nname[0] == '%' && strcmp(nname, TID) == 0) {
     841          53 :                         list_append(p->exps, ne=exp_alias(sql, mtalias, TID, pa, TID, sql_bind_localtype("oid"), CARD_MULTI, 0, 1, 1));
     842          53 :                         ne->nid = e->nid;
     843          53 :                         ne->alias.label = e->alias.label;
     844          53 :                         rel_base_use_tid(sql, p);
     845         879 :                 } else if (nname[0] != '%' && (cn = ol_find_name(mt->columns, nname))) {
     846         877 :                         sql_column *c = cn->data, *rc = ol_fetch(t->columns, c->colnr);
     847             : 
     848             :                         /* with name find column in merge table, with colnr find column in member */
     849         877 :                         ne = exp_alias(sql, mtalias, exp_name(e), pa, rc->base.name, &rc->type, CARD_MULTI, rc->null, is_column_unique(rc), 0);
     850         877 :                         if (rc->t->pkey && ((sql_kc*)rc->t->pkey->k.columns->h->data)->c == rc) {
     851          19 :                                 prop *p = ne->p = prop_create(sql->sa, PROP_HASHCOL, ne->p);
     852          19 :                                 p->value.pval = rc->t->pkey;
     853         858 :                         } else if (rc->unique == 2) {
     854           0 :                                 prop *p = ne->p = prop_create(sql->sa, PROP_HASHCOL, ne->p);
     855           0 :                                 p->value.pval = NULL;
     856             :                         }
     857         877 :                         set_basecol(ne);
     858         877 :                         sql_column_get_statistics(sql, c, ne);
     859         877 :                         rel_base_use(sql, p, rc->colnr);
     860         877 :                         list_append(p->exps, ne);
     861         877 :                         ne->nid = e->nid;
     862         877 :                         ne->alias.label = e->alias.label;
     863           2 :                 } else if (nname[0] == '%' && ol_length(mt->idxs) && (ci = ol_find_name(mt->idxs, nname + 1))) {
     864           2 :                         sql_idx *i = ci->data, *ri = NULL;
     865             : 
     866             :                         /* indexes don't have a number field like 'colnr', so get the index the old way */
     867           4 :                         for (node *nn = mt->idxs->l->h, *mm = t->idxs->l->h; nn && mm ; nn = nn->next, mm = mm->next) {
     868           4 :                                 sql_idx *ii = nn->data;
     869             : 
     870           4 :                                 if (ii->base.id == i->base.id) {
     871           2 :                                         ri = mm->data;
     872           2 :                                         break;
     873             :                                 }
     874             :                         }
     875             : 
     876           2 :                         assert((!hash_index(ri->type) || list_length(ri->columns) > 1) && idx_has_column(ri->type));
     877           2 :                         sql_subtype *t = (ri->type == join_idx) ? sql_bind_localtype("oid") : sql_bind_localtype("lng");
     878           2 :                         char *iname1 = sa_strconcat(sql->sa, "%", i->base.name), *iname2 = sa_strconcat(sql->sa, "%", ri->base.name);
     879             : 
     880           2 :                         ne = exp_alias(sql, mtalias, iname1, pa, iname2, t, CARD_MULTI, has_nil(e), is_unique(e), 1);
     881             :                         /* index names are prefixed, to make them independent */
     882           2 :                         if (hash_index(ri->type)) {
     883           0 :                                 prop *p = ne->p = prop_create(sql->sa, PROP_HASHIDX, ne->p);
     884           0 :                                 p->value.pval = ri;
     885           2 :                         } else if (ri->type == join_idx) {
     886           2 :                                 prop *p = ne->p = prop_create(sql->sa, PROP_JOINIDX, ne->p);
     887           2 :                                 p->value.pval = ri;
     888             :                         }
     889           2 :                         ne->nid = e->nid;
     890           2 :                         ne->alias.label = e->alias.label;
     891           2 :                         list_append(p->exps, ne);
     892             :                 }
     893             :         }
     894         550 :         rel_base_set_mergetable(p, mt);
     895         550 :         return p;
     896             : }
     897             : 
     898             : void
     899           0 : rel_base_dump_exps( stream *fout, sql_rel *rel)
     900             : {
     901           0 :         int i = 0, comma = 0;
     902           0 :         sql_table *t = rel->l;
     903           0 :         rel_base_t *ba = rel->r;
     904           0 :         assert(ba);
     905           0 :         mnstr_printf(fout, "[ ");
     906           0 :         for (node *cn = ol_first_node(t->columns); cn; cn = cn->next, i++) {
     907           0 :                 if (rel_base_is_used(ba, i)) {
     908           0 :                         sql_column *c = cn->data;
     909           0 :                         mnstr_printf(fout, "%s\"%s\".\"%s\"", comma?", ":"", t->base.name, c->base.name);
     910           0 :                         if (ba->name)
     911           0 :                                 mnstr_printf(fout, " as \"%s\".\"%s\"", ba->name->name, c->base.name);
     912             :                         comma = 1;
     913             :                 }
     914             :         }
     915           0 :         if (rel_base_is_used(ba, i)) {
     916           0 :                 mnstr_printf(fout, "%s\"%s\".\"%%TID%%\"", comma?", ":"", t->base.name);
     917           0 :                 if (ba->name)
     918           0 :                         mnstr_printf(fout, " as \"%s\".\"%%TID%%\"", ba->name->name);
     919             :                 comma = 1;
     920             :         }
     921           0 :         i++;
     922           0 :         for (node *in = ol_first_node(t->idxs); in; in = in->next, i++) {
     923           0 :                 if (rel_base_is_used(ba, i)) {
     924           0 :                         sql_idx *i = in->data;
     925           0 :                         mnstr_printf(fout, "%s\"%s\".\"%s\"", comma?", ":"", t->base.name, i->base.name);
     926           0 :                         if (ba->name)
     927           0 :                                 mnstr_printf(fout, " as \"%s\".\"%s\"", ba->name->name, i->base.name);
     928             :                         comma = 1;
     929             :                 }
     930             :         }
     931           0 :         mnstr_printf(fout, " ]");
     932           0 : }
     933             : 
     934             : int
     935          72 : rel_base_has_column_privileges(mvc *sql, sql_rel *rel)
     936             : {
     937          72 :         sql_table *t = rel->l;
     938          72 :         int has = 0;
     939             : 
     940         227 :         for (node *m = ol_first_node(t->columns); m && !has; m = m->next) {
     941         155 :                 sql_column *c = m->data;
     942             : 
     943         155 :                 if (column_privs(sql, c, PRIV_SELECT))
     944          33 :                         has = 1;
     945             :         }
     946          72 :         return has;
     947             : }
     948             : 
     949             : void
     950         550 : rel_base_set_mergetable(sql_rel *rel, sql_table *mt)
     951             : {
     952         550 :         rel_base_t *ba = rel->r;
     953             : 
     954         550 :         if (ba)
     955         550 :                 ba->mt = mt;
     956         550 : }
     957             : 
     958             : sql_table *
     959      105746 : rel_base_get_mergetable(sql_rel *rel)
     960             : {
     961      105746 :         rel_base_t *ba = rel->r;
     962             : 
     963      105746 :         return ba ? ba->mt : NULL;
     964             : }

Generated by: LCOV version 1.14