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 86498 : rel_getcount(mvc *sql, sql_rel *rel)
23 : {
24 86498 : if (!sql->session->tr)
25 : return 0;
26 :
27 86498 : switch(rel->op) {
28 86498 : case op_basetable: {
29 86498 : sql_table *t = rel->l;
30 :
31 86498 : if (t && isTable(t)) {
32 86498 : sqlstore *store = sql->session->tr->store;
33 86498 : 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 89297 : find_basetables(mvc *sql, sql_rel *rel, list *tables )
45 : {
46 221364 : 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 221364 : if (!rel)
52 : return;
53 221364 : switch (rel->op) {
54 86573 : case op_basetable: {
55 86573 : sql_table *t = rel->l;
56 :
57 86573 : if (t && isTable(t))
58 86498 : append(tables, rel);
59 : break;
60 : }
61 215 : case op_table:
62 215 : if (IS_TABLE_PROD_FUNC(rel->flag) || rel->flag == TABLE_FROM_RELATION)
63 215 : if (rel->l)
64 : find_basetables(sql, rel->l, tables);
65 : break;
66 68959 : 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 68959 : if (rel->l)
78 68959 : find_basetables(sql, rel->l, tables);
79 68959 : if (rel->r)
80 : find_basetables(sql, rel->r, tables);
81 : break;
82 65617 : case op_semi:
83 : case op_anti:
84 : case op_groupby:
85 : case op_project:
86 : case op_select:
87 : case op_topn:
88 : case op_sample:
89 : case op_truncate:
90 65617 : if (rel->l)
91 : find_basetables(sql, rel->l, tables);
92 : break;
93 0 : case op_ddl:
94 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*/) {
95 0 : if (rel->l)
96 : find_basetables(sql, rel->l, tables);
97 0 : } else if (rel->flag == ddl_list || rel->flag == ddl_exception) {
98 0 : if (rel->l)
99 0 : find_basetables(sql, rel->l, tables);
100 0 : if (rel->r)
101 : find_basetables(sql, rel->r, tables);
102 : }
103 : break;
104 : }
105 : }
106 :
107 : static sql_rel *
108 20338 : _rel_partition(mvc *sql, sql_rel *rel)
109 : {
110 20338 : list *tables = sa_list(sql->sa);
111 : /* find basetable relations */
112 : /* mark one (largest) with REL_PARTITION */
113 20338 : find_basetables(sql, rel, tables);
114 20338 : if (list_length(tables)) {
115 20096 : sql_rel *r;
116 20096 : node *n;
117 20096 : int i, mi = 0;
118 20096 : lng *sizes = SA_NEW_ARRAY(sql->sa, lng, list_length(tables)), m = 0;
119 :
120 106594 : for(i=0, n = tables->h; n; i++, n = n->next) {
121 86498 : r = n->data;
122 86498 : sizes[i] = rel_getcount(sql, r);
123 86498 : if (sizes[i] > m) {
124 26359 : m = sizes[i];
125 26359 : mi = i;
126 : }
127 : }
128 33606 : for(i=0, n = tables->h; i<mi; i++, n = n->next)
129 : ;
130 20096 : r = n->data;
131 : /* TODO, we now pick first (okay?)! In case of self joins we need to pick the correct table */
132 20096 : r->flag = REL_PARTITION;
133 : }
134 20338 : return rel;
135 : }
136 :
137 : static int
138 166534 : has_groupby(sql_rel *rel)
139 : {
140 250957 : if (!rel)
141 : return 0;
142 :
143 247727 : switch (rel->op) {
144 : case op_groupby:
145 : return 1;
146 57211 : case op_join:
147 : case op_left:
148 : case op_right:
149 : case op_full:
150 :
151 : case op_semi:
152 : case op_anti:
153 :
154 : case op_union:
155 : case op_inter:
156 : case op_except:
157 :
158 : case op_merge:
159 57211 : return has_groupby(rel->l) || has_groupby(rel->r);
160 84177 : case op_project:
161 : case op_select:
162 : case op_topn:
163 : case op_sample:
164 84177 : return has_groupby(rel->l);
165 0 : case op_insert:
166 : case op_update:
167 : case op_delete:
168 : case op_truncate:
169 0 : return has_groupby(rel->r);
170 0 : case op_ddl:
171 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)
172 0 : return has_groupby(rel->l);
173 : if (rel->flag == ddl_list || rel->flag == ddl_exception)
174 0 : return has_groupby(rel->l) || has_groupby(rel->r);
175 : return 0;
176 246 : case op_table:
177 246 : if (IS_TABLE_PROD_FUNC(rel->flag) || rel->flag == TABLE_FROM_RELATION)
178 246 : return has_groupby(rel->l);
179 : return 0;
180 : case op_basetable:
181 : return 0;
182 : }
183 : return 0;
184 : }
185 :
186 : sql_rel *
187 970413 : rel_partition(mvc *sql, sql_rel *rel)
188 : {
189 970413 : if (mvc_highwater(sql))
190 0 : return sql_error(sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
191 :
192 970421 : switch (rel->op) {
193 91146 : case op_basetable:
194 : case op_sample:
195 91146 : rel->flag = REL_PARTITION;
196 91146 : break;
197 405457 : case op_project:
198 : case op_select:
199 : case op_groupby:
200 : case op_topn:
201 405457 : if (rel->l)
202 246358 : rel_partition(sql, rel->l);
203 : break;
204 11643 : case op_semi:
205 : case op_anti:
206 :
207 : case op_union:
208 : case op_inter:
209 : case op_except:
210 :
211 : case op_merge:
212 11643 : if (rel->l)
213 11643 : rel_partition(sql, rel->l);
214 11643 : if (rel->r)
215 11643 : rel_partition(sql, rel->r);
216 : break;
217 152699 : case op_insert:
218 : case op_update:
219 : case op_delete:
220 : case op_truncate:
221 152699 : if (rel->r && rel->card <= CARD_AGGR)
222 104757 : rel_partition(sql, rel->r);
223 : break;
224 29671 : case op_join:
225 : case op_left:
226 : case op_right:
227 : case op_full:
228 29671 : if (has_groupby(rel->l) || has_groupby(rel->r)) {
229 9333 : if (rel->l)
230 9333 : rel_partition(sql, rel->l);
231 9333 : if (rel->r)
232 9333 : rel_partition(sql, rel->r);
233 : } else {
234 20338 : _rel_partition(sql, rel);
235 : }
236 : break;
237 278398 : case op_ddl:
238 278398 : 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) {
239 32152 : if (rel->l)
240 31800 : rel_partition(sql, rel->l);
241 : } else if (rel->flag == ddl_list || rel->flag == ddl_exception) {
242 696 : if (rel->l)
243 547 : rel_partition(sql, rel->l);
244 696 : if (rel->r)
245 662 : rel_partition(sql, rel->r);
246 : }
247 : break;
248 1407 : case op_table:
249 1407 : if ((IS_TABLE_PROD_FUNC(rel->flag) || rel->flag == TABLE_FROM_RELATION) && rel->l)
250 283 : rel_partition(sql, rel->l);
251 : break;
252 : default:
253 0 : assert(0);
254 : break;
255 : }
256 : return rel;
257 : }
|