LCOV - code coverage report
Current view: top level - sql/server - rel_partition.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 100 117 85.5 %
Date: 2025-03-24 21:28:01 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, 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             : }

Generated by: LCOV version 1.14