LCOV - code coverage report
Current view: top level - sql/server - rel_statistics_functions.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 468 517 90.5 %
Date: 2024-10-04 20:04:04 Functions: 29 30 96.7 %

          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 "rel_statistics.h"
      15             : #include "mtime.h"
      16             : 
      17             : sql_hash *sql_functions_lookup = NULL;
      18             : 
      19             : static void
      20       39473 : sql_add_propagate_statistics(mvc *sql, sql_exp *e)
      21             : {
      22       39473 :         list *l = e->l;
      23       39473 :         sql_exp *first = l->h->data, *second = l->h->next->data;
      24       39473 :         atom *lmax, *rmax, *lmin, *rmin, *res1 = NULL, *res2 = NULL;
      25       39473 :         str msg1 = NULL, msg2 = NULL;
      26       39473 :         prop *est;
      27             : 
      28       39473 :         if ((lmax = find_prop_and_get(first->p, PROP_MAX)) && (rmax = find_prop_and_get(second->p, PROP_MAX)) &&
      29       17193 :                 (lmin = find_prop_and_get(first->p, PROP_MIN)) && (rmin = find_prop_and_get(second->p, PROP_MIN))) {
      30       17192 :                 sql_subfunc *f = (sql_subfunc *)e->f;
      31             : 
      32       17192 :                 if (strcmp(f->func->mod, "calc") == 0) {
      33       17041 :                         res1 = atom_add(sql->sa, atom_copy(sql->sa, lmax), atom_copy(sql->sa, rmax));
      34       17041 :                         res2 = atom_add(sql->sa, atom_copy(sql->sa, lmin), atom_copy(sql->sa, rmin));
      35             :                 } else {
      36         151 :                         sql_subtype tp;
      37             : 
      38         151 :                         assert(strcmp(f->func->mod, "mtime") == 0);
      39         151 :                         if (strcmp(f->func->imp, "date_add_msec_interval") == 0) {
      40          40 :                                 date sub1, sub2;
      41             : 
      42          40 :                                 if (!(msg1 = date_add_msec_interval(&sub1, (date)lmax->data.val.ival, rmax->data.val.lval)) &&
      43          40 :                                         !(msg2 = date_add_msec_interval(&sub2, (date)lmin->data.val.ival, rmin->data.val.lval))) {
      44          40 :                                         sql_find_subtype(&tp, "date", 0, 0);
      45          40 :                                         res1 = atom_general_ptr(sql->sa, &tp, &sub1);
      46          40 :                                         res2 = atom_general_ptr(sql->sa, &tp, &sub2);
      47             :                                 }
      48         111 :                         } else if (strcmp(f->func->imp, "addmonths") == 0) {
      49          10 :                                 date sub1, sub2;
      50             : 
      51          10 :                                 if (!(msg1 = date_addmonths(&sub1, (date)lmax->data.val.ival, rmax->data.val.ival)) &&
      52          10 :                                         !(msg2 = date_addmonths(&sub2, (date)lmin->data.val.ival, rmin->data.val.ival))) {
      53          10 :                                         sql_find_subtype(&tp, "date", 0, 0);
      54          10 :                                         res1 = atom_general_ptr(sql->sa, &tp, &sub1);
      55          10 :                                         res2 = atom_general_ptr(sql->sa, &tp, &sub2);
      56             :                                 }
      57         101 :                         } else if (strcmp(f->func->imp, "time_add_msec_interval") == 0) {
      58           2 :                                 daytime v1 = (daytime)lmax->data.val.lval, v2 = (daytime)lmin->data.val.lval,
      59           2 :                                                 sub1 = time_add_msec_interval(v1, rmax->data.val.lval),
      60           2 :                                                 sub2 = time_add_msec_interval(v2, rmin->data.val.lval);
      61             : 
      62           2 :                                 if (sub1 >= v1 && sub2 >= v2) { /* look for overflows */
      63           2 :                                         sql_find_subtype(&tp, "time", 0, 0);
      64           2 :                                         res1 = atom_general_ptr(sql->sa, &tp, &sub1);
      65           2 :                                         res2 = atom_general_ptr(sql->sa, &tp, &sub2);
      66             :                                 }
      67          99 :                         } else if (strcmp(f->func->imp, "timestamp_add_msec_interval") == 0) {
      68          99 :                                 timestamp sub1, sub2;
      69             : 
      70          99 :                                 if (!(msg1 = timestamp_add_msec_interval(&sub1, (timestamp)lmax->data.val.lval, rmax->data.val.lval)) &&
      71          99 :                                         !(msg2 = timestamp_add_msec_interval(&sub2, (timestamp)lmin->data.val.lval, rmin->data.val.lval))) {
      72          99 :                                         sql_find_subtype(&tp, "timestamp", 0, 0);
      73          99 :                                         res1 = atom_general_ptr(sql->sa, &tp, &sub1);
      74          99 :                                         res2 = atom_general_ptr(sql->sa, &tp, &sub2);
      75             :                                 }
      76           0 :                         } else if (strcmp(f->func->imp, "timestamp_add_month_interval") == 0) {
      77           0 :                                 timestamp sub1, sub2;
      78             : 
      79           0 :                                 if (!(msg1 = timestamp_add_month_interval(&sub1, (timestamp)lmax->data.val.lval, rmax->data.val.ival)) &&
      80           0 :                                         !(msg2 = timestamp_add_month_interval(&sub2, (timestamp)lmin->data.val.lval, rmin->data.val.ival))) {
      81           0 :                                         sql_find_subtype(&tp, "timestamp", 0, 0);
      82           0 :                                         res1 = atom_general_ptr(sql->sa, &tp, &sub1);
      83           0 :                                         res2 = atom_general_ptr(sql->sa, &tp, &sub2);
      84             :                                 }
      85             :                         }
      86             :                 }
      87             : 
      88       17192 :                 if (res1 && res2) { /* if the min/max pair overflows, then don't propagate */
      89       16144 :                         if (atom_cmp(res1, res2) > 0) {
      90       15114 :                                 set_minmax_property(sql, e, PROP_MAX, res1);
      91       15114 :                                 set_minmax_property(sql, e, PROP_MIN, res2);
      92             :                         } else {
      93        1030 :                                 set_minmax_property(sql, e, PROP_MAX, res2);
      94        1030 :                                 set_minmax_property(sql, e, PROP_MIN, res1);
      95             :                         }
      96             :                 }
      97       17192 :                 freeException(msg1);
      98       17192 :                 freeException(msg2);
      99             :         }
     100             :         /* propagate estimate */
     101       39473 :         if (!exp_is_atom(first) && exp_is_atom(second) && (est = find_prop(first->p, PROP_NUNIQUES))) {
     102       16225 :                 prop *p = e->p = prop_create(sql->sa, PROP_NUNIQUES, e->p);
     103       16225 :                 p->value.dval = est->value.dval;
     104       23248 :         } else if (exp_is_atom(first) && !exp_is_atom(second) && (est = find_prop(second->p, PROP_NUNIQUES))) {
     105          49 :                 prop *p = e->p = prop_create(sql->sa, PROP_NUNIQUES, e->p);
     106          49 :                 p->value.dval = est->value.dval;
     107             :         }
     108       39473 : }
     109             : 
     110             : static void
     111       11184 : sql_sub_propagate_statistics(mvc *sql, sql_exp *e)
     112             : {
     113       11184 :         list *l = e->l;
     114       11184 :         sql_exp *first = l->h->data, *second = l->h->next->data;
     115       11184 :         atom *lmax, *rmax, *lmin, *rmin, *res1 = NULL, *res2 = NULL;
     116       11184 :         prop *est;
     117             : 
     118       11184 :         if ((lmax = find_prop_and_get(first->p, PROP_MAX)) && (rmax = find_prop_and_get(second->p, PROP_MAX)) &&
     119        3840 :                 (lmin = find_prop_and_get(first->p, PROP_MIN)) && (rmin = find_prop_and_get(second->p, PROP_MIN))) {
     120        3840 :                 sql_subfunc *f = (sql_subfunc *)e->f;
     121        3840 :                 str msg1 = NULL, msg2 = NULL;
     122             : 
     123        3840 :                 if (strcmp(f->func->mod, "calc") == 0) {
     124        3801 :                         res1 = atom_sub(sql->sa, atom_copy(sql->sa, lmax), atom_copy(sql->sa, rmin));
     125        3801 :                         res2 = atom_sub(sql->sa, atom_copy(sql->sa, lmin), atom_copy(sql->sa, rmax));
     126             :                 } else {
     127          39 :                         sql_subtype tp;
     128             : 
     129          39 :                         assert(strcmp(f->func->mod, "mtime") == 0);
     130          39 :                         if (strcmp(f->func->imp, "diff") == 0) {
     131          29 :                                 sql_subtype *t1 = exp_subtype(first);
     132             : 
     133          29 :                                 switch (t1->type->eclass) {
     134          10 :                                 case EC_DATE: {
     135          10 :                                         res1 = atom_int(sql->sa, exp_subtype(e), date_diff_imp((date)lmax->data.val.ival, (date)rmin->data.val.ival));
     136          10 :                                         res2 = atom_int(sql->sa, exp_subtype(e), date_diff_imp((date)lmin->data.val.ival, (date)rmax->data.val.ival));
     137          10 :                                 } break;
     138           3 :                                 case EC_TIME: {
     139           3 :                                         res1 = atom_int(sql->sa, exp_subtype(e), daytime_diff((daytime)lmax->data.val.lval, (daytime)rmin->data.val.lval));
     140           3 :                                         res2 = atom_int(sql->sa, exp_subtype(e), daytime_diff((daytime)lmin->data.val.lval, (daytime)rmax->data.val.lval));
     141           3 :                                 } break;
     142          16 :                                 case EC_TIMESTAMP: {
     143          16 :                                         res1 = atom_int(sql->sa, exp_subtype(e), TSDIFF((timestamp)lmax->data.val.lval, (timestamp)rmin->data.val.lval));
     144          16 :                                         res2 = atom_int(sql->sa, exp_subtype(e), TSDIFF((timestamp)lmin->data.val.lval, (timestamp)rmax->data.val.lval));
     145          16 :                                 } break;
     146             :                                 default:
     147             :                                         break;
     148             :                                 }
     149          10 :                         } else if (strcmp(f->func->imp, "date_sub_msec_interval") == 0) {
     150           5 :                                 date sub1, sub2;
     151             : 
     152           5 :                                 if (!(msg1 = date_sub_msec_interval(&sub1, (date)lmax->data.val.ival, rmin->data.val.lval)) &&
     153           5 :                                         !(msg2 = date_sub_msec_interval(&sub2, (date)lmin->data.val.ival, rmax->data.val.lval))) {
     154           5 :                                         sql_find_subtype(&tp, "date", 0, 0);
     155           5 :                                         res1 = atom_general_ptr(sql->sa, &tp, &sub1);
     156           5 :                                         res2 = atom_general_ptr(sql->sa, &tp, &sub2);
     157             :                                 }
     158           5 :                         } else if (strcmp(f->func->imp, "date_sub_month_interval") == 0) {
     159           1 :                                 date sub1, sub2;
     160             : 
     161           1 :                                 if (!(msg1 = date_submonths(&sub1, (date)lmax->data.val.ival, rmin->data.val.ival)) &&
     162           0 :                                         !(msg2 = date_submonths(&sub2, (date)lmin->data.val.ival, rmax->data.val.ival))) {
     163           0 :                                         sql_find_subtype(&tp, "date", 0, 0);
     164           0 :                                         res1 = atom_general_ptr(sql->sa, &tp, &sub1);
     165           0 :                                         res2 = atom_general_ptr(sql->sa, &tp, &sub2);
     166             :                                 }
     167           4 :                         } else if (strcmp(f->func->imp, "time_sub_msec_interval") == 0) {
     168           2 :                                 daytime v1 = (daytime)lmax->data.val.lval, v2 = (daytime)lmin->data.val.lval,
     169           2 :                                                 sub1 = time_sub_msec_interval(v1, rmin->data.val.lval),
     170           2 :                                                 sub2 = time_sub_msec_interval(v2, rmax->data.val.lval);
     171             : 
     172           2 :                                 if (sub1 <= v1 && sub2 <= v2) { /* look for overflows */
     173           2 :                                         sql_find_subtype(&tp, "time", 0, 0);
     174           2 :                                         res1 = atom_general_ptr(sql->sa, &tp, &sub1);
     175           2 :                                         res2 = atom_general_ptr(sql->sa, &tp, &sub2);
     176             :                                 }
     177           2 :                         } else if (strcmp(f->func->imp, "timestamp_sub_msec_interval") == 0) {
     178           2 :                                 timestamp sub1, sub2;
     179             : 
     180           2 :                                 if (!(msg1 = timestamp_sub_msec_interval(&sub1, (timestamp)lmax->data.val.lval, rmin->data.val.lval)) &&
     181           2 :                                         !(msg2 = timestamp_sub_msec_interval(&sub2, (timestamp)lmin->data.val.lval, rmax->data.val.lval))) {
     182           2 :                                         sql_find_subtype(&tp, "timestamp", 0, 0);
     183           2 :                                         res1 = atom_general_ptr(sql->sa, &tp, &sub1);
     184           2 :                                         res2 = atom_general_ptr(sql->sa, &tp, &sub2);
     185             :                                 }
     186           0 :                         } else if (strcmp(f->func->imp, "timestamp_sub_month_interval") == 0) {
     187           0 :                                 timestamp sub1, sub2;
     188             : 
     189           0 :                                 if (!(msg1 = timestamp_sub_month_interval(&sub1, (timestamp)lmax->data.val.lval, rmin->data.val.ival)) &&
     190           0 :                                         !(msg2 = timestamp_sub_month_interval(&sub2, (timestamp)lmin->data.val.lval, rmax->data.val.ival))) {
     191           0 :                                         sql_find_subtype(&tp, "timestamp", 0, 0);
     192           0 :                                         res1 = atom_general_ptr(sql->sa, &tp, &sub1);
     193           0 :                                         res2 = atom_general_ptr(sql->sa, &tp, &sub2);
     194             :                                 }
     195             :                         }
     196             :                 }
     197             : 
     198        3840 :                 if (res1 && res2) { /* if the min/max pair overflows, then don't propagate */
     199        3839 :                         if (atom_cmp(res1, res2) > 0) {
     200        3759 :                                 set_minmax_property(sql, e, PROP_MAX, res1);
     201        3759 :                                 set_minmax_property(sql, e, PROP_MIN, res2);
     202             :                         } else {
     203          80 :                                 set_minmax_property(sql, e, PROP_MAX, res2);
     204          80 :                                 set_minmax_property(sql, e, PROP_MIN, res1);
     205             :                         }
     206             :                 }
     207        3840 :                 freeException(msg1);
     208        3840 :                 freeException(msg2);
     209             :         }
     210             :         /* propagate estimate */
     211       11184 :         if (!exp_is_atom(first) && exp_is_atom(second) && (est = find_prop(first->p, PROP_NUNIQUES))) {
     212        4003 :                 prop *p = e->p = prop_create(sql->sa, PROP_NUNIQUES, e->p);
     213        4003 :                 p->value.dval = est->value.dval;
     214        7181 :         } else if (exp_is_atom(first) && !exp_is_atom(second) && (est = find_prop(second->p, PROP_NUNIQUES))) {
     215          29 :                 prop *p = e->p = prop_create(sql->sa, PROP_NUNIQUES, e->p);
     216          29 :                 p->value.dval = est->value.dval;
     217             :         }
     218       11184 : }
     219             : 
     220             : static void
     221       14785 : sql_mul_propagate_statistics(mvc *sql, sql_exp *e)
     222             : {
     223       14785 :         list *l = e->l;
     224       14785 :         sql_exp *first = l->h->data, *second = l->h->next->data;
     225       14785 :         atom *lmax, *rmax, *lmin, *rmin;
     226             : 
     227       14785 :         if ((lmax = find_prop_and_get(first->p, PROP_MAX)) && (rmax = find_prop_and_get(second->p, PROP_MAX)) &&
     228        8871 :                 (lmin = find_prop_and_get(first->p, PROP_MIN)) && (rmin = find_prop_and_get(second->p, PROP_MIN))) {
     229        8871 :                 atom *res1 = atom_mul(sql->sa, atom_copy(sql->sa, lmax), atom_copy(sql->sa, rmax));
     230        8871 :                 atom *res2 = atom_mul(sql->sa, atom_copy(sql->sa, lmin), atom_copy(sql->sa, rmin));
     231             : 
     232        8871 :                 if (res1 && res2) { /* if the min/max pair overflows, then don't propagate */
     233        8800 :                         atom *zero1 = atom_zero_value(sql->sa, &(lmax->tpe)), *zero2 = atom_zero_value(sql->sa, &(rmax->tpe));
     234        8800 :                         int cmp1 = atom_cmp(lmax, zero1), cmp2 = atom_cmp(lmin, zero1), cmp3 = atom_cmp(rmin, zero2), cmp4 = atom_cmp(rmax, zero2);
     235             : 
     236        8800 :                         if (cmp1 >= 0 && cmp2 >= 0 && cmp3 >= 0 && cmp4 >= 0) { /* if all positive then propagate */
     237        8765 :                                 set_minmax_property(sql, e, PROP_MAX, res1);
     238        8765 :                                 set_minmax_property(sql, e, PROP_MIN, res2);
     239          35 :                         } else if (cmp1 < 0 && cmp2 < 0 && cmp3 < 0 && cmp4 < 0) { /* if all negative propagate by swapping min and max */
     240           6 :                                 set_minmax_property(sql, e, PROP_MAX, res2);
     241           6 :                                 set_minmax_property(sql, e, PROP_MIN, res1);
     242             :                         }
     243             :                 }
     244             :         }
     245       14785 : }
     246             : 
     247             : static void
     248        1381 : sql_div_propagate_statistics(mvc *sql, sql_exp *e)
     249             : {
     250        1381 :         list *l = e->l;
     251        1381 :         sql_exp *first = l->h->data, *second = l->h->next->data;
     252        1381 :         atom *lmax, *rmax, *lmin, *rmin;
     253             : 
     254        1381 :         if ((lmax = find_prop_and_get(first->p, PROP_MAX)) && (rmax = find_prop_and_get(second->p, PROP_MAX)) &&
     255         301 :                 (lmin = find_prop_and_get(first->p, PROP_MIN)) && (rmin = find_prop_and_get(second->p, PROP_MIN))) {
     256         301 :                 atom *res1 = atom_div(sql->sa, atom_copy(sql->sa, lmax), atom_copy(sql->sa, rmin));
     257         301 :                 atom *res2 = atom_div(sql->sa, atom_copy(sql->sa, lmin), atom_copy(sql->sa, rmax));
     258             : 
     259         301 :                 if (res1 && res2) { /* on div by zero don't propagate */
     260         277 :                         atom *zero1 = atom_zero_value(sql->sa, &(lmax->tpe)), *zero2 = atom_zero_value(sql->sa, &(rmax->tpe));
     261         277 :                         int cmp1 = atom_cmp(lmax, zero1), cmp2 = atom_cmp(lmin, zero1), cmp3 = atom_cmp(rmin, zero2), cmp4 = atom_cmp(rmax, zero2);
     262             : 
     263         277 :                         if (cmp1 >= 0 && cmp2 >= 0 && cmp3 >= 0 && cmp4 >= 0) { /* if all positive then propagate */
     264         252 :                                 set_minmax_property(sql, e, PROP_MAX, res1);
     265         252 :                                 set_minmax_property(sql, e, PROP_MIN, res2);
     266          25 :                         } else if (cmp1 < 0 && cmp2 < 0 && cmp3 < 0 && cmp4 < 0) { /* if all negative propagate by swapping min and max */
     267           3 :                                 set_minmax_property(sql, e, PROP_MAX, res2);
     268           3 :                                 set_minmax_property(sql, e, PROP_MIN, res1);
     269             :                         }
     270             :                 }
     271             :         }
     272        1381 : }
     273             : 
     274             : static void
     275         366 : sql_extend_min_max(mvc *sql, sql_exp *e, sql_exp *first, sql_exp *second)
     276             : {
     277         366 :         atom *lval, *rval;
     278             : 
     279         366 :         if ((lval = find_prop_and_get(first->p, PROP_MAX)) && (rval = find_prop_and_get(second->p, PROP_MAX)))
     280         318 :                 set_minmax_property(sql, e, PROP_MAX, atom_cmp(lval, rval) > 0 ? lval : rval);
     281         366 :         if ((lval = find_prop_and_get(first->p, PROP_MIN)) && (rval = find_prop_and_get(second->p, PROP_MIN)))
     282         324 :                 set_minmax_property(sql, e, PROP_MIN, atom_cmp(lval, rval) > 0 ? rval : lval);
     283         366 : }
     284             : 
     285             : static void
     286         366 : sql_least_greatest_propagate_statistics(mvc *sql, sql_exp *e)
     287             : {
     288         366 :         list *l = e->l;
     289         366 :         sql_extend_min_max(sql, e, l->h->data, l->h->next->data);
     290         366 : }
     291             : 
     292             : static void
     293       20686 : sql_ifthenelse_propagate_statistics(mvc *sql, sql_exp *e)
     294             : {
     295       20686 :         list *l = e->l;
     296       20686 :         sql_exp *first = l->h->next->data;
     297       20686 :         atom *curmin = NULL, *curmax = NULL, *lval;
     298       20686 :         unsigned int i = 0;
     299             : 
     300       20686 :         assert(list_length(l) >= 2);
     301       20686 :         if ((lval = find_prop_and_get(first->p, PROP_MAX)))
     302             :                 curmax = lval;
     303       20686 :         if ((lval = find_prop_and_get(first->p, PROP_MIN)))
     304             :                 curmin = lval;
     305       36472 :         for (node *n = l->h->next->next ; n && curmin && curmax ; n = n->next) {
     306       15786 :                 if ((i & 1) || n == l->t) { /* the last expression, ie the result, must be included */
     307       15786 :                         sql_exp *next = n->data;
     308       15786 :                         if ((lval = find_prop_and_get(next->p, PROP_MAX))) {
     309        7736 :                                 curmax = atom_cmp(lval, curmax) > 0 ? lval : curmax;
     310             :                         } else {
     311             :                                 curmax = NULL;
     312             :                         }
     313       15786 :                         if ((lval = find_prop_and_get(next->p, PROP_MIN))) {
     314        7736 :                                 curmin = atom_cmp(lval, curmin) > 0 ? curmin : lval;
     315             :                         } else {
     316             :                                 curmin = NULL;
     317             :                         }
     318             :                 }
     319       15786 :                 i++;
     320             :         }
     321             : 
     322       20686 :         if (curmin && curmax) {
     323        7736 :                 set_minmax_property(sql, e, PROP_MAX, curmax);
     324        7736 :                 set_minmax_property(sql, e, PROP_MIN, curmin);
     325             :         }
     326       20686 : }
     327             : 
     328             : static void
     329        4360 : sql_casewhen_propagate_statistics(mvc *sql, sql_exp *e)
     330             : {
     331        4360 :         list *l = e->l;
     332        4360 :         sql_exp *first = l->h->next->next->data;
     333        4360 :         atom *curmin = NULL, *curmax = NULL, *lval;
     334        4360 :         unsigned int i = 0;
     335             : 
     336        4360 :         assert(list_length(l) >= 3);
     337        4360 :         if ((lval = find_prop_and_get(first->p, PROP_MAX)))
     338             :                 curmax = lval;
     339        4360 :         if ((lval = find_prop_and_get(first->p, PROP_MIN)))
     340             :                 curmin = lval;
     341       32081 :         for (node *n = l->h->next->next->next ; n && curmin && curmax ; n = n->next) {
     342       27721 :                 if ((i & 1) || n == l->t) { /* the last expression, ie the result, must be included */
     343       15442 :                         sql_exp *next = n->data;
     344       15442 :                         if ((lval = find_prop_and_get(next->p, PROP_MAX))) {
     345       13242 :                                 curmax = atom_cmp(lval, curmax) > 0 ? lval : curmax;
     346             :                         } else {
     347             :                                 curmax = NULL;
     348             :                         }
     349       15442 :                         if ((lval = find_prop_and_get(next->p, PROP_MIN))) {
     350       13242 :                                 curmin = atom_cmp(lval, curmin) > 0 ? curmin : lval;
     351             :                         } else {
     352             :                                 curmin = NULL;
     353             :                         }
     354             :                 }
     355       27721 :                 i++;
     356             :         }
     357             : 
     358        4360 :         if (curmin && curmax) {
     359        1395 :                 set_minmax_property(sql, e, PROP_MAX, curmax);
     360        1395 :                 set_minmax_property(sql, e, PROP_MIN, curmin);
     361             :         }
     362        4360 : }
     363             : 
     364             : static void
     365          88 : sql_nullif_propagate_statistics(mvc *sql, sql_exp *e)
     366             : {
     367          88 :         list *l = e->l;
     368          88 :         sql_exp *first = l->h->data;
     369          88 :         atom *lval;
     370             : 
     371          88 :         if ((lval = find_prop_and_get(first->p, PROP_MAX)))
     372          53 :                 set_minmax_property(sql, e, PROP_MAX, lval);
     373          88 :         if ((lval = find_prop_and_get(first->p, PROP_MIN)))
     374          53 :                 set_minmax_property(sql, e, PROP_MIN, lval);
     375          88 : }
     376             : 
     377             : static void
     378        3584 : sql_neg_propagate_statistics(mvc *sql, sql_exp *e)
     379             : {
     380        3584 :         list *l = e->l;
     381        3584 :         sql_exp *first = l->h->data;
     382        3584 :         atom *lval;
     383        3584 :         prop *est;
     384             : 
     385        3584 :         if ((lval = find_prop_and_get(first->p, PROP_MIN))) {
     386        3420 :                 atom *res = atom_copy(sql->sa, lval);
     387        3420 :                 if ((res = atom_neg(sql->sa, res)))
     388        3420 :                         set_minmax_property(sql, e, PROP_MAX, res);
     389             :         }
     390        3584 :         if ((lval = find_prop_and_get(first->p, PROP_MAX))) {
     391        3418 :                 atom *res = atom_copy(sql->sa, lval);
     392        3418 :                 if ((res = atom_neg(sql->sa, res)))
     393        3418 :                         set_minmax_property(sql, e, PROP_MIN, res);
     394             :         }
     395        3584 :         if ((est = find_prop(first->p, PROP_NUNIQUES))) {
     396        3487 :                 prop *p = e->p = prop_create(sql->sa, PROP_NUNIQUES, e->p);
     397        3487 :                 p->value.dval = est->value.dval;
     398             :         }
     399        3584 : }
     400             : 
     401             : static void
     402          15 : sql_sign_propagate_statistics(mvc *sql, sql_exp *e)
     403             : {
     404          15 :         list *l = e->l;
     405          15 :         sql_exp *first = l->h->data;
     406          15 :         atom *omin, *omax;
     407          15 :         sql_subtype *bte = sql_bind_localtype("bte");
     408          15 :         bool properties_set = false;
     409             : 
     410          15 :         if ((omin = find_prop_and_get(first->p, PROP_MIN)) && (omax = find_prop_and_get(first->p, PROP_MAX))) {
     411          10 :                 atom *zero1 = atom_zero_value(sql->sa, &(omin->tpe));
     412          10 :                 int cmp1 = atom_cmp(omax, zero1), cmp2 = atom_cmp(omin, zero1);
     413             : 
     414          10 :                 if (cmp1 == 0 && cmp2 == 0) {
     415           0 :                         set_minmax_property(sql, e, PROP_MAX, atom_int(sql->sa, bte, 0));
     416           0 :                         set_minmax_property(sql, e, PROP_MIN, atom_int(sql->sa, bte, 0));
     417           0 :                         properties_set = true;
     418          10 :                 } else if (cmp1 > 0 && cmp2 > 0) {
     419           3 :                         set_minmax_property(sql, e, PROP_MAX, atom_int(sql->sa, bte, 1));
     420           3 :                         set_minmax_property(sql, e, PROP_MIN, atom_int(sql->sa, bte, 1));
     421           3 :                         properties_set = true;
     422           7 :                 } else if (cmp1 < 0 && cmp2 < 0) {
     423           1 :                         set_minmax_property(sql, e, PROP_MAX, atom_int(sql->sa, bte, -1));
     424           1 :                         set_minmax_property(sql, e, PROP_MIN, atom_int(sql->sa, bte, -1));
     425           1 :                         properties_set = true;
     426             :                 }
     427             :         }
     428           4 :         if (!properties_set) {
     429          11 :                 set_minmax_property(sql, e, PROP_MAX, atom_int(sql->sa, bte, 1));
     430          11 :                 set_minmax_property(sql, e, PROP_MIN, atom_int(sql->sa, bte, -1));
     431             :         }
     432          15 :         prop *p = e->p = prop_create(sql->sa, PROP_NUNIQUES, e->p);
     433          15 :         p->value.dval = 2;
     434          15 : }
     435             : 
     436             : static void
     437        2077 : sql_abs_propagate_statistics(mvc *sql, sql_exp *e)
     438             : {
     439        2077 :         list *l = e->l;
     440        2077 :         sql_exp *first = l->h->data;
     441        2077 :         atom *omin, *omax;
     442             : 
     443        2077 :         if ((omin = find_prop_and_get(first->p, PROP_MIN)) && (omax = find_prop_and_get(first->p, PROP_MAX))) {
     444        1222 :                 atom *zero = atom_zero_value(sql->sa, &(omin->tpe));
     445        1222 :                 int cmp1 = atom_cmp(omax, zero), cmp2 = atom_cmp(omin, zero);
     446             : 
     447        1222 :                 if (cmp1 >= 0 && cmp2 >= 0) {
     448        1017 :                         set_minmax_property(sql, e, PROP_MAX, omax);
     449        1017 :                         set_minmax_property(sql, e, PROP_MIN, omin);
     450         205 :                 } else if (cmp1 < 0 && cmp2 < 0) {
     451          15 :                         atom *res1 = atom_copy(sql->sa, omin), *res2 = atom_copy(sql->sa, omax);
     452             : 
     453          15 :                         if ((res1 = atom_absolute(sql->sa, res1)) && (res2 = atom_absolute(sql->sa, res2))) {
     454          15 :                                 set_minmax_property(sql, e, PROP_MAX, res1);
     455          15 :                                 set_minmax_property(sql, e, PROP_MIN, res2);
     456             :                         }
     457             :                 } else {
     458         190 :                         atom *res1 = atom_copy(sql->sa, omin);
     459             : 
     460         190 :                         if ((res1 = atom_absolute(sql->sa, res1))) {
     461         369 :                                 set_minmax_property(sql, e, PROP_MAX, atom_cmp(res1, omax) > 0 ? res1 : omax);
     462         190 :                                 set_minmax_property(sql, e, PROP_MIN, zero);
     463             :                         }
     464             :                 }
     465             :         }
     466        2077 : }
     467             : 
     468             : static void
     469        1426 : sql_coalesce_propagate_statistics(mvc *sql, sql_exp *e)
     470             : {
     471        1426 :         list *l = e->l;
     472        1426 :         sql_exp *first = l->h->data;
     473        1426 :         atom *curmin = NULL, *curmax = NULL, *lval;
     474             : 
     475        1426 :         if ((lval = find_prop_and_get(first->p, PROP_MAX)))
     476             :                 curmax = lval;
     477        1426 :         if ((lval = find_prop_and_get(first->p, PROP_MIN)))
     478             :                 curmin = lval;
     479        1773 :         for (node *n = l->h->next ; n && curmin && curmax ; n = n->next) {
     480         347 :                 sql_exp *next = n->data;
     481             : 
     482         347 :                 if ((lval = find_prop_and_get(next->p, PROP_MAX))) {
     483         176 :                         curmax = atom_cmp(lval, curmax) > 0 ? lval : curmax;
     484             :                 } else {
     485             :                         curmax = NULL;
     486             :                 }
     487         347 :                 if ((lval = find_prop_and_get(next->p, PROP_MIN))) {
     488         176 :                         curmin = atom_cmp(lval, curmin) > 0 ? curmin : lval;
     489             :                 } else {
     490             :                         curmin = NULL;
     491             :                 }
     492             :         }
     493             : 
     494        1426 :         if (curmin && curmax) {
     495         131 :                 set_minmax_property(sql, e, PROP_MAX, curmax);
     496         131 :                 set_minmax_property(sql, e, PROP_MIN, curmin);
     497             :         }
     498        1426 : }
     499             : 
     500             : static void
     501           3 : sql_century_propagate_statistics(mvc *sql, sql_exp *e)
     502             : {
     503           3 :         list *l = e->l;
     504           3 :         sql_exp *first = l->h->data;
     505           3 :         atom *omin, *omax;
     506           3 :         int nmin = -50, nmax = 1800;
     507             : 
     508           3 :         if ((omin = find_prop_and_get(first->p, PROP_MIN)) && (omax = find_prop_and_get(first->p, PROP_MAX))) {
     509           2 :                 sql_subtype *tp = exp_subtype(first);
     510           2 :                 if (tp->type->eclass == EC_TIMESTAMP) {
     511           1 :                         nmin = timestamp_century((timestamp)omin->data.val.lval);
     512           1 :                         nmax = timestamp_century((timestamp)omax->data.val.lval);
     513           1 :                 } else if (tp->type->eclass == EC_DATE) {
     514           1 :                         nmin = date_century((date)omin->data.val.ival);
     515           1 :                         nmax = date_century((date)omax->data.val.ival);
     516             :                 }
     517             :         }
     518             : 
     519           3 :         set_minmax_property(sql, e, PROP_MAX, atom_int(sql->sa, sql_bind_localtype("int"), nmax));
     520           3 :         set_minmax_property(sql, e, PROP_MIN, atom_int(sql->sa, sql_bind_localtype("int"), nmin));
     521           3 : }
     522             : 
     523             : static void
     524           0 : sql_decade_propagate_statistics(mvc *sql, sql_exp *e)
     525             : {
     526           0 :         list *l = e->l;
     527           0 :         sql_exp *first = l->h->data;
     528           0 :         atom *omin, *omax;
     529           0 :         int nmin = -500, nmax = 18000;
     530             : 
     531           0 :         if ((omin = find_prop_and_get(first->p, PROP_MIN)) && (omax = find_prop_and_get(first->p, PROP_MAX))) {
     532           0 :                 sql_subtype *tp = exp_subtype(first);
     533           0 :                 if (tp->type->eclass == EC_TIMESTAMP) {
     534           0 :                         nmin = timestamp_decade((timestamp)omin->data.val.lval);
     535           0 :                         nmax = timestamp_decade((timestamp)omax->data.val.lval);
     536           0 :                 } else if (tp->type->eclass == EC_DATE) {
     537           0 :                         nmin = date_decade((date)omin->data.val.ival);
     538           0 :                         nmax = date_decade((date)omax->data.val.ival);
     539             :                 }
     540             :         }
     541             : 
     542           0 :         set_minmax_property(sql, e, PROP_MAX, atom_int(sql->sa, sql_bind_localtype("int"), nmax));
     543           0 :         set_minmax_property(sql, e, PROP_MIN, atom_int(sql->sa, sql_bind_localtype("int"), nmin));
     544           0 : }
     545             : 
     546             : static void
     547          53 : sql_year_propagate_statistics(mvc *sql, sql_exp *e)
     548             : {
     549          53 :         list *l = e->l;
     550          53 :         sql_exp *first = l->h->data;
     551          53 :         atom *omin, *omax;
     552          53 :         int nmin = -5000, nmax = 180000;
     553             : 
     554          53 :         if ((omin = find_prop_and_get(first->p, PROP_MIN)) && (omax = find_prop_and_get(first->p, PROP_MAX))) {
     555          38 :                 sql_subtype *tp = exp_subtype(first);
     556          38 :                 if (tp->type->eclass == EC_TIMESTAMP) {
     557           4 :                         nmin = timestamp_year((timestamp)omin->data.val.lval);
     558           4 :                         nmax = timestamp_year((timestamp)omax->data.val.lval);
     559          34 :                 } else if (tp->type->eclass == EC_DATE) {
     560          34 :                         nmin = date_year((date)omin->data.val.ival);
     561          34 :                         nmax = date_year((date)omax->data.val.ival);
     562             :                 }
     563             :         }
     564             : 
     565          53 :         set_minmax_property(sql, e, PROP_MAX, atom_int(sql->sa, sql_bind_localtype("int"), nmax));
     566          53 :         set_minmax_property(sql, e, PROP_MIN, atom_int(sql->sa, sql_bind_localtype("int"), nmin));
     567          53 : }
     568             : 
     569             : static void
     570          15 : sql_quarter_propagate_statistics(mvc *sql, sql_exp *e)
     571             : {
     572          15 :         set_minmax_property(sql, e, PROP_MAX, atom_int(sql->sa, sql_bind_localtype("int"), 4));
     573          15 :         set_minmax_property(sql, e, PROP_MIN, atom_int(sql->sa, sql_bind_localtype("int"), 1));
     574          15 :         prop *p = e->p = prop_create(sql->sa, PROP_NUNIQUES, e->p);
     575          15 :         p->value.dval = 4;
     576          15 : }
     577             : 
     578             : static void
     579          61 : sql_month_propagate_statistics(mvc *sql, sql_exp *e)
     580             : {
     581          61 :         set_minmax_property(sql, e, PROP_MAX, atom_int(sql->sa, sql_bind_localtype("int"), 12));
     582          61 :         set_minmax_property(sql, e, PROP_MIN, atom_int(sql->sa, sql_bind_localtype("int"), 1));
     583          61 :         prop *p = e->p = prop_create(sql->sa, PROP_NUNIQUES, e->p);
     584          61 :         p->value.dval = 12;
     585          61 : }
     586             : 
     587             : static void
     588          25 : sql_day_propagate_statistics(mvc *sql, sql_exp *e)
     589             : {
     590          25 :         list *l = e->l;
     591          25 :         sql_exp *first = l->h->data;
     592          25 :         sql_subtype *tp = exp_subtype(first);
     593          25 :         const char *localtype = tp->type->eclass == EC_SEC ? "lng" : "int";
     594          25 :         atom *omin, *omax;
     595          25 :         lng nmin = 1, nmax = 31;
     596             : 
     597          25 :         if ((omin = find_prop_and_get(first->p, PROP_MIN)) && (omax = find_prop_and_get(first->p, PROP_MAX))) {
     598          14 :                 if (tp->type->eclass == EC_SEC) {
     599           5 :                         nmin = sql_day(omin->data.val.lval);
     600           5 :                         nmax = sql_day(omax->data.val.lval);
     601             :                 }
     602             :         }
     603             : 
     604          25 :         set_minmax_property(sql, e, PROP_MAX, atom_int(sql->sa, sql_bind_localtype(localtype), nmax));
     605          25 :         set_minmax_property(sql, e, PROP_MIN, atom_int(sql->sa, sql_bind_localtype(localtype), nmin));
     606          25 :         prop *p = e->p = prop_create(sql->sa, PROP_NUNIQUES, e->p);
     607          25 :         p->value.dval = (dbl) (nmax - nmin + 1);
     608          25 : }
     609             : 
     610             : static void
     611           3 : sql_dayofyear_propagate_statistics(mvc *sql, sql_exp *e)
     612             : {
     613           3 :         set_minmax_property(sql, e, PROP_MAX, atom_int(sql->sa, sql_bind_localtype("int"), 366));
     614           3 :         set_minmax_property(sql, e, PROP_MIN, atom_int(sql->sa, sql_bind_localtype("int"), 1));
     615           3 :         prop *p = e->p = prop_create(sql->sa, PROP_NUNIQUES, e->p);
     616           3 :         p->value.dval = 366;
     617           3 : }
     618             : 
     619             : static void
     620          17 : sql_weekofyear_propagate_statistics(mvc *sql, sql_exp *e)
     621             : {
     622          17 :         set_minmax_property(sql, e, PROP_MAX, atom_int(sql->sa, sql_bind_localtype("int"), 53));
     623          17 :         set_minmax_property(sql, e, PROP_MIN, atom_int(sql->sa, sql_bind_localtype("int"), 1));
     624          17 :         prop *p = e->p = prop_create(sql->sa, PROP_NUNIQUES, e->p);
     625          17 :         p->value.dval = 53;
     626          17 : }
     627             : 
     628             : static void
     629           4 : sql_dayofweek_propagate_statistics(mvc *sql, sql_exp *e)
     630             : {
     631           4 :         set_minmax_property(sql, e, PROP_MAX, atom_int(sql->sa, sql_bind_localtype("int"), 7));
     632           4 :         set_minmax_property(sql, e, PROP_MIN, atom_int(sql->sa, sql_bind_localtype("int"), 1));
     633           4 :         prop *p = e->p = prop_create(sql->sa, PROP_NUNIQUES, e->p);
     634           4 :         p->value.dval = 7;
     635           4 : }
     636             : 
     637             : static void
     638          20 : sql_hour_propagate_statistics(mvc *sql, sql_exp *e)
     639             : {
     640          20 :         list *l = e->l;
     641          20 :         sql_exp *first = l->h->data;
     642          20 :         atom *omin, *omax;
     643          20 :         int nmin = 0, nmax = 23;
     644          20 :         sql_subtype *tp = exp_subtype(first);
     645          20 :         const char *localtype = tp->type->eclass == EC_SEC ? "lng" : "int";
     646             : 
     647          20 :         if ((omin = find_prop_and_get(first->p, PROP_MIN)) && (omax = find_prop_and_get(first->p, PROP_MAX))) {
     648           8 :                 if (tp->type->eclass == EC_TIME) {
     649           6 :                         nmin = daytime_hour((daytime)omin->data.val.lval);
     650           6 :                         nmax = daytime_hour((daytime)omax->data.val.lval);
     651             :                 }
     652             :         }
     653             : 
     654          20 :         set_minmax_property(sql, e, PROP_MAX, atom_int(sql->sa, sql_bind_localtype(localtype), nmax));
     655          20 :         set_minmax_property(sql, e, PROP_MIN, atom_int(sql->sa, sql_bind_localtype(localtype), nmin));
     656          20 :         prop *p = e->p = prop_create(sql->sa, PROP_NUNIQUES, e->p);
     657          20 :         p->value.dval = 24;
     658          20 : }
     659             : 
     660             : static void
     661          22 : sql_minute_propagate_statistics(mvc *sql, sql_exp *e)
     662             : {
     663          22 :         set_minmax_property(sql, e, PROP_MAX, atom_int(sql->sa, sql_bind_localtype("int"), 59));
     664          22 :         set_minmax_property(sql, e, PROP_MIN, atom_int(sql->sa, sql_bind_localtype("int"), 0));
     665          22 :         prop *p = e->p = prop_create(sql->sa, PROP_NUNIQUES, e->p);
     666          22 :         p->value.dval = 60;
     667          22 : }
     668             : 
     669             : static void
     670          25 : sql_second_propagate_statistics(mvc *sql, sql_exp *e)
     671             : {
     672          25 :         list *l = e->l;
     673          25 :         sql_exp *first = l->h->data;
     674          25 :         sql_subtype *tp = exp_subtype(first), tp_res;
     675          25 :         int nmin = 0, nmax = 59;
     676             : 
     677          25 :         if (tp->type->eclass == EC_TIMESTAMP || tp->type->eclass == EC_TIME) {
     678          24 :                 nmax = 59999999;
     679          24 :                 sql_find_subtype(&tp_res, "decimal", 8, 6);
     680             :         } else {
     681           1 :                 sql_find_subtype(&tp_res, "int", 0, 0);
     682             :         }
     683          25 :         set_minmax_property(sql, e, PROP_MAX, atom_int(sql->sa, &tp_res, nmax));
     684          25 :         set_minmax_property(sql, e, PROP_MIN, atom_int(sql->sa, &tp_res, nmin));
     685          25 :         prop *p = e->p = prop_create(sql->sa, PROP_NUNIQUES, e->p);
     686          25 :         p->value.dval = 60;
     687          25 : }
     688             : 
     689             : static void
     690           6 : sql_epoch_ms_propagate_statistics(mvc *sql, sql_exp *e)
     691             : {
     692           6 :         list *l = e->l;
     693           6 :         sql_exp *first = l->h->data;
     694           6 :         atom *omin, *omax, *nmin = NULL, *nmax = NULL;
     695           6 :         sql_subtype *tp = exp_subtype(first);
     696             : 
     697           6 :         if ((omin = find_prop_and_get(first->p, PROP_MIN)) && (omax = find_prop_and_get(first->p, PROP_MAX))) {
     698           1 :                 switch (tp->type->eclass) {
     699           1 :                 case EC_DATE: {
     700           1 :                         nmax = atom_int(sql->sa, sql_bind_localtype("lng"), date_to_msec_since_epoch((date)omax->data.val.ival));
     701           1 :                         nmin = atom_int(sql->sa, sql_bind_localtype("lng"), date_to_msec_since_epoch((date)omin->data.val.ival));
     702           1 :                 } break;
     703           0 :                 case EC_TIME: {
     704           0 :                         nmax = atom_int(sql->sa, sql_bind_localtype("lng"), daytime_to_msec_since_epoch((daytime)omax->data.val.lval));
     705           0 :                         nmin = atom_int(sql->sa, sql_bind_localtype("lng"), daytime_to_msec_since_epoch((daytime)omin->data.val.lval));
     706           0 :                 } break;
     707           0 :                 case EC_TIMESTAMP: {
     708           0 :                         nmax = atom_int(sql->sa, sql_bind_localtype("lng"), timestamp_to_msec_since_epoch((timestamp)omax->data.val.lval));
     709           0 :                         nmin = atom_int(sql->sa, sql_bind_localtype("lng"), timestamp_to_msec_since_epoch((timestamp)omin->data.val.lval));
     710           0 :                 } break;
     711           0 :                 case EC_SEC: {
     712           0 :                         nmax = atom_int(sql->sa, sql_bind_localtype("lng"), msec_since_epoch(omax->data.val.lval));
     713           0 :                         nmin = atom_int(sql->sa, sql_bind_localtype("lng"), msec_since_epoch(omin->data.val.lval));
     714           0 :                 } break;
     715             :                 default:
     716             :                         break;
     717             :                 }
     718           1 :                 if (nmin && nmax) {
     719           1 :                         set_minmax_property(sql, e, PROP_MAX, nmax);
     720           1 :                         set_minmax_property(sql, e, PROP_MIN, nmin);
     721             :                 }
     722             :         }
     723           6 : }
     724             : 
     725             : static void
     726        4413 : sql_min_max_propagate_statistics(mvc *sql, sql_exp *e)
     727             : {
     728        4413 :         list *l = e->l;
     729        4413 :         if (list_empty(l))
     730             :                 return;
     731        4413 :         sql_exp *first = l->h->data;
     732        4413 :         atom *omin, *omax;
     733             : 
     734        4413 :         if ((omin = find_prop_and_get(first->p, PROP_MIN)) && (omax = find_prop_and_get(first->p, PROP_MAX))) {
     735        1867 :                 set_minmax_property(sql, e, PROP_MAX, omax);
     736        1867 :                 set_minmax_property(sql, e, PROP_MIN, omin);
     737             :         }
     738             : }
     739             : 
     740             : static void
     741        1541 : sql_avg_propagate_statistics(mvc *sql, sql_exp *e)
     742             : {
     743        1541 :         list *l = e->l;
     744        1541 :         sql_exp *first = l->h->data;
     745        1541 :         atom *omin, *omax;
     746             : 
     747        1541 :         if ((omin = find_prop_and_get(first->p, PROP_MIN)) && (omax = find_prop_and_get(first->p, PROP_MAX))) {
     748        1250 :                 sql_subtype *etype = exp_subtype(e), *ftype = exp_subtype(first);
     749        1250 :                 if (ftype && etype->type->base.id == ftype->type->base.id) { /* average on decimals or intervals */
     750          68 :                         set_minmax_property(sql, e, PROP_MAX, omax);
     751          68 :                         set_minmax_property(sql, e, PROP_MIN, omin);
     752        1182 :                 } else if (ftype && etype) { /* average on integer types */
     753        1182 :                         assert(etype->type->eclass == EC_FLT);
     754        1182 :                         atom *min_cast = atom_copy(sql->sa, omin), *max_cast = atom_copy(sql->sa, omax);
     755        1182 :                         if ((min_cast = atom_cast(sql->sa, min_cast, etype)) && (max_cast = atom_cast(sql->sa, max_cast, etype))) {
     756        1167 :                                 set_minmax_property(sql, e, PROP_MAX, max_cast);
     757        1167 :                                 set_minmax_property(sql, e, PROP_MIN, min_cast);
     758             :                         }
     759             :                 }
     760             :         }
     761        1541 : }
     762             : 
     763             : static void
     764        2238 : sql_zero_or_one_propagate_statistics(mvc *sql, sql_exp *e)
     765             : {
     766        2238 :         list *l = e->l;
     767        2238 :         sql_exp *first = l->h->data;
     768        2238 :         atom *omin, *omax;
     769             : 
     770        2238 :         if ((omin = find_prop_and_get(first->p, PROP_MIN)) && (omax = find_prop_and_get(first->p, PROP_MAX))) {
     771          23 :                 set_minmax_property(sql, e, PROP_MAX, omax);
     772          23 :                 set_minmax_property(sql, e, PROP_MIN, omin);
     773             :         }
     774        2238 : }
     775             : 
     776             : static struct function_properties functions_list[35] = {
     777             :         /* arithmetic functions */
     778             :         {"sql_add", &sql_add_propagate_statistics},
     779             :         {"sql_sub", &sql_sub_propagate_statistics},
     780             :         {"sql_mul", &sql_mul_propagate_statistics},
     781             :         {"sql_div", &sql_div_propagate_statistics},
     782             :         {"sql_neg", &sql_neg_propagate_statistics},
     783             :         {"sign", &sql_sign_propagate_statistics},
     784             :         {"abs", &sql_abs_propagate_statistics},
     785             : 
     786             :         /* sql comparison functions */
     787             :         {"sql_min", &sql_least_greatest_propagate_statistics},
     788             :         {"sql_max", &sql_least_greatest_propagate_statistics},
     789             :         {"least", &sql_least_greatest_propagate_statistics},
     790             :         {"greatest", &sql_least_greatest_propagate_statistics},
     791             :         {"ifthenelse", &sql_ifthenelse_propagate_statistics},
     792             :         {"nullif", &sql_nullif_propagate_statistics},
     793             :         {"coalesce", &sql_coalesce_propagate_statistics},
     794             :         {"casewhen", &sql_casewhen_propagate_statistics},
     795             : 
     796             :         /* time functions */
     797             :         {"century", &sql_century_propagate_statistics},
     798             :         {"decade", &sql_decade_propagate_statistics},
     799             :         {"year", &sql_year_propagate_statistics},
     800             :         {"quarter", &sql_quarter_propagate_statistics},
     801             :         {"month", &sql_month_propagate_statistics},
     802             :         {"day", &sql_day_propagate_statistics},
     803             :         {"dayofyear", &sql_dayofyear_propagate_statistics},
     804             :         {"weekofyear", &sql_weekofyear_propagate_statistics},
     805             :         {"usweekofyear", &sql_weekofyear_propagate_statistics},
     806             :         {"dayofweek", &sql_dayofweek_propagate_statistics},
     807             :         {"dayofmonth", &sql_day_propagate_statistics},
     808             :         {"week", &sql_weekofyear_propagate_statistics},
     809             :         {"hour", &sql_hour_propagate_statistics},
     810             :         {"minute", &sql_minute_propagate_statistics},
     811             :         {"second", &sql_second_propagate_statistics},
     812             :         {"epoch_ms", &sql_epoch_ms_propagate_statistics},
     813             : 
     814             :         /* aggregates */
     815             :         {"min", &sql_min_max_propagate_statistics},
     816             :         {"max", &sql_min_max_propagate_statistics},
     817             :         {"avg", &sql_avg_propagate_statistics},
     818             :         {"zero_or_one", &sql_zero_or_one_propagate_statistics}
     819             : };
     820             : 
     821             : void
     822         329 : initialize_sql_functions_lookup(allocator *sa)
     823             : {
     824         329 :         int nentries = sizeof(functions_list) / sizeof(functions_list[0]);
     825             : 
     826         329 :         sql_functions_lookup = hash_new(sa, nentries, (fkeyvalue)&hash_key);
     827       11844 :         for (int i = 0; i < nentries ; i++) {
     828       11515 :                 int key = hash_key(functions_list[i].name);
     829             : 
     830       11515 :                 hash_add(sql_functions_lookup, key, &(functions_list[i]));
     831             :         }
     832         329 : }

Generated by: LCOV version 1.14