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-10-07 21:21:43 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             : 
      21             : static lng
      22       92056 : rel_getcount(mvc *sql, sql_rel *rel)
      23             : {
      24       92056 :         if (!sql->session->tr)
      25             :                 return 0;
      26             : 
      27       92056 :         switch(rel->op) {
      28       92056 :         case op_basetable: {
      29       92056 :                 sql_table *t = rel->l;
      30             : 
      31       92056 :                 if (t && isTable(t)) {
      32       92056 :                         sqlstore *store = sql->session->tr->store;
      33       92056 :                         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       95814 : find_basetables(mvc *sql, sql_rel *rel, list *tables )
      45             : {
      46      235964 :         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      235964 :         if (!rel)
      52             :                 return;
      53      235964 :         switch (rel->op) {
      54       92131 :         case op_basetable: {
      55       92131 :                 sql_table *t = rel->l;
      56             : 
      57       92131 :                 if (t && isTable(t))
      58       92056 :                         append(tables, rel);
      59             :                 break;
      60             :         }
      61         252 :         case op_table:
      62         252 :                 if (IS_TABLE_PROD_FUNC(rel->flag) || rel->flag == TABLE_FROM_RELATION)
      63         252 :                         if (rel->l)
      64             :                                 find_basetables(sql, rel->l, tables);
      65             :                 break;
      66       71451 :         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       71451 :                 if (rel->l)
      78       71451 :                         find_basetables(sql, rel->l, tables);
      79       71451 :                 if (rel->r)
      80             :                         find_basetables(sql, rel->r, tables);
      81             :                 break;
      82         787 :         case op_munion:
      83         787 :                 assert(rel->l);
      84        3063 :                 for (node *n = ((list*)rel->l)->h; n; n = n->next)
      85        2276 :                         find_basetables(sql, n->data, tables);
      86             :                 break;
      87       71343 :         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       71343 :                 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       22087 : _rel_partition(mvc *sql, sql_rel *rel)
     114             : {
     115       22087 :         list *tables = sa_list(sql->sa);
     116             :         /* find basetable relations */
     117             :         /* mark one (largest) with REL_PARTITION */
     118       22087 :         find_basetables(sql, rel, tables);
     119       22087 :         if (list_length(tables)) {
     120       21789 :                 sql_rel *r;
     121       21789 :                 node *n;
     122       21789 :                 int i, mi = 0;
     123       21789 :                 lng *sizes = SA_NEW_ARRAY(sql->sa, lng, list_length(tables)), m = 0;
     124             : 
     125      113845 :                 for(i=0, n = tables->h; n; i++, n = n->next) {
     126       92056 :                         r = n->data;
     127       92056 :                         sizes[i] = rel_getcount(sql, r);
     128       92056 :                         if (sizes[i] > m) {
     129       28766 :                                 m = sizes[i];
     130       28766 :                                 mi = i;
     131             :                         }
     132             :                 }
     133       35537 :                 for(i=0, n = tables->h; i<mi; i++, n = n->next)
     134             :                         ;
     135       21789 :                 r = n->data;
     136             :                 /*  TODO, we now pick first (okay?)! In case of self joins we need to pick the correct table */
     137       21789 :                 r->flag = REL_PARTITION;
     138             :         }
     139       22087 :         return rel;
     140             : }
     141             : 
     142             : static int
     143      170657 : has_groupby(sql_rel *rel)
     144             : {
     145      262173 :         if (!rel)
     146             :                 return 0;
     147             : 
     148      258759 :         switch (rel->op) {
     149             :                 case op_groupby:
     150             :                         return 1;
     151       56034 :                 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       56034 :                         return has_groupby(rel->l) || has_groupby(rel->r);
     165        1330 :                 case op_munion:
     166        3737 :                         for (node *n = ((list*)rel->l)->h; n; n = n->next)
     167        2910 :                                 if (has_groupby(n->data))
     168             :                                         return 1;
     169             :                         return 0;
     170       91216 :                 case op_project:
     171             :                 case op_select:
     172             :                 case op_topn:
     173             :                 case op_sample:
     174       91216 :                         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         300 :                 case op_table:
     187         300 :                         if (IS_TABLE_PROD_FUNC(rel->flag) || rel->flag == TABLE_FROM_RELATION)
     188         300 :                                 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     1000419 : rel_partition(mvc *sql, sql_rel *rel)
     198             : {
     199     1000419 :         if (mvc_highwater(sql))
     200         320 :                 return sql_error(sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
     201             : 
     202     1000359 :         switch (rel->op) {
     203       92020 :         case op_basetable:
     204             :         case op_sample:
     205       92020 :                 rel->flag = REL_PARTITION;
     206       92020 :                 break;
     207      420392 :         case op_project:
     208             :         case op_select:
     209             :         case op_groupby:
     210             :         case op_topn:
     211      420392 :                 if (rel->l)
     212      254911 :                         rel_partition(sql, rel->l);
     213             :                 break;
     214        6157 :         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        6157 :                 if (rel->l)
     223        6157 :                         rel_partition(sql, rel->l);
     224        6157 :                 if (rel->r)
     225        6157 :                         rel_partition(sql, rel->r);
     226             :                 break;
     227        4121 :         case op_munion:
     228       15263 :                 for (node *n = ((list*)rel->l)->h; n; n = n->next)
     229       11142 :                         rel_partition(sql, n->data);
     230             :                 break;
     231      150182 :         case op_insert:
     232             :         case op_update:
     233             :         case op_delete:
     234             :         case op_truncate:
     235      150182 :                 if (rel->r && rel->card <= CARD_AGGR)
     236      102647 :                         rel_partition(sql, rel->r);
     237             :                 break;
     238       30463 :         case op_join:
     239             :         case op_left:
     240             :         case op_right:
     241             :         case op_full:
     242       30463 :                 if (has_groupby(rel->l) || has_groupby(rel->r)) {
     243        8376 :                         if (rel->l)
     244        8376 :                                 rel_partition(sql, rel->l);
     245        8376 :                         if (rel->r)
     246        8376 :                                 rel_partition(sql, rel->r);
     247             :                 } else {
     248       22087 :                         _rel_partition(sql, rel);
     249             :                 }
     250             :                 break;
     251      295362 :         case op_ddl:
     252      295362 :                 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       32680 :                         if (rel->l)
     254       32323 :                                 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        1662 :         case op_table:
     263        1662 :                 if ((IS_TABLE_PROD_FUNC(rel->flag) || rel->flag == TABLE_FROM_RELATION) && rel->l)
     264         268 :                         rel_partition(sql, rel->l);
     265             :                 break;
     266             :         default:
     267           0 :                 assert(0);
     268             :                 break;
     269             :         }
     270             :         return rel;
     271             : }

Generated by: LCOV version 1.14