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 : sql_alias *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 : sql_alias *
44 214612 : rel_base_name(sql_rel *r)
45 : {
46 214612 : rel_base_t *ba = r->r;
47 214612 : if (ba->name)
48 : return ba->name;
49 : return NULL;
50 : }
51 :
52 : sql_alias *
53 0 : rel_base_rename(sql_rel *r, sql_alias *name)
54 : {
55 0 : rel_base_t *ba = r->r;
56 0 : assert(ba->name);
57 0 : ba->name->name = name->name;
58 0 : ba->name->parent = name->parent;
59 0 : return name;
60 : }
61 :
62 : int
63 1050 : rel_base_idx_nid(sql_rel *r, sql_idx *i)
64 : {
65 1050 : rel_base_t *ba = r->r;
66 1050 : sql_table *b = r->l;
67 1050 : if (i) {
68 1050 : int j = ba->basenr + ol_length(b->columns) + 1;
69 1120 : for (node *in = ol_first_node(i->t->idxs); in; in = in->next, j++) {
70 1120 : if (i == in->data)
71 1050 : return -(ba->basenr + j);
72 : }
73 : }
74 : return 0;
75 : }
76 :
77 : sql_column*
78 308441 : rel_base_find_column(sql_rel *r, int nid)
79 : {
80 308441 : rel_base_t *ba = r->r;
81 308441 : sql_table *b = r->l;
82 308441 : nid = -nid;
83 308441 : if ((nid - ba->basenr) >= ol_length(b->columns))
84 : return NULL;
85 210336 : return ol_fetch(b->columns, nid - ba->basenr);
86 : }
87 :
88 : int
89 35000 : rel_base_nid(sql_rel *r, sql_column *c)
90 : {
91 35000 : rel_base_t *ba = r->r;
92 35000 : sql_table *b = r->l;
93 35000 : if (c)
94 24111 : return -(ba->basenr + c->colnr);
95 10889 : return -(ba->basenr + ol_length(b->columns));
96 : }
97 :
98 : bool
99 1920417 : rel_base_has_nid(sql_rel *r, int nid)
100 : {
101 1920417 : rel_base_t *ba = r->r;
102 1920417 : sql_table *b = r->l;
103 :
104 1920417 : nid = -nid;
105 1920417 : return (nid >= ba->basenr && nid <= ba->basenr + ol_length(b->columns));
106 : }
107 :
108 : int
109 1785851 : rel_base_use( mvc *sql, sql_rel *rt, int nr)
110 : {
111 1785851 : assert(is_basetable(rt->op));
112 1785851 : sql_table *t = rt->l;
113 1785851 : rel_base_t *ba = rt->r;
114 :
115 1785851 : if (ba->disallowed && nr < ol_length(t->columns)) {
116 34 : sql_column *c = ol_fetch(t->columns, nr);
117 34 : if (!column_privs(sql, c, PRIV_SELECT))
118 : return -1;
119 : }
120 1785834 : rel_base_set_used(ba, nr);
121 1785834 : return 0;
122 : }
123 :
124 : void
125 8043 : rel_base_use_tid( mvc *sql, sql_rel *rt)
126 : {
127 8043 : sql_table *t = rt->l;
128 8043 : rel_base_use(sql, rt, ol_length(t->columns));
129 8043 : }
130 :
131 : void
132 399413 : rel_base_use_all( mvc *sql, sql_rel *rel)
133 : {
134 399413 : sql_table *t = rel->l;
135 399413 : rel_base_t *ba = rel->r;
136 :
137 399413 : if (ba->disallowed) {
138 10 : int i = 0;
139 33 : for (node *cn = ol_first_node(t->columns); cn; cn = cn->next, i++) {
140 23 : sql_column *c = cn->data;
141 23 : if (!column_privs(sql, c, PRIV_SELECT))
142 12 : continue;
143 11 : rel_base_set_used(ba, i);
144 : }
145 : } else {
146 399403 : int len = USED_LEN(ol_length(t->columns) + 1 + ol_length(t->idxs));
147 803219 : for (int i = 0; i < len; i++)
148 403518 : ba->used[i] = ~0U;
149 : }
150 399711 : }
151 :
152 : static rel_base_t* rel_nested_basetable_add_cols(mvc *sql, rel_base_t *pba, char *colname, sql_table *t, list *exps);
153 :
154 : static node *
155 169 : rel_nested_basetable_add_ccols(mvc *sql, rel_base_t *ba, sql_column *c, node *cn, list *exps)
156 : {
157 169 : sql_alias *atname = a_create(sql->sa, c->base.name);
158 169 : atname->parent = ba->name;
159 169 : int i = sql->nid;
160 169 : prop *p = NULL;
161 169 : sql_exp *e = NULL;
162 :
163 169 : sql->nid += list_length(c->type.type->d.fields);
164 533 : for (node *n = c->type.type->d.fields->h; n && cn; n = n->next, i++) {
165 364 : sql_column *c = cn->data;
166 364 : if (!column_privs(sql, c, PRIV_SELECT))
167 0 : continue;
168 364 : if (c->type.multiset) {
169 62 : e = exp_alias(sql, atname, c->base.name, atname, c->base.name, &c->type, CARD_MULTI, c->null, is_column_unique(c), 1);
170 62 : prop *p = p = prop_create(sql->sa, PROP_NESTED, e->p);
171 62 : p->value.pval = c;
172 62 : e->p = p;
173 62 : if (e)
174 62 : e->f = sa_list(sql->sa);
175 62 : if (!e || !e->f)
176 : return NULL;
177 62 : sql_table *t = mvc_bind_table(sql, c->t->s, c->storage_type);
178 62 : if (rel_nested_basetable_add_cols(sql, ba, c->base.name, t, e->f) == NULL)
179 0 : e = NULL;
180 62 : cn = cn->next;
181 302 : } else if (c->type.type->composite) {
182 36 : e = exp_alias(sql, atname, c->base.name, atname, c->base.name, &c->type, CARD_MULTI, c->null, is_column_unique(c), 0);
183 36 : if (e)
184 36 : e->f = sa_list(sql->sa);
185 36 : if (!e || !e->f)
186 0 : return NULL;
187 36 : cn = rel_nested_basetable_add_ccols(sql, ba, c, cn->next, e->f);
188 : } else {
189 266 : e = exp_alias(sql, atname, c->base.name, atname, c->base.name, &c->type, CARD_MULTI, c->null, is_column_unique(c), 1);
190 266 : cn = cn->next;
191 : }
192 364 : if (e == NULL)
193 : return NULL;
194 364 : e->nid = -(i);
195 364 : e->alias.label = e->nid;
196 364 : if (c->t->pkey && ((sql_kc*)c->t->pkey->k.columns->h->data)->c == c) {
197 0 : p = e->p = prop_create(sql->sa, PROP_HASHCOL, e->p);
198 0 : p->value.pval = c->t->pkey;
199 364 : } else if (c->unique == 2) {
200 0 : p = e->p = prop_create(sql->sa, PROP_HASHCOL, e->p);
201 0 : p->value.pval = NULL;
202 : }
203 364 : set_intern(e);
204 364 : set_basecol(e);
205 364 : sql_column_get_statistics(sql, c, e);
206 364 : append(exps, e);
207 : }
208 : return cn;
209 : }
210 :
211 : static rel_base_t*
212 121 : rel_nested_basetable_add_cols(mvc *sql, rel_base_t *pba, char *colname, sql_table *t, list *exps)
213 : {
214 121 : allocator *sa = sql->sa;
215 121 : int nrcols = ol_length(t->columns), end = nrcols + 1 + ol_length(t->idxs);
216 121 : rel_base_t *ba = (rel_base_t*)sa_zalloc(sa, sizeof(rel_base_t) + sizeof(int)*USED_LEN(end));
217 :
218 121 : ba->basenr = sql->nid;
219 121 : sql->nid += end;
220 :
221 121 : if (!ba)
222 : return NULL;
223 :
224 121 : sql_alias *atname = a_create(sa, colname);
225 121 : atname->parent = ba->name;
226 121 : int i = 0;
227 121 : prop *p = NULL;
228 121 : sql_exp *e = NULL;
229 519 : for (node *cn = ol_first_node(t->columns); cn; i++) {
230 398 : sql_column *c = cn->data;
231 398 : if (!column_privs(sql, c, PRIV_SELECT))
232 0 : continue;
233 398 : if (c->type.multiset) {
234 8 : e = exp_alias(sql, atname, c->base.name, atname, c->base.name, &c->type, CARD_MULTI, c->null, is_column_unique(c), 1);
235 8 : prop *p = p = prop_create(sql->sa, PROP_NESTED, e->p);
236 8 : p->value.pval = c;
237 8 : e->p = p;
238 8 : if (e)
239 8 : e->f = sa_list(sql->sa);
240 8 : if (!e || !e->f)
241 : return NULL;
242 8 : sql_table *t = mvc_bind_table(sql, c->t->s, c->storage_type);
243 8 : if (rel_nested_basetable_add_cols(sql, pba, c->base.name, t, e->f) == NULL)
244 0 : e = NULL;
245 8 : cn = cn->next;
246 390 : } else if (c->type.type->composite) {
247 48 : e = exp_alias(sql, atname, c->base.name, atname, c->base.name, &c->type, CARD_MULTI, c->null, is_column_unique(c), 0);
248 48 : if (e)
249 48 : e->f = sa_list(sql->sa);
250 48 : if (!e || !e->f)
251 0 : return NULL;
252 48 : cn = rel_nested_basetable_add_ccols(sql, ba, c, cn->next, e->f);
253 : } else {
254 342 : e = exp_alias(sql, atname, c->base.name, atname, c->base.name, &c->type, CARD_MULTI, c->null, is_column_unique(c), 1);
255 342 : cn = cn->next;
256 : }
257 398 : if (e == NULL)
258 : return NULL;
259 398 : e->nid = -(ba->basenr + i);
260 398 : e->alias.label = e->nid;
261 398 : if (c->t->pkey && ((sql_kc*)c->t->pkey->k.columns->h->data)->c == c) {
262 0 : p = e->p = prop_create(sa, PROP_HASHCOL, e->p);
263 0 : p->value.pval = c->t->pkey;
264 398 : } else if (c->unique == 2) {
265 0 : p = e->p = prop_create(sa, PROP_HASHCOL, e->p);
266 0 : p->value.pval = NULL;
267 : }
268 398 : set_intern(e);
269 398 : set_basecol(e);
270 398 : sql_column_get_statistics(sql, c, e);
271 398 : append(exps, e);
272 : }
273 : return ba;
274 : }
275 :
276 : static sql_rel *
277 122 : rel_nested_basetable(mvc *sql, sql_table *t, sql_alias *atname)
278 : {
279 122 : allocator *sa = sql->sa;
280 122 : sql_rel *rel = rel_create(sa);
281 : /* keep all column exp's as one large list in the result already */
282 :
283 122 : int nrcols = ol_length(t->columns), end = nrcols + 1 + ol_length(t->idxs);
284 122 : rel_base_t *ba = (rel_base_t*)sa_zalloc(sa, sizeof(rel_base_t) + sizeof(int)*USED_LEN(end));
285 122 : sqlstore *store = sql->session->tr->store;
286 :
287 122 : if(!rel || !ba)
288 : return NULL;
289 :
290 122 : ba->basenr = sql->nid;
291 122 : sql->nid += end;
292 122 : if (isTable(t) && t->s && !isDeclaredTable(t)) /* count active rows only */
293 122 : set_count_prop(sql->sa, rel, (BUN)store->storage_api.count_del(sql->session->tr, t, CNT_ACTIVE));
294 122 : assert(atname);
295 122 : if (!a_cmp_obj_name(atname, t->base.name))
296 21 : ba->name = atname;
297 : else
298 101 : ba->name = table_alias(sql->sa, t, schema_alias(sql->sa, t->s));
299 122 : int i = 0;
300 122 : prop *p = NULL;
301 122 : rel->exps = new_exp_list(sa);
302 122 : sql_exp *e = NULL;
303 375 : for (node *cn = ol_first_node(t->columns); cn; i++) {
304 253 : sql_column *c = cn->data;
305 253 : if (!column_privs(sql, c, PRIV_SELECT))
306 0 : continue;
307 253 : if (c->type.multiset) {
308 51 : e = exp_alias(sql, atname, c->base.name, atname, c->base.name, &c->type, CARD_MULTI, c->null, is_column_unique(c), 0);
309 51 : prop *p = p = prop_create(sql->sa, PROP_NESTED, e->p);
310 51 : p->value.pval = c;
311 51 : e->p = p;
312 51 : if (e)
313 51 : e->f = sa_list(sql->sa);
314 51 : if (!e || !e->f)
315 : return NULL;
316 51 : sql_table *t = mvc_bind_table(sql, c->t->s, c->storage_type);
317 51 : if (rel_nested_basetable_add_cols(sql, ba, c->base.name, t, e->f) == NULL)
318 0 : e = NULL;
319 51 : cn = cn->next;
320 202 : } else if (c->type.type->composite) {
321 85 : e = exp_alias(sql, atname, c->base.name, atname, c->base.name, &c->type, CARD_MULTI, c->null, is_column_unique(c), 0);
322 85 : if (e)
323 85 : e->f = sa_list(sql->sa);
324 85 : if (!e || !e->f)
325 0 : return NULL;
326 85 : cn = rel_nested_basetable_add_ccols(sql, ba, c, cn->next, e->f);
327 : } else {
328 117 : e = exp_alias(sql, atname, c->base.name, atname, c->base.name, &c->type, CARD_MULTI, c->null, is_column_unique(c), 0);
329 117 : cn = cn->next;
330 : }
331 253 : if (e == NULL) {
332 0 : rel_destroy(rel);
333 0 : return NULL;
334 : }
335 253 : e->nid = -(ba->basenr + i);
336 253 : e->alias.label = e->nid;
337 253 : if (c->t->pkey && ((sql_kc*)c->t->pkey->k.columns->h->data)->c == c) {
338 0 : p = e->p = prop_create(sa, PROP_HASHCOL, e->p);
339 0 : p->value.pval = c->t->pkey;
340 253 : } else if (c->unique == 2) {
341 0 : p = e->p = prop_create(sa, PROP_HASHCOL, e->p);
342 0 : p->value.pval = NULL;
343 : }
344 253 : set_basecol(e);
345 253 : sql_column_get_statistics(sql, c, e);
346 253 : append(rel->exps, e);
347 : }
348 122 : e = exp_alias(sql, atname, TID, atname, TID, sql_bind_localtype("oid"), CARD_MULTI, 0, 1, 1);
349 122 : if (e == NULL) {
350 0 : rel_destroy(rel);
351 0 : return NULL;
352 : }
353 122 : e->nid = -(ba->basenr + i);
354 122 : e->alias.label = e->nid;
355 122 : append(rel->exps, e);
356 122 : i++;
357 : /* todo add idx's */
358 :
359 122 : rel->l = t;
360 122 : rel->r = ba;
361 122 : rel->op = op_basetable;
362 122 : rel->card = CARD_MULTI;
363 122 : rel->nrcols = nrcols;
364 122 : return rel;
365 : }
366 :
367 : sql_rel *
368 635524 : rel_basetable(mvc *sql, sql_table *t, sql_alias *atname)
369 : {
370 635524 : if (t->multiset || t->composite)
371 122 : return rel_nested_basetable(sql, t, atname);
372 635402 : allocator *sa = sql->sa;
373 635402 : sql_rel *rel = rel_create(sa);
374 635598 : int nrcols = ol_length(t->columns), end = nrcols + 1 + ol_length(t->idxs);
375 635692 : rel_base_t *ba = (rel_base_t*)sa_zalloc(sa, sizeof(rel_base_t) + sizeof(int)*USED_LEN(end));
376 635817 : sqlstore *store = sql->session->tr->store;
377 :
378 635817 : if(!rel || !ba)
379 : return NULL;
380 :
381 635817 : ba->basenr = sql->nid;
382 635817 : sql->nid += end;
383 635817 : if (isTable(t) && t->s && !isDeclaredTable(t)) /* count active rows only */
384 574485 : set_count_prop(sql->sa, rel, (BUN)store->storage_api.count_del(sql->session->tr, t, CNT_ACTIVE));
385 635678 : assert(atname);
386 635678 : if (!a_cmp_obj_name(atname, t->base.name))
387 256147 : ba->name = atname;
388 : else
389 379450 : ba->name = table_alias(sql->sa, t, schema_alias(sql->sa, t->s));
390 1427234 : for(int i = nrcols; i<end; i++)
391 791622 : rel_base_set_used(ba, i);
392 635612 : rel->l = t;
393 635612 : rel->r = ba;
394 635612 : rel->op = op_basetable;
395 635612 : rel->card = CARD_MULTI;
396 635612 : rel->nrcols = nrcols;
397 635612 : return rel;
398 : }
399 :
400 : void
401 55 : rel_base_copy(mvc *sql, sql_rel *in, sql_rel *out)
402 : {
403 55 : allocator *sa = sql->sa;
404 55 : sql_table *t = in->l;
405 55 : rel_base_t *ba = in->r;
406 :
407 55 : assert(is_basetable(in->op) && is_basetable(out->op));
408 55 : int nrcols = ol_length(t->columns), end = nrcols + 1 + ol_length(t->idxs);
409 55 : size_t bsize = sizeof(rel_base_t) + sizeof(uint32_t)*USED_LEN(end);
410 55 : rel_base_t *nba = (rel_base_t*)sa_alloc(sa, bsize);
411 :
412 55 : memcpy(nba, ba, bsize);
413 55 : if (ba->name)
414 55 : nba->name = a_create(sa, sa_strdup(sa, ba->name->name));
415 :
416 55 : out->l = t;
417 55 : out->r = nba;
418 55 : }
419 :
420 : sql_rel *
421 0 : rel_base_bind_column_( sql_rel *rel, const char *cname)
422 : {
423 0 : sql_table *t = rel->l;
424 0 : node *n = ol_find_name(t->columns, cname);
425 0 : if (n)
426 0 : return rel;
427 : return NULL;
428 : }
429 :
430 : static sql_exp *
431 2384654 : bind_col_exp(mvc *sql, rel_base_t *ba, sql_alias *name, sql_column *c)
432 : {
433 2384654 : prop *p = NULL;
434 2384654 : sql_exp *e = exp_column(sql->sa, name, c->base.name, &c->type, CARD_MULTI, c->null, is_column_unique(c), 0);
435 :
436 2384653 : if (e) {
437 2384653 : e->nid = -(ba->basenr + c->colnr);
438 2384653 : e->alias.label = e->nid;
439 : }
440 2384653 : if (c->type.type->composite && !c->type.multiset)
441 0 : e->virt = 1;
442 2384653 : if (c->t->pkey && ((sql_kc*)c->t->pkey->k.columns->h->data)->c == c) {
443 85516 : p = e->p = prop_create(sql->sa, PROP_HASHCOL, e->p);
444 85516 : p->value.pval = c->t->pkey;
445 2299137 : } else if (c->unique == 2) {
446 23313 : p = e->p = prop_create(sql->sa, PROP_HASHCOL, e->p);
447 23313 : p->value.pval = NULL;
448 : }
449 2384653 : set_basecol(e);
450 2384653 : sql_column_get_statistics(sql, c, e);
451 2384673 : return e;
452 : }
453 :
454 : static sql_exp *
455 1703112 : bind_col(mvc *sql, sql_rel *rel, sql_alias *name, sql_column *c )
456 : {
457 1703112 : if (!c || rel_base_use(sql, rel, c->colnr)) {
458 : /* error */
459 12 : return NULL;
460 : }
461 1703100 : return bind_col_exp(sql, rel->r, name, c);
462 : }
463 :
464 : sql_exp *
465 240 : rel_base_bind_colnr( mvc *sql, sql_rel *rel, int nr)
466 : {
467 240 : sql_table *t = rel->l;
468 240 : rel_base_t *ba = rel->r;
469 240 : return bind_col(sql, rel, ba->name, ol_fetch(t->columns, nr));
470 : }
471 :
472 : sql_exp *
473 0 : rel_base_find_label( mvc *sql, sql_rel *rel, int label)
474 : {
475 0 : sql_table *t = rel->l;
476 0 : rel_base_t *ba = rel->r;
477 :
478 0 : label = -label;
479 0 : int colnr = label - ba->basenr;
480 0 : if (colnr > ol_length(t->columns))
481 : return NULL;
482 0 : return rel_base_bind_colnr(sql, rel, colnr);
483 : }
484 :
485 : sql_exp *
486 4091302 : rel_base_bind_column( mvc *sql, sql_rel *rel, const char *cname, int no_tname)
487 : {
488 4091302 : sql_table *t = rel->l;
489 4091302 : rel_base_t *ba = rel->r;
490 4091302 : (void)no_tname;
491 4091302 : node *n = t ? ol_find_name(t->columns, cname) : NULL;
492 4091302 : if (!n)
493 3246581 : return NULL;
494 844721 : return bind_col(sql, rel, ba->name, n->data);
495 : }
496 :
497 : sql_rel *
498 0 : rel_base_bind_column2_( sql_rel *rel, const char *tname, const char *cname)
499 : {
500 0 : sql_table *t = rel->l;
501 0 : rel_base_t *ba = rel->r;
502 :
503 0 : assert(ba);
504 0 : if (ba->name && !a_cmp_obj_name(ba->name, tname))
505 : return NULL;
506 0 : node *n = ol_find_name(t->columns, cname);
507 0 : if (!n)
508 : return NULL;
509 : return rel;
510 : }
511 :
512 : sql_exp *
513 1408827 : rel_base_bind_column2( mvc *sql, sql_rel *rel, sql_alias *tname, const char *cname)
514 : {
515 1408827 : sql_table *t = rel->l;
516 1408827 : rel_base_t *ba = rel->r;
517 :
518 1408827 : assert(ba);
519 1408827 : if (ba->name && !a_match_obj(ba->name, tname)) { /* TODO handle more levels */
520 720093 : node *n = ol_find_name(t->columns, tname->name);
521 720093 : if (n) {
522 28 : sql_column *c = n->data;
523 28 : if (c->type.type->composite) {
524 0 : n = n->next;
525 0 : for(node *m = c->type.type->d.fields->h; m; m = m->next, n = n->next) {
526 0 : sql_arg *a = m->data;
527 0 : if (strcmp(a->name, cname) == 0) {
528 0 : c = n->data;
529 0 : return bind_col(sql, rel, ba->name, c);
530 : }
531 : }
532 : }
533 : }
534 : return NULL;
535 : }
536 688734 : node *n = ol_find_name(t->columns, cname);
537 688734 : if (!n)
538 : return NULL;
539 688729 : sql_column *c = n->data;
540 688729 : return bind_col(sql, rel, ba->name, c);
541 : }
542 :
543 : sql_exp *
544 0 : rel_base_bind_column3( mvc *sql, sql_rel *rel, sql_alias *tname, const char *cname)
545 : {
546 0 : sql_alias *name = rel_base_name(rel);
547 0 : if (!a_match(name, tname))
548 : return NULL;
549 0 : return rel_base_bind_column(sql, rel, cname, 0);
550 : }
551 :
552 : list *
553 105130 : rel_base_projection( mvc *sql, sql_rel *rel, int intern)
554 : {
555 105130 : int i = 0;
556 105130 : sql_table *t = rel->l;
557 105130 : rel_base_t *ba = rel->r;
558 105130 : sql_alias *name = ba->name;
559 105130 : list *exps = new_exp_list(sql->sa);
560 105137 : prop *p;
561 :
562 786812 : for (node *cn = ol_first_node(t->columns); cn; cn = cn->next, i++) {
563 681667 : if (rel_base_is_used(ba, i)) {
564 681562 : sql_exp *e = bind_col_exp(sql, ba, name, cn->data);
565 681567 : append(exps, e);
566 : }
567 : }
568 105145 : if ((intern && rel_base_is_used(ba, i)) || list_empty(exps)) { /* Add TID column if no column is used */
569 80359 : sql_exp *e = exp_column(sql->sa, name, TID, sql_bind_localtype("oid"), CARD_MULTI, 0, 1, 1);
570 80359 : e->nid = -(ba->basenr + i);
571 80359 : e->alias.label = e->nid;
572 80359 : append(exps, e);
573 : }
574 105145 : i++;
575 105145 : if (intern) {
576 80359 : int j = i;
577 112409 : for (node *in = ol_first_node(t->idxs); in; in = in->next, j++) {
578 32050 : if (rel_base_is_used(ba, j)) {
579 32050 : sql_idx *i = in->data;
580 32050 : sql_subtype *t = sql_bind_localtype("lng"); /* hash "lng" */
581 32050 : int has_nils = 0, unique;
582 :
583 32050 : if ((hash_index(i->type) && list_length(i->columns) <= 1) || !idx_has_column(i->type))
584 31137 : continue;
585 :
586 913 : if (i->type == join_idx)
587 767 : t = sql_bind_localtype("oid");
588 :
589 913 : char *iname = sa_strconcat( sql->sa, "%", i->base.name);
590 1970 : for (node *n = i->columns->h ; n && !has_nils; n = n->next) { /* check for NULL values */
591 1057 : sql_kc *kc = n->data;
592 :
593 1057 : if (kc->c->null)
594 725 : has_nils = 1;
595 : }
596 913 : unique = list_length(i->columns) == 1 && is_column_unique(((sql_kc*)i->columns->h->data)->c);
597 913 : sql_exp *e = exp_column(sql->sa, name, iname, t, CARD_MULTI, has_nils, unique, 1);
598 913 : e->nid = -(ba->basenr + j);
599 913 : e->alias.label = e->nid;
600 913 : if (hash_index(i->type)) {
601 146 : p = e->p = prop_create(sql->sa, PROP_HASHIDX, e->p);
602 146 : p->value.pval = i;
603 : }
604 913 : if (i->type == join_idx) {
605 767 : p = e->p = prop_create(sql->sa, PROP_JOINIDX, e->p);
606 767 : p->value.pval = i;
607 : }
608 913 : append(exps, e);
609 : }
610 : }
611 : }
612 105145 : return exps;
613 : }
614 :
615 : list *
616 14271 : rel_base_project_all( mvc *sql, sql_rel *rel, char *tname)
617 : {
618 14271 : sql_table *t = rel->l;
619 14271 : rel_base_t *ba = rel->r;
620 14271 : sql_alias *name = ba->name;
621 14271 : list *exps = new_exp_list(sql->sa);
622 :
623 14271 : if (!exps || !a_cmp_obj_name(name, tname))
624 46 : return NULL;
625 :
626 183647 : for (node *cn = ol_first_node(t->columns); cn; cn = cn->next)
627 169422 : append(exps, bind_col( sql, rel, name, cn->data));
628 : return exps;
629 : }
630 :
631 : sql_rel *
632 519 : rel_base_add_columns( mvc *sql, sql_rel *r)
633 : {
634 519 : sql_table *t = r->l;
635 519 : rel_base_t *ba = r->r;
636 :
637 519 : r->exps = new_exp_list(sql->sa);
638 519 : if(!r->exps) {
639 0 : rel_destroy(r);
640 0 : return NULL;
641 : }
642 :
643 519 : int i = 0;
644 519 : prop *p = NULL;
645 519 : node *cn;
646 519 : sql_alias *ta = table_alias(sql->sa, t, NULL);
647 519 : sql_alias *atname = ba->name;
648 :
649 1553 : for (cn = ol_first_node(t->columns); cn; cn = cn->next, i++) {
650 1034 : sql_column *c = cn->data;
651 1034 : sql_exp *e = exp_alias(sql, atname, c->base.name, ta, c->base.name, &c->type, CARD_MULTI, c->null, is_column_unique(c), 0);
652 :
653 1034 : if (e == NULL) {
654 0 : rel_destroy(r);
655 0 : return NULL;
656 : }
657 1034 : e->nid = -(ba->basenr + i);
658 1034 : e->alias.label = e->nid;
659 1034 : if (c->t->pkey && ((sql_kc*)c->t->pkey->k.columns->h->data)->c == c) {
660 0 : p = e->p = prop_create(sql->sa, PROP_HASHCOL, e->p);
661 0 : p->value.pval = c->t->pkey;
662 1034 : } else if (c->unique == 2) {
663 0 : p = e->p = prop_create(sql->sa, PROP_HASHCOL, e->p);
664 0 : p->value.pval = NULL;
665 : }
666 1034 : set_basecol(e);
667 1034 : sql_column_get_statistics(sql, c, e);
668 1034 : append(r->exps, e);
669 : }
670 : return r;
671 : }
672 :
673 : sql_rel *
674 2188942 : rewrite_basetable(mvc *sql, sql_rel *rel)
675 : {
676 2188942 : if (is_basetable(rel->op) && !rel->exps) {
677 458999 : allocator *sa = sql->sa;
678 458999 : sql_table *t = rel->l;
679 458999 : rel_base_t *ba = rel->r;
680 :
681 458999 : rel->exps = new_exp_list(sa);
682 459098 : if(!rel->exps) {
683 0 : rel_destroy(rel);
684 0 : return NULL;
685 : }
686 :
687 459098 : int i = 0;
688 459098 : prop *p = NULL;
689 459098 : node *cn;
690 459098 : const char *tname = t->base.name;
691 459098 : sql_alias *atname = ba->name;
692 :
693 459098 : if (isRemote(t))
694 287 : tname = mapiuri_table(t->query, sql->sa, tname);
695 459098 : sql_alias *ta = a_create(sql->sa, tname);
696 3309704 : for (cn = ol_first_node(t->columns); cn; cn = cn->next, i++) {
697 2850517 : if (!rel_base_is_used(ba, i))
698 1064581 : continue;
699 :
700 1785936 : sql_column *c = cn->data;
701 1785936 : sql_exp *e = exp_alias(sql, atname, c->base.name, ta, c->base.name, &c->type, CARD_MULTI, c->null, is_column_unique(c), c->column_type == 16);
702 :
703 1786150 : if (e == NULL) {
704 0 : rel_destroy(rel);
705 0 : return NULL;
706 : }
707 1786150 : e->nid = -(ba->basenr + i);
708 1786150 : e->alias.label = e->nid;
709 1786150 : if (c->t->pkey && ((sql_kc*)c->t->pkey->k.columns->h->data)->c == c) {
710 58381 : p = e->p = prop_create(sa, PROP_HASHCOL, e->p);
711 58381 : p->value.pval = c->t->pkey;
712 1727769 : } else if (c->unique == 2) {
713 12197 : p = e->p = prop_create(sa, PROP_HASHCOL, e->p);
714 12197 : p->value.pval = NULL;
715 : }
716 1786150 : set_basecol(e);
717 1786150 : sql_column_get_statistics(sql, c, e);
718 1786620 : append(rel->exps, e);
719 : }
720 459187 : if (rel_base_is_used(ba, i) || list_empty(rel->exps)) { /* Add TID column if no column is used */
721 459187 : sql_exp *e = exp_alias(sql, atname, TID, ta, TID, sql_bind_localtype("oid"), CARD_MULTI, 0, 1, 1);
722 459229 : if (e == NULL) {
723 0 : rel_destroy(rel);
724 0 : return NULL;
725 : }
726 459229 : e->nid = -(ba->basenr + i);
727 459229 : e->alias.label = e->nid;
728 459229 : append(rel->exps, e);
729 : }
730 459243 : i++;
731 459243 : int j = i;
732 582471 : for (cn = ol_first_node(t->idxs); cn; cn = cn->next, j++) {
733 123372 : if (!rel_base_is_used(ba, j))
734 0 : continue;
735 :
736 123372 : sql_exp *e;
737 123372 : sql_idx *i = cn->data;
738 123372 : sql_subtype *t;
739 123372 : char *iname = NULL;
740 123372 : int has_nils = 0, unique;
741 :
742 : /* do not include empty indices in the plan */
743 123372 : if ((hash_index(i->type) && list_length(i->columns) <= 1) || !idx_has_column(i->type))
744 105327 : continue;
745 :
746 18045 : t = (i->type == join_idx) ? sql_bind_localtype("oid") : sql_bind_localtype("lng");
747 18045 : iname = sa_strconcat( sa, "%", i->base.name);
748 39791 : for (node *n = i->columns->h ; n && !has_nils; n = n->next) { /* check for NULL values */
749 21746 : sql_kc *kc = n->data;
750 :
751 21746 : if (kc->c->null)
752 13227 : has_nils = 1;
753 : }
754 18045 : unique = list_length(i->columns) == 1 && is_column_unique(((sql_kc*)i->columns->h->data)->c);
755 18045 : e = exp_alias(sql, atname, iname, ta, iname, t, CARD_MULTI, has_nils, unique, 1);
756 18045 : if (e == NULL) {
757 0 : rel_destroy(rel);
758 0 : return NULL;
759 : }
760 : /* index names are prefixed, to make them independent */
761 18045 : if (hash_index(i->type)) {
762 10067 : p = e->p = prop_create(sa, PROP_HASHIDX, e->p);
763 10067 : p->value.pval = i;
764 : }
765 18045 : if (i->type == join_idx) {
766 7978 : p = e->p = prop_create(sa, PROP_JOINIDX, e->p);
767 7978 : p->value.pval = i;
768 : }
769 18045 : e->nid = -(ba->basenr + j);
770 18045 : e->alias.label = e->nid;
771 18045 : append(rel->exps, e);
772 : }
773 : }
774 : return rel;
775 : }
776 :
777 : sql_exp *
778 1039 : basetable_get_tid_or_add_it(mvc *sql, sql_rel *rel)
779 : {
780 1039 : sql_exp *res = NULL;
781 :
782 1039 : if (is_basetable(rel->op)) {
783 1039 : sql_table *t = rel->l;
784 1039 : rel_base_t *ba = rel->r;
785 1039 : const char *tname = t->base.name;
786 1039 : sql_alias *atname = ba->name;
787 :
788 1039 : if (isRemote(t))
789 0 : tname = mapiuri_table(t->query, sql->sa, tname);
790 1039 : sql_alias *ta = a_create(sql->sa, tname);
791 1039 : if (!rel->exps) { /* no exps yet, just set TID */
792 1012 : rel_base_use_tid(sql, rel);
793 1012 : res = exp_alias(sql, atname, TID, ta, TID, sql_bind_localtype("oid"), CARD_MULTI, 0, 1, 1);
794 1012 : res->nid = -(ba->basenr + ol_length(t->columns));
795 1012 : res->alias.label = res->nid;
796 27 : } else if (!rel_base_is_used(ba, ol_length(t->columns)) || /* exps set, but no TID, add it */
797 27 : !(res = exps_bind_column2(rel->exps, atname, TID, NULL))) { /* exps set with TID, but maybe rel_dce removed it */
798 0 : node *n = NULL;
799 0 : rel_base_use_tid(sql, rel);
800 0 : res = exp_alias(sql, atname, TID, ta, TID, sql_bind_localtype("oid"), CARD_MULTI, 0, 1, 1);
801 0 : res->nid = -(ba->basenr + ol_length(t->columns));
802 0 : res->alias.label = res->nid;
803 :
804 : /* search for indexes */
805 0 : for (node *cn = rel->exps->h; cn && !n; cn = cn->next) {
806 0 : sql_exp *e = cn->data;
807 :
808 0 : if (is_intern(e))
809 0 : n = cn;
810 : }
811 0 : if (n) { /* has indexes, insert TID before them */
812 0 : list_append_before(rel->exps, n, res);
813 : } else {
814 0 : list_append(rel->exps, res);
815 : }
816 : }
817 : }
818 1039 : return res;
819 : }
820 :
821 : sql_rel *
822 548 : rel_rename_part(mvc *sql, sql_rel *p, sql_rel *mt_rel, sql_alias *mtalias)
823 : {
824 548 : sql_exp *ne = NULL;
825 548 : sql_table *mt = rel_base_table(mt_rel), *t = rel_base_table(p);
826 548 : rel_base_t *mt_ba = mt_rel->r, *p_ba = p->r;
827 548 : p_ba->basenr = mt_ba->basenr;
828 :
829 548 : assert(!p->exps);
830 548 : p->exps = sa_list(sql->sa);
831 548 : const char *pname = t->base.name;
832 548 : if (isRemote(t))
833 37 : pname = mapiuri_table(t->query, sql->sa, pname);
834 548 : sql_alias *pa = a_create(sql->sa, pname);
835 1478 : for (node *n = mt_rel->exps->h; n; n = n->next) {
836 930 : sql_exp *e = n->data;
837 930 : node *cn = NULL, *ci = NULL;
838 930 : const char *nname = e->r;
839 :
840 930 : if (nname[0] == '%' && strcmp(nname, TID) == 0) {
841 53 : list_append(p->exps, ne=exp_alias(sql, mtalias, TID, pa, TID, sql_bind_localtype("oid"), CARD_MULTI, 0, 1, 1));
842 53 : ne->nid = e->nid;
843 53 : ne->alias.label = e->alias.label;
844 53 : rel_base_use_tid(sql, p);
845 877 : } else if (nname[0] != '%' && (cn = ol_find_name(mt->columns, nname))) {
846 875 : sql_column *c = cn->data, *rc = ol_fetch(t->columns, c->colnr);
847 :
848 : /* with name find column in merge table, with colnr find column in member */
849 875 : ne = exp_alias(sql, mtalias, exp_name(e), pa, rc->base.name, &rc->type, CARD_MULTI, rc->null, is_column_unique(rc), 0);
850 875 : if (rc->t->pkey && ((sql_kc*)rc->t->pkey->k.columns->h->data)->c == rc) {
851 19 : prop *p = ne->p = prop_create(sql->sa, PROP_HASHCOL, ne->p);
852 19 : p->value.pval = rc->t->pkey;
853 856 : } else if (rc->unique == 2) {
854 0 : prop *p = ne->p = prop_create(sql->sa, PROP_HASHCOL, ne->p);
855 0 : p->value.pval = NULL;
856 : }
857 875 : set_basecol(ne);
858 875 : sql_column_get_statistics(sql, c, ne);
859 875 : rel_base_use(sql, p, rc->colnr);
860 875 : list_append(p->exps, ne);
861 875 : ne->nid = e->nid;
862 875 : ne->alias.label = e->alias.label;
863 2 : } else if (nname[0] == '%' && ol_length(mt->idxs) && (ci = ol_find_name(mt->idxs, nname + 1))) {
864 2 : sql_idx *i = ci->data, *ri = NULL;
865 :
866 : /* indexes don't have a number field like 'colnr', so get the index the old way */
867 4 : for (node *nn = mt->idxs->l->h, *mm = t->idxs->l->h; nn && mm ; nn = nn->next, mm = mm->next) {
868 4 : sql_idx *ii = nn->data;
869 :
870 4 : if (ii->base.id == i->base.id) {
871 2 : ri = mm->data;
872 2 : break;
873 : }
874 : }
875 :
876 2 : assert((!hash_index(ri->type) || list_length(ri->columns) > 1) && idx_has_column(ri->type));
877 2 : sql_subtype *t = (ri->type == join_idx) ? sql_bind_localtype("oid") : sql_bind_localtype("lng");
878 2 : char *iname1 = sa_strconcat(sql->sa, "%", i->base.name), *iname2 = sa_strconcat(sql->sa, "%", ri->base.name);
879 :
880 2 : ne = exp_alias(sql, mtalias, iname1, pa, iname2, t, CARD_MULTI, has_nil(e), is_unique(e), 1);
881 : /* index names are prefixed, to make them independent */
882 2 : if (hash_index(ri->type)) {
883 0 : prop *p = ne->p = prop_create(sql->sa, PROP_HASHIDX, ne->p);
884 0 : p->value.pval = ri;
885 2 : } else if (ri->type == join_idx) {
886 2 : prop *p = ne->p = prop_create(sql->sa, PROP_JOINIDX, ne->p);
887 2 : p->value.pval = ri;
888 : }
889 2 : ne->nid = e->nid;
890 2 : ne->alias.label = e->alias.label;
891 2 : list_append(p->exps, ne);
892 : }
893 : }
894 548 : rel_base_set_mergetable(p, mt);
895 548 : return p;
896 : }
897 :
898 : void
899 0 : rel_base_dump_exps( stream *fout, sql_rel *rel)
900 : {
901 0 : int i = 0, comma = 0;
902 0 : sql_table *t = rel->l;
903 0 : rel_base_t *ba = rel->r;
904 0 : assert(ba);
905 0 : mnstr_printf(fout, "[ ");
906 0 : for (node *cn = ol_first_node(t->columns); cn; cn = cn->next, i++) {
907 0 : if (rel_base_is_used(ba, i)) {
908 0 : sql_column *c = cn->data;
909 0 : mnstr_printf(fout, "%s\"%s\".\"%s\"", comma?", ":"", t->base.name, c->base.name);
910 0 : if (ba->name)
911 0 : mnstr_printf(fout, " as \"%s\".\"%s\"", ba->name->name, c->base.name);
912 : comma = 1;
913 : }
914 : }
915 0 : if (rel_base_is_used(ba, i)) {
916 0 : mnstr_printf(fout, "%s\"%s\".\"%%TID%%\"", comma?", ":"", t->base.name);
917 0 : if (ba->name)
918 0 : mnstr_printf(fout, " as \"%s\".\"%%TID%%\"", ba->name->name);
919 : comma = 1;
920 : }
921 0 : i++;
922 0 : for (node *in = ol_first_node(t->idxs); in; in = in->next, i++) {
923 0 : if (rel_base_is_used(ba, i)) {
924 0 : sql_idx *i = in->data;
925 0 : mnstr_printf(fout, "%s\"%s\".\"%s\"", comma?", ":"", t->base.name, i->base.name);
926 0 : if (ba->name)
927 0 : mnstr_printf(fout, " as \"%s\".\"%s\"", ba->name->name, i->base.name);
928 : comma = 1;
929 : }
930 : }
931 0 : mnstr_printf(fout, " ]");
932 0 : }
933 :
934 : int
935 72 : rel_base_has_column_privileges(mvc *sql, sql_rel *rel)
936 : {
937 72 : sql_table *t = rel->l;
938 72 : int has = 0;
939 :
940 227 : for (node *m = ol_first_node(t->columns); m && !has; m = m->next) {
941 155 : sql_column *c = m->data;
942 :
943 155 : if (column_privs(sql, c, PRIV_SELECT))
944 33 : has = 1;
945 : }
946 72 : return has;
947 : }
948 :
949 : void
950 548 : rel_base_set_mergetable(sql_rel *rel, sql_table *mt)
951 : {
952 548 : rel_base_t *ba = rel->r;
953 :
954 548 : if (ba)
955 548 : ba->mt = mt;
956 548 : }
957 :
958 : sql_table *
959 105915 : rel_base_get_mergetable(sql_rel *rel)
960 : {
961 105915 : rel_base_t *ba = rel->r;
962 :
963 105915 : return ba ? ba->mt : NULL;
964 : }
|