Line data Source code
1 : /*
2 : * SPDX-License-Identifier: MPL-2.0
3 : *
4 : * This Source Code Form is subject to the terms of the Mozilla Public
5 : * License, v. 2.0. If a copy of the MPL was not distributed with this
6 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 : *
8 : * Copyright 2024 MonetDB Foundation;
9 : * Copyright August 2008 - 2023 MonetDB B.V.;
10 : * Copyright 1997 - July 2008 CWI.
11 : */
12 :
13 : #include "monetdb_config.h"
14 : #include "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 :
21 : static lng
22 93116 : rel_getcount(mvc *sql, sql_rel *rel)
23 : {
24 93116 : if (!sql->session->tr)
25 : return 0;
26 :
27 93116 : switch(rel->op) {
28 93116 : case op_basetable: {
29 93116 : sql_table *t = rel->l;
30 :
31 93116 : if (t && isTable(t)) {
32 93116 : sqlstore *store = sql->session->tr->store;
33 93116 : return (lng)store->storage_api.count_col(sql->session->tr, ol_first_node(t->columns)->data, 0);
34 : }
35 : return 0;
36 : }
37 : default:
38 0 : assert(0);
39 : return 0;
40 : }
41 : }
42 :
43 : static void
44 96978 : find_basetables(mvc *sql, sql_rel *rel, list *tables )
45 : {
46 238718 : if (mvc_highwater(sql)) {
47 0 : (void) sql_error(sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
48 0 : return;
49 : }
50 :
51 238718 : if (!rel)
52 : return;
53 238718 : switch (rel->op) {
54 93191 : case op_basetable: {
55 93191 : sql_table *t = rel->l;
56 :
57 93191 : if (t && isTable(t))
58 93116 : append(tables, rel);
59 : break;
60 : }
61 256 : case op_table:
62 256 : if (IS_TABLE_PROD_FUNC(rel->flag) || rel->flag == TABLE_FROM_RELATION)
63 256 : if (rel->l)
64 : find_basetables(sql, rel->l, tables);
65 : break;
66 72219 : case op_join:
67 : case op_left:
68 : case op_right:
69 : case op_full:
70 : case op_union:
71 : case op_inter:
72 : case op_except:
73 : case op_insert:
74 : case op_update:
75 : case op_delete:
76 : case op_merge:
77 72219 : if (rel->l)
78 72219 : find_basetables(sql, rel->l, tables);
79 72219 : if (rel->r)
80 : find_basetables(sql, rel->r, tables);
81 : break;
82 797 : case op_munion:
83 797 : assert(rel->l);
84 3093 : for (node *n = ((list*)rel->l)->h; n; n = n->next)
85 2296 : find_basetables(sql, n->data, tables);
86 : break;
87 72255 : case op_semi:
88 : case op_anti:
89 : case op_groupby:
90 : case op_project:
91 : case op_select:
92 : case op_topn:
93 : case op_sample:
94 : case op_truncate:
95 72255 : if (rel->l)
96 : find_basetables(sql, rel->l, tables);
97 : break;
98 0 : case op_ddl:
99 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*/) {
100 0 : if (rel->l)
101 : find_basetables(sql, rel->l, tables);
102 0 : } else if (rel->flag == ddl_list || rel->flag == ddl_exception) {
103 0 : if (rel->l)
104 0 : find_basetables(sql, rel->l, tables);
105 0 : if (rel->r)
106 : find_basetables(sql, rel->r, tables);
107 : }
108 : break;
109 : }
110 : }
111 :
112 : static sql_rel *
113 22463 : _rel_partition(mvc *sql, sql_rel *rel)
114 : {
115 22463 : list *tables = sa_list(sql->sa);
116 : /* find basetable relations */
117 : /* mark one (largest) with REL_PARTITION */
118 22463 : find_basetables(sql, rel, tables);
119 22463 : if (list_length(tables)) {
120 22151 : sql_rel *r;
121 22151 : node *n;
122 22151 : int i, mi = 0;
123 22151 : lng *sizes = SA_NEW_ARRAY(sql->sa, lng, list_length(tables)), m = 0;
124 :
125 115267 : for(i=0, n = tables->h; n; i++, n = n->next) {
126 93116 : r = n->data;
127 93116 : sizes[i] = rel_getcount(sql, r);
128 93116 : if (sizes[i] > m) {
129 29281 : m = sizes[i];
130 29281 : mi = i;
131 : }
132 : }
133 36144 : for(i=0, n = tables->h; i<mi; i++, n = n->next)
134 : ;
135 22151 : r = n->data;
136 : /* TODO, we now pick first (okay?)! In case of self joins we need to pick the correct table */
137 22151 : r->flag = REL_PARTITION;
138 : }
139 22463 : return rel;
140 : }
141 :
142 : static int
143 173342 : has_groupby(sql_rel *rel)
144 : {
145 266203 : if (!rel)
146 : return 0;
147 :
148 262665 : switch (rel->op) {
149 : case op_groupby:
150 : return 1;
151 56612 : case op_join:
152 : case op_left:
153 : case op_right:
154 : case op_full:
155 :
156 : case op_semi:
157 : case op_anti:
158 :
159 : case op_union:
160 : case op_inter:
161 : case op_except:
162 :
163 : case op_merge:
164 56612 : return has_groupby(rel->l) || has_groupby(rel->r);
165 1344 : case op_munion:
166 3771 : for (node *n = ((list*)rel->l)->h; n; n = n->next)
167 2934 : if (has_groupby(n->data))
168 : return 1;
169 : return 0;
170 92550 : case op_project:
171 : case op_select:
172 : case op_topn:
173 : case op_sample:
174 92550 : return has_groupby(rel->l);
175 0 : case op_insert:
176 : case op_update:
177 : case op_delete:
178 : case op_truncate:
179 0 : return has_groupby(rel->r);
180 0 : case op_ddl:
181 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)
182 0 : return has_groupby(rel->l);
183 : if (rel->flag == ddl_list || rel->flag == ddl_exception)
184 0 : return has_groupby(rel->l) || has_groupby(rel->r);
185 : return 0;
186 311 : case op_table:
187 311 : if (IS_TABLE_PROD_FUNC(rel->flag) || rel->flag == TABLE_FROM_RELATION)
188 311 : return has_groupby(rel->l);
189 : return 0;
190 : case op_basetable:
191 : return 0;
192 : }
193 : return 0;
194 : }
195 :
196 : sql_rel *
197 1008799 : rel_partition(mvc *sql, sql_rel *rel)
198 : {
199 1008799 : if (mvc_highwater(sql))
200 0 : return sql_error(sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
201 :
202 1008802 : switch (rel->op) {
203 93130 : case op_basetable:
204 : case op_sample:
205 93130 : rel->flag = REL_PARTITION;
206 93130 : break;
207 424458 : case op_project:
208 : case op_select:
209 : case op_groupby:
210 : case op_topn:
211 424458 : if (rel->l)
212 258027 : rel_partition(sql, rel->l);
213 : break;
214 6228 : case op_semi:
215 : case op_anti:
216 :
217 : case op_union:
218 : case op_inter:
219 : case op_except:
220 :
221 : case op_merge:
222 6228 : if (rel->l)
223 6228 : rel_partition(sql, rel->l);
224 6228 : if (rel->r)
225 6228 : rel_partition(sql, rel->r);
226 : break;
227 4127 : case op_munion:
228 15281 : for (node *n = ((list*)rel->l)->h; n; n = n->next)
229 11154 : rel_partition(sql, n->data);
230 : break;
231 151002 : case op_insert:
232 : case op_update:
233 : case op_delete:
234 : case op_truncate:
235 151002 : if (rel->r && rel->card <= CARD_AGGR)
236 103001 : rel_partition(sql, rel->r);
237 : break;
238 31489 : case op_join:
239 : case op_left:
240 : case op_right:
241 : case op_full:
242 31489 : if (has_groupby(rel->l) || has_groupby(rel->r)) {
243 9026 : if (rel->l)
244 9026 : rel_partition(sql, rel->l);
245 9026 : if (rel->r)
246 9026 : rel_partition(sql, rel->r);
247 : } else {
248 22463 : _rel_partition(sql, rel);
249 : }
250 : break;
251 296805 : case op_ddl:
252 296805 : 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) {
253 32875 : if (rel->l)
254 32515 : rel_partition(sql, rel->l);
255 : } else if (rel->flag == ddl_list || rel->flag == ddl_exception) {
256 722 : if (rel->l)
257 565 : rel_partition(sql, rel->l);
258 722 : if (rel->r)
259 688 : rel_partition(sql, rel->r);
260 : }
261 : break;
262 1563 : case op_table:
263 1563 : if ((IS_TABLE_PROD_FUNC(rel->flag) || rel->flag == TABLE_FROM_RELATION) && rel->l)
264 283 : rel_partition(sql, rel->l);
265 : break;
266 : default:
267 0 : assert(0);
268 : break;
269 : }
270 : return rel;
271 : }
|