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