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_rel.h"
15 : #include "rel_exp.h"
16 : #include "rel_prop.h"
17 : #include "rel_basetable.h"
18 : #include "rel_remote.h"
19 : #include "sql_privileges.h"
20 :
21 : #define USED_LEN(nr) ((nr+31)/32)
22 : #define rel_base_set_used(b,nr) b->used[(nr)/32] |= (1U<<((nr)%32))
23 : #define rel_base_is_used(b,nr) ((b->used[(nr)/32]&(1U<<((nr)%32))) != 0)
24 :
25 : typedef struct rel_base_t {
26 : sql_table *mt;
27 : char *name;
28 : int disallowed; /* ie check per column */
29 : uint32_t used[];
30 : } rel_base_t;
31 :
32 : void
33 72 : rel_base_disallow(sql_rel *r)
34 : {
35 72 : rel_base_t *ba = r->r;
36 72 : ba->disallowed = 1;
37 72 : }
38 :
39 : char *
40 126900 : rel_base_name(sql_rel *r)
41 : {
42 126900 : sql_table *t = r->l;
43 126900 : rel_base_t *ba = r->r;
44 126900 : if (ba->name)
45 : return ba->name;
46 125512 : return t->base.name;
47 : }
48 :
49 : char *
50 0 : rel_base_rename(sql_rel *r, char *name)
51 : {
52 0 : rel_base_t *ba = r->r;
53 0 : ba->name = name;
54 0 : return name;
55 : }
56 :
57 : int
58 1646644 : rel_base_use( mvc *sql, sql_rel *rt, int nr)
59 : {
60 1646644 : assert(is_basetable(rt->op));
61 1646644 : sql_table *t = rt->l;
62 1646644 : rel_base_t *ba = rt->r;
63 :
64 1646644 : if (ba->disallowed && nr < ol_length(t->columns)) {
65 29 : sql_column *c = ol_fetch(t->columns, nr);
66 29 : if (!column_privs(sql, c, PRIV_SELECT))
67 : return -1;
68 : }
69 1646632 : rel_base_set_used(ba, nr);
70 1646632 : return 0;
71 : }
72 :
73 : void
74 6800 : rel_base_use_tid( mvc *sql, sql_rel *rt)
75 : {
76 6800 : sql_table *t = rt->l;
77 6800 : rel_base_use(sql, rt, ol_length(t->columns));
78 6800 : }
79 :
80 : void
81 371781 : rel_base_use_all( mvc *sql, sql_rel *rel)
82 : {
83 371781 : sql_table *t = rel->l;
84 371781 : rel_base_t *ba = rel->r;
85 :
86 371781 : if (ba->disallowed) {
87 10 : int i = 0;
88 33 : for (node *cn = ol_first_node(t->columns); cn; cn = cn->next, i++) {
89 23 : sql_column *c = cn->data;
90 23 : if (!column_privs(sql, c, PRIV_SELECT))
91 12 : continue;
92 11 : rel_base_set_used(ba, i);
93 : }
94 : } else {
95 371771 : int len = USED_LEN(ol_length(t->columns) + 1 + ol_length(t->idxs));
96 747654 : for (int i = 0; i < len; i++)
97 375885 : ba->used[i] = ~0U;
98 : }
99 371779 : }
100 :
101 : sql_rel *
102 593868 : rel_basetable(mvc *sql, sql_table *t, const char *atname)
103 : {
104 593868 : sql_allocator *sa = sql->sa;
105 593868 : sql_rel *rel = rel_create(sa);
106 593864 : int nrcols = ol_length(t->columns), end = nrcols + 1 + ol_length(t->idxs);
107 593864 : rel_base_t *ba = (rel_base_t*)sa_zalloc(sa, sizeof(rel_base_t) + sizeof(int)*USED_LEN(end));
108 :
109 593861 : if(!rel || !ba)
110 : return NULL;
111 :
112 593861 : assert(atname);
113 593861 : if (strcmp(atname, t->base.name) != 0)
114 231190 : ba->name = sa_strdup(sa, atname);
115 1334665 : for(int i = nrcols; i<end; i++)
116 740804 : rel_base_set_used(ba, i);
117 593861 : rel->l = t;
118 593861 : rel->r = ba;
119 593861 : rel->op = op_basetable;
120 593861 : rel->card = CARD_MULTI;
121 593861 : rel->nrcols = nrcols;
122 593861 : return rel;
123 : }
124 :
125 : void
126 60 : rel_base_copy(mvc *sql, sql_rel *in, sql_rel *out)
127 : {
128 60 : sql_allocator *sa = sql->sa;
129 60 : sql_table *t = in->l;
130 60 : rel_base_t *ba = in->r;
131 :
132 60 : assert(is_basetable(in->op) && is_basetable(out->op));
133 60 : int nrcols = ol_length(t->columns), end = nrcols + 1 + ol_length(t->idxs);
134 60 : size_t bsize = sizeof(rel_base_t) + sizeof(uint32_t)*USED_LEN(end);
135 60 : rel_base_t *nba = (rel_base_t*)sa_alloc(sa, bsize);
136 :
137 60 : memcpy(nba, ba, bsize);
138 60 : if (ba->name)
139 0 : nba->name = sa_strdup(sa, ba->name);
140 :
141 60 : out->l = t;
142 60 : out->r = nba;
143 60 : }
144 :
145 : sql_rel *
146 2 : rel_base_bind_column_( sql_rel *rel, const char *cname)
147 : {
148 2 : sql_table *t = rel->l;
149 2 : node *n = ol_find_name(t->columns, cname);
150 2 : if (n)
151 0 : return rel;
152 : return NULL;
153 : }
154 :
155 : static sql_exp *
156 2179427 : bind_col_exp(mvc *sql, char *name, sql_column *c)
157 : {
158 2179427 : prop *p = NULL;
159 2179427 : sql_exp *e = exp_column(sql->sa, name, c->base.name, &c->type, CARD_MULTI, c->null, is_column_unique(c), 0);
160 :
161 2179425 : if (c->t->pkey && ((sql_kc*)c->t->pkey->k.columns->h->data)->c == c) {
162 79992 : p = e->p = prop_create(sql->sa, PROP_HASHCOL, e->p);
163 79992 : p->value.pval = c->t->pkey;
164 2099433 : } else if (c->unique == 2) {
165 21624 : p = e->p = prop_create(sql->sa, PROP_HASHCOL, e->p);
166 21624 : p->value.pval = NULL;
167 : }
168 2179425 : set_basecol(e);
169 2179425 : return e;
170 : }
171 :
172 : static sql_exp *
173 1567556 : bind_col(mvc *sql, sql_rel *rel, char *name, sql_column *c )
174 : {
175 1567556 : if (rel_base_use(sql, rel, c->colnr)) {
176 : /* error */
177 : return NULL;
178 : }
179 1567544 : return bind_col_exp(sql, name, c);
180 : }
181 :
182 : sql_exp *
183 224 : rel_base_bind_colnr( mvc *sql, sql_rel *rel, int nr)
184 : {
185 224 : sql_table *t = rel->l;
186 224 : rel_base_t *ba = rel->r;
187 224 : return bind_col(sql, rel, ba->name?ba->name:t->base.name, ol_fetch(t->columns, nr));
188 : }
189 :
190 : sql_exp *
191 4040396 : rel_base_bind_column( mvc *sql, sql_rel *rel, const char *cname, int no_tname)
192 : {
193 4040396 : sql_table *t = rel->l;
194 4040396 : rel_base_t *ba = rel->r;
195 4040396 : (void)no_tname;
196 4040396 : node *n = t ? ol_find_name(t->columns, cname) : NULL;
197 4040396 : if (!n)
198 3233553 : return NULL;
199 806843 : return bind_col(sql, rel, ba->name?ba->name:t->base.name, n->data);
200 : }
201 :
202 : sql_rel *
203 1838853 : rel_base_bind_column2_( sql_rel *rel, const char *tname, const char *cname)
204 : {
205 1838853 : sql_table *t = rel->l;
206 1838853 : rel_base_t *ba = rel->r;
207 :
208 1838853 : assert(ba);
209 1838853 : if ((ba->name && strcmp(ba->name, tname) != 0) || (!ba->name && strcmp(t->base.name, tname) != 0))
210 : return NULL;
211 377934 : node *n = ol_find_name(t->columns, cname);
212 377934 : if (!n)
213 : return NULL;
214 : return rel;
215 : }
216 :
217 : sql_exp *
218 1284480 : rel_base_bind_column2( mvc *sql, sql_rel *rel, const char *tname, const char *cname)
219 : {
220 1284480 : sql_table *t = rel->l;
221 1284480 : rel_base_t *ba = rel->r;
222 :
223 1284480 : assert(ba);
224 1284480 : if ((ba->name && strcmp(ba->name, tname) != 0) || (!ba->name && strcmp(t->base.name, tname) != 0))
225 : return NULL;
226 620809 : node *n = ol_find_name(t->columns, cname);
227 620809 : if (!n)
228 : return NULL;
229 620804 : sql_column *c = n->data;
230 620804 : return bind_col(sql, rel, ba->name?ba->name:t->base.name, c);
231 : }
232 :
233 : sql_exp *
234 0 : rel_base_bind_column3( mvc *sql, sql_rel *rel, const char *sname, const char *tname, const char *cname)
235 : {
236 0 : sql_table *t = rel->l;
237 0 : if (!t->s || strcmp(t->s->base.name, sname) != 0)
238 : return NULL;
239 0 : return rel_base_bind_column2(sql, rel, tname, cname);
240 : }
241 :
242 : list *
243 97557 : rel_base_projection( mvc *sql, sql_rel *rel, int intern)
244 : {
245 97557 : int i = 0;
246 97557 : sql_table *t = rel->l;
247 97557 : rel_base_t *ba = rel->r;
248 97557 : char *name = ba->name?ba->name:t->base.name;
249 97557 : list *exps = new_exp_list(sql->sa);
250 97556 : prop *p;
251 :
252 709446 : for (node *cn = ol_first_node(t->columns); cn; cn = cn->next, i++) {
253 611891 : if (rel_base_is_used(ba, i))
254 611884 : append(exps, bind_col_exp(sql, name, cn->data));
255 : }
256 97555 : if ((intern && rel_base_is_used(ba, i)) || list_empty(exps)) /* Add TID column if no column is used */
257 74254 : append(exps, exp_column(sql->sa, name, TID, sql_bind_localtype("oid"), CARD_MULTI, 0, 1, 1));
258 97555 : i++;
259 97555 : if (intern) {
260 104436 : for (node *in = ol_first_node(t->idxs); in; in = in->next, i++) {
261 30182 : if (rel_base_is_used(ba, i)) {
262 30182 : sql_idx *i = in->data;
263 30182 : sql_subtype *t = sql_bind_localtype("lng"); /* hash "lng" */
264 30182 : int has_nils = 0, unique;
265 :
266 30182 : if ((hash_index(i->type) && list_length(i->columns) <= 1) || !idx_has_column(i->type))
267 29277 : continue;
268 :
269 905 : if (i->type == join_idx)
270 765 : t = sql_bind_localtype("oid");
271 :
272 905 : char *iname = sa_strconcat( sql->sa, "%", i->base.name);
273 1948 : for (node *n = i->columns->h ; n && !has_nils; n = n->next) { /* check for NULL values */
274 1043 : sql_kc *kc = n->data;
275 :
276 1043 : if (kc->c->null)
277 724 : has_nils = 1;
278 : }
279 905 : unique = list_length(i->columns) == 1 && is_column_unique(((sql_kc*)i->columns->h->data)->c);
280 905 : sql_exp *e = exp_column(sql->sa, name, iname, t, CARD_MULTI, has_nils, unique, 1);
281 905 : if (hash_index(i->type)) {
282 140 : p = e->p = prop_create(sql->sa, PROP_HASHIDX, e->p);
283 140 : p->value.pval = i;
284 : }
285 905 : if (i->type == join_idx) {
286 765 : p = e->p = prop_create(sql->sa, PROP_JOINIDX, e->p);
287 765 : p->value.pval = i;
288 : }
289 905 : append(exps, e);
290 : }
291 : }
292 : }
293 97555 : return exps;
294 : }
295 :
296 : list *
297 13979 : rel_base_project_all( mvc *sql, sql_rel *rel, char *tname)
298 : {
299 13979 : sql_table *t = rel->l;
300 13979 : rel_base_t *ba = rel->r;
301 13979 : char *name = ba->name?ba->name:t->base.name;
302 13979 : list *exps = new_exp_list(sql->sa);
303 :
304 13979 : if (!exps || strcmp(name, tname) != 0)
305 : return NULL;
306 :
307 153652 : for (node *cn = ol_first_node(t->columns); cn; cn = cn->next)
308 139685 : append(exps, bind_col( sql, rel, name, cn->data));
309 : return exps;
310 : }
311 :
312 : sql_rel *
313 470 : rel_base_add_columns( mvc *sql, sql_rel *r)
314 : {
315 470 : sql_table *t = r->l;
316 470 : rel_base_t *ba = r->r;
317 :
318 470 : r->exps = new_exp_list(sql->sa);
319 470 : if(!r->exps) {
320 0 : rel_destroy(r);
321 0 : return NULL;
322 : }
323 :
324 470 : int i = 0;
325 470 : prop *p = NULL;
326 470 : node *cn;
327 470 : const char *tname = t->base.name;
328 470 : const char *atname = ba->name?ba->name:tname;
329 :
330 1407 : for (cn = ol_first_node(t->columns); cn; cn = cn->next, i++) {
331 937 : sql_column *c = cn->data;
332 937 : sql_exp *e = exp_alias(sql->sa, atname, c->base.name, tname, c->base.name, &c->type, CARD_MULTI, c->null, is_column_unique(c), 0);
333 :
334 937 : if (e == NULL) {
335 0 : rel_destroy(r);
336 0 : return NULL;
337 : }
338 937 : if (c->t->pkey && ((sql_kc*)c->t->pkey->k.columns->h->data)->c == c) {
339 0 : p = e->p = prop_create(sql->sa, PROP_HASHCOL, e->p);
340 0 : p->value.pval = c->t->pkey;
341 937 : } else if (c->unique == 2) {
342 0 : p = e->p = prop_create(sql->sa, PROP_HASHCOL, e->p);
343 0 : p->value.pval = NULL;
344 : }
345 937 : set_basecol(e);
346 937 : append(r->exps, e);
347 : }
348 : return r;
349 : }
350 :
351 : sql_rel *
352 2353005 : rewrite_basetable(mvc *sql, sql_rel *rel)
353 : {
354 2353005 : if (is_basetable(rel->op) && !rel->exps) {
355 433220 : sql_allocator *sa = sql->sa;
356 433220 : sql_table *t = rel->l;
357 433220 : rel_base_t *ba = rel->r;
358 :
359 433220 : rel->exps = new_exp_list(sa);
360 433219 : if(!rel->exps) {
361 0 : rel_destroy(rel);
362 0 : return NULL;
363 : }
364 :
365 433219 : int i = 0;
366 433219 : prop *p = NULL;
367 433219 : node *cn;
368 433219 : const char *tname = t->base.name;
369 433219 : const char *atname = ba->name?ba->name:tname;
370 :
371 433219 : if (isRemote(t))
372 278 : tname = mapiuri_table(t->query, sql->sa, tname);
373 3045020 : for (cn = ol_first_node(t->columns); cn; cn = cn->next, i++) {
374 2611805 : if (!rel_base_is_used(ba, i))
375 1012022 : continue;
376 :
377 1599783 : sql_column *c = cn->data;
378 1599783 : sql_exp *e = exp_alias(sa, atname, c->base.name, tname, c->base.name, &c->type, CARD_MULTI, c->null, is_column_unique(c), 0);
379 :
380 1599755 : if (e == NULL) {
381 0 : rel_destroy(rel);
382 0 : return NULL;
383 : }
384 1599755 : if (c->t->pkey && ((sql_kc*)c->t->pkey->k.columns->h->data)->c == c) {
385 55510 : p = e->p = prop_create(sa, PROP_HASHCOL, e->p);
386 55510 : p->value.pval = c->t->pkey;
387 1544245 : } else if (c->unique == 2) {
388 11451 : p = e->p = prop_create(sa, PROP_HASHCOL, e->p);
389 11451 : p->value.pval = NULL;
390 : }
391 1599755 : set_basecol(e);
392 1599755 : append(rel->exps, e);
393 : }
394 433215 : if (rel_base_is_used(ba, i) || list_empty(rel->exps)) /* Add TID column if no column is used */
395 433215 : append(rel->exps, exp_alias(sa, atname, TID, tname, TID, sql_bind_localtype("oid"), CARD_MULTI, 0, 1, 1));
396 433207 : i++;
397 :
398 551998 : for (cn = ol_first_node(t->idxs); cn; cn = cn->next, i++) {
399 118791 : if (!rel_base_is_used(ba, i))
400 0 : continue;
401 :
402 118791 : sql_exp *e;
403 118791 : sql_idx *i = cn->data;
404 118791 : sql_subtype *t;
405 118791 : char *iname = NULL;
406 118791 : int has_nils = 0, unique;
407 :
408 : /* do not include empty indices in the plan */
409 118791 : if ((hash_index(i->type) && list_length(i->columns) <= 1) || !idx_has_column(i->type))
410 100764 : continue;
411 :
412 18027 : t = (i->type == join_idx) ? sql_bind_localtype("oid") : sql_bind_localtype("lng");
413 18027 : iname = sa_strconcat( sa, "%", i->base.name);
414 39718 : for (node *n = i->columns->h ; n && !has_nils; n = n->next) { /* check for NULL values */
415 21691 : sql_kc *kc = n->data;
416 :
417 21691 : if (kc->c->null)
418 13168 : has_nils = 1;
419 : }
420 18027 : unique = list_length(i->columns) == 1 && is_column_unique(((sql_kc*)i->columns->h->data)->c);
421 18027 : e = exp_alias(sa, atname, iname, tname, iname, t, CARD_MULTI, has_nils, unique, 1);
422 : /* index names are prefixed, to make them independent */
423 18027 : if (hash_index(i->type)) {
424 10007 : p = e->p = prop_create(sa, PROP_HASHIDX, e->p);
425 10007 : p->value.pval = i;
426 : }
427 18027 : if (i->type == join_idx) {
428 8020 : p = e->p = prop_create(sa, PROP_JOINIDX, e->p);
429 8020 : p->value.pval = i;
430 : }
431 18027 : append(rel->exps, e);
432 : }
433 : }
434 : return rel;
435 : }
436 :
437 : sql_exp *
438 15 : basetable_get_tid_or_add_it(mvc *sql, sql_rel *rel)
439 : {
440 15 : sql_exp *res = NULL;
441 :
442 15 : if (is_basetable(rel->op)) {
443 15 : sql_allocator *sa = sql->sa;
444 15 : sql_table *t = rel->l;
445 15 : rel_base_t *ba = rel->r;
446 15 : const char *tname = t->base.name;
447 15 : const char *atname = ba->name?ba->name:tname;
448 :
449 15 : if (isRemote(t))
450 0 : tname = mapiuri_table(t->query, sql->sa, tname);
451 15 : if (!rel->exps) { /* no exps yet, just set TID */
452 0 : rel_base_use_tid(sql, rel);
453 0 : res = exp_alias(sa, atname, TID, tname, TID, sql_bind_localtype("oid"), CARD_MULTI, 0, 1, 1);
454 15 : } else if (!rel_base_is_used(ba, ol_length(t->columns)) || /* exps set, but no TID, add it */
455 15 : !(res = exps_bind_column2(rel->exps, atname, TID, NULL))) { /* exps set with TID, but maybe rel_dce removed it */
456 0 : node *n = NULL;
457 0 : rel_base_use_tid(sql, rel);
458 0 : res = exp_alias(sa, atname, TID, tname, TID, sql_bind_localtype("oid"), CARD_MULTI, 0, 1, 1);
459 :
460 : /* search for indexes */
461 0 : for (node *cn = rel->exps->h; cn && !n; cn = cn->next) {
462 0 : sql_exp *e = cn->data;
463 :
464 0 : if (is_intern(e))
465 0 : n = cn;
466 : }
467 0 : if (n) { /* has indexes, insert TID before them */
468 0 : list_append_before(rel->exps, n, res);
469 : } else {
470 0 : list_append(rel->exps, res);
471 : }
472 : }
473 : }
474 15 : return res;
475 : }
476 :
477 : sql_rel *
478 482 : rel_rename_part(mvc *sql, sql_rel *p, sql_rel *mt_rel, const char *mtalias)
479 : {
480 482 : sql_table *mt = rel_base_table(mt_rel), *t = rel_base_table(p);
481 :
482 482 : assert(!p->exps);
483 482 : p->exps = sa_list(sql->sa);
484 482 : const char *pname = t->base.name;
485 482 : if (isRemote(t))
486 37 : pname = mapiuri_table(t->query, sql->sa, pname);
487 1367 : for (node *n = mt_rel->exps->h; n; n = n->next) {
488 885 : sql_exp *e = n->data;
489 885 : node *cn = NULL, *ci = NULL;
490 885 : const char *nname = e->r;
491 :
492 885 : if (nname[0] == '%' && strcmp(nname, TID) == 0) {
493 71 : list_append(p->exps, exp_alias(sql->sa, mtalias, TID, pname, TID, sql_bind_localtype("oid"), CARD_MULTI, 0, 1, 1));
494 71 : rel_base_use_tid(sql, p);
495 1626 : } else if (nname[0] != '%' && (cn = ol_find_name(mt->columns, nname))) {
496 812 : sql_column *c = cn->data, *rc = ol_fetch(t->columns, c->colnr);
497 :
498 : /* with name find column in merge table, with colnr find column in member */
499 812 : sql_exp *ne = exp_alias(sql->sa, mtalias, exp_name(e), pname, rc->base.name, &rc->type, CARD_MULTI, rc->null, is_column_unique(rc), 0);
500 812 : if (rc->t->pkey && ((sql_kc*)rc->t->pkey->k.columns->h->data)->c == rc) {
501 22 : prop *p = ne->p = prop_create(sql->sa, PROP_HASHCOL, ne->p);
502 22 : p->value.pval = rc->t->pkey;
503 790 : } else if (rc->unique == 2) {
504 0 : prop *p = ne->p = prop_create(sql->sa, PROP_HASHCOL, ne->p);
505 0 : p->value.pval = NULL;
506 : }
507 812 : set_basecol(ne);
508 812 : rel_base_use(sql, p, rc->colnr);
509 812 : list_append(p->exps, ne);
510 2 : } else if (nname[0] == '%' && ol_length(mt->idxs) && (ci = ol_find_name(mt->idxs, nname + 1))) {
511 2 : sql_idx *i = ci->data, *ri = NULL;
512 :
513 : /* indexes don't have a number field like 'colnr', so get the index the old way */
514 4 : for (node *nn = mt->idxs->l->h, *mm = t->idxs->l->h; nn && mm ; nn = nn->next, mm = mm->next) {
515 4 : sql_idx *ii = nn->data;
516 :
517 4 : if (ii->base.id == i->base.id) {
518 2 : ri = mm->data;
519 2 : break;
520 : }
521 : }
522 :
523 2 : assert((!hash_index(ri->type) || list_length(ri->columns) > 1) && idx_has_column(ri->type));
524 2 : sql_subtype *t = (ri->type == join_idx) ? sql_bind_localtype("oid") : sql_bind_localtype("lng");
525 2 : char *iname1 = sa_strconcat(sql->sa, "%", i->base.name), *iname2 = sa_strconcat(sql->sa, "%", ri->base.name);
526 :
527 2 : sql_exp *ne = exp_alias(sql->sa, mtalias, iname1, pname, iname2, t, CARD_MULTI, has_nil(e), is_unique(e), 1);
528 : /* index names are prefixed, to make them independent */
529 2 : if (hash_index(ri->type)) {
530 0 : prop *p = ne->p = prop_create(sql->sa, PROP_HASHIDX, ne->p);
531 0 : p->value.pval = ri;
532 2 : } else if (ri->type == join_idx) {
533 2 : prop *p = ne->p = prop_create(sql->sa, PROP_JOINIDX, ne->p);
534 2 : p->value.pval = ri;
535 : }
536 2 : list_append(p->exps, ne);
537 : }
538 : }
539 482 : rel_base_set_mergetable(p, mt);
540 482 : return p;
541 : }
542 :
543 : void
544 0 : rel_base_dump_exps( stream *fout, sql_rel *rel)
545 : {
546 0 : int i = 0, comma = 0;
547 0 : sql_table *t = rel->l;
548 0 : rel_base_t *ba = rel->r;
549 0 : assert(ba);
550 0 : mnstr_printf(fout, "[ ");
551 0 : for (node *cn = ol_first_node(t->columns); cn; cn = cn->next, i++) {
552 0 : if (rel_base_is_used(ba, i)) {
553 0 : sql_column *c = cn->data;
554 0 : mnstr_printf(fout, "%s\"%s\".\"%s\"", comma?", ":"", t->base.name, c->base.name);
555 0 : if (ba->name)
556 0 : mnstr_printf(fout, " as \"%s\".\"%s\"", ba->name, c->base.name);
557 : comma = 1;
558 : }
559 : }
560 0 : if (rel_base_is_used(ba, i)) {
561 0 : mnstr_printf(fout, "%s\"%s\".\"%%TID\"", comma?", ":"", t->base.name);
562 0 : if (ba->name)
563 0 : mnstr_printf(fout, " as \"%s\".\"%%TID\"", ba->name);
564 : comma = 1;
565 : }
566 0 : i++;
567 0 : for (node *in = ol_first_node(t->idxs); in; in = in->next, i++) {
568 0 : if (rel_base_is_used(ba, i)) {
569 0 : sql_idx *i = in->data;
570 0 : mnstr_printf(fout, "%s\"%s\".\"%s\"", comma?", ":"", t->base.name, i->base.name);
571 0 : if (ba->name)
572 0 : mnstr_printf(fout, " as \"%s\".\"%s\"", ba->name, i->base.name);
573 : comma = 1;
574 : }
575 : }
576 0 : mnstr_printf(fout, " ]");
577 0 : }
578 :
579 : int
580 72 : rel_base_has_column_privileges(mvc *sql, sql_rel *rel)
581 : {
582 72 : sql_table *t = rel->l;
583 72 : int has = 0;
584 :
585 227 : for (node *m = ol_first_node(t->columns); m && !has; m = m->next) {
586 155 : sql_column *c = m->data;
587 :
588 155 : if (column_privs(sql, c, PRIV_SELECT))
589 33 : has = 1;
590 : }
591 72 : return has;
592 : }
593 :
594 : void
595 482 : rel_base_set_mergetable(sql_rel *rel, sql_table *mt)
596 : {
597 482 : rel_base_t *ba = rel->r;
598 :
599 482 : if (ba)
600 482 : ba->mt = mt;
601 482 : }
602 :
603 : sql_table *
604 1053529 : rel_base_get_mergetable(sql_rel *rel)
605 : {
606 1053529 : rel_base_t *ba = rel->r;
607 :
608 1053529 : return ba ? ba->mt : NULL;
609 : }
|