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 "sql_query.h"
15 : #include "rel_partition.h"
16 : #include "rel_exp.h"
17 : #include "rel_prop.h"
18 : #include "rel_dump.h"
19 : #include "rel_select.h"
20 : #include "sql_storage.h"
21 :
22 : static lng
23 93512 : rel_getcount(mvc *sql, sql_rel *rel)
24 : {
25 93512 : if (!sql->session->tr)
26 : return 0;
27 :
28 93512 : switch(rel->op) {
29 93512 : case op_basetable: {
30 93512 : sql_table *t = rel->l;
31 :
32 93512 : if (t && isTable(t)) {
33 93512 : sqlstore *store = sql->session->tr->store;
34 93512 : node *fn = t->columns->l->t;//ol_first_node(t->columns);
35 93512 : return (lng)store->storage_api.count_col(sql->session->tr, fn->data, 0);
36 : }
37 : return 0;
38 : }
39 : default:
40 0 : assert(0);
41 : return 0;
42 : }
43 : }
44 :
45 : static void
46 97486 : find_basetables(mvc *sql, sql_rel *rel, list *tables )
47 : {
48 240213 : if (mvc_highwater(sql)) {
49 0 : (void) sql_error(sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
50 0 : return;
51 : }
52 :
53 240213 : if (!rel)
54 : return;
55 240213 : switch (rel->op) {
56 93587 : case op_basetable: {
57 93587 : sql_table *t = rel->l;
58 :
59 93587 : if (t && isTable(t))
60 93512 : append(tables, rel);
61 : break;
62 : }
63 287 : case op_table:
64 287 : if (IS_TABLE_PROD_FUNC(rel->flag) || rel->flag == TABLE_FROM_RELATION)
65 287 : if (rel->l)
66 : find_basetables(sql, rel->l, tables);
67 : break;
68 72506 : case op_join:
69 : case op_left:
70 : case op_right:
71 : case op_full:
72 : case op_union:
73 : case op_inter:
74 : case op_except:
75 : case op_insert:
76 : case op_update:
77 : case op_delete:
78 : case op_merge:
79 72506 : if (rel->l)
80 72506 : find_basetables(sql, rel->l, tables);
81 72506 : if (rel->r)
82 : find_basetables(sql, rel->r, tables);
83 : break;
84 818 : case op_munion:
85 818 : assert(rel->l);
86 3157 : for (node *n = ((list*)rel->l)->h; n; n = n->next)
87 2339 : find_basetables(sql, n->data, tables);
88 : break;
89 73015 : case op_semi:
90 : case op_anti:
91 : case op_groupby:
92 : case op_project:
93 : case op_select:
94 : case op_topn:
95 : case op_sample:
96 : case op_truncate:
97 73015 : if (rel->l)
98 : find_basetables(sql, rel->l, tables);
99 : break;
100 0 : case op_ddl:
101 0 : if (rel->flag == ddl_output || rel->flag == ddl_create_seq || rel->flag == ddl_alter_seq/* || rel->flag == ddl_alter_table || rel->flag == ddl_create_table || rel->flag == ddl_create_view*/) {
102 0 : if (rel->l)
103 : find_basetables(sql, rel->l, tables);
104 0 : } else if (rel->flag == ddl_list || rel->flag == ddl_exception) {
105 0 : if (rel->l)
106 0 : find_basetables(sql, rel->l, tables);
107 0 : if (rel->r)
108 : find_basetables(sql, rel->r, tables);
109 : }
110 : break;
111 : }
112 : }
113 :
114 : static sql_rel *
115 22641 : _rel_partition(mvc *sql, sql_rel *rel)
116 : {
117 22641 : list *tables = sa_list(sql->sa);
118 : /* find basetable relations */
119 : /* mark one (largest) with REL_PARTITION */
120 22641 : find_basetables(sql, rel, tables);
121 22641 : if (list_length(tables)) {
122 22292 : sql_rel *r;
123 22292 : node *n;
124 22292 : int i, mi = 0;
125 22292 : lng *sizes = SA_NEW_ARRAY(sql->sa, lng, list_length(tables)), m = 0;
126 :
127 115804 : for(i=0, n = tables->h; n; i++, n = n->next) {
128 93512 : r = n->data;
129 93512 : sizes[i] = rel_getcount(sql, r);
130 93512 : if (sizes[i] > m) {
131 29098 : m = sizes[i];
132 29098 : mi = i;
133 : }
134 : }
135 35616 : for(i=0, n = tables->h; i<mi; i++, n = n->next)
136 : ;
137 22292 : r = n->data;
138 : /* TODO, we now pick first (okay?)! In case of self joins we need to pick the correct table */
139 22292 : r->flag = REL_PARTITION;
140 : }
141 22641 : return rel;
142 : }
143 :
144 : static int
145 174210 : has_groupby(sql_rel *rel)
146 : {
147 267833 : if (!rel)
148 : return 0;
149 :
150 264179 : switch (rel->op) {
151 : case op_groupby:
152 : return 1;
153 56809 : case op_join:
154 : case op_left:
155 : case op_right:
156 : case op_full:
157 :
158 : case op_semi:
159 : case op_anti:
160 :
161 : case op_union:
162 : case op_inter:
163 : case op_except:
164 :
165 : case op_merge:
166 56809 : return has_groupby(rel->l) || has_groupby(rel->r);
167 1470 : case op_munion:
168 3944 : for (node *n = ((list*)rel->l)->h; n; n = n->next)
169 3084 : if (has_groupby(n->data))
170 : return 1;
171 : return 0;
172 93265 : case op_project:
173 : case op_select:
174 : case op_topn:
175 : case op_sample:
176 93265 : return has_groupby(rel->l);
177 0 : case op_insert:
178 : case op_update:
179 : case op_delete:
180 : case op_truncate:
181 0 : return has_groupby(rel->r);
182 0 : case op_ddl:
183 0 : if (rel->flag == ddl_output || rel->flag == ddl_create_seq || rel->flag == ddl_alter_seq || rel->flag == ddl_alter_table || rel->flag == ddl_create_table || rel->flag == ddl_create_view)
184 0 : return has_groupby(rel->l);
185 : if (rel->flag == ddl_list || rel->flag == ddl_exception)
186 0 : return has_groupby(rel->l) || has_groupby(rel->r);
187 : return 0;
188 358 : case op_table:
189 358 : if (IS_TABLE_PROD_FUNC(rel->flag) || rel->flag == TABLE_FROM_RELATION)
190 358 : return has_groupby(rel->l);
191 : return 0;
192 : case op_basetable:
193 : return 0;
194 : }
195 : return 0;
196 : }
197 :
198 : sql_rel *
199 1059288 : rel_partition(mvc *sql, sql_rel *rel)
200 : {
201 1059288 : if (mvc_highwater(sql))
202 148 : return sql_error(sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
203 :
204 1059280 : switch (rel->op) {
205 94987 : case op_basetable:
206 : case op_sample:
207 94987 : rel->flag = REL_PARTITION;
208 94987 : break;
209 433611 : case op_project:
210 : case op_select:
211 : case op_groupby:
212 : case op_topn:
213 433611 : if (rel->l)
214 264872 : rel_partition(sql, rel->l);
215 : break;
216 6319 : case op_semi:
217 : case op_anti:
218 :
219 : case op_union:
220 : case op_inter:
221 : case op_except:
222 :
223 : case op_merge:
224 6319 : if (rel->l)
225 6319 : rel_partition(sql, rel->l);
226 6319 : if (rel->r)
227 6319 : rel_partition(sql, rel->r);
228 : break;
229 4215 : case op_munion:
230 15537 : for (node *n = ((list*)rel->l)->h; n; n = n->next)
231 11322 : rel_partition(sql, n->data);
232 : break;
233 150605 : case op_insert:
234 : case op_update:
235 : case op_delete:
236 : case op_truncate:
237 150605 : if (rel->r && rel->card <= CARD_AGGR)
238 102701 : rel_partition(sql, rel->r);
239 : break;
240 31720 : case op_join:
241 : case op_left:
242 : case op_right:
243 : case op_full:
244 31720 : if (has_groupby(rel->l) || has_groupby(rel->r)) {
245 9079 : if (rel->l)
246 9079 : rel_partition(sql, rel->l);
247 9079 : if (rel->r)
248 9079 : rel_partition(sql, rel->r);
249 : } else {
250 22641 : _rel_partition(sql, rel);
251 : }
252 : break;
253 336097 : case op_ddl:
254 336097 : if (rel->flag == ddl_output || rel->flag == ddl_create_seq || rel->flag == ddl_alter_seq || rel->flag == ddl_alter_table || rel->flag == ddl_create_table || rel->flag == ddl_create_view) {
255 33520 : if (rel->l)
256 33157 : rel_partition(sql, rel->l);
257 : } else if (rel->flag == ddl_list || rel->flag == ddl_exception) {
258 725 : if (rel->l)
259 568 : rel_partition(sql, rel->l);
260 725 : if (rel->r)
261 691 : rel_partition(sql, rel->r);
262 : }
263 : break;
264 1726 : case op_table:
265 1726 : if ((IS_TABLE_PROD_FUNC(rel->flag) || rel->flag == TABLE_FROM_RELATION) && rel->l)
266 283 : rel_partition(sql, rel->l);
267 : break;
268 : default:
269 0 : assert(0);
270 : break;
271 : }
272 : return rel;
273 : }
|