LCOV - code coverage report
Current view: top level - sql/server - rel_partition.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 99 116 85.3 %
Date: 2024-12-20 21:24:02 Functions: 5 5 100.0 %

          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             : }

Generated by: LCOV version 1.14