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 : 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 213901 : rel_base_name(sql_rel *r)
45 : {
46 213901 : sql_table *t = r->l;
47 213901 : rel_base_t *ba = r->r;
48 213901 : if (ba->name)
49 : return ba->name;
50 135259 : 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 1050 : rel_base_idx_nid(sql_rel *r, sql_idx *i)
63 : {
64 1050 : rel_base_t *ba = r->r;
65 1050 : sql_table *b = r->l;
66 1050 : if (i) {
67 1050 : int j = ba->basenr + ol_length(b->columns) + 1;
68 1120 : for (node *in = ol_first_node(i->t->idxs); in; in = in->next, j++) {
69 1120 : if (i == in->data)
70 1050 : return -(ba->basenr + j);
71 : }
72 : }
73 : return 0;
74 : }
75 :
76 : sql_column*
77 306957 : rel_base_find_column(sql_rel *r, int nid)
78 : {
79 306957 : rel_base_t *ba = r->r;
80 306957 : sql_table *b = r->l;
81 306957 : nid = -nid;
82 306957 : if ((nid - ba->basenr) >= ol_length(b->columns))
83 : return NULL;
84 208620 : return ol_fetch(b->columns, nid - ba->basenr);
85 : }
86 :
87 : int
88 34973 : rel_base_nid(sql_rel *r, sql_column *c)
89 : {
90 34973 : rel_base_t *ba = r->r;
91 34973 : sql_table *b = r->l;
92 34973 : if (c)
93 24102 : return -(ba->basenr + c->colnr);
94 10871 : return -(ba->basenr + ol_length(b->columns));
95 : }
96 :
97 : bool
98 1915976 : rel_base_has_nid(sql_rel *r, int nid)
99 : {
100 1915976 : rel_base_t *ba = r->r;
101 1915976 : sql_table *b = r->l;
102 :
103 1915976 : nid = -nid;
104 1915976 : return (nid >= ba->basenr && nid <= ba->basenr + ol_length(b->columns));
105 : }
106 :
107 : int
108 1743384 : rel_base_use( mvc *sql, sql_rel *rt, int nr)
109 : {
110 1743384 : assert(is_basetable(rt->op));
111 1743384 : sql_table *t = rt->l;
112 1743384 : rel_base_t *ba = rt->r;
113 :
114 1743384 : 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 1743367 : rel_base_set_used(ba, nr);
120 1743367 : return 0;
121 : }
122 :
123 : void
124 8034 : rel_base_use_tid( mvc *sql, sql_rel *rt)
125 : {
126 8034 : sql_table *t = rt->l;
127 8034 : rel_base_use(sql, rt, ol_length(t->columns));
128 8034 : }
129 :
130 : void
131 388527 : rel_base_use_all( mvc *sql, sql_rel *rel)
132 : {
133 388527 : sql_table *t = rel->l;
134 388527 : rel_base_t *ba = rel->r;
135 :
136 388527 : 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 388517 : int len = USED_LEN(ol_length(t->columns) + 1 + ol_length(t->idxs));
146 780700 : for (int i = 0; i < len; i++)
147 392183 : ba->used[i] = ~0U;
148 : }
149 388527 : }
150 :
151 : sql_rel *
152 631561 : rel_basetable(mvc *sql, sql_table *t, const char *atname)
153 : {
154 631561 : allocator *sa = sql->sa;
155 631561 : sql_rel *rel = rel_create(sa);
156 631559 : int nrcols = ol_length(t->columns), end = nrcols + 1 + ol_length(t->idxs);
157 631555 : rel_base_t *ba = (rel_base_t*)sa_zalloc(sa, sizeof(rel_base_t) + sizeof(int)*USED_LEN(end));
158 631556 : sqlstore *store = sql->session->tr->store;
159 :
160 631556 : if(!rel || !ba)
161 : return NULL;
162 :
163 631556 : ba->basenr = sql->nid;
164 631556 : sql->nid += end;
165 631556 : if (isTable(t) && t->s && !isDeclaredTable(t)) /* count active rows only */
166 570490 : set_count_prop(sql->sa, rel, (BUN)store->storage_api.count_col(sql->session->tr, ol_first_node(t->columns)->data, 10));
167 631560 : assert(atname);
168 631560 : if (strcmp(atname, t->base.name) != 0)
169 255167 : ba->name = sa_strdup(sa, atname);
170 1418850 : for(int i = nrcols; i<end; i++)
171 787290 : rel_base_set_used(ba, i);
172 631560 : rel->l = t;
173 631560 : rel->r = ba;
174 631560 : rel->op = op_basetable;
175 631560 : rel->card = CARD_MULTI;
176 631560 : rel->nrcols = nrcols;
177 631560 : 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 2331289 : bind_col_exp(mvc *sql, rel_base_t *ba, char *name, sql_column *c)
212 : {
213 2331289 : prop *p = NULL;
214 2331289 : sql_exp *e = exp_column(sql->sa, name, c->base.name, &c->type, CARD_MULTI, c->null, is_column_unique(c), 0);
215 :
216 2331272 : if (e) {
217 2331272 : e->nid = -(ba->basenr + c->colnr);
218 2331272 : e->alias.label = e->nid;
219 : }
220 2331272 : if (c->t->pkey && ((sql_kc*)c->t->pkey->k.columns->h->data)->c == c) {
221 85298 : p = e->p = prop_create(sql->sa, PROP_HASHCOL, e->p);
222 85298 : p->value.pval = c->t->pkey;
223 2245974 : } else if (c->unique == 2) {
224 23226 : p = e->p = prop_create(sql->sa, PROP_HASHCOL, e->p);
225 23226 : p->value.pval = NULL;
226 : }
227 2331272 : set_basecol(e);
228 2331272 : sql_column_get_statistics(sql, c, e);
229 2331286 : return e;
230 : }
231 :
232 : static sql_exp *
233 1660891 : bind_col(mvc *sql, sql_rel *rel, char *name, sql_column *c )
234 : {
235 1660891 : if (!c || rel_base_use(sql, rel, c->colnr)) {
236 : /* error */
237 12 : return NULL;
238 : }
239 1660879 : 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 4081142 : rel_base_bind_column( mvc *sql, sql_rel *rel, const char *cname, int no_tname)
265 : {
266 4081142 : sql_table *t = rel->l;
267 4081142 : rel_base_t *ba = rel->r;
268 4081142 : (void)no_tname;
269 4081142 : node *n = t ? ol_find_name(t->columns, cname) : NULL;
270 4081142 : if (!n)
271 3246479 : return NULL;
272 834663 : 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 1402648 : rel_base_bind_column2( mvc *sql, sql_rel *rel, const char *tname, const char *cname)
292 : {
293 1402648 : sql_table *t = rel->l;
294 1402648 : rel_base_t *ba = rel->r;
295 :
296 1402648 : assert(ba);
297 1402648 : if ((ba->name && strcmp(ba->name, tname) != 0) || (!ba->name && strcmp(t->base.name, tname) != 0))
298 : return NULL;
299 685291 : node *n = ol_find_name(t->columns, cname);
300 685291 : if (!n)
301 : return NULL;
302 685286 : sql_column *c = n->data;
303 685286 : 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 105082 : rel_base_projection( mvc *sql, sql_rel *rel, int intern)
317 : {
318 105082 : int i = 0;
319 105082 : sql_table *t = rel->l;
320 105082 : rel_base_t *ba = rel->r;
321 105082 : char *name = ba->name?ba->name:t->base.name;
322 105082 : list *exps = new_exp_list(sql->sa);
323 105082 : prop *p;
324 :
325 775599 : for (node *cn = ol_first_node(t->columns); cn; cn = cn->next, i++) {
326 670517 : if (rel_base_is_used(ba, i)) {
327 670413 : sql_exp *e = bind_col_exp(sql, ba, name, cn->data);
328 670407 : append(exps, e);
329 : }
330 : }
331 105082 : if ((intern && rel_base_is_used(ba, i)) || list_empty(exps)) { /* Add TID column if no column is used */
332 79940 : sql_exp *e = exp_column(sql->sa, name, TID, sql_bind_localtype("oid"), CARD_MULTI, 0, 1, 1);
333 79940 : e->nid = -(ba->basenr + i);
334 79940 : e->alias.label = e->nid;
335 79940 : append(exps, e);
336 : }
337 105082 : i++;
338 105082 : if (intern) {
339 79940 : int j = i;
340 111857 : for (node *in = ol_first_node(t->idxs); in; in = in->next, j++) {
341 31917 : if (rel_base_is_used(ba, j)) {
342 31917 : sql_idx *i = in->data;
343 31917 : sql_subtype *t = sql_bind_localtype("lng"); /* hash "lng" */
344 31917 : int has_nils = 0, unique;
345 :
346 31917 : if ((hash_index(i->type) && list_length(i->columns) <= 1) || !idx_has_column(i->type))
347 31010 : 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 105082 : return exps;
376 : }
377 :
378 : list *
379 14213 : rel_base_project_all( mvc *sql, sql_rel *rel, char *tname)
380 : {
381 14213 : sql_table *t = rel->l;
382 14213 : rel_base_t *ba = rel->r;
383 14213 : char *name = ba->name?ba->name:t->base.name;
384 14213 : list *exps = new_exp_list(sql->sa);
385 :
386 14213 : if (!exps || strcmp(name, tname) != 0)
387 : return NULL;
388 :
389 154869 : for (node *cn = ol_first_node(t->columns); cn; cn = cn->next)
390 140702 : append(exps, bind_col( sql, rel, name, cn->data));
391 : return exps;
392 : }
393 :
394 : sql_rel *
395 517 : rel_base_add_columns( mvc *sql, sql_rel *r)
396 : {
397 517 : sql_table *t = r->l;
398 517 : rel_base_t *ba = r->r;
399 :
400 517 : r->exps = new_exp_list(sql->sa);
401 517 : if(!r->exps) {
402 0 : rel_destroy(r);
403 0 : return NULL;
404 : }
405 :
406 517 : int i = 0;
407 517 : prop *p = NULL;
408 517 : node *cn;
409 517 : const char *tname = t->base.name;
410 517 : const char *atname = ba->name?ba->name:tname;
411 :
412 1547 : for (cn = ol_first_node(t->columns); cn; cn = cn->next, i++) {
413 1030 : sql_column *c = cn->data;
414 1030 : 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 1030 : if (e == NULL) {
417 0 : rel_destroy(r);
418 0 : return NULL;
419 : }
420 1030 : e->nid = -(ba->basenr + i);
421 1030 : e->alias.label = e->nid;
422 1030 : 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 1030 : } 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 1030 : set_basecol(e);
430 1030 : sql_column_get_statistics(sql, c, e);
431 1030 : append(r->exps, e);
432 : }
433 : return r;
434 : }
435 :
436 : sql_rel *
437 2487967 : rewrite_basetable(mvc *sql, sql_rel *rel)
438 : {
439 2487967 : if (is_basetable(rel->op) && !rel->exps) {
440 455814 : allocator *sa = sql->sa;
441 455814 : sql_table *t = rel->l;
442 455814 : rel_base_t *ba = rel->r;
443 :
444 455814 : rel->exps = new_exp_list(sa);
445 455812 : if(!rel->exps) {
446 0 : rel_destroy(rel);
447 0 : return NULL;
448 : }
449 :
450 455812 : int i = 0;
451 455812 : prop *p = NULL;
452 455812 : node *cn;
453 455812 : const char *tname = t->base.name;
454 455812 : const char *atname = ba->name?ba->name:tname;
455 :
456 455812 : if (isRemote(t))
457 287 : tname = mapiuri_table(t->query, sql->sa, tname);
458 3236006 : for (cn = ol_first_node(t->columns); cn; cn = cn->next, i++) {
459 2780194 : if (!rel_base_is_used(ba, i))
460 1044036 : continue;
461 :
462 1736158 : sql_column *c = cn->data;
463 1736158 : 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 1736118 : if (e == NULL) {
466 0 : rel_destroy(rel);
467 0 : return NULL;
468 : }
469 1736118 : e->nid = -(ba->basenr + i);
470 1736118 : e->alias.label = e->nid;
471 1736118 : if (c->t->pkey && ((sql_kc*)c->t->pkey->k.columns->h->data)->c == c) {
472 58216 : p = e->p = prop_create(sa, PROP_HASHCOL, e->p);
473 58216 : p->value.pval = c->t->pkey;
474 1677902 : } else if (c->unique == 2) {
475 12155 : p = e->p = prop_create(sa, PROP_HASHCOL, e->p);
476 12155 : p->value.pval = NULL;
477 : }
478 1736118 : set_basecol(e);
479 1736118 : sql_column_get_statistics(sql, c, e);
480 1736166 : append(rel->exps, e);
481 : }
482 455812 : if (rel_base_is_used(ba, i) || list_empty(rel->exps)) { /* Add TID column if no column is used */
483 455812 : sql_exp *e = exp_alias(sql, atname, TID, tname, TID, sql_bind_localtype("oid"), CARD_MULTI, 0, 1, 1);
484 455806 : if (e == NULL) {
485 0 : rel_destroy(rel);
486 0 : return NULL;
487 : }
488 455806 : e->nid = -(ba->basenr + i);
489 455806 : e->alias.label = e->nid;
490 455806 : append(rel->exps, e);
491 : }
492 455804 : i++;
493 455804 : int j = i;
494 578939 : for (cn = ol_first_node(t->idxs); cn; cn = cn->next, j++) {
495 123135 : if (!rel_base_is_used(ba, j))
496 0 : continue;
497 :
498 123135 : sql_exp *e;
499 123135 : sql_idx *i = cn->data;
500 123135 : sql_subtype *t;
501 123135 : char *iname = NULL;
502 123135 : int has_nils = 0, unique;
503 :
504 : /* do not include empty indices in the plan */
505 123135 : if ((hash_index(i->type) && list_length(i->columns) <= 1) || !idx_has_column(i->type))
506 105089 : continue;
507 :
508 18045 : t = (i->type == join_idx) ? sql_bind_localtype("oid") : sql_bind_localtype("lng");
509 18045 : iname = sa_strconcat( sa, "%", i->base.name);
510 39791 : for (node *n = i->columns->h ; n && !has_nils; n = n->next) { /* check for NULL values */
511 21746 : sql_kc *kc = n->data;
512 :
513 21746 : if (kc->c->null)
514 13227 : has_nils = 1;
515 : }
516 18045 : unique = list_length(i->columns) == 1 && is_column_unique(((sql_kc*)i->columns->h->data)->c);
517 18045 : e = exp_alias(sql, atname, iname, tname, iname, t, CARD_MULTI, has_nils, unique, 1);
518 18045 : if (e == NULL) {
519 0 : rel_destroy(rel);
520 0 : return NULL;
521 : }
522 : /* index names are prefixed, to make them independent */
523 18045 : if (hash_index(i->type)) {
524 10067 : p = e->p = prop_create(sa, PROP_HASHIDX, e->p);
525 10067 : p->value.pval = i;
526 : }
527 18045 : 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 18045 : e->nid = -(ba->basenr + j);
532 18045 : e->alias.label = e->nid;
533 18045 : append(rel->exps, e);
534 : }
535 : }
536 : return rel;
537 : }
538 :
539 : sql_exp *
540 1039 : basetable_get_tid_or_add_it(mvc *sql, sql_rel *rel)
541 : {
542 1039 : sql_exp *res = NULL;
543 :
544 1039 : if (is_basetable(rel->op)) {
545 1039 : sql_table *t = rel->l;
546 1039 : rel_base_t *ba = rel->r;
547 1039 : const char *tname = t->base.name;
548 1039 : const char *atname = ba->name?ba->name:tname;
549 :
550 1039 : if (isRemote(t))
551 0 : tname = mapiuri_table(t->query, sql->sa, tname);
552 1039 : if (!rel->exps) { /* no exps yet, just set TID */
553 1012 : rel_base_use_tid(sql, rel);
554 1012 : res = exp_alias(sql, atname, TID, tname, TID, sql_bind_localtype("oid"), CARD_MULTI, 0, 1, 1);
555 1012 : res->nid = -(ba->basenr + ol_length(t->columns));
556 1012 : 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 1039 : return res;
580 : }
581 :
582 : sql_rel *
583 550 : rel_rename_part(mvc *sql, sql_rel *p, sql_rel *mt_rel, const char *mtalias)
584 : {
585 550 : sql_exp *ne = NULL;
586 550 : sql_table *mt = rel_base_table(mt_rel), *t = rel_base_table(p);
587 550 : rel_base_t *mt_ba = mt_rel->r, *p_ba = p->r;
588 550 : p_ba->basenr = mt_ba->basenr;
589 :
590 550 : assert(!p->exps);
591 550 : p->exps = sa_list(sql->sa);
592 550 : const char *pname = t->base.name;
593 550 : if (isRemote(t))
594 37 : pname = mapiuri_table(t->query, sql->sa, pname);
595 1482 : for (node *n = mt_rel->exps->h; n; n = n->next) {
596 932 : sql_exp *e = n->data;
597 932 : node *cn = NULL, *ci = NULL;
598 932 : const char *nname = e->r;
599 :
600 932 : 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 879 : } else if (nname[0] != '%' && (cn = ol_find_name(mt->columns, nname))) {
606 877 : 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 877 : ne = exp_alias(sql, mtalias, exp_name(e), pname, rc->base.name, &rc->type, CARD_MULTI, rc->null, is_column_unique(rc), 0);
610 877 : 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 858 : } 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 877 : set_basecol(ne);
618 877 : sql_column_get_statistics(sql, c, ne);
619 877 : rel_base_use(sql, p, rc->colnr);
620 877 : list_append(p->exps, ne);
621 877 : ne->nid = e->nid;
622 877 : 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 550 : rel_base_set_mergetable(p, mt);
655 550 : 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 550 : rel_base_set_mergetable(sql_rel *rel, sql_table *mt)
711 : {
712 550 : rel_base_t *ba = rel->r;
713 :
714 550 : if (ba)
715 550 : ba->mt = mt;
716 550 : }
717 :
718 : sql_table *
719 172570 : rel_base_get_mergetable(sql_rel *rel)
720 : {
721 172570 : rel_base_t *ba = rel->r;
722 :
723 172570 : return ba ? ba->mt : NULL;
724 : }
|