LCOV - code coverage report
Current view: top level - sql/backends/monet5 - sql_statistics.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 146 214 68.2 %
Date: 2021-10-13 02:24:04 Functions: 2 2 100.0 %

          Line data    Source code
       1             : /*
       2             :  * This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       5             :  *
       6             :  * Copyright 1997 - July 2008 CWI, August 2008 - 2021 MonetDB B.V.
       7             :  */
       8             : 
       9             : /* (c) M.L. Kersten
      10             : Most optimizers need easy access to key information
      11             : for proper plan generation. Amongst others, this
      12             : information consists of the tuple count, size,
      13             : min- and max-value, and the null-density.
      14             : They are kept around as persistent tables, modeled
      15             : directly as a collection of BATs.
      16             : 
      17             : We made need an directly accessible structure to speedup
      18             : analysis by optimizers.
      19             : */
      20             : #include "monetdb_config.h"
      21             : #include "sql_statistics.h"
      22             : #include "sql_execute.h"
      23             : 
      24             : str
      25          28 : sql_drop_statistics(mvc *m, sql_table *t)
      26             : {
      27             :         node *ncol;
      28             :         sql_trans *tr;
      29             :         sql_schema *sys;
      30             :         sql_table *sysstats;
      31             :         sql_column *statsid;
      32             :         oid rid;
      33             :         int log_res = LOG_OK;
      34             : 
      35          28 :         tr = m->session->tr;
      36          28 :         sys = mvc_bind_schema(m, "sys");
      37          28 :         if (sys == NULL)
      38           0 :                 throw(SQL, "sql_drop_statistics", SQLSTATE(3F000) "Internal error: No schema sys");
      39          28 :         sysstats = mvc_bind_table(m, sys, "statistics");
      40          28 :         if (sysstats == NULL)
      41           0 :                 throw(SQL, "sql_drop_statistics", SQLSTATE(3F000) "No table sys.statistics");
      42          28 :         statsid = mvc_bind_column(m, sysstats, "column_id");
      43          28 :         if (statsid == NULL)
      44           0 :                 throw(SQL, "sql_drop_statistics", SQLSTATE(3F000) "No table sys.statistics");
      45             : 
      46             :         /* Do all the validations before any drop */
      47          28 :         if (!isTable(t))
      48           0 :                 throw(SQL, "sql_drop_statistics", SQLSTATE(42S02) "DROP STATISTICS: %s '%s' is not persistent", TABLE_TYPE_DESCRIPTION(t->type, t->properties), t->base.name);
      49          28 :         if (!table_privs(m, t, PRIV_SELECT))
      50           0 :                 throw(SQL, "sql_drop_statistics", SQLSTATE(42000) "DROP STATISTICS: access denied for %s to table '%s.%s'",
      51           0 :                           get_string_global_var(m, "current_user"), t->s->base.name, t->base.name);
      52          28 :         if (isTable(t) && ol_first_node(t->columns)) {
      53          81 :                 for (ncol = ol_first_node((t)->columns); ncol; ncol = ncol->next) {
      54          53 :                         sql_column *c = (sql_column *) ncol->data;
      55             : 
      56          53 :                         if (!column_privs(m, c, PRIV_SELECT))
      57           0 :                                 throw(SQL, "sql_drop_statistics", SQLSTATE(42000) "DROP STATISTICS: access denied for %s to column '%s' on table '%s.%s'",
      58           0 :                                           get_string_global_var(m, "current_user"), c->base.name, t->s->base.name, t->base.name);
      59             :                 }
      60             :         }
      61             : 
      62          28 :         sqlstore *store = tr->store;
      63          28 :         if (isTable(t) && ol_first_node(t->columns)) {
      64          81 :                 for (ncol = ol_first_node((t)->columns); ncol; ncol = ncol->next) {
      65          53 :                         sql_column *c = ncol->data;
      66             : 
      67          53 :                         rid = store->table_api.column_find_row(tr, statsid, &c->base.id, NULL);
      68          53 :                         if (!is_oid_nil(rid) && (log_res = store->table_api.table_delete(tr, sysstats, rid)) != LOG_OK)
      69           0 :                                 throw(SQL, "sql.sql_drop_statistics", SQLSTATE(42000) "DROP STATISTICS: failed%s", log_res == LOG_CONFLICT ? " due to conflict with another transaction" : "");
      70             :                 }
      71             :         }
      72             :         return MAL_SUCCEED;
      73             : }
      74             : 
      75             : str
      76          37 : sql_analyze(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
      77             : {
      78          37 :         mvc *m = NULL;
      79          37 :         str msg = getSQLContext(cntxt, mb, &m, NULL);
      80          37 :         sql_trans *tr = m->session->tr;
      81             :         node *ncol;
      82          37 :         char *maxval = NULL, *minval = NULL;
      83          37 :         size_t minlen = 0, maxlen = 0;
      84             :         str sch = 0, tbl = 0, col = 0;
      85             :         bit sorted, revsorted;  /* not bool since address is taken */
      86          37 :         lng nils = 0;
      87          37 :         lng uniq = 0;
      88          37 :         lng samplesize = *getArgReference_lng(stk, pci, 2);
      89          37 :         int argc = pci->argc;
      90          37 :         int width = 0;
      91          37 :         int minmax = *getArgReference_int(stk, pci, 1);
      92             :         int sfnd = 0, tfnd = 0, cfnd = 0, log_res = LOG_OK;
      93             :         sql_schema *sys;
      94             :         sql_table *sysstats;
      95             :         sql_column *statsid;
      96             :         oid rid;
      97             :         timestamp ts;
      98             : 
      99          37 :         if (msg != MAL_SUCCEED || (msg = checkSQLContext(cntxt)) != NULL)
     100           0 :                 return msg;
     101             : 
     102          37 :         sys = mvc_bind_schema(m, "sys");
     103          37 :         if (sys == NULL)
     104           0 :                 throw(SQL, "sql.analyze", SQLSTATE(3F000) "Internal error: No schema sys");
     105          37 :         sysstats = mvc_bind_table(m, sys, "statistics");
     106          37 :         if (sysstats == NULL)
     107           0 :                 throw(SQL, "sql.analyze", SQLSTATE(3F000) "Internal error: No table sys.statistics");
     108          37 :         statsid = mvc_bind_column(m, sysstats, "column_id");
     109          37 :         if (statsid == NULL)
     110           0 :                 throw(SQL, "sql.analyze", SQLSTATE(3F000) "Internal error: No table sys.statistics");
     111             : 
     112          37 :         switch (argc) {
     113          10 :         case 6:
     114          10 :                 col = *getArgReference_str(stk, pci, 5);
     115          10 :                 if (strNil(col))
     116           0 :                         throw(SQL, "sql.analyze", SQLSTATE(42000) "Column name cannot be NULL");
     117             :                 /* fall through */
     118             :         case 5:
     119          30 :                 tbl = *getArgReference_str(stk, pci, 4);
     120          30 :                 if (strNil(tbl))
     121           0 :                         throw(SQL, "sql.analyze", SQLSTATE(42000) "Table name cannot be NULL");
     122             :                 /* fall through */
     123             :         case 4:
     124          37 :                 sch = *getArgReference_str(stk, pci, 3);
     125          37 :                 if (strNil(sch))
     126           0 :                         throw(SQL, "sql.analyze", SQLSTATE(42000) "Schema name cannot be NULL");
     127             :         }
     128             : 
     129          37 :         TRC_DEBUG(SQL_PARSER, "analyze %s.%s.%s sample " LLFMT "%s\n", (sch ? sch : ""), (tbl ? tbl : " "), (col ? col : " "), samplesize, (minmax)?"MinMax":"");
     130             : 
     131             :         /* Do all the validations before doing any analyze */
     132             :         struct os_iter si;
     133          37 :         os_iterator(&si, tr->cat->schemas, tr, NULL);
     134         336 :         for(sql_base *b = oi_next(&si); b; b = oi_next(&si)) {
     135             :                 sql_schema *s = (sql_schema *)b;
     136         300 :                 if (s->base.name[0] == '%')
     137         264 :                         continue;
     138             : 
     139         263 :                 if (sch && strcmp(s->base.name, sch))
     140         227 :                         continue;
     141             :                 sfnd = 1;
     142             :                 struct os_iter oi;
     143          36 :                 os_iterator(&oi, s->tables, tr, NULL);
     144        3921 :                 for(sql_base *b = oi_next(&oi); b; b = oi_next(&oi)) {
     145             :                         sql_table *t = (sql_table *)b;
     146             : 
     147        3886 :                         if (tbl && strcmp(t->base.name, tbl))
     148        3605 :                                 continue;
     149             :                         tfnd = 1;
     150         281 :                         if (tbl && !isTable(t))
     151           1 :                                 throw(SQL, "analyze", SQLSTATE(42S02) "%s '%s' is not persistent", TABLE_TYPE_DESCRIPTION(t->type, t->properties), t->base.name);
     152         280 :                         if (!table_privs(m, t, PRIV_SELECT))
     153           0 :                                 throw(SQL, "analyze", SQLSTATE(42000) "ANALYZE: access denied for %s to table '%s.%s'",
     154           0 :                                           get_string_global_var(m, "current_user"), t->s->base.name, t->base.name);
     155         280 :                         if (isTable(t) && ol_first_node(t->columns)) {
     156         624 :                                 for (ncol = ol_first_node((t)->columns); ncol; ncol = ncol->next) {
     157         513 :                                         sql_column *c = (sql_column *) ncol->data;
     158             : 
     159         513 :                                         if (col && strcmp(c->base.name, col))
     160          16 :                                                 continue;
     161             :                                         cfnd = 1;
     162         497 :                                         if (!column_privs(m, c, PRIV_SELECT))
     163           0 :                                                 throw(SQL, "analyze", SQLSTATE(42000) "ANALYZE: access denied for %s to column '%s' on table '%s.%s'",
     164           0 :                                                           get_string_global_var(m, "current_user"), c->base.name, t->s->base.name, t->base.name);
     165             :                                 }
     166             :                         }
     167             :                 }
     168             :         }
     169          36 :         if (sch && !sfnd)
     170           1 :                 throw(SQL, "analyze", SQLSTATE(3F000) "Schema '%s' does not exist", sch);
     171          35 :         if (tbl && !tfnd)
     172           0 :                 throw(SQL, "analyze", SQLSTATE(42S02) "Table '%s' does not exist", tbl);
     173          35 :         if (col && !cfnd)
     174           0 :                 throw(SQL, "analyze", SQLSTATE(38000) "Column '%s' does not exist", col);
     175             : 
     176          35 :         sqlstore *store = tr->store;
     177          35 :         os_iterator(&si, tr->cat->schemas, tr, NULL);
     178         310 :         for(sql_base *b = oi_next(&si); b; b = oi_next(&si)) {
     179             :                 sql_schema *s = (sql_schema *)b;
     180         276 :                 if (b->name[0] == '%')
     181         241 :                         continue;
     182             : 
     183         242 :                 if (sch && strcmp(sch, b->name))
     184         207 :                         continue;
     185             :                 struct os_iter oi;
     186          35 :                 os_iterator(&oi, s->tables, tr, NULL);
     187        3915 :                 for(sql_base *b = oi_next(&oi); b; b = oi_next(&oi)) {
     188             :                         sql_table *t = (sql_table *) b;
     189             : 
     190        3881 :                         if (tbl && strcmp(b->name, tbl))
     191        3601 :                                 continue;
     192         280 :                         if (isTable(t) && ol_first_node(t->columns)) {
     193             :                                 BAT *cands;
     194             : 
     195         111 :                                 if ((cands = store->storage_api.bind_cands(tr, t, 1, 0)) == NULL) {
     196           0 :                                         GDKfree(maxval);
     197           0 :                                         GDKfree(minval);
     198           1 :                                         throw(SQL, "analyze", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     199             :                                 }
     200             : 
     201         623 :                                 for (ncol = ol_first_node((t)->columns); ncol; ncol = ncol->next) {
     202         513 :                                         sql_base *bc = ncol->data;
     203             :                                         sql_column *c = (sql_column *) ncol->data;
     204             :                                         BAT *bn, *nbn, *br;
     205             :                                         BAT *bsample;
     206             :                                         lng sz;
     207             :                                         ssize_t (*tostr)(str*,size_t*,const void*,bool);
     208             :                                         void *val=0;
     209             : 
     210         513 :                                         if (col && strcmp(bc->name, col))
     211          16 :                                                 continue;
     212             : 
     213             :                                         /* remove cached value */
     214         497 :                                         if (c->min)
     215           0 :                                                 c->min = NULL;
     216         497 :                                         if (c->max)
     217           0 :                                                 c->max = NULL;
     218             : 
     219         497 :                                         if ((bn = store->storage_api.bind_col(tr, c, RDONLY)) == NULL) {
     220             :                                                 /* XXX throw error instead? */
     221           0 :                                                 continue;
     222             :                                         }
     223         497 :                                         nbn = BATproject(cands, bn);
     224         497 :                                         BBPunfix(bn->batCacheid);
     225         497 :                                         if (!nbn) {
     226             :                                                 /* XXX throw error instead? */
     227           0 :                                                 continue;
     228             :                                         }
     229             :                                         bn = nbn;
     230         497 :                                         sz = BATcount(bn);
     231         497 :                                         tostr = BATatoms[bn->ttype].atomToStr;
     232             : 
     233         497 :                                         rid = store->table_api.column_find_row(tr, statsid, &c->base.id, NULL);
     234         497 :                                         if (samplesize > 0) {
     235           0 :                                                 bsample = BATsample(bn, (BUN) samplesize);
     236             :                                         } else
     237             :                                                 bsample = NULL;
     238         497 :                                         br = BATselect(bn, bsample, ATOMnilptr(bn->ttype), NULL, true, false, false);
     239         497 :                                         if (br == NULL) {
     240           0 :                                                 BBPunfix(bn->batCacheid);
     241           0 :                                                 if (bsample)
     242           0 :                                                         BBPunfix(bsample->batCacheid);
     243             :                                                 /* XXX throw error instead? */
     244           0 :                                                 continue;
     245             :                                         }
     246         497 :                                         nils = BATcount(br);
     247         497 :                                         BBPunfix(br->batCacheid);
     248         497 :                                         if (bn->tkey)
     249          33 :                                                 uniq = sz;
     250         464 :                                         else if (!minmax) {
     251             :                                                 BAT *en;
     252         446 :                                                 if (bsample)
     253           0 :                                                         br = BATproject(bsample, bn);
     254             :                                                 else
     255             :                                                         br = bn;
     256         892 :                                                 if (br && (en = BATunique(br, NULL)) != NULL) {
     257         446 :                                                         uniq = canditer_init(&(struct canditer){0}, NULL, en);
     258         446 :                                                         BBPunfix(en->batCacheid);
     259             :                                                 } else
     260           0 :                                                         uniq = 0;
     261         446 :                                                 if (bsample && br)
     262           0 :                                                         BBPunfix(br->batCacheid);
     263             :                                         }
     264         497 :                                         if (bsample)
     265           0 :                                                 BBPunfix(bsample->batCacheid);
     266             :                                         /* use BATordered(_rev)
     267             :                                          * and not
     268             :                                          * BATt(rev)ordered
     269             :                                          * because we want to
     270             :                                          * know for sure */
     271         497 :                                         sorted = BATordered(bn);
     272         497 :                                         revsorted = BATordered_rev(bn);
     273             : 
     274             :                                         // Gather the min/max value for builtin types
     275         497 :                                         width = bn->twidth;
     276             : 
     277         497 :                                         if (maxlen < 4) {
     278          34 :                                                 GDKfree(maxval);
     279          34 :                                                 maxval = GDKmalloc(4);
     280          34 :                                                 if (maxval == NULL) {
     281           0 :                                                         GDKfree(minval);
     282           0 :                                                         BBPunfix(bn->batCacheid);
     283           0 :                                                         BBPunfix(cands->batCacheid);
     284           1 :                                                         throw(SQL, "analyze", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     285             :                                                 }
     286          34 :                                                 maxlen = 4;
     287             :                                         }
     288         497 :                                         if (minlen < 4) {
     289          34 :                                                 GDKfree(minval);
     290          34 :                                                 minval = GDKmalloc(4);
     291          34 :                                                 if (minval == NULL){
     292           0 :                                                         GDKfree(maxval);
     293           0 :                                                         BBPunfix(bn->batCacheid);
     294           0 :                                                         BBPunfix(cands->batCacheid);
     295           0 :                                                         throw(SQL, "analyze", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     296             :                                                 }
     297          34 :                                                 minlen = 4;
     298             :                                         }
     299         497 :                                         if (tostr) {
     300         497 :                                                 if ((val = BATmax(bn, NULL)) == NULL)
     301           0 :                                                         strcpy(maxval, str_nil);
     302             :                                                 else {
     303         497 :                                                         if (tostr(&maxval, &maxlen, val, false) < 0) {
     304           0 :                                                                 GDKfree(val);
     305           0 :                                                                 GDKfree(minval);
     306           0 :                                                                 GDKfree(maxval);
     307           0 :                                                                 BBPunfix(bn->batCacheid);
     308           0 :                                                                 BBPunfix(cands->batCacheid);
     309           0 :                                                                 throw(SQL, "analyze", GDK_EXCEPTION);
     310             :                                                         }
     311         497 :                                                         GDKfree(val);
     312             :                                                 }
     313         497 :                                                 if ((val = BATmin(bn, NULL)) == NULL)
     314           0 :                                                         strcpy(minval, str_nil);
     315             :                                                 else {
     316         497 :                                                         if (tostr(&minval, &minlen, val, false) < 0) {
     317           0 :                                                                 GDKfree(val);
     318           0 :                                                                 GDKfree(minval);
     319           0 :                                                                 GDKfree(maxval);
     320           0 :                                                                 BBPunfix(bn->batCacheid);
     321           0 :                                                                 BBPunfix(cands->batCacheid);
     322           0 :                                                                 throw(SQL, "analyze", GDK_EXCEPTION);
     323             :                                                         }
     324         497 :                                                         GDKfree(val);
     325             :                                                 }
     326             :                                         } else {
     327           0 :                                                 strcpy(maxval, str_nil);
     328           0 :                                                 strcpy(minval, str_nil);
     329             :                                         }
     330         497 :                                         BBPunfix(bn->batCacheid);
     331         497 :                                         ts = timestamp_current();
     332         497 :                                         if (!is_oid_nil(rid) && (log_res = store->table_api.table_delete(tr, sysstats, rid)) != LOG_OK) {
     333           0 :                                                 GDKfree(maxval);
     334           0 :                                                 GDKfree(minval);
     335           0 :                                                 BBPunfix(cands->batCacheid);
     336           0 :                                                 throw(SQL, "analyze", SQLSTATE(42000) "ANALYZE: failed%s", log_res == LOG_CONFLICT ? " due to conflict with another transaction" : "");
     337             :                                         }
     338         994 :                                         if ((log_res = store->table_api.table_insert(tr, sysstats, &c->base.id, &c->type.type->base.name, &width, &ts, samplesize ? &samplesize : &sz, &sz, &uniq, &nils, &minval, &maxval, &sorted, &revsorted)) != LOG_OK) {
     339           1 :                                                 GDKfree(maxval);
     340           1 :                                                 GDKfree(minval);
     341           1 :                                                 BBPunfix(cands->batCacheid);
     342           1 :                                                 throw(SQL, "analyze", SQLSTATE(42000) "ANALYZE: failed%s", log_res == LOG_CONFLICT ? " due to conflict with another transaction" : "");
     343             :                                         }
     344         496 :                                         if (!isNew(c) && (log_res = sql_trans_add_dependency(tr, c->base.id, ddl)) != LOG_OK) {
     345           0 :                                                 GDKfree(maxval);
     346           0 :                                                 GDKfree(minval);
     347           0 :                                                 BBPunfix(cands->batCacheid);
     348           0 :                                                 throw(SQL, "analyze", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     349             :                                         }
     350             :                                 }
     351         110 :                                 BBPunfix(cands->batCacheid);
     352             :                         }
     353             :                 }
     354             :         }
     355          34 :         GDKfree(maxval);
     356          34 :         GDKfree(minval);
     357          34 :         return MAL_SUCCEED;
     358             : }

Generated by: LCOV version 1.14