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 213873 : rel_base_name(sql_rel *r)
45 : {
46 213873 : rel_base_t *ba = r->r;
47 213873 : 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 307735 : rel_base_find_column(sql_rel *r, int nid)
79 : {
80 307735 : rel_base_t *ba = r->r;
81 307735 : sql_table *b = r->l;
82 307735 : nid = -nid;
83 307735 : if ((nid - ba->basenr) >= ol_length(b->columns))
84 : return NULL;
85 209788 : return ol_fetch(b->columns, nid - ba->basenr);
86 : }
87 :
88 : int
89 34973 : rel_base_nid(sql_rel *r, sql_column *c)
90 : {
91 34973 : rel_base_t *ba = r->r;
92 34973 : sql_table *b = r->l;
93 34973 : if (c)
94 24102 : return -(ba->basenr + c->colnr);
95 10871 : return -(ba->basenr + ol_length(b->columns));
96 : }
97 :
98 : bool
99 1917858 : rel_base_has_nid(sql_rel *r, int nid)
100 : {
101 1917858 : rel_base_t *ba = r->r;
102 1917858 : sql_table *b = r->l;
103 :
104 1917858 : nid = -nid;
105 1917858 : return (nid >= ba->basenr && nid <= ba->basenr + ol_length(b->columns));
106 : }
107 :
108 : int
109 1780763 : rel_base_use( mvc *sql, sql_rel *rt, int nr)
110 : {
111 1780763 : assert(is_basetable(rt->op));
112 1780763 : sql_table *t = rt->l;
113 1780763 : rel_base_t *ba = rt->r;
114 :
115 1780763 : 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 1780746 : rel_base_set_used(ba, nr);
121 1780746 : return 0;
122 : }
123 :
124 : void
125 8034 : rel_base_use_tid( mvc *sql, sql_rel *rt)
126 : {
127 8034 : sql_table *t = rt->l;
128 8034 : rel_base_use(sql, rt, ol_length(t->columns));
129 8034 : }
130 :
131 : void
132 398591 : rel_base_use_all( mvc *sql, sql_rel *rel)
133 : {
134 398591 : sql_table *t = rel->l;
135 398591 : rel_base_t *ba = rel->r;
136 :
137 398591 : 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 398581 : int len = USED_LEN(ol_length(t->columns) + 1 + ol_length(t->idxs));
147 801672 : for (int i = 0; i < len; i++)
148 402749 : ba->used[i] = ~0U;
149 : }
150 398933 : }
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 66 : rel_nested_basetable_add_ccols(mvc *sql, rel_base_t *ba, sql_column *c, node *cn, list *exps)
156 : {
157 66 : sql_alias *atname = a_create(sql->sa, c->base.name);
158 66 : atname->parent = ba->name;
159 66 : int i = sql->nid;
160 66 : prop *p = NULL;
161 66 : sql_exp *e = NULL;
162 :
163 66 : sql->nid += list_length(c->type.type->d.fields);
164 245 : for (node *n = c->type.type->d.fields->h; n && cn; n = n->next, i++) {
165 179 : sql_column *c = cn->data;
166 179 : if (!column_privs(sql, c, PRIV_SELECT))
167 0 : continue;
168 179 : if (c->type.multiset) {
169 24 : e = exp_alias(sql, atname, c->base.name, atname, c->base.name, &c->type, CARD_MULTI, c->null, is_column_unique(c), 1);
170 24 : prop *p = p = prop_create(sql->sa, PROP_NESTED, e->p);
171 24 : p->value.pval = c;
172 24 : e->p = p;
173 24 : if (e)
174 24 : e->f = sa_list(sql->sa);
175 24 : if (!e || !e->f)
176 : return NULL;
177 24 : sql_table *t = mvc_bind_table(sql, c->t->s, c->storage_type);
178 24 : if (rel_nested_basetable_add_cols(sql, ba, c->base.name, t, e->f) == NULL)
179 0 : e = NULL;
180 24 : cn = cn->next;
181 155 : } else if (c->type.type->composite) {
182 12 : e = exp_alias(sql, atname, c->base.name, atname, c->base.name, &c->type, CARD_MULTI, c->null, is_column_unique(c), 0);
183 12 : if (e)
184 12 : e->f = sa_list(sql->sa);
185 12 : if (!e || !e->f)
186 0 : return NULL;
187 12 : cn = rel_nested_basetable_add_ccols(sql, ba, c, cn->next, e->f);
188 : } else {
189 143 : e = exp_alias(sql, atname, c->base.name, atname, c->base.name, &c->type, CARD_MULTI, c->null, is_column_unique(c), 1);
190 143 : cn = cn->next;
191 : }
192 179 : if (e == NULL)
193 : return NULL;
194 179 : e->nid = -(i);
195 179 : e->alias.label = e->nid;
196 179 : 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 179 : } 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 179 : set_intern(e);
204 179 : set_basecol(e);
205 179 : sql_column_get_statistics(sql, c, e);
206 179 : append(exps, e);
207 : }
208 : return cn;
209 : }
210 :
211 : static rel_base_t*
212 62 : rel_nested_basetable_add_cols(mvc *sql, rel_base_t *pba, char *colname, sql_table *t, list *exps)
213 : {
214 62 : allocator *sa = sql->sa;
215 62 : int nrcols = ol_length(t->columns), end = nrcols + 1 + ol_length(t->idxs);
216 62 : rel_base_t *ba = (rel_base_t*)sa_zalloc(sa, sizeof(rel_base_t) + sizeof(int)*USED_LEN(end));
217 :
218 62 : ba->basenr = sql->nid;
219 62 : sql->nid += end;
220 :
221 62 : if (!ba)
222 : return NULL;
223 :
224 62 : sql_alias *atname = a_create(sa, colname);
225 62 : atname->parent = ba->name;
226 62 : int i = 0;
227 62 : prop *p = NULL;
228 62 : sql_exp *e = NULL;
229 267 : for (node *cn = ol_first_node(t->columns); cn; i++) {
230 205 : sql_column *c = cn->data;
231 205 : if (!column_privs(sql, c, PRIV_SELECT))
232 0 : continue;
233 205 : 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 197 : } else if (c->type.type->composite) {
247 10 : e = exp_alias(sql, atname, c->base.name, atname, c->base.name, &c->type, CARD_MULTI, c->null, is_column_unique(c), 0);
248 10 : if (e)
249 10 : e->f = sa_list(sql->sa);
250 10 : if (!e || !e->f)
251 0 : return NULL;
252 10 : cn = rel_nested_basetable_add_ccols(sql, ba, c, cn->next, e->f);
253 : } else {
254 187 : e = exp_alias(sql, atname, c->base.name, atname, c->base.name, &c->type, CARD_MULTI, c->null, is_column_unique(c), 1);
255 187 : cn = cn->next;
256 : }
257 205 : if (e == NULL)
258 : return NULL;
259 205 : e->nid = -(ba->basenr + i);
260 205 : e->alias.label = e->nid;
261 205 : 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 205 : } 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 205 : set_intern(e);
269 205 : set_basecol(e);
270 205 : sql_column_get_statistics(sql, c, e);
271 205 : append(exps, e);
272 : }
273 : return ba;
274 : }
275 :
276 : static sql_rel *
277 74 : rel_nested_basetable(mvc *sql, sql_table *t, sql_alias *atname)
278 : {
279 74 : allocator *sa = sql->sa;
280 74 : sql_rel *rel = rel_create(sa);
281 : /* keep all column exp's as one large list in the result already */
282 :
283 74 : int nrcols = ol_length(t->columns), end = nrcols + 1 + ol_length(t->idxs);
284 74 : rel_base_t *ba = (rel_base_t*)sa_zalloc(sa, sizeof(rel_base_t) + sizeof(int)*USED_LEN(end));
285 74 : sqlstore *store = sql->session->tr->store;
286 :
287 74 : if(!rel || !ba)
288 : return NULL;
289 :
290 74 : ba->basenr = sql->nid;
291 74 : sql->nid += end;
292 74 : if (isTable(t) && t->s && !isDeclaredTable(t)) /* count active rows only */
293 74 : set_count_prop(sql->sa, rel, (BUN)store->storage_api.count_del(sql->session->tr, t, CNT_ACTIVE));
294 74 : assert(atname);
295 74 : if (!a_cmp_obj_name(atname, t->base.name))
296 8 : ba->name = atname;
297 : else
298 66 : ba->name = table_alias(sql->sa, t, schema_alias(sql->sa, t->s));
299 74 : int i = 0;
300 74 : prop *p = NULL;
301 74 : rel->exps = new_exp_list(sa);
302 74 : sql_exp *e = NULL;
303 182 : for (node *cn = ol_first_node(t->columns); cn; i++) {
304 108 : sql_column *c = cn->data;
305 108 : if (!column_privs(sql, c, PRIV_SELECT))
306 0 : continue;
307 108 : if (c->type.multiset) {
308 30 : e = exp_alias(sql, atname, c->base.name, atname, c->base.name, &c->type, CARD_MULTI, c->null, is_column_unique(c), 0);
309 30 : prop *p = p = prop_create(sql->sa, PROP_NESTED, e->p);
310 30 : p->value.pval = c;
311 30 : e->p = p;
312 30 : if (e)
313 30 : e->f = sa_list(sql->sa);
314 30 : if (!e || !e->f)
315 : return NULL;
316 30 : sql_table *t = mvc_bind_table(sql, c->t->s, c->storage_type);
317 30 : if (rel_nested_basetable_add_cols(sql, ba, c->base.name, t, e->f) == NULL)
318 0 : e = NULL;
319 30 : cn = cn->next;
320 78 : } else if (c->type.type->composite) {
321 44 : e = exp_alias(sql, atname, c->base.name, atname, c->base.name, &c->type, CARD_MULTI, c->null, is_column_unique(c), 0);
322 44 : if (e)
323 44 : e->f = sa_list(sql->sa);
324 44 : if (!e || !e->f)
325 0 : return NULL;
326 44 : cn = rel_nested_basetable_add_ccols(sql, ba, c, cn->next, e->f);
327 : } else {
328 34 : e = exp_alias(sql, atname, c->base.name, atname, c->base.name, &c->type, CARD_MULTI, c->null, is_column_unique(c), 0);
329 34 : cn = cn->next;
330 : }
331 108 : if (e == NULL) {
332 0 : rel_destroy(rel);
333 0 : return NULL;
334 : }
335 108 : e->nid = -(ba->basenr + i);
336 108 : e->alias.label = e->nid;
337 108 : 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 108 : } 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 108 : set_basecol(e);
345 108 : sql_column_get_statistics(sql, c, e);
346 108 : append(rel->exps, e);
347 : }
348 74 : e = exp_alias(sql, atname, TID, atname, TID, sql_bind_localtype("oid"), CARD_MULTI, 0, 1, 1);
349 74 : if (e == NULL) {
350 0 : rel_destroy(rel);
351 0 : return NULL;
352 : }
353 74 : e->nid = -(ba->basenr + i);
354 74 : e->alias.label = e->nid;
355 74 : append(rel->exps, e);
356 74 : i++;
357 : /* todo add idx's */
358 :
359 74 : rel->l = t;
360 74 : rel->r = ba;
361 74 : rel->op = op_basetable;
362 74 : rel->card = CARD_MULTI;
363 74 : rel->nrcols = nrcols;
364 74 : return rel;
365 : }
366 :
367 : sql_rel *
368 634115 : rel_basetable(mvc *sql, sql_table *t, sql_alias *atname)
369 : {
370 634115 : if (t->multiset || t->composite)
371 74 : return rel_nested_basetable(sql, t, atname);
372 634041 : allocator *sa = sql->sa;
373 634041 : sql_rel *rel = rel_create(sa);
374 634268 : int nrcols = ol_length(t->columns), end = nrcols + 1 + ol_length(t->idxs);
375 634340 : rel_base_t *ba = (rel_base_t*)sa_zalloc(sa, sizeof(rel_base_t) + sizeof(int)*USED_LEN(end));
376 634462 : sqlstore *store = sql->session->tr->store;
377 :
378 634462 : if(!rel || !ba)
379 : return NULL;
380 :
381 634462 : ba->basenr = sql->nid;
382 634462 : sql->nid += end;
383 634462 : if (isTable(t) && t->s && !isDeclaredTable(t)) /* count active rows only */
384 573368 : set_count_prop(sql->sa, rel, (BUN)store->storage_api.count_del(sql->session->tr, t, CNT_ACTIVE));
385 634302 : assert(atname);
386 634302 : if (!a_cmp_obj_name(atname, t->base.name))
387 255265 : ba->name = atname;
388 : else
389 378974 : ba->name = table_alias(sql->sa, t, schema_alias(sql->sa, t->s));
390 1424372 : for(int i = nrcols; i<end; i++)
391 790075 : rel_base_set_used(ba, i);
392 634297 : rel->l = t;
393 634297 : rel->r = ba;
394 634297 : rel->op = op_basetable;
395 634297 : rel->card = CARD_MULTI;
396 634297 : rel->nrcols = nrcols;
397 634297 : 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 2379719 : bind_col_exp(mvc *sql, rel_base_t *ba, sql_alias *name, sql_column *c)
432 : {
433 2379719 : prop *p = NULL;
434 2379719 : sql_exp *e = exp_column(sql->sa, name, c->base.name, &c->type, CARD_MULTI, c->null, is_column_unique(c), 0);
435 :
436 2379723 : if (e) {
437 2379723 : e->nid = -(ba->basenr + c->colnr);
438 2379723 : e->alias.label = e->nid;
439 : }
440 2379723 : if (c->type.type->composite && !c->type.multiset)
441 0 : e->virt = 1;
442 2379723 : if (c->t->pkey && ((sql_kc*)c->t->pkey->k.columns->h->data)->c == c) {
443 85329 : p = e->p = prop_create(sql->sa, PROP_HASHCOL, e->p);
444 85329 : p->value.pval = c->t->pkey;
445 2294394 : } else if (c->unique == 2) {
446 23236 : p = e->p = prop_create(sql->sa, PROP_HASHCOL, e->p);
447 23236 : p->value.pval = NULL;
448 : }
449 2379723 : set_basecol(e);
450 2379723 : sql_column_get_statistics(sql, c, e);
451 2379729 : return e;
452 : }
453 :
454 : static sql_exp *
455 1698126 : bind_col(mvc *sql, sql_rel *rel, sql_alias *name, sql_column *c )
456 : {
457 1698126 : if (!c || rel_base_use(sql, rel, c->colnr)) {
458 : /* error */
459 12 : return NULL;
460 : }
461 1698114 : 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 4089338 : rel_base_bind_column( mvc *sql, sql_rel *rel, const char *cname, int no_tname)
487 : {
488 4089338 : sql_table *t = rel->l;
489 4089338 : rel_base_t *ba = rel->r;
490 4089338 : (void)no_tname;
491 4089338 : node *n = t ? ol_find_name(t->columns, cname) : NULL;
492 4089338 : if (!n)
493 3246515 : return NULL;
494 842823 : 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 1403837 : rel_base_bind_column2( mvc *sql, sql_rel *rel, sql_alias *tname, const char *cname)
514 : {
515 1403837 : sql_table *t = rel->l;
516 1403837 : rel_base_t *ba = rel->r;
517 :
518 1403837 : assert(ba);
519 1403837 : if (ba->name && !a_match_obj(ba->name, tname)) { /* TODO handle more levels */
520 717519 : node *n = ol_find_name(t->columns, tname->name);
521 717519 : 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 686318 : node *n = ol_find_name(t->columns, cname);
537 686318 : if (!n)
538 : return NULL;
539 686313 : sql_column *c = n->data;
540 686313 : 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 105228 : rel_base_projection( mvc *sql, sql_rel *rel, int intern)
554 : {
555 105228 : int i = 0;
556 105228 : sql_table *t = rel->l;
557 105228 : rel_base_t *ba = rel->r;
558 105228 : sql_alias *name = ba->name;
559 105228 : list *exps = new_exp_list(sql->sa);
560 105231 : prop *p;
561 :
562 786946 : for (node *cn = ol_first_node(t->columns); cn; cn = cn->next, i++) {
563 681711 : if (rel_base_is_used(ba, i)) {
564 681601 : sql_exp *e = bind_col_exp(sql, ba, name, cn->data);
565 681613 : append(exps, e);
566 : }
567 : }
568 105235 : if ((intern && rel_base_is_used(ba, i)) || list_empty(exps)) { /* Add TID column if no column is used */
569 80066 : sql_exp *e = exp_column(sql->sa, name, TID, sql_bind_localtype("oid"), CARD_MULTI, 0, 1, 1);
570 80066 : e->nid = -(ba->basenr + i);
571 80066 : e->alias.label = e->nid;
572 80066 : append(exps, e);
573 : }
574 105235 : i++;
575 105235 : if (intern) {
576 80066 : int j = i;
577 112002 : for (node *in = ol_first_node(t->idxs); in; in = in->next, j++) {
578 31936 : if (rel_base_is_used(ba, j)) {
579 31936 : sql_idx *i = in->data;
580 31936 : sql_subtype *t = sql_bind_localtype("lng"); /* hash "lng" */
581 31936 : int has_nils = 0, unique;
582 :
583 31936 : if ((hash_index(i->type) && list_length(i->columns) <= 1) || !idx_has_column(i->type))
584 31023 : 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 105235 : return exps;
613 : }
614 :
615 : list *
616 14215 : rel_base_project_all( mvc *sql, sql_rel *rel, char *tname)
617 : {
618 14215 : sql_table *t = rel->l;
619 14215 : rel_base_t *ba = rel->r;
620 14215 : sql_alias *name = ba->name;
621 14215 : list *exps = new_exp_list(sql->sa);
622 :
623 14215 : if (!exps || !a_cmp_obj_name(name, tname))
624 46 : return NULL;
625 :
626 182919 : for (node *cn = ol_first_node(t->columns); cn; cn = cn->next)
627 168750 : append(exps, bind_col( sql, rel, name, cn->data));
628 : return exps;
629 : }
630 :
631 : sql_rel *
632 517 : rel_base_add_columns( mvc *sql, sql_rel *r)
633 : {
634 517 : sql_table *t = r->l;
635 517 : rel_base_t *ba = r->r;
636 :
637 517 : r->exps = new_exp_list(sql->sa);
638 517 : if(!r->exps) {
639 0 : rel_destroy(r);
640 0 : return NULL;
641 : }
642 :
643 517 : int i = 0;
644 517 : prop *p = NULL;
645 517 : node *cn;
646 517 : sql_alias *ta = table_alias(sql->sa, t, NULL);
647 517 : sql_alias *atname = ba->name;
648 :
649 1547 : for (cn = ol_first_node(t->columns); cn; cn = cn->next, i++) {
650 1030 : sql_column *c = cn->data;
651 1030 : 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 1030 : if (e == NULL) {
654 0 : rel_destroy(r);
655 0 : return NULL;
656 : }
657 1030 : e->nid = -(ba->basenr + i);
658 1030 : e->alias.label = e->nid;
659 1030 : 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 1030 : } 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 1030 : set_basecol(e);
667 1030 : sql_column_get_statistics(sql, c, e);
668 1030 : append(r->exps, e);
669 : }
670 : return r;
671 : }
672 :
673 : sql_rel *
674 2184234 : rewrite_basetable(mvc *sql, sql_rel *rel)
675 : {
676 2184234 : if (is_basetable(rel->op) && !rel->exps) {
677 458374 : allocator *sa = sql->sa;
678 458374 : sql_table *t = rel->l;
679 458374 : rel_base_t *ba = rel->r;
680 :
681 458374 : rel->exps = new_exp_list(sa);
682 458474 : if(!rel->exps) {
683 0 : rel_destroy(rel);
684 0 : return NULL;
685 : }
686 :
687 458474 : int i = 0;
688 458474 : prop *p = NULL;
689 458474 : node *cn;
690 458474 : const char *tname = t->base.name;
691 458474 : sql_alias *atname = ba->name;
692 :
693 458474 : if (isRemote(t))
694 287 : tname = mapiuri_table(t->query, sql->sa, tname);
695 458474 : sql_alias *ta = a_create(sql->sa, tname);
696 3305225 : for (cn = ol_first_node(t->columns); cn; cn = cn->next, i++) {
697 2846660 : if (!rel_base_is_used(ba, i))
698 1062509 : continue;
699 :
700 1784151 : sql_column *c = cn->data;
701 1784151 : 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 1784245 : if (e == NULL) {
704 0 : rel_destroy(rel);
705 0 : return NULL;
706 : }
707 1784245 : e->nid = -(ba->basenr + i);
708 1784245 : e->alias.label = e->nid;
709 1784245 : if (c->t->pkey && ((sql_kc*)c->t->pkey->k.columns->h->data)->c == c) {
710 58325 : p = e->p = prop_create(sa, PROP_HASHCOL, e->p);
711 58326 : p->value.pval = c->t->pkey;
712 1725920 : } else if (c->unique == 2) {
713 12164 : p = e->p = prop_create(sa, PROP_HASHCOL, e->p);
714 12164 : p->value.pval = NULL;
715 : }
716 1784246 : set_basecol(e);
717 1784246 : sql_column_get_statistics(sql, c, e);
718 1784733 : append(rel->exps, e);
719 : }
720 458565 : if (rel_base_is_used(ba, i) || list_empty(rel->exps)) { /* Add TID column if no column is used */
721 458565 : sql_exp *e = exp_alias(sql, atname, TID, ta, TID, sql_bind_localtype("oid"), CARD_MULTI, 0, 1, 1);
722 458541 : if (e == NULL) {
723 0 : rel_destroy(rel);
724 0 : return NULL;
725 : }
726 458541 : e->nid = -(ba->basenr + i);
727 458541 : e->alias.label = e->nid;
728 458541 : append(rel->exps, e);
729 : }
730 458641 : i++;
731 458641 : int j = i;
732 581741 : for (cn = ol_first_node(t->idxs); cn; cn = cn->next, j++) {
733 123261 : if (!rel_base_is_used(ba, j))
734 0 : continue;
735 :
736 123261 : sql_exp *e;
737 123261 : sql_idx *i = cn->data;
738 123261 : sql_subtype *t;
739 123261 : char *iname = NULL;
740 123261 : int has_nils = 0, unique;
741 :
742 : /* do not include empty indices in the plan */
743 123261 : if ((hash_index(i->type) && list_length(i->columns) <= 1) || !idx_has_column(i->type))
744 105217 : 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 550 : rel_rename_part(mvc *sql, sql_rel *p, sql_rel *mt_rel, sql_alias *mtalias)
823 : {
824 550 : sql_exp *ne = NULL;
825 550 : sql_table *mt = rel_base_table(mt_rel), *t = rel_base_table(p);
826 550 : rel_base_t *mt_ba = mt_rel->r, *p_ba = p->r;
827 550 : p_ba->basenr = mt_ba->basenr;
828 :
829 550 : assert(!p->exps);
830 550 : p->exps = sa_list(sql->sa);
831 550 : const char *pname = t->base.name;
832 550 : if (isRemote(t))
833 37 : pname = mapiuri_table(t->query, sql->sa, pname);
834 550 : sql_alias *pa = a_create(sql->sa, pname);
835 1482 : for (node *n = mt_rel->exps->h; n; n = n->next) {
836 932 : sql_exp *e = n->data;
837 932 : node *cn = NULL, *ci = NULL;
838 932 : const char *nname = e->r;
839 :
840 932 : 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 879 : } else if (nname[0] != '%' && (cn = ol_find_name(mt->columns, nname))) {
846 877 : 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 877 : ne = exp_alias(sql, mtalias, exp_name(e), pa, rc->base.name, &rc->type, CARD_MULTI, rc->null, is_column_unique(rc), 0);
850 877 : 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 858 : } 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 877 : set_basecol(ne);
858 877 : sql_column_get_statistics(sql, c, ne);
859 877 : rel_base_use(sql, p, rc->colnr);
860 877 : list_append(p->exps, ne);
861 877 : ne->nid = e->nid;
862 877 : 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 550 : rel_base_set_mergetable(p, mt);
895 550 : 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 550 : rel_base_set_mergetable(sql_rel *rel, sql_table *mt)
951 : {
952 550 : rel_base_t *ba = rel->r;
953 :
954 550 : if (ba)
955 550 : ba->mt = mt;
956 550 : }
957 :
958 : sql_table *
959 105746 : rel_base_get_mergetable(sql_rel *rel)
960 : {
961 105746 : rel_base_t *ba = rel->r;
962 :
963 105746 : return ba ? ba->mt : NULL;
964 : }
|