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 : #include "sql_storage.h"
21 :
22 : static lng
23 93678 : rel_getcount(mvc *sql, sql_rel *rel)
24 : {
25 93678 : if (!sql->session->tr)
26 : return 0;
27 :
28 93678 : switch(rel->op) {
29 93678 : case op_basetable: {
30 93678 : sql_table *t = rel->l;
31 :
32 93678 : if (t && isTable(t)) {
33 93678 : sqlstore *store = sql->session->tr->store;
34 93678 : return (lng)store->storage_api.count_col(sql->session->tr, ol_first_node(t->columns)->data, 0);
35 : }
36 : return 0;
37 : }
38 : default:
39 0 : assert(0);
40 : return 0;
41 : }
42 : }
43 :
44 : static void
45 97658 : find_basetables(mvc *sql, sql_rel *rel, list *tables )
46 : {
47 240391 : if (mvc_highwater(sql)) {
48 0 : (void) sql_error(sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
49 0 : return;
50 : }
51 :
52 240391 : if (!rel)
53 : return;
54 240391 : switch (rel->op) {
55 93753 : case op_basetable: {
56 93753 : sql_table *t = rel->l;
57 :
58 93753 : if (t && isTable(t))
59 93678 : append(tables, rel);
60 : break;
61 : }
62 287 : case op_table:
63 287 : if (IS_TABLE_PROD_FUNC(rel->flag) || rel->flag == TABLE_FROM_RELATION)
64 287 : if (rel->l)
65 : find_basetables(sql, rel->l, tables);
66 : break;
67 72626 : case op_join:
68 : case op_left:
69 : case op_right:
70 : case op_full:
71 : case op_union:
72 : case op_inter:
73 : case op_except:
74 : case op_insert:
75 : case op_update:
76 : case op_delete:
77 : case op_merge:
78 72626 : if (rel->l)
79 72626 : find_basetables(sql, rel->l, tables);
80 72626 : if (rel->r)
81 : find_basetables(sql, rel->r, tables);
82 : break;
83 814 : case op_munion:
84 814 : assert(rel->l);
85 3145 : for (node *n = ((list*)rel->l)->h; n; n = n->next)
86 2331 : find_basetables(sql, n->data, tables);
87 : break;
88 72911 : case op_semi:
89 : case op_anti:
90 : case op_groupby:
91 : case op_project:
92 : case op_select:
93 : case op_topn:
94 : case op_sample:
95 : case op_truncate:
96 72911 : if (rel->l)
97 : find_basetables(sql, rel->l, tables);
98 : break;
99 0 : case op_ddl:
100 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*/) {
101 0 : if (rel->l)
102 : find_basetables(sql, rel->l, tables);
103 0 : } else if (rel->flag == ddl_list || rel->flag == ddl_exception) {
104 0 : if (rel->l)
105 0 : find_basetables(sql, rel->l, tables);
106 0 : if (rel->r)
107 : find_basetables(sql, rel->r, tables);
108 : }
109 : break;
110 : }
111 : }
112 :
113 : static sql_rel *
114 22701 : _rel_partition(mvc *sql, sql_rel *rel)
115 : {
116 22701 : list *tables = sa_list(sql->sa);
117 : /* find basetable relations */
118 : /* mark one (largest) with REL_PARTITION */
119 22701 : find_basetables(sql, rel, tables);
120 22701 : if (list_length(tables)) {
121 22352 : sql_rel *r;
122 22352 : node *n;
123 22352 : int i, mi = 0;
124 22352 : lng *sizes = SA_NEW_ARRAY(sql->sa, lng, list_length(tables)), m = 0;
125 :
126 116030 : for(i=0, n = tables->h; n; i++, n = n->next) {
127 93678 : r = n->data;
128 93678 : sizes[i] = rel_getcount(sql, r);
129 93678 : if (sizes[i] > m) {
130 29522 : m = sizes[i];
131 29522 : mi = i;
132 : }
133 : }
134 36388 : for(i=0, n = tables->h; i<mi; i++, n = n->next)
135 : ;
136 22352 : r = n->data;
137 : /* TODO, we now pick first (okay?)! In case of self joins we need to pick the correct table */
138 22352 : r->flag = REL_PARTITION;
139 : }
140 22701 : return rel;
141 : }
142 :
143 : static int
144 174088 : has_groupby(sql_rel *rel)
145 : {
146 267585 : if (!rel)
147 : return 0;
148 :
149 263921 : switch (rel->op) {
150 : case op_groupby:
151 : return 1;
152 56683 : case op_join:
153 : case op_left:
154 : case op_right:
155 : case op_full:
156 :
157 : case op_semi:
158 : case op_anti:
159 :
160 : case op_union:
161 : case op_inter:
162 : case op_except:
163 :
164 : case op_merge:
165 56683 : return has_groupby(rel->l) || has_groupby(rel->r);
166 1409 : case op_munion:
167 3871 : for (node *n = ((list*)rel->l)->h; n; n = n->next)
168 3017 : if (has_groupby(n->data))
169 : return 1;
170 : return 0;
171 93139 : case op_project:
172 : case op_select:
173 : case op_topn:
174 : case op_sample:
175 93139 : return has_groupby(rel->l);
176 0 : case op_insert:
177 : case op_update:
178 : case op_delete:
179 : case op_truncate:
180 0 : return has_groupby(rel->r);
181 0 : case op_ddl:
182 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)
183 0 : return has_groupby(rel->l);
184 : if (rel->flag == ddl_list || rel->flag == ddl_exception)
185 0 : return has_groupby(rel->l) || has_groupby(rel->r);
186 : return 0;
187 358 : case op_table:
188 358 : if (IS_TABLE_PROD_FUNC(rel->flag) || rel->flag == TABLE_FROM_RELATION)
189 358 : return has_groupby(rel->l);
190 : return 0;
191 : case op_basetable:
192 : return 0;
193 : }
194 : return 0;
195 : }
196 :
197 : sql_rel *
198 1013996 : rel_partition(mvc *sql, sql_rel *rel)
199 : {
200 1013996 : if (mvc_highwater(sql))
201 216 : return sql_error(sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
202 :
203 1013990 : switch (rel->op) {
204 94350 : case op_basetable:
205 : case op_sample:
206 94350 : rel->flag = REL_PARTITION;
207 94350 : break;
208 426371 : case op_project:
209 : case op_select:
210 : case op_groupby:
211 : case op_topn:
212 426371 : if (rel->l)
213 260573 : rel_partition(sql, rel->l);
214 : break;
215 6321 : case op_semi:
216 : case op_anti:
217 :
218 : case op_union:
219 : case op_inter:
220 : case op_except:
221 :
222 : case op_merge:
223 6321 : if (rel->l)
224 6321 : rel_partition(sql, rel->l);
225 6321 : if (rel->r)
226 6321 : rel_partition(sql, rel->r);
227 : break;
228 4217 : case op_munion:
229 15543 : for (node *n = ((list*)rel->l)->h; n; n = n->next)
230 11326 : rel_partition(sql, n->data);
231 : break;
232 150207 : case op_insert:
233 : case op_update:
234 : case op_delete:
235 : case op_truncate:
236 150207 : if (rel->r && rel->card <= CARD_AGGR)
237 102353 : rel_partition(sql, rel->r);
238 : break;
239 31813 : case op_join:
240 : case op_left:
241 : case op_right:
242 : case op_full:
243 31813 : if (has_groupby(rel->l) || has_groupby(rel->r)) {
244 9112 : if (rel->l)
245 9112 : rel_partition(sql, rel->l);
246 9112 : if (rel->r)
247 9112 : rel_partition(sql, rel->r);
248 : } else {
249 22701 : _rel_partition(sql, rel);
250 : }
251 : break;
252 299117 : case op_ddl:
253 299117 : 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) {
254 33140 : if (rel->l)
255 32780 : rel_partition(sql, rel->l);
256 : } else if (rel->flag == ddl_list || rel->flag == ddl_exception) {
257 722 : if (rel->l)
258 565 : rel_partition(sql, rel->l);
259 722 : if (rel->r)
260 688 : rel_partition(sql, rel->r);
261 : }
262 : break;
263 1594 : case op_table:
264 1594 : if ((IS_TABLE_PROD_FUNC(rel->flag) || rel->flag == TABLE_FROM_RELATION) && rel->l)
265 283 : rel_partition(sql, rel->l);
266 : break;
267 : default:
268 0 : assert(0);
269 : break;
270 : }
271 : return rel;
272 : }
|