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