LCOV - code coverage report
Current view: top level - sql/server - rel_sequence.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 185 236 78.4 %
Date: 2021-10-13 02:24:04 Functions: 8 8 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             : #include "monetdb_config.h"
      10             : #include "rel_select.h"
      11             : #include "rel_rel.h"
      12             : #include "rel_sequence.h"
      13             : #include "rel_exp.h"
      14             : #include "sql_privileges.h"
      15             : 
      16             : char*
      17         188 : sql_next_seq_name(mvc *m)
      18             : {
      19         188 :         sqlid id = store_next_oid(m->session->tr->store);
      20             :         size_t len = 5 + 10;    /* max nr of digits of (4 bytes) int is 10 */
      21         188 :         char *msg = sa_alloc(m->sa, len);
      22             : 
      23         188 :         snprintf(msg, len, "seq_%d", id);
      24         188 :         return msg;
      25             : }
      26             : 
      27             : static sql_rel *
      28          31 : rel_drop_seq(sql_allocator *sa, char *sname, char *seqname)
      29             : {
      30          31 :         sql_rel *rel = rel_create(sa);
      31          31 :         list *exps = new_exp_list(sa);
      32          31 :         if(!rel || !exps)
      33             :                 return NULL;
      34             : 
      35          31 :         append(exps, exp_atom_clob(sa, sname));
      36          31 :         append(exps, exp_atom_clob(sa, seqname));
      37          31 :         append(exps, exp_atom_int(sa, 0));
      38          31 :         rel->l = NULL;
      39          31 :         rel->r = NULL;
      40          31 :         rel->op = op_ddl;
      41          31 :         rel->flag = ddl_drop_seq;
      42          31 :         rel->exps = exps;
      43          31 :         rel->card = 0;
      44          31 :         rel->nrcols = 0;
      45          31 :         return rel;
      46             : }
      47             : 
      48             : static sql_rel *
      49         340 : rel_seq(sql_allocator *sa, int cat_type, char *sname, sql_sequence *s, sql_rel *r, sql_exp *val)
      50             : {
      51         340 :         sql_rel *rel = rel_create(sa);
      52         340 :         list *exps = new_exp_list(sa);
      53         340 :         if(!rel || !exps)
      54             :                 return NULL;
      55             : 
      56         340 :         if (val)
      57          43 :                 append(exps, val);
      58             :         else
      59         297 :                 append(exps, exp_atom_int(sa, 0));
      60         340 :         append(exps, exp_atom_str(sa, sname, sql_bind_localtype("str") ));
      61         340 :         append(exps, exp_atom_str(sa, s->base.name, sql_bind_localtype("str") ));
      62         340 :         append(exps, exp_atom_ptr(sa, s));
      63         340 :         rel->l = r;
      64         340 :         rel->r = NULL;
      65         340 :         rel->op = op_ddl;
      66         340 :         rel->flag = cat_type;
      67         340 :         rel->exps = exps;
      68         340 :         rel->card = CARD_MULTI;
      69         340 :         rel->nrcols = 0;
      70         340 :         return rel;
      71             : }
      72             : 
      73             : static sql_rel *
      74         297 : rel_create_seq(
      75             :         mvc *sql,
      76             :         dlist *qname,
      77             :         sql_subtype *tpe,
      78             :         lng start,
      79             :         lng inc,
      80             :         lng min,
      81             :         lng max,
      82             :         lng cache,
      83             :         bit cycle,
      84             :         bit bedropped)
      85             : {
      86             :         sql_rel *res = NULL;
      87             :         sql_sequence *seq = NULL;
      88         297 :         char *sname = qname_schema(qname);
      89         297 :         char *name = qname_schema_object(qname);
      90         297 :         sql_schema *s = cur_schema(sql);
      91             : 
      92         297 :         if (sname && !(s = mvc_bind_schema(sql, sname)))
      93           0 :                 return sql_error(sql, ERR_NOTFOUND, SQLSTATE(3F000) "CREATE SEQUENCE: no such schema '%s'", sname);
      94         297 :         if (!mvc_schema_privs(sql, s))
      95           0 :                 return sql_error(sql, 02, SQLSTATE(42000) "CREATE SEQUENCE: access denied for %s to schema '%s'", get_string_global_var(sql, "current_user"), s->base.name);
      96             :         (void) tpe;
      97         297 :         if (find_sql_sequence(sql->session->tr, s, name))
      98           0 :                 return sql_error(sql, 02, SQLSTATE(42000) "CREATE SEQUENCE: name '%s' already in use", name);
      99         297 :         if (!mvc_schema_privs(sql, s))
     100           0 :                 return sql_error(sql, 02, SQLSTATE(42000) "CREATE SEQUENCE: insufficient privileges "
     101             :                                 "for '%s' in schema '%s'", get_string_global_var(sql, "current_user"), s->base.name);
     102             : 
     103             :         /* generate defaults */
     104         297 :         if (is_lng_nil(start)) start = 1;
     105         297 :         if (is_lng_nil(inc)) inc = 1;
     106         297 :         if (is_lng_nil(min)) min = 0;
     107         297 :         if (cycle && (!is_lng_nil(max) && max < 0)) cycle = 0;
     108         297 :         if (is_lng_nil(max)) max = 0;
     109         297 :         if (is_lng_nil(cache)) cache = 1;
     110             : 
     111         297 :         seq = create_sql_sequence(sql->store, sql->sa, s, name, start, min, max, inc, cache, cycle);
     112         297 :         seq->bedropped = bedropped;
     113         297 :         res = rel_seq(sql->sa, ddl_create_seq, s->base.name, seq, NULL, NULL);
     114             :         /* for multi statements we keep the sequence around */
     115         297 :         if (res && stack_has_frame(sql, "%MUL") != 0) {
     116         188 :                 if (!stack_push_rel_view(sql, name, rel_dup(res)))
     117           0 :                         return sql_error(sql, 02, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     118             :         }
     119             : 
     120             :         return res;
     121             : }
     122             : 
     123             : #define SEQ_TYPE        0
     124             : #define SEQ_START       1
     125             : #define SEQ_INC         2
     126             : #define SEQ_MIN         3
     127             : #define SEQ_MAX         4
     128             : #define SEQ_CYCLE       5
     129             : #define SEQ_CACHE       6
     130             : 
     131             : static sql_rel *
     132         307 : list_create_seq(
     133             :         mvc *sql,
     134             :         dlist *qname,
     135             :         dlist *options,
     136             :         bit bedropped)
     137             : {
     138             :         dnode *n;
     139             :         sql_subtype *t = NULL;
     140         307 :         lng start = lng_nil, inc = lng_nil, min = lng_nil, max = lng_nil, cache = lng_nil;
     141             :         unsigned int used = 0;
     142             :         bit cycle = 0;
     143             : 
     144         307 :         if (options) {
     145             :                 /* check if no option is given twice */
     146         709 :                 for (n = options->h; n; n = n->next) {
     147         414 :                         symbol *s = n->data.sym;
     148             : 
     149         414 :                         switch(s->token) {
     150         290 :                         case SQL_TYPE: {
     151             :                                 bool found = false;
     152         290 :                                 const char *valid_types[4] = {"tinyint", "smallint", "int", "bigint"};
     153             :                                 size_t number_valid_types = sizeof(valid_types) / sizeof(valid_types[0]);
     154             : 
     155         290 :                                 if ((used&(1<<SEQ_TYPE)))
     156           8 :                                         return sql_error(sql, 02, SQLSTATE(3F000) "CREATE SEQUENCE: AS type found should be used as most once");
     157         290 :                                 used |= (1<<SEQ_TYPE);
     158         290 :                                 t = &s->data.lval->h->data.typeval;
     159         898 :                                 for (size_t i = 0; i < number_valid_types; i++) {
     160         890 :                                         if (strcasecmp(valid_types[i], t->type->base.name) == 0) {
     161             :                                                 found = true;
     162             :                                                 break;
     163             :                                         }
     164             :                                 }
     165         290 :                                 if (!found)
     166           8 :                                         return sql_error(sql, 02, SQLSTATE(42000) "CREATE SEQUENCE: The type of the sequence must be either tinyint, smallint, int or bigint");
     167         282 :                         } break;
     168          46 :                         case SQL_START:
     169          46 :                                 if ((used&(1<<SEQ_START)))
     170           0 :                                         return sql_error(sql, 02, SQLSTATE(3F000) "CREATE SEQUENCE: START value should be passed as most once");
     171          46 :                                 used |= (1<<SEQ_START);
     172          46 :                                 if (is_lng_nil(s->data.l_val))
     173           0 :                                         return sql_error(sql, 02, SQLSTATE(42000) "CREATE SEQUENCE: START must not be null");
     174             :                                 start = s->data.l_val;
     175             :                                 break;
     176          17 :                         case SQL_INC:
     177          17 :                                 if ((used&(1<<SEQ_INC)))
     178           0 :                                         return sql_error(sql, 02, SQLSTATE(3F000) "CREATE SEQUENCE: INCREMENT value should be passed as most once");
     179          17 :                                 used |= (1<<SEQ_INC);
     180          17 :                                 if (is_lng_nil(s->data.l_val))
     181           0 :                                         return sql_error(sql, 02, SQLSTATE(42000) "CREATE SEQUENCE: INCREMENT must not be null");
     182             :                                 inc = s->data.l_val;
     183             :                                 break;
     184          15 :                         case SQL_MINVALUE:
     185          15 :                                 if ((used&(1<<SEQ_MIN)))
     186           0 :                                         return sql_error(sql, 02, SQLSTATE(3F000) "CREATE SEQUENCE: MINVALUE or NO MINVALUE should be passed as most once");
     187          15 :                                 used |= (1<<SEQ_MIN);
     188          15 :                                 if (is_lng_nil(s->data.l_val))
     189           0 :                                         return sql_error(sql, 02, SQLSTATE(42000) "CREATE SEQUENCE: MINVALUE must not be null");
     190             :                                 min = s->data.l_val;
     191             :                                 break;
     192          19 :                         case SQL_MAXVALUE:
     193          19 :                                 if ((used&(1<<SEQ_MAX)))
     194           0 :                                         return sql_error(sql, 02, SQLSTATE(3F000) "CREATE SEQUENCE: MAXVALUE or NO MAXVALUE should be passed as most once");
     195          19 :                                 used |= (1<<SEQ_MAX);
     196          19 :                                 if (is_lng_nil(s->data.l_val))
     197           0 :                                         return sql_error(sql, 02, SQLSTATE(42000) "CREATE SEQUENCE: MAXVALUE must be non-NULL");
     198             :                                 max = s->data.l_val;
     199             :                                 break;
     200          17 :                         case SQL_CYCLE:
     201          17 :                                 if ((used&(1<<SEQ_CYCLE)))
     202           0 :                                         return sql_error(sql, 02, SQLSTATE(3F000) "CREATE SEQUENCE: CYCLE or NO CYCLE should be passed as most once");
     203          17 :                                 used |= (1<<SEQ_CYCLE);
     204          17 :                                 cycle = s->data.i_val != 0;
     205          17 :                                 break;
     206          10 :                         case SQL_CACHE:
     207          10 :                                 if ((used&(1<<SEQ_CACHE)))
     208           0 :                                         return sql_error(sql, 02, SQLSTATE(3F000) "CREATE SEQUENCE: CACHE value should be passed as most once");
     209          10 :                                 used |= (1<<SEQ_CACHE);
     210          10 :                                 if (is_lng_nil(s->data.l_val))
     211           0 :                                         return sql_error(sql, 02, SQLSTATE(42000) "CREATE SEQUENCE: CACHE must be non-NULL");
     212             :                                 cache = s->data.l_val;
     213             :                                 break;
     214             :                         default:
     215           0 :                                 assert(0);
     216             :                         }
     217             :                 }
     218         295 :                 if (!is_lng_nil(start)) {
     219          46 :                         if (!is_lng_nil(min) && start < min)
     220           1 :                                 return sql_error(sql, 02, SQLSTATE(42000) "CREATE SEQUENCE: START value is lesser than MINVALUE ("LLFMT" < "LLFMT")", start, min);
     221          45 :                         if (!is_lng_nil(max) && start > max)
     222           1 :                                 return sql_error(sql, 02, SQLSTATE(42000) "CREATE SEQUENCE: START value is higher than MAXVALUE ("LLFMT" > "LLFMT")", start, max);
     223             :                 }
     224         293 :                 if (!is_lng_nil(min) && !is_lng_nil(max) && max < min)
     225           0 :                         return sql_error(sql, 02, SQLSTATE(42000) "CREATE SEQUENCE: MAXVALUE value is lesser than MINVALUE ("LLFMT" < "LLFMT")", max, min);
     226             :         }
     227         297 :         if (is_lng_nil(start) && !is_lng_nil(min) && min) /* if start value not set, set it to the minimum if available */
     228             :                 start = min;
     229         297 :         return rel_create_seq(sql, qname, t, start, inc, min, max, cache, cycle, bedropped);
     230             : }
     231             : 
     232             : static sql_rel *
     233          43 : rel_alter_seq(
     234             :                 sql_query *query,
     235             :                 dlist *qname,
     236             :                 sql_subtype *tpe,
     237             :                 dlist* start_list,
     238             :                 lng inc,
     239             :                 lng min,
     240             :                 lng max,
     241             :                 lng cache,
     242             :                 bit cycle)
     243             : {
     244          43 :         mvc *sql = query->sql;
     245          43 :         char *sname = qname_schema(qname);
     246          43 :         char *name = qname_schema_object(qname);
     247             :         sql_sequence *seq;
     248          43 :         int start_type = start_list->h->data.i_val;
     249          43 :         sql_rel *r = NULL;
     250             :         sql_exp *val = NULL;
     251             : 
     252          43 :         assert(start_list->h->type == type_int);
     253             :         (void) tpe;
     254          43 :         if (!(seq = find_sequence_on_scope(sql, sname, name, "ALTER SEQUENCE")))
     255             :                 return NULL;
     256          43 :         if (!mvc_schema_privs(sql, seq->s))
     257           0 :                 return sql_error(sql, 02, SQLSTATE(42000) "ALTER SEQUENCE: insufficient privileges "
     258           0 :                                 "for '%s' in schema '%s'", get_string_global_var(sql, "current_user"), seq->s->base.name);
     259             : 
     260             :         /* first alter the known values */
     261          43 :         seq = create_sql_sequence(sql->store, sql->sa, seq->s, name, seq->start, min, max, inc, cache, (bit) cycle);
     262             : 
     263             :         /* restart may be a query, i.e. we create a statement
     264             :            restart(ssname,seqname,value) */
     265             : 
     266          43 :         if (start_type == 0) {
     267           0 :                 val = exp_atom_lng(sql->sa, seq->start);
     268          43 :         } else if (start_type == 1) { /* value (exp) */
     269           7 :                 exp_kind ek = {type_value, card_value, FALSE};
     270           7 :                 sql_subtype *lng_t = sql_bind_localtype("lng");
     271             : 
     272           7 :                 val = rel_value_exp2(query, &r, start_list->h->next->data.sym, sql_sel, ek);
     273           7 :                 if (!val || !(val = exp_check_type(sql, lng_t, r, val, type_equal)))
     274           0 :                         return NULL;
     275           7 :                 if (r && r->op == op_project) {
     276           0 :                         exp_label(sql->sa, val, ++sql->label);
     277           0 :                         val = rel_project_add_exp(sql, r, val);
     278             :                 }
     279          36 :         } else if (start_type == 2) {
     280          36 :                 assert (start_list->h->next->type == type_lng);
     281          36 :                 val = exp_atom_lng(sql->sa, start_list->h->next->data.l_val);
     282             :         }
     283          43 :         if (val && val->card > CARD_ATOM) {
     284           0 :                 sql_subfunc *zero_or_one = sql_bind_func(sql, "sys", "zero_or_one", exp_subtype(val), NULL, F_AGGR);
     285           0 :                 val = exp_aggr1(sql->sa, val, zero_or_one, 0, 0, CARD_ATOM, has_nil(val));
     286             :         }
     287          43 :         return rel_seq(sql->sa, ddl_alter_seq, seq->s->base.name, seq, r, val);
     288             : }
     289             : 
     290             : static sql_rel *
     291          43 : list_alter_seq(
     292             :         sql_query *query,
     293             :         dlist *qname,
     294             :         dlist *options)
     295             : {
     296          43 :         mvc *sql = query->sql;
     297             :         dnode *n;
     298             :         sql_subtype* t = NULL;
     299          43 :         lng inc = lng_nil, min = lng_nil, max = lng_nil, cache = lng_nil;
     300             :         dlist *start = NULL;
     301             :         unsigned int used = 0;
     302             :         bit cycle = 0;
     303             : 
     304             :         /* check if no option is given twice */
     305         159 :         for (n = options->h; n; n = n->next) {
     306         116 :                 symbol *s = n->data.sym;
     307             : 
     308         116 :                 switch(s->token) {
     309           0 :                 case SQL_TYPE:
     310           0 :                         if ((used&(1<<SEQ_TYPE)))
     311           0 :                                 return sql_error(sql, 02, SQLSTATE(3F000) "ALTER SEQUENCE: AS type found should be used as most once");
     312           0 :                         used |= (1<<SEQ_TYPE);
     313           0 :                         t = &s->data.lval->h->data.typeval;
     314           0 :                         break;
     315          43 :                 case SQL_START:
     316          43 :                         if ((used&(1<<SEQ_START)))
     317           0 :                                 return sql_error(sql, 02, SQLSTATE(3F000) "ALTER SEQUENCE: START value should be passed as most once");
     318          43 :                         used |= (1<<SEQ_START);
     319          43 :                         if (is_lng_nil(s->data.l_val))
     320           0 :                                 return sql_error(sql, 02, SQLSTATE(42000) "ALTER SEQUENCE: START must be non-NULL");
     321          43 :                         start = s->data.lval;
     322          43 :                         break;
     323           5 :                 case SQL_INC:
     324           5 :                         if ((used&(1<<SEQ_INC)))
     325           0 :                                 return sql_error(sql, 02, SQLSTATE(3F000) "ALTER SEQUENCE: INCREMENT value should be passed as most once");
     326           5 :                         used |= (1<<SEQ_INC);
     327           5 :                         if (is_lng_nil(s->data.l_val))
     328           0 :                                 return sql_error(sql, 02, SQLSTATE(42000) "ALTER SEQUENCE: INCREMENT must be non-NULL");
     329             :                         inc = s->data.l_val;
     330             :                         break;
     331          31 :                 case SQL_MINVALUE:
     332          31 :                         if ((used&(1<<SEQ_MIN)))
     333           0 :                                 return sql_error(sql, 02, SQLSTATE(3F000) "ALTER SEQUENCE: MINVALUE or NO MINVALUE should be passed as most once");
     334          31 :                         used |= (1<<SEQ_MIN);
     335          31 :                         if (is_lng_nil(s->data.l_val))
     336           0 :                                 return sql_error(sql, 02, SQLSTATE(42000) "ALTER SEQUENCE: MINVALUE must be non-NULL");
     337             :                         min = s->data.l_val;
     338             :                         break;
     339           5 :                 case SQL_MAXVALUE:
     340           5 :                         if ((used&(1<<SEQ_MAX)))
     341           0 :                                 return sql_error(sql, 02, SQLSTATE(3F000) "ALTER SEQUENCE: MAXVALUE or NO MAXVALUE should be passed as most once");
     342           5 :                         used |= (1<<SEQ_MAX);
     343           5 :                         if (is_lng_nil(s->data.l_val))
     344           0 :                                 return sql_error(sql, 02, SQLSTATE(42000) "ALTER SEQUENCE: MAXVALUE must be non-NULL");
     345             :                         max = s->data.l_val;
     346             :                         break;
     347          32 :                 case SQL_CYCLE:
     348          32 :                         if ((used&(1<<SEQ_CYCLE)))
     349           0 :                                 return sql_error(sql, 02, SQLSTATE(3F000) "ALTER SEQUENCE: CYCLE or NO CYCLE should be passed as most once");
     350          32 :                         used |= (1<<SEQ_CYCLE);
     351          32 :                         cycle = s->data.i_val != 0;
     352          32 :                         break;
     353           0 :                 case SQL_CACHE:
     354           0 :                         if ((used&(1<<SEQ_CACHE)))
     355           0 :                                 return sql_error(sql, 02, SQLSTATE(3F000) "ALTER SEQUENCE: CACHE value should be passed as most once");
     356           0 :                         used |= (1<<SEQ_CACHE);
     357           0 :                         if (is_lng_nil(s->data.l_val))
     358           0 :                                 return sql_error(sql, 02, SQLSTATE(42000) "ALTER SEQUENCE: CACHE must be non-NULL");
     359             :                         cache = s->data.l_val;
     360             :                         break;
     361             :                 default:
     362           0 :                         assert(0);
     363             :                 }
     364             :         }
     365          43 :         if (!is_lng_nil(min) && !is_lng_nil(max) && max < min)
     366           0 :                 return sql_error(sql, 02, SQLSTATE(42000) "ALTER SEQUENCE: MAXVALUE value is lesser than MINVALUE ("LLFMT" < "LLFMT")", max, min);
     367          43 :         return rel_alter_seq(query, qname, t, start, inc, min, max, cache, cycle);
     368             : }
     369             : 
     370             : sql_rel *
     371         381 : rel_sequences(sql_query *query, symbol *s)
     372             : {
     373         381 :         mvc *sql = query->sql;
     374             :         sql_rel *res = NULL;
     375             : 
     376         381 :         switch (s->token) {
     377         307 :                 case SQL_CREATE_SEQ:
     378             :                 {
     379         307 :                         dlist *l = s->data.lval;
     380             : 
     381         307 :                         res = list_create_seq(
     382             : /* mvc* sql */          sql,
     383         307 : /* dlist* qname */      l->h->data.lval,
     384         307 : /* dlist* options */    l->h->next->data.lval,
     385         307 : /* bit bedropped */     (bit) (l->h->next->next->data.i_val != 0));
     386             :                 }
     387         307 :                 break;
     388          43 :                 case SQL_ALTER_SEQ:
     389             :                 {
     390          43 :                         dlist* l = s->data.lval;
     391             : 
     392          43 :                         res = list_alter_seq(
     393             : /* mvc* sql */          query,
     394          43 : /* dlist* qname */      l->h->data.lval,
     395          43 : /* dlist* options */    l->h->next->data.lval);
     396             :                 }
     397          43 :                 break;
     398          31 :                 case SQL_DROP_SEQ:
     399             :                 {
     400          31 :                         dlist *l = s->data.lval;
     401          31 :                         char *sname = qname_schema(l->h->data.lval);
     402          31 :                         char *seqname = qname_schema_object(l->h->data.lval);
     403             :                         sql_sequence *seq = NULL;
     404             : 
     405          31 :                         if (!(seq = find_sequence_on_scope(sql, sname, seqname, "DROP SEQUENCE")))
     406             :                                 return NULL;
     407          31 :                         res = rel_drop_seq(sql->sa, seq->s->base.name, seqname);
     408             :                 }
     409          31 :                 break;
     410           0 :                 default:
     411           0 :                         return sql_error(sql, 01, SQLSTATE(42000) "sql_stmt Symbol(%p)->token = %s", s, token2string(s->token));
     412             :         }
     413         381 :         sql->type = Q_SCHEMA;
     414         381 :         return res;
     415             : }

Generated by: LCOV version 1.14