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 : #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 : char *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 : char *
44 212114 : rel_base_name(sql_rel *r)
45 : {
46 212114 : sql_table *t = r->l;
47 212114 : rel_base_t *ba = r->r;
48 212114 : if (ba->name)
49 : return ba->name;
50 134588 : return t->base.name;
51 : }
52 :
53 : char *
54 0 : rel_base_rename(sql_rel *r, char *name)
55 : {
56 0 : rel_base_t *ba = r->r;
57 0 : ba->name = name;
58 0 : return name;
59 : }
60 :
61 : int
62 1046 : rel_base_idx_nid(sql_rel *r, sql_idx *i)
63 : {
64 1046 : rel_base_t *ba = r->r;
65 1046 : sql_table *b = r->l;
66 1046 : if (i) {
67 1046 : int j = ba->basenr + ol_length(b->columns) + 1;
68 1116 : for (node *in = ol_first_node(i->t->idxs); in; in = in->next, j++) {
69 1116 : if (i == in->data)
70 1046 : return -(ba->basenr + j);
71 : }
72 : }
73 : return 0;
74 : }
75 :
76 : sql_column*
77 304165 : rel_base_find_column(sql_rel *r, int nid)
78 : {
79 304165 : rel_base_t *ba = r->r;
80 304165 : sql_table *b = r->l;
81 304165 : nid = -nid;
82 304165 : if ((nid - ba->basenr) >= ol_length(b->columns))
83 : return NULL;
84 206825 : return ol_fetch(b->columns, nid - ba->basenr);
85 : }
86 :
87 : int
88 34786 : rel_base_nid(sql_rel *r, sql_column *c)
89 : {
90 34786 : rel_base_t *ba = r->r;
91 34786 : sql_table *b = r->l;
92 34786 : if (c)
93 24035 : return -(ba->basenr + c->colnr);
94 10751 : return -(ba->basenr + ol_length(b->columns));
95 : }
96 :
97 : bool
98 1913588 : rel_base_has_nid(sql_rel *r, int nid)
99 : {
100 1913588 : rel_base_t *ba = r->r;
101 1913588 : sql_table *b = r->l;
102 :
103 1913588 : nid = -nid;
104 1913588 : return (nid >= ba->basenr && nid <= ba->basenr + ol_length(b->columns));
105 : }
106 :
107 : int
108 1724714 : rel_base_use( mvc *sql, sql_rel *rt, int nr)
109 : {
110 1724714 : assert(is_basetable(rt->op));
111 1724714 : sql_table *t = rt->l;
112 1724714 : rel_base_t *ba = rt->r;
113 :
114 1724714 : if (ba->disallowed && nr < ol_length(t->columns)) {
115 34 : sql_column *c = ol_fetch(t->columns, nr);
116 34 : if (!column_privs(sql, c, PRIV_SELECT))
117 : return -1;
118 : }
119 1724697 : rel_base_set_used(ba, nr);
120 1724697 : return 0;
121 : }
122 :
123 : void
124 7968 : rel_base_use_tid( mvc *sql, sql_rel *rt)
125 : {
126 7968 : sql_table *t = rt->l;
127 7968 : rel_base_use(sql, rt, ol_length(t->columns));
128 7968 : }
129 :
130 : void
131 405536 : rel_base_use_all( mvc *sql, sql_rel *rel)
132 : {
133 405536 : sql_table *t = rel->l;
134 405536 : rel_base_t *ba = rel->r;
135 :
136 405536 : if (ba->disallowed) {
137 10 : int i = 0;
138 33 : for (node *cn = ol_first_node(t->columns); cn; cn = cn->next, i++) {
139 23 : sql_column *c = cn->data;
140 23 : if (!column_privs(sql, c, PRIV_SELECT))
141 12 : continue;
142 11 : rel_base_set_used(ba, i);
143 : }
144 : } else {
145 405526 : int len = USED_LEN(ol_length(t->columns) + 1 + ol_length(t->idxs));
146 815328 : for (int i = 0; i < len; i++)
147 409662 : ba->used[i] = ~0U;
148 : }
149 405676 : }
150 :
151 : sql_rel *
152 626784 : rel_basetable(mvc *sql, sql_table *t, const char *atname)
153 : {
154 626784 : allocator *sa = sql->sa;
155 626784 : sql_rel *rel = rel_create(sa);
156 626965 : int nrcols = ol_length(t->columns), end = nrcols + 1 + ol_length(t->idxs);
157 627253 : rel_base_t *ba = (rel_base_t*)sa_zalloc(sa, sizeof(rel_base_t) + sizeof(int)*USED_LEN(end));
158 627108 : sqlstore *store = sql->session->tr->store;
159 :
160 627108 : if(!rel || !ba)
161 : return NULL;
162 :
163 627108 : ba->basenr = sql->nid;
164 627108 : sql->nid += end;
165 627108 : if (isTable(t) && t->s && !isDeclaredTable(t)) /* count active rows only */
166 566805 : set_count_prop(sql->sa, rel, (BUN)store->storage_api.count_col(sql->session->tr, ol_first_node(t->columns)->data, 10));
167 627092 : assert(atname);
168 627092 : if (strcmp(atname, t->base.name) != 0)
169 252446 : ba->name = sa_strdup(sa, atname);
170 1409227 : for(int i = nrcols; i<end; i++)
171 782135 : rel_base_set_used(ba, i);
172 627092 : rel->l = t;
173 627092 : rel->r = ba;
174 627092 : rel->op = op_basetable;
175 627092 : rel->card = CARD_MULTI;
176 627092 : rel->nrcols = nrcols;
177 627092 : return rel;
178 : }
179 :
180 : void
181 55 : rel_base_copy(mvc *sql, sql_rel *in, sql_rel *out)
182 : {
183 55 : allocator *sa = sql->sa;
184 55 : sql_table *t = in->l;
185 55 : rel_base_t *ba = in->r;
186 :
187 55 : assert(is_basetable(in->op) && is_basetable(out->op));
188 55 : int nrcols = ol_length(t->columns), end = nrcols + 1 + ol_length(t->idxs);
189 55 : size_t bsize = sizeof(rel_base_t) + sizeof(uint32_t)*USED_LEN(end);
190 55 : rel_base_t *nba = (rel_base_t*)sa_alloc(sa, bsize);
191 :
192 55 : memcpy(nba, ba, bsize);
193 55 : if (ba->name)
194 0 : nba->name = sa_strdup(sa, ba->name);
195 :
196 55 : out->l = t;
197 55 : out->r = nba;
198 55 : }
199 :
200 : sql_rel *
201 0 : rel_base_bind_column_( sql_rel *rel, const char *cname)
202 : {
203 0 : sql_table *t = rel->l;
204 0 : node *n = ol_find_name(t->columns, cname);
205 0 : if (n)
206 0 : return rel;
207 : return NULL;
208 : }
209 :
210 : static sql_exp *
211 2307472 : bind_col_exp(mvc *sql, rel_base_t *ba, char *name, sql_column *c)
212 : {
213 2307472 : prop *p = NULL;
214 2307472 : sql_exp *e = exp_column(sql->sa, name, c->base.name, &c->type, CARD_MULTI, c->null, is_column_unique(c), 0);
215 :
216 2307475 : if (e) {
217 2307475 : e->nid = -(ba->basenr + c->colnr);
218 2307475 : e->alias.label = e->nid;
219 : }
220 2307475 : if (c->t->pkey && ((sql_kc*)c->t->pkey->k.columns->h->data)->c == c) {
221 84709 : p = e->p = prop_create(sql->sa, PROP_HASHCOL, e->p);
222 84709 : p->value.pval = c->t->pkey;
223 2222766 : } else if (c->unique == 2) {
224 22983 : p = e->p = prop_create(sql->sa, PROP_HASHCOL, e->p);
225 22983 : p->value.pval = NULL;
226 : }
227 2307475 : set_basecol(e);
228 2307475 : sql_column_get_statistics(sql, c, e);
229 2307487 : return e;
230 : }
231 :
232 : static sql_exp *
233 1642926 : bind_col(mvc *sql, sql_rel *rel, char *name, sql_column *c )
234 : {
235 1642926 : if (!c || rel_base_use(sql, rel, c->colnr)) {
236 : /* error */
237 12 : return NULL;
238 : }
239 1642914 : return bind_col_exp(sql, rel->r, name, c);
240 : }
241 :
242 : sql_exp *
243 240 : rel_base_bind_colnr( mvc *sql, sql_rel *rel, int nr)
244 : {
245 240 : sql_table *t = rel->l;
246 240 : rel_base_t *ba = rel->r;
247 240 : return bind_col(sql, rel, ba->name?ba->name:t->base.name, ol_fetch(t->columns, nr));
248 : }
249 :
250 : sql_exp *
251 0 : rel_base_find_label( mvc *sql, sql_rel *rel, int label)
252 : {
253 0 : sql_table *t = rel->l;
254 0 : rel_base_t *ba = rel->r;
255 :
256 0 : label = -label;
257 0 : int colnr = label - ba->basenr;
258 0 : if (colnr > ol_length(t->columns))
259 : return NULL;
260 0 : return rel_base_bind_colnr(sql, rel, colnr);
261 : }
262 :
263 : sql_exp *
264 4072212 : rel_base_bind_column( mvc *sql, sql_rel *rel, const char *cname, int no_tname)
265 : {
266 4072212 : sql_table *t = rel->l;
267 4072212 : rel_base_t *ba = rel->r;
268 4072212 : (void)no_tname;
269 4072212 : node *n = t ? ol_find_name(t->columns, cname) : NULL;
270 4072212 : if (!n)
271 3246287 : return NULL;
272 825925 : return bind_col(sql, rel, ba->name?ba->name:t->base.name, n->data);
273 : }
274 :
275 : sql_rel *
276 0 : rel_base_bind_column2_( sql_rel *rel, const char *tname, const char *cname)
277 : {
278 0 : sql_table *t = rel->l;
279 0 : rel_base_t *ba = rel->r;
280 :
281 0 : assert(ba);
282 0 : if ((ba->name && strcmp(ba->name, tname) != 0) || (!ba->name && strcmp(t->base.name, tname) != 0))
283 : return NULL;
284 0 : node *n = ol_find_name(t->columns, cname);
285 0 : if (!n)
286 : return NULL;
287 : return rel;
288 : }
289 :
290 : sql_exp *
291 1384061 : rel_base_bind_column2( mvc *sql, sql_rel *rel, const char *tname, const char *cname)
292 : {
293 1384061 : sql_table *t = rel->l;
294 1384061 : rel_base_t *ba = rel->r;
295 :
296 1384061 : assert(ba);
297 1384061 : if ((ba->name && strcmp(ba->name, tname) != 0) || (!ba->name && strcmp(t->base.name, tname) != 0))
298 : return NULL;
299 677744 : node *n = ol_find_name(t->columns, cname);
300 677744 : if (!n)
301 : return NULL;
302 677739 : sql_column *c = n->data;
303 677739 : return bind_col(sql, rel, ba->name?ba->name:t->base.name, c);
304 : }
305 :
306 : sql_exp *
307 0 : rel_base_bind_column3( mvc *sql, sql_rel *rel, const char *sname, const char *tname, const char *cname)
308 : {
309 0 : sql_table *t = rel->l;
310 0 : if (!t->s || strcmp(t->s->base.name, sname) != 0)
311 : return NULL;
312 0 : return rel_base_bind_column2(sql, rel, tname, cname);
313 : }
314 :
315 : list *
316 104150 : rel_base_projection( mvc *sql, sql_rel *rel, int intern)
317 : {
318 104150 : int i = 0;
319 104150 : sql_table *t = rel->l;
320 104150 : rel_base_t *ba = rel->r;
321 104150 : char *name = ba->name?ba->name:t->base.name;
322 104150 : list *exps = new_exp_list(sql->sa);
323 104153 : prop *p;
324 :
325 768834 : for (node *cn = ol_first_node(t->columns); cn; cn = cn->next, i++) {
326 664673 : if (rel_base_is_used(ba, i)) {
327 664564 : sql_exp *e = bind_col_exp(sql, ba, name, cn->data);
328 664576 : append(exps, e);
329 : }
330 : }
331 104161 : if ((intern && rel_base_is_used(ba, i)) || list_empty(exps)) { /* Add TID column if no column is used */
332 79081 : sql_exp *e = exp_column(sql->sa, name, TID, sql_bind_localtype("oid"), CARD_MULTI, 0, 1, 1);
333 79081 : e->nid = -(ba->basenr + i);
334 79081 : e->alias.label = e->nid;
335 79081 : append(exps, e);
336 : }
337 104160 : i++;
338 104160 : if (intern) {
339 79081 : int j = i;
340 110650 : for (node *in = ol_first_node(t->idxs); in; in = in->next, j++) {
341 31569 : if (rel_base_is_used(ba, j)) {
342 31569 : sql_idx *i = in->data;
343 31569 : sql_subtype *t = sql_bind_localtype("lng"); /* hash "lng" */
344 31569 : int has_nils = 0, unique;
345 :
346 31569 : if ((hash_index(i->type) && list_length(i->columns) <= 1) || !idx_has_column(i->type))
347 30662 : continue;
348 :
349 907 : if (i->type == join_idx)
350 765 : t = sql_bind_localtype("oid");
351 :
352 907 : char *iname = sa_strconcat( sql->sa, "%", i->base.name);
353 1954 : for (node *n = i->columns->h ; n && !has_nils; n = n->next) { /* check for NULL values */
354 1047 : sql_kc *kc = n->data;
355 :
356 1047 : if (kc->c->null)
357 724 : has_nils = 1;
358 : }
359 907 : unique = list_length(i->columns) == 1 && is_column_unique(((sql_kc*)i->columns->h->data)->c);
360 907 : sql_exp *e = exp_column(sql->sa, name, iname, t, CARD_MULTI, has_nils, unique, 1);
361 907 : e->nid = -(ba->basenr + j);
362 907 : e->alias.label = e->nid;
363 907 : if (hash_index(i->type)) {
364 142 : p = e->p = prop_create(sql->sa, PROP_HASHIDX, e->p);
365 142 : p->value.pval = i;
366 : }
367 907 : if (i->type == join_idx) {
368 765 : p = e->p = prop_create(sql->sa, PROP_JOINIDX, e->p);
369 765 : p->value.pval = i;
370 : }
371 907 : append(exps, e);
372 : }
373 : }
374 : }
375 104160 : return exps;
376 : }
377 :
378 : list *
379 14045 : rel_base_project_all( mvc *sql, sql_rel *rel, char *tname)
380 : {
381 14045 : sql_table *t = rel->l;
382 14045 : rel_base_t *ba = rel->r;
383 14045 : char *name = ba->name?ba->name:t->base.name;
384 14045 : list *exps = new_exp_list(sql->sa);
385 :
386 14045 : if (!exps || strcmp(name, tname) != 0)
387 : return NULL;
388 :
389 153021 : for (node *cn = ol_first_node(t->columns); cn; cn = cn->next)
390 139022 : append(exps, bind_col( sql, rel, name, cn->data));
391 : return exps;
392 : }
393 :
394 : sql_rel *
395 511 : rel_base_add_columns( mvc *sql, sql_rel *r)
396 : {
397 511 : sql_table *t = r->l;
398 511 : rel_base_t *ba = r->r;
399 :
400 511 : r->exps = new_exp_list(sql->sa);
401 511 : if(!r->exps) {
402 0 : rel_destroy(r);
403 0 : return NULL;
404 : }
405 :
406 511 : int i = 0;
407 511 : prop *p = NULL;
408 511 : node *cn;
409 511 : const char *tname = t->base.name;
410 511 : const char *atname = ba->name?ba->name:tname;
411 :
412 1529 : for (cn = ol_first_node(t->columns); cn; cn = cn->next, i++) {
413 1018 : sql_column *c = cn->data;
414 1018 : sql_exp *e = exp_alias(sql, atname, c->base.name, tname, c->base.name, &c->type, CARD_MULTI, c->null, is_column_unique(c), 0);
415 :
416 1018 : if (e == NULL) {
417 0 : rel_destroy(r);
418 0 : return NULL;
419 : }
420 1018 : e->nid = -(ba->basenr + i);
421 1018 : e->alias.label = e->nid;
422 1018 : if (c->t->pkey && ((sql_kc*)c->t->pkey->k.columns->h->data)->c == c) {
423 0 : p = e->p = prop_create(sql->sa, PROP_HASHCOL, e->p);
424 0 : p->value.pval = c->t->pkey;
425 1018 : } else if (c->unique == 2) {
426 0 : p = e->p = prop_create(sql->sa, PROP_HASHCOL, e->p);
427 0 : p->value.pval = NULL;
428 : }
429 1018 : set_basecol(e);
430 1018 : sql_column_get_statistics(sql, c, e);
431 1018 : append(r->exps, e);
432 : }
433 : return r;
434 : }
435 :
436 : sql_rel *
437 2440680 : rewrite_basetable(mvc *sql, sql_rel *rel)
438 : {
439 2440680 : if (is_basetable(rel->op) && !rel->exps) {
440 453430 : allocator *sa = sql->sa;
441 453430 : sql_table *t = rel->l;
442 453430 : rel_base_t *ba = rel->r;
443 :
444 453430 : rel->exps = new_exp_list(sa);
445 453359 : if(!rel->exps) {
446 0 : rel_destroy(rel);
447 0 : return NULL;
448 : }
449 :
450 453359 : int i = 0;
451 453359 : prop *p = NULL;
452 453359 : node *cn;
453 453359 : const char *tname = t->base.name;
454 453359 : const char *atname = ba->name?ba->name:tname;
455 :
456 453359 : if (isRemote(t))
457 285 : tname = mapiuri_table(t->query, sql->sa, tname);
458 3219831 : for (cn = ol_first_node(t->columns); cn; cn = cn->next, i++) {
459 2766265 : if (!rel_base_is_used(ba, i))
460 1038275 : continue;
461 :
462 1727990 : sql_column *c = cn->data;
463 1727990 : sql_exp *e = exp_alias(sql, atname, c->base.name, tname, c->base.name, &c->type, CARD_MULTI, c->null, is_column_unique(c), 0);
464 :
465 1727758 : if (e == NULL) {
466 0 : rel_destroy(rel);
467 0 : return NULL;
468 : }
469 1727758 : e->nid = -(ba->basenr + i);
470 1727758 : e->alias.label = e->nid;
471 1727758 : if (c->t->pkey && ((sql_kc*)c->t->pkey->k.columns->h->data)->c == c) {
472 58029 : p = e->p = prop_create(sa, PROP_HASHCOL, e->p);
473 58029 : p->value.pval = c->t->pkey;
474 1669729 : } else if (c->unique == 2) {
475 12049 : p = e->p = prop_create(sa, PROP_HASHCOL, e->p);
476 12049 : p->value.pval = NULL;
477 : }
478 1727758 : set_basecol(e);
479 1727758 : sql_column_get_statistics(sql, c, e);
480 1728751 : append(rel->exps, e);
481 : }
482 453566 : if (rel_base_is_used(ba, i) || list_empty(rel->exps)) { /* Add TID column if no column is used */
483 453566 : sql_exp *e = exp_alias(sql, atname, TID, tname, TID, sql_bind_localtype("oid"), CARD_MULTI, 0, 1, 1);
484 453432 : if (e == NULL) {
485 0 : rel_destroy(rel);
486 0 : return NULL;
487 : }
488 453432 : e->nid = -(ba->basenr + i);
489 453432 : e->alias.label = e->nid;
490 453432 : append(rel->exps, e);
491 : }
492 453635 : i++;
493 453635 : int j = i;
494 576188 : for (cn = ol_first_node(t->idxs); cn; cn = cn->next, j++) {
495 122715 : if (!rel_base_is_used(ba, j))
496 0 : continue;
497 :
498 122715 : sql_exp *e;
499 122715 : sql_idx *i = cn->data;
500 122715 : sql_subtype *t;
501 122715 : char *iname = NULL;
502 122715 : int has_nils = 0, unique;
503 :
504 : /* do not include empty indices in the plan */
505 122715 : if ((hash_index(i->type) && list_length(i->columns) <= 1) || !idx_has_column(i->type))
506 104714 : continue;
507 :
508 18002 : t = (i->type == join_idx) ? sql_bind_localtype("oid") : sql_bind_localtype("lng");
509 18002 : iname = sa_strconcat( sa, "%", i->base.name);
510 39669 : for (node *n = i->columns->h ; n && !has_nils; n = n->next) { /* check for NULL values */
511 21667 : sql_kc *kc = n->data;
512 :
513 21667 : if (kc->c->null)
514 13185 : has_nils = 1;
515 : }
516 18002 : unique = list_length(i->columns) == 1 && is_column_unique(((sql_kc*)i->columns->h->data)->c);
517 18002 : e = exp_alias(sql, atname, iname, tname, iname, t, CARD_MULTI, has_nils, unique, 1);
518 18002 : if (e == NULL) {
519 0 : rel_destroy(rel);
520 0 : return NULL;
521 : }
522 : /* index names are prefixed, to make them independent */
523 18002 : if (hash_index(i->type)) {
524 10024 : p = e->p = prop_create(sa, PROP_HASHIDX, e->p);
525 10024 : p->value.pval = i;
526 : }
527 18002 : if (i->type == join_idx) {
528 7978 : p = e->p = prop_create(sa, PROP_JOINIDX, e->p);
529 7978 : p->value.pval = i;
530 : }
531 18002 : e->nid = -(ba->basenr + j);
532 18002 : e->alias.label = e->nid;
533 18002 : append(rel->exps, e);
534 : }
535 : }
536 : return rel;
537 : }
538 :
539 : sql_exp *
540 1036 : basetable_get_tid_or_add_it(mvc *sql, sql_rel *rel)
541 : {
542 1036 : sql_exp *res = NULL;
543 :
544 1036 : if (is_basetable(rel->op)) {
545 1036 : sql_table *t = rel->l;
546 1036 : rel_base_t *ba = rel->r;
547 1036 : const char *tname = t->base.name;
548 1036 : const char *atname = ba->name?ba->name:tname;
549 :
550 1036 : if (isRemote(t))
551 0 : tname = mapiuri_table(t->query, sql->sa, tname);
552 1036 : if (!rel->exps) { /* no exps yet, just set TID */
553 1009 : rel_base_use_tid(sql, rel);
554 1009 : res = exp_alias(sql, atname, TID, tname, TID, sql_bind_localtype("oid"), CARD_MULTI, 0, 1, 1);
555 1009 : res->nid = -(ba->basenr + ol_length(t->columns));
556 1009 : res->alias.label = res->nid;
557 27 : } else if (!rel_base_is_used(ba, ol_length(t->columns)) || /* exps set, but no TID, add it */
558 27 : !(res = exps_bind_column2(rel->exps, atname, TID, NULL))) { /* exps set with TID, but maybe rel_dce removed it */
559 0 : node *n = NULL;
560 0 : rel_base_use_tid(sql, rel);
561 0 : res = exp_alias(sql, atname, TID, tname, TID, sql_bind_localtype("oid"), CARD_MULTI, 0, 1, 1);
562 0 : res->nid = -(ba->basenr + ol_length(t->columns));
563 0 : res->alias.label = res->nid;
564 :
565 : /* search for indexes */
566 0 : for (node *cn = rel->exps->h; cn && !n; cn = cn->next) {
567 0 : sql_exp *e = cn->data;
568 :
569 0 : if (is_intern(e))
570 0 : n = cn;
571 : }
572 0 : if (n) { /* has indexes, insert TID before them */
573 0 : list_append_before(rel->exps, n, res);
574 : } else {
575 0 : list_append(rel->exps, res);
576 : }
577 : }
578 : }
579 1036 : return res;
580 : }
581 :
582 : sql_rel *
583 549 : rel_rename_part(mvc *sql, sql_rel *p, sql_rel *mt_rel, const char *mtalias)
584 : {
585 549 : sql_exp *ne = NULL;
586 549 : sql_table *mt = rel_base_table(mt_rel), *t = rel_base_table(p);
587 549 : rel_base_t *mt_ba = mt_rel->r, *p_ba = p->r;
588 549 : p_ba->basenr = mt_ba->basenr;
589 :
590 549 : assert(!p->exps);
591 549 : p->exps = sa_list(sql->sa);
592 549 : const char *pname = t->base.name;
593 549 : if (isRemote(t))
594 37 : pname = mapiuri_table(t->query, sql->sa, pname);
595 1480 : for (node *n = mt_rel->exps->h; n; n = n->next) {
596 931 : sql_exp *e = n->data;
597 931 : node *cn = NULL, *ci = NULL;
598 931 : const char *nname = e->r;
599 :
600 931 : if (nname[0] == '%' && strcmp(nname, TID) == 0) {
601 53 : list_append(p->exps, ne=exp_alias(sql, mtalias, TID, pname, TID, sql_bind_localtype("oid"), CARD_MULTI, 0, 1, 1));
602 53 : ne->nid = e->nid;
603 53 : ne->alias.label = e->alias.label;
604 53 : rel_base_use_tid(sql, p);
605 878 : } else if (nname[0] != '%' && (cn = ol_find_name(mt->columns, nname))) {
606 876 : sql_column *c = cn->data, *rc = ol_fetch(t->columns, c->colnr);
607 :
608 : /* with name find column in merge table, with colnr find column in member */
609 876 : ne = exp_alias(sql, mtalias, exp_name(e), pname, rc->base.name, &rc->type, CARD_MULTI, rc->null, is_column_unique(rc), 0);
610 876 : if (rc->t->pkey && ((sql_kc*)rc->t->pkey->k.columns->h->data)->c == rc) {
611 19 : prop *p = ne->p = prop_create(sql->sa, PROP_HASHCOL, ne->p);
612 19 : p->value.pval = rc->t->pkey;
613 857 : } else if (rc->unique == 2) {
614 0 : prop *p = ne->p = prop_create(sql->sa, PROP_HASHCOL, ne->p);
615 0 : p->value.pval = NULL;
616 : }
617 876 : set_basecol(ne);
618 876 : sql_column_get_statistics(sql, c, ne);
619 876 : rel_base_use(sql, p, rc->colnr);
620 876 : list_append(p->exps, ne);
621 876 : ne->nid = e->nid;
622 876 : ne->alias.label = e->alias.label;
623 2 : } else if (nname[0] == '%' && ol_length(mt->idxs) && (ci = ol_find_name(mt->idxs, nname + 1))) {
624 2 : sql_idx *i = ci->data, *ri = NULL;
625 :
626 : /* indexes don't have a number field like 'colnr', so get the index the old way */
627 4 : for (node *nn = mt->idxs->l->h, *mm = t->idxs->l->h; nn && mm ; nn = nn->next, mm = mm->next) {
628 4 : sql_idx *ii = nn->data;
629 :
630 4 : if (ii->base.id == i->base.id) {
631 2 : ri = mm->data;
632 2 : break;
633 : }
634 : }
635 :
636 2 : assert((!hash_index(ri->type) || list_length(ri->columns) > 1) && idx_has_column(ri->type));
637 2 : sql_subtype *t = (ri->type == join_idx) ? sql_bind_localtype("oid") : sql_bind_localtype("lng");
638 2 : char *iname1 = sa_strconcat(sql->sa, "%", i->base.name), *iname2 = sa_strconcat(sql->sa, "%", ri->base.name);
639 :
640 2 : ne = exp_alias(sql, mtalias, iname1, pname, iname2, t, CARD_MULTI, has_nil(e), is_unique(e), 1);
641 : /* index names are prefixed, to make them independent */
642 2 : if (hash_index(ri->type)) {
643 0 : prop *p = ne->p = prop_create(sql->sa, PROP_HASHIDX, ne->p);
644 0 : p->value.pval = ri;
645 2 : } else if (ri->type == join_idx) {
646 2 : prop *p = ne->p = prop_create(sql->sa, PROP_JOINIDX, ne->p);
647 2 : p->value.pval = ri;
648 : }
649 2 : ne->nid = e->nid;
650 2 : ne->alias.label = e->alias.label;
651 2 : list_append(p->exps, ne);
652 : }
653 : }
654 549 : rel_base_set_mergetable(p, mt);
655 549 : return p;
656 : }
657 :
658 : void
659 0 : rel_base_dump_exps( stream *fout, sql_rel *rel)
660 : {
661 0 : int i = 0, comma = 0;
662 0 : sql_table *t = rel->l;
663 0 : rel_base_t *ba = rel->r;
664 0 : assert(ba);
665 0 : mnstr_printf(fout, "[ ");
666 0 : for (node *cn = ol_first_node(t->columns); cn; cn = cn->next, i++) {
667 0 : if (rel_base_is_used(ba, i)) {
668 0 : sql_column *c = cn->data;
669 0 : mnstr_printf(fout, "%s\"%s\".\"%s\"", comma?", ":"", t->base.name, c->base.name);
670 0 : if (ba->name)
671 0 : mnstr_printf(fout, " as \"%s\".\"%s\"", ba->name, c->base.name);
672 : comma = 1;
673 : }
674 : }
675 0 : if (rel_base_is_used(ba, i)) {
676 0 : mnstr_printf(fout, "%s\"%s\".\"%%TID%%\"", comma?", ":"", t->base.name);
677 0 : if (ba->name)
678 0 : mnstr_printf(fout, " as \"%s\".\"%%TID%%\"", ba->name);
679 : comma = 1;
680 : }
681 0 : i++;
682 0 : for (node *in = ol_first_node(t->idxs); in; in = in->next, i++) {
683 0 : if (rel_base_is_used(ba, i)) {
684 0 : sql_idx *i = in->data;
685 0 : mnstr_printf(fout, "%s\"%s\".\"%s\"", comma?", ":"", t->base.name, i->base.name);
686 0 : if (ba->name)
687 0 : mnstr_printf(fout, " as \"%s\".\"%s\"", ba->name, i->base.name);
688 : comma = 1;
689 : }
690 : }
691 0 : mnstr_printf(fout, " ]");
692 0 : }
693 :
694 : int
695 72 : rel_base_has_column_privileges(mvc *sql, sql_rel *rel)
696 : {
697 72 : sql_table *t = rel->l;
698 72 : int has = 0;
699 :
700 227 : for (node *m = ol_first_node(t->columns); m && !has; m = m->next) {
701 155 : sql_column *c = m->data;
702 :
703 155 : if (column_privs(sql, c, PRIV_SELECT))
704 33 : has = 1;
705 : }
706 72 : return has;
707 : }
708 :
709 : void
710 549 : rel_base_set_mergetable(sql_rel *rel, sql_table *mt)
711 : {
712 549 : rel_base_t *ba = rel->r;
713 :
714 549 : if (ba)
715 549 : ba->mt = mt;
716 549 : }
717 :
718 : sql_table *
719 173221 : rel_base_get_mergetable(sql_rel *rel)
720 : {
721 173221 : rel_base_t *ba = rel->r;
722 :
723 173221 : return ba ? ba->mt : NULL;
724 : }
|