| 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 - 2019 MonetDB B.V. |
| 7 | */ |
| 8 | |
| 9 | #include "monetdb_config.h" |
| 10 | #include "rel_psm.h" |
| 11 | #include "rel_semantic.h" |
| 12 | #include "rel_schema.h" |
| 13 | #include "rel_select.h" |
| 14 | #include "rel_rel.h" |
| 15 | #include "rel_exp.h" |
| 16 | #include "rel_updates.h" |
| 17 | #include "sql_privileges.h" |
| 18 | |
| 19 | static list *sequential_block(sql_query *query, sql_subtype *restype, list *restypelist, dlist *blk, char *opt_name, int is_func); |
| 20 | |
| 21 | sql_rel * |
| 22 | rel_psm_block(sql_allocator *sa, list *l) |
| 23 | { |
| 24 | if (l) { |
| 25 | sql_rel *r = rel_create(sa); |
| 26 | if(!r) |
| 27 | return NULL; |
| 28 | |
| 29 | r->op = op_ddl; |
| 30 | r->flag = ddl_psm; |
| 31 | r->exps = l; |
| 32 | return r; |
| 33 | } |
| 34 | return NULL; |
| 35 | } |
| 36 | |
| 37 | sql_rel * |
| 38 | rel_psm_stmt(sql_allocator *sa, sql_exp *e) |
| 39 | { |
| 40 | if (e) { |
| 41 | list *l = sa_list(sa); |
| 42 | if(!l) |
| 43 | return NULL; |
| 44 | |
| 45 | list_append(l, e); |
| 46 | return rel_psm_block(sa, l); |
| 47 | } |
| 48 | return NULL; |
| 49 | } |
| 50 | |
| 51 | /* SET variable = value and set (variable1, .., variableN) = (query) */ |
| 52 | static sql_exp * |
| 53 | psm_set_exp(sql_query *query, dnode *n) |
| 54 | { |
| 55 | mvc *sql = query->sql; |
| 56 | symbol *val = n->next->data.sym; |
| 57 | sql_exp *e = NULL; |
| 58 | int level = 0, is_last = 0; |
| 59 | sql_subtype *tpe = NULL; |
| 60 | sql_rel *rel = NULL; |
| 61 | sql_exp *res = NULL; |
| 62 | int single = (n->type == type_string); |
| 63 | |
| 64 | if (single) { |
| 65 | exp_kind ek = {type_value, card_value, FALSE}; |
| 66 | const char *name = n->data.sval; |
| 67 | /* name can be |
| 68 | 'parameter of the function' (ie in the param list) |
| 69 | or a local or global variable, declared earlier |
| 70 | */ |
| 71 | |
| 72 | /* check if variable is known from the stack */ |
| 73 | if (!stack_find_var(sql, name)) { |
| 74 | sql_arg *a = sql_bind_param(sql, name); |
| 75 | |
| 76 | if (!a) /* not parameter, ie local var ? */ |
| 77 | return sql_error(sql, 01, SQLSTATE(42000) "Variable %s unknown" , name); |
| 78 | tpe = &a->type; |
| 79 | } else { |
| 80 | tpe = stack_find_type(sql, name); |
| 81 | } |
| 82 | |
| 83 | e = rel_value_exp2(query, &rel, val, sql_sel, ek, &is_last); |
| 84 | if (!e || (rel && e->card > CARD_AGGR)) |
| 85 | return NULL; |
| 86 | |
| 87 | level = stack_find_frame(sql, name); |
| 88 | e = rel_check_type(sql, tpe, rel, e, type_cast); |
| 89 | if (!e) |
| 90 | return NULL; |
| 91 | |
| 92 | res = exp_set(sql->sa, name, e, level); |
| 93 | } else { /* multi assignment */ |
| 94 | exp_kind ek = {type_value, card_relation, FALSE}; |
| 95 | sql_rel *rel_val = rel_subquery(query, NULL, val, ek); |
| 96 | dlist *vars = n->data.lval; |
| 97 | dnode *m; |
| 98 | node *n; |
| 99 | list *b; |
| 100 | |
| 101 | if (!rel_val || !is_project(rel_val->op) || dlist_length(vars) != list_length(rel_val->exps)) |
| 102 | return sql_error(sql, 02, SQLSTATE(42000) "SET: Number of variables not equal to number of supplied values" ); |
| 103 | |
| 104 | b = sa_list(sql->sa); |
| 105 | append(b, exp_rel(sql, rel_val)); |
| 106 | |
| 107 | for(m = vars->h, n = rel_val->exps->h; n && m; n = n->next, m = m->next) { |
| 108 | char *vname = m->data.sval; |
| 109 | sql_exp *v = n->data; |
| 110 | |
| 111 | if (!stack_find_var(sql, vname)) { |
| 112 | sql_arg *a = sql_bind_param(sql, vname); |
| 113 | |
| 114 | if (!a) /* not parameter, ie local var ? */ |
| 115 | return sql_error(sql, 01, SQLSTATE(42000) "Variable %s unknown" , vname); |
| 116 | tpe = &a->type; |
| 117 | } else { |
| 118 | tpe = stack_find_type(sql, vname); |
| 119 | } |
| 120 | |
| 121 | if (!exp_name(v)) |
| 122 | exp_label(sql->sa, v, ++sql->label); |
| 123 | v = exp_ref(sql->sa, v); |
| 124 | |
| 125 | level = stack_find_frame(sql, vname); |
| 126 | v = rel_check_type(sql, tpe, rel_val, v, type_cast); |
| 127 | if (!v) |
| 128 | return NULL; |
| 129 | if (v->card > CARD_AGGR) { |
| 130 | sql_subaggr *zero_or_one = sql_bind_aggr(sql->sa, sql->session->schema, "zero_or_one" , exp_subtype(v)); |
| 131 | assert(zero_or_one); |
| 132 | v = exp_aggr1(sql->sa, v, zero_or_one, 0, 0, CARD_ATOM, 0); |
| 133 | } |
| 134 | append(b, exp_set(sql->sa, vname, v, level)); |
| 135 | } |
| 136 | res = exp_rel(sql, rel_psm_block(sql->sa, b)); |
| 137 | } |
| 138 | return res; |
| 139 | } |
| 140 | |
| 141 | static sql_exp* |
| 142 | rel_psm_call(sql_query * query, symbol *se) |
| 143 | { |
| 144 | mvc *sql = query->sql; |
| 145 | sql_subtype *t; |
| 146 | sql_exp *res = NULL; |
| 147 | exp_kind ek = {type_value, card_none, FALSE}; |
| 148 | sql_rel *rel = NULL; |
| 149 | |
| 150 | res = rel_value_exp(query, &rel, se, sql_sel, ek); |
| 151 | if (!res || rel || ((t=exp_subtype(res)) && t->type)) /* only procedures */ |
| 152 | return sql_error(sql, 01, SQLSTATE(42000) "Function calls are ignored" ); |
| 153 | return res; |
| 154 | } |
| 155 | |
| 156 | static list * |
| 157 | rel_psm_declare(mvc *sql, dnode *n) |
| 158 | { |
| 159 | list *l = sa_list(sql->sa); |
| 160 | |
| 161 | while(n) { /* list of 'identfiers with type' */ |
| 162 | dnode *ids = n->data.sym->data.lval->h->data.lval->h; |
| 163 | sql_subtype *ctype = &n->data.sym->data.lval->h->next->data.typeval; |
| 164 | while(ids) { |
| 165 | const char *name = ids->data.sval; |
| 166 | sql_exp *r = NULL; |
| 167 | |
| 168 | /* check if we overwrite a scope local variable declare x; declare x; */ |
| 169 | if (frame_find_var(sql, name)) { |
| 170 | return sql_error(sql, 01, |
| 171 | SQLSTATE(42000) "Variable '%s' already declared" , name); |
| 172 | } |
| 173 | /* variables are put on stack, |
| 174 | * TODO make sure on plan/explain etc they only |
| 175 | * exist during plan phase */ |
| 176 | if(!stack_push_var(sql, name, ctype)) { |
| 177 | return sql_error(sql, 02, SQLSTATE(HY001) MAL_MALLOC_FAIL); |
| 178 | } |
| 179 | r = exp_var(sql->sa, sa_strdup(sql->sa, name), ctype, sql->frame); |
| 180 | append(l, r); |
| 181 | ids = ids->next; |
| 182 | } |
| 183 | n = n->next; |
| 184 | } |
| 185 | return l; |
| 186 | } |
| 187 | |
| 188 | static sql_exp * |
| 189 | rel_psm_declare_table(sql_query *query, dnode *n) |
| 190 | { |
| 191 | mvc *sql = query->sql; |
| 192 | sql_rel *rel = NULL, *baset = NULL; |
| 193 | dlist *qname = n->next->data.lval; |
| 194 | const char *name = qname_table(qname); |
| 195 | const char *sname = qname_schema(qname); |
| 196 | sql_table *t; |
| 197 | |
| 198 | if (sname) /* not allowed here */ |
| 199 | return sql_error(sql, 02, SQLSTATE(42000) "DECLARE TABLE: qualified name not allowed" ); |
| 200 | if (frame_find_var(sql, name)) |
| 201 | return sql_error(sql, 01, SQLSTATE(42000) "Variable '%s' already declared" , name); |
| 202 | |
| 203 | assert(n->next->next->next->type == type_int); |
| 204 | rel = rel_create_table(query, cur_schema(sql), SQL_DECLARED_TABLE, NULL, name, n->next->next->data.sym, |
| 205 | n->next->next->next->data.i_val, NULL, NULL, NULL, false, NULL, 0); |
| 206 | |
| 207 | if (!rel) |
| 208 | return NULL; |
| 209 | if(rel->op == op_ddl) { |
| 210 | baset = rel; |
| 211 | } else if(rel->op == op_insert) { |
| 212 | baset = rel->l; |
| 213 | } else { |
| 214 | return NULL; |
| 215 | } |
| 216 | if(baset->flag != ddl_create_table) |
| 217 | return NULL; |
| 218 | t = (sql_table*)((atom*)((sql_exp*)baset->exps->t->data)->l)->data.val.pval; |
| 219 | if(!stack_push_table(sql, name, baset, t)) |
| 220 | return sql_error(sql, 02, SQLSTATE(HY001) MAL_MALLOC_FAIL); |
| 221 | return exp_table(sql->sa, sa_strdup(sql->sa, name), t, sql->frame); |
| 222 | } |
| 223 | |
| 224 | /* [ label: ] |
| 225 | while (cond) do |
| 226 | statement_list |
| 227 | end [ label ] |
| 228 | currently we only parse the labels, they cannot be used as there is no |
| 229 | |
| 230 | support for LEAVE and ITERATE (sql multi-level break and continue) |
| 231 | */ |
| 232 | static sql_exp * |
| 233 | rel_psm_while_do( sql_query *query, sql_subtype *res, list *restypelist, dnode *w, int is_func ) |
| 234 | { |
| 235 | mvc *sql = query->sql; |
| 236 | if (!w) |
| 237 | return NULL; |
| 238 | if (w->type == type_symbol) { |
| 239 | sql_exp *cond; |
| 240 | list *whilestmts; |
| 241 | dnode *n = w; |
| 242 | sql_rel *rel = NULL; |
| 243 | |
| 244 | cond = rel_logical_value_exp(query, &rel, n->data.sym, sql_sel); |
| 245 | n = n->next; |
| 246 | whilestmts = sequential_block(query, res, restypelist, n->data.lval, n->next->data.sval, is_func); |
| 247 | |
| 248 | if (sql->session->status || !cond || !whilestmts) |
| 249 | return NULL; |
| 250 | if (rel) { |
| 251 | assert(0); |
| 252 | sql_exp *er = exp_rel(sql, rel); |
| 253 | list *b = sa_list(sql->sa); |
| 254 | |
| 255 | append(b, er); |
| 256 | append(b, exp_while( sql->sa, cond, whilestmts )); |
| 257 | return exp_rel(sql, rel_psm_block(sql->sa, b)); |
| 258 | } |
| 259 | return exp_while( sql->sa, cond, whilestmts ); |
| 260 | } |
| 261 | return NULL; |
| 262 | } |
| 263 | |
| 264 | /* if (cond) then statement_list |
| 265 | [ elseif (cond) then statement_list ]* |
| 266 | [ else statement_list ] |
| 267 | end if |
| 268 | */ |
| 269 | static list * |
| 270 | psm_if_then_else( sql_query *query, sql_subtype *res, list *restypelist, dnode *elseif, int is_func) |
| 271 | { |
| 272 | mvc *sql = query->sql; |
| 273 | if (!elseif) |
| 274 | return NULL; |
| 275 | assert(elseif->type == type_symbol); |
| 276 | if (elseif->data.sym && elseif->data.sym->token == SQL_IF) { |
| 277 | sql_exp *cond; |
| 278 | list *ifstmts, *elsestmts; |
| 279 | dnode *n = elseif->data.sym->data.lval->h; |
| 280 | sql_rel *rel = NULL; |
| 281 | |
| 282 | cond = rel_logical_value_exp(query, &rel, n->data.sym, sql_sel); |
| 283 | n = n->next; |
| 284 | ifstmts = sequential_block(query, res, restypelist, n->data.lval, NULL, is_func); |
| 285 | n = n->next; |
| 286 | elsestmts = psm_if_then_else( query, res, restypelist, n, is_func); |
| 287 | |
| 288 | if (sql->session->status || !cond || !ifstmts) |
| 289 | return NULL; |
| 290 | if (rel) { |
| 291 | assert(0); |
| 292 | sql_exp *er = exp_rel(sql, rel); |
| 293 | list *b = sa_list(sql->sa); |
| 294 | |
| 295 | append(b, er); |
| 296 | append(b, exp_if(sql->sa, cond, ifstmts, elsestmts)); |
| 297 | return b; |
| 298 | } |
| 299 | return append(sa_list(sql->sa), exp_if( sql->sa, cond, ifstmts, elsestmts)); |
| 300 | } else { /* else */ |
| 301 | symbol *e = elseif->data.sym; |
| 302 | |
| 303 | if (e==NULL || (e->token != SQL_ELSE)) |
| 304 | return NULL; |
| 305 | return sequential_block( query, res, restypelist, e->data.lval, NULL, is_func); |
| 306 | } |
| 307 | } |
| 308 | |
| 309 | static sql_exp * |
| 310 | rel_psm_if_then_else( sql_query *query, sql_subtype *res, list *restypelist, dnode *elseif, int is_func) |
| 311 | { |
| 312 | mvc *sql = query->sql; |
| 313 | if (!elseif) |
| 314 | return NULL; |
| 315 | if (elseif->next && elseif->type == type_symbol) { /* if or elseif */ |
| 316 | sql_exp *cond; |
| 317 | list *ifstmts, *elsestmts; |
| 318 | dnode *n = elseif; |
| 319 | sql_rel *rel = NULL; |
| 320 | |
| 321 | cond = rel_logical_value_exp(query, &rel, n->data.sym, sql_sel); |
| 322 | n = n->next; |
| 323 | ifstmts = sequential_block(query, res, restypelist, n->data.lval, NULL, is_func); |
| 324 | n = n->next; |
| 325 | elsestmts = psm_if_then_else( query, res, restypelist, n, is_func); |
| 326 | if (sql->session->status || !cond || !ifstmts) |
| 327 | return NULL; |
| 328 | if (rel) { |
| 329 | assert(0); |
| 330 | sql_exp *er = exp_rel(sql, rel); |
| 331 | list *b = sa_list(sql->sa); |
| 332 | |
| 333 | append(b, er); |
| 334 | append(b, exp_if(sql->sa, cond, ifstmts, elsestmts)); |
| 335 | return exp_rel(sql, rel_psm_block(sql->sa, b)); |
| 336 | } |
| 337 | return exp_if( sql->sa, cond, ifstmts, elsestmts); |
| 338 | } |
| 339 | return NULL; |
| 340 | } |
| 341 | |
| 342 | /* 1 |
| 343 | CASE |
| 344 | WHEN search_condition THEN statements |
| 345 | [ WHEN search_condition THEN statements ] |
| 346 | [ ELSE statements ] |
| 347 | END CASE |
| 348 | |
| 349 | 2 |
| 350 | CASE case_value |
| 351 | WHEN when_value THEN statements |
| 352 | [ WHEN when_value THEN statements ] |
| 353 | [ ELSE statements ] |
| 354 | END CASE |
| 355 | */ |
| 356 | static list * |
| 357 | rel_psm_case( sql_query *query, sql_subtype *res, list *restypelist, dnode *case_when, int is_func ) |
| 358 | { |
| 359 | mvc *sql = query->sql; |
| 360 | list *case_stmts = sa_list(sql->sa); |
| 361 | |
| 362 | if (!case_when) |
| 363 | return NULL; |
| 364 | |
| 365 | /* case 1 */ |
| 366 | if (case_when->type == type_symbol) { |
| 367 | dnode *n = case_when; |
| 368 | symbol *case_value = n->data.sym; |
| 369 | dlist *when_statements = n->next->data.lval; |
| 370 | dlist *else_statements = n->next->next->data.lval; |
| 371 | list *else_stmt = NULL; |
| 372 | sql_rel *rel = NULL; |
| 373 | exp_kind ek = {type_value, card_value, FALSE}; |
| 374 | sql_exp *v = rel_value_exp(query, &rel, case_value, sql_sel, ek); |
| 375 | |
| 376 | if (!v) |
| 377 | return NULL; |
| 378 | if (rel) |
| 379 | return sql_error(sql, 02, SQLSTATE(42000) "CASE: No SELECT statements allowed within the CASE condition" ); |
| 380 | if (else_statements) { |
| 381 | else_stmt = sequential_block( query, res, restypelist, else_statements, NULL, is_func); |
| 382 | if (!else_stmt) |
| 383 | return NULL; |
| 384 | } |
| 385 | n = when_statements->h; |
| 386 | while(n) { |
| 387 | dnode *m = n->data.sym->data.lval->h; |
| 388 | sql_exp *cond=0, *when_value = rel_value_exp(query, &rel, m->data.sym, sql_sel, ek); |
| 389 | list *if_stmts = NULL; |
| 390 | sql_exp *case_stmt = NULL; |
| 391 | |
| 392 | if (!when_value || rel || |
| 393 | (cond = rel_binop_(sql, rel, v, when_value, NULL, "=" , card_value)) == NULL || |
| 394 | (if_stmts = sequential_block( query, res, restypelist, m->next->data.lval, NULL, is_func)) == NULL ) { |
| 395 | if (rel) |
| 396 | return sql_error(sql, 02, SQLSTATE(42000) "CASE: No SELECT statements allowed within the CASE condition" ); |
| 397 | return NULL; |
| 398 | } |
| 399 | case_stmt = exp_if(sql->sa, cond, if_stmts, NULL); |
| 400 | list_append(case_stmts, case_stmt); |
| 401 | n = n->next; |
| 402 | } |
| 403 | if (else_stmt) |
| 404 | list_merge(case_stmts, else_stmt, NULL); |
| 405 | return case_stmts; |
| 406 | } else { |
| 407 | /* case 2 */ |
| 408 | dnode *n = case_when; |
| 409 | dlist *whenlist = n->data.lval; |
| 410 | dlist *else_statements = n->next->data.lval; |
| 411 | list *else_stmt = NULL; |
| 412 | |
| 413 | if (else_statements) { |
| 414 | else_stmt = sequential_block( query, res, restypelist, else_statements, NULL, is_func); |
| 415 | if (!else_stmt) |
| 416 | return NULL; |
| 417 | } |
| 418 | n = whenlist->h; |
| 419 | while(n) { |
| 420 | dnode *m = n->data.sym->data.lval->h; |
| 421 | sql_rel *rel = NULL; |
| 422 | sql_exp *cond = rel_logical_value_exp(query, &rel, m->data.sym, sql_sel); |
| 423 | list *if_stmts = NULL; |
| 424 | sql_exp *case_stmt = NULL; |
| 425 | |
| 426 | if (!cond || rel || |
| 427 | (if_stmts = sequential_block( query, res, restypelist, m->next->data.lval, NULL, is_func)) == NULL ) { |
| 428 | if (rel) |
| 429 | return sql_error(sql, 02, SQLSTATE(42000) "CASE: No SELECT statements allowed within the CASE condition" ); |
| 430 | return NULL; |
| 431 | } |
| 432 | case_stmt = exp_if(sql->sa, cond, if_stmts, NULL); |
| 433 | list_append(case_stmts, case_stmt); |
| 434 | n = n->next; |
| 435 | } |
| 436 | if (else_stmt) |
| 437 | list_merge(case_stmts, else_stmt, NULL); |
| 438 | return case_stmts; |
| 439 | } |
| 440 | } |
| 441 | |
| 442 | /* return val; |
| 443 | */ |
| 444 | static list * |
| 445 | rel_psm_return( sql_query *query, sql_subtype *restype, list *restypelist, symbol *return_sym ) |
| 446 | { |
| 447 | mvc *sql = query->sql; |
| 448 | exp_kind ek = {type_value, card_value, FALSE}; |
| 449 | sql_exp *res; |
| 450 | sql_rel *rel = NULL; |
| 451 | int is_last = 0; |
| 452 | list *l = sa_list(sql->sa); |
| 453 | |
| 454 | if (restypelist) |
| 455 | ek.card = card_relation; |
| 456 | res = rel_value_exp2(query, &rel, return_sym, sql_sel, ek, &is_last); |
| 457 | if (!res) |
| 458 | return NULL; |
| 459 | if (!rel && exp_is_rel(res)) |
| 460 | rel = exp_rel_get_rel(sql->sa, res); |
| 461 | if (ek.card != card_relation && (!restype || (res = rel_check_type(sql, restype, rel, res, type_equal)) == NULL)) |
| 462 | return (!restype)?sql_error(sql, 02, SQLSTATE(42000) "RETURN: return type does not match" ):NULL; |
| 463 | else if (ek.card == card_relation && !rel) |
| 464 | return NULL; |
| 465 | |
| 466 | if (rel && !is_ddl(rel->op) && ek.card == card_relation) { |
| 467 | list *exps = sa_list(sql->sa), *oexps = rel->exps; |
| 468 | node *n, *m; |
| 469 | int isproject = (rel->op == op_project); |
| 470 | sql_rel *l = rel->l, *oexps_rel = rel; |
| 471 | |
| 472 | if (is_topn(rel->op) || is_sample(rel->op)) { |
| 473 | oexps_rel = l; |
| 474 | oexps = l->exps; |
| 475 | } |
| 476 | for (n = oexps->h, m = restypelist->h; n && m; n = n->next, m = m->next) { |
| 477 | sql_exp *e = n->data; |
| 478 | sql_arg *ce = m->data; |
| 479 | const char *cname = exp_name(e); |
| 480 | char name[16]; |
| 481 | |
| 482 | if (!cname) |
| 483 | cname = sa_strdup(sql->sa, number2name(name, sizeof(name), ++sql->label)); |
| 484 | if (!isproject) |
| 485 | e = exp_ref(sql->sa, e); |
| 486 | e = rel_check_type(sql, &ce->type, oexps_rel, e, type_equal); |
| 487 | if (!e) |
| 488 | return NULL; |
| 489 | append(exps, e); |
| 490 | } |
| 491 | if (isproject) |
| 492 | rel -> exps = exps; |
| 493 | else |
| 494 | rel = rel_project(sql->sa, rel, exps); |
| 495 | res = exp_rel(sql, rel); |
| 496 | } else if (rel && restypelist){ /* handle return table-var */ |
| 497 | list *exps = sa_list(sql->sa); |
| 498 | sql_table *t = rel_ddl_table_get(rel); |
| 499 | node *n, *m; |
| 500 | const char *tname = t->base.name; |
| 501 | |
| 502 | if (cs_size(&t->columns) != list_length(restypelist)) |
| 503 | return sql_error(sql, 02, SQLSTATE(42000) "RETURN: number of columns do not match" ); |
| 504 | for (n = t->columns.set->h, m = restypelist->h; n && m; n = n->next, m = m->next) { |
| 505 | sql_column *c = n->data; |
| 506 | sql_arg *ce = m->data; |
| 507 | sql_exp *e = exp_column(sql->sa, tname, c->base.name, &c->type, CARD_MULTI, c->null, 0); |
| 508 | |
| 509 | e = rel_check_type(sql, &ce->type, rel, e, type_equal); |
| 510 | if (!e) |
| 511 | return NULL; |
| 512 | append(exps, e); |
| 513 | } |
| 514 | rel = rel_project(sql->sa, rel, exps); |
| 515 | res = exp_rel(sql, rel); |
| 516 | } |
| 517 | append(l, res = exp_return(sql->sa, res, stack_nr_of_declared_tables(sql))); |
| 518 | if (ek.card != card_relation) |
| 519 | res->card = CARD_ATOM; |
| 520 | else |
| 521 | res->card = CARD_MULTI; |
| 522 | return l; |
| 523 | } |
| 524 | |
| 525 | static list * |
| 526 | rel_select_into( sql_query *query, symbol *sq, exp_kind ek) |
| 527 | { |
| 528 | mvc *sql = query->sql; |
| 529 | SelectNode *sn = (SelectNode*)sq; |
| 530 | dlist *into = sn->into; |
| 531 | node *m; |
| 532 | dnode *n; |
| 533 | sql_rel *r; |
| 534 | list *nl = NULL; |
| 535 | |
| 536 | /* SELECT ... INTO var_list */ |
| 537 | sn->into = NULL; |
| 538 | r = rel_subquery(query, NULL, sq, ek); |
| 539 | if (!r) |
| 540 | return NULL; |
| 541 | nl = sa_list(sql->sa); |
| 542 | append(nl, exp_rel(sql, r)); |
| 543 | for (m = r->exps->h, n = into->h; m && n; m = m->next, n = n->next) { |
| 544 | sql_subtype *tpe = NULL; |
| 545 | char *nme = n->data.sval; |
| 546 | sql_exp *v = m->data; |
| 547 | int level; |
| 548 | |
| 549 | if (!stack_find_var(sql, nme)) |
| 550 | return sql_error(sql, 02, SQLSTATE(42000) "SELECT INTO: variable '%s' unknown" , nme); |
| 551 | /* dynamic check for single values */ |
| 552 | if (v->card > CARD_AGGR) { |
| 553 | sql_subaggr *zero_or_one = sql_bind_aggr(sql->sa, sql->session->schema, "zero_or_one" , exp_subtype(v)); |
| 554 | assert(zero_or_one); |
| 555 | v = exp_aggr1(sql->sa, v, zero_or_one, 0, 0, CARD_ATOM, 0); |
| 556 | } |
| 557 | tpe = stack_find_type(sql, nme); |
| 558 | level = stack_find_frame(sql, nme); |
| 559 | if (!v || !(v = rel_check_type(sql, tpe, r, v, type_equal))) |
| 560 | return NULL; |
| 561 | v = exp_set(sql->sa, nme, v, level); |
| 562 | list_append(nl, v); |
| 563 | } |
| 564 | return nl; |
| 565 | } |
| 566 | |
| 567 | extern sql_rel * |
| 568 | rel_select_with_into(sql_query *query, symbol *sq) |
| 569 | { |
| 570 | exp_kind ek = {type_value, card_row, TRUE}; |
| 571 | list *reslist = rel_select_into(query, sq, ek); |
| 572 | if (!reslist) |
| 573 | return NULL; |
| 574 | return rel_psm_block(query->sql->sa, reslist); |
| 575 | } |
| 576 | |
| 577 | static int has_return( list *l ); |
| 578 | |
| 579 | static int |
| 580 | exp_has_return(sql_exp *e) |
| 581 | { |
| 582 | if (e->type == e_psm) { |
| 583 | if (e->flag & PSM_RETURN) |
| 584 | return 1; |
| 585 | if (e->flag & PSM_IF) |
| 586 | return has_return(e->r) && (!e->f || has_return(e->f)); |
| 587 | } |
| 588 | return 0; |
| 589 | } |
| 590 | |
| 591 | static int |
| 592 | has_return( list *l ) |
| 593 | { |
| 594 | node *n = l->t; |
| 595 | sql_exp *e = n->data; |
| 596 | |
| 597 | /* last statment of sequential block */ |
| 598 | if (exp_has_return(e)) |
| 599 | return 1; |
| 600 | return 0; |
| 601 | } |
| 602 | |
| 603 | static list * |
| 604 | sequential_block (sql_query *query, sql_subtype *restype, list *restypelist, dlist *blk, char *opt_label, int is_func) |
| 605 | { |
| 606 | mvc *sql = query->sql; |
| 607 | list *l=0; |
| 608 | dnode *n; |
| 609 | |
| 610 | assert(!restype || !restypelist); |
| 611 | |
| 612 | if (THRhighwater()) |
| 613 | return sql_error(sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space" ); |
| 614 | |
| 615 | if (blk->h) |
| 616 | l = sa_list(sql->sa); |
| 617 | if(!stack_push_frame(sql, opt_label)) |
| 618 | return sql_error(sql, 02, SQLSTATE(HY001) MAL_MALLOC_FAIL); |
| 619 | for (n = blk->h; n; n = n->next ) { |
| 620 | sql_exp *res = NULL; |
| 621 | list *reslist = NULL; |
| 622 | symbol *s = n->data.sym; |
| 623 | |
| 624 | switch (s->token) { |
| 625 | case SQL_SET: |
| 626 | res = psm_set_exp(query, s->data.lval->h); |
| 627 | break; |
| 628 | case SQL_DECLARE: |
| 629 | reslist = rel_psm_declare(sql, s->data.lval->h); |
| 630 | break; |
| 631 | case SQL_DECLARE_TABLE: |
| 632 | case SQL_CREATE_TABLE: |
| 633 | res = rel_psm_declare_table(query, s->data.lval->h); |
| 634 | break; |
| 635 | case SQL_WHILE: |
| 636 | res = rel_psm_while_do(query, restype, restypelist, s->data.lval->h, is_func); |
| 637 | break; |
| 638 | case SQL_IF: |
| 639 | res = rel_psm_if_then_else(query, restype, restypelist, s->data.lval->h, is_func); |
| 640 | break; |
| 641 | case SQL_CASE: |
| 642 | reslist = rel_psm_case(query, restype, restypelist, s->data.lval->h, is_func); |
| 643 | break; |
| 644 | case SQL_CALL: |
| 645 | res = rel_psm_call(query, s->data.sym); |
| 646 | break; |
| 647 | case SQL_RETURN: |
| 648 | /*If it is not a function it cannot have a return statement*/ |
| 649 | if (!is_func) |
| 650 | res = sql_error(sql, 01, SQLSTATE(42000) "Return statement in the procedure body" ); |
| 651 | else { |
| 652 | /* should be last statement of a sequential_block */ |
| 653 | if (n->next) { |
| 654 | res = sql_error(sql, 01, SQLSTATE(42000) "Statement after return" ); |
| 655 | } else { |
| 656 | res = NULL; |
| 657 | reslist = rel_psm_return(query, restype, restypelist, s->data.sym); |
| 658 | } |
| 659 | } |
| 660 | break; |
| 661 | case SQL_SELECT: { /* row selections (into variables) */ |
| 662 | exp_kind ek = {type_value, card_row, TRUE}; |
| 663 | reslist = rel_select_into(query, s, ek); |
| 664 | } break; |
| 665 | case SQL_COPYFROM: |
| 666 | case SQL_BINCOPYFROM: |
| 667 | case SQL_INSERT: |
| 668 | case SQL_UPDATE: |
| 669 | case SQL_DELETE: |
| 670 | case SQL_TRUNCATE: |
| 671 | case SQL_MERGE: { |
| 672 | sql_rel *r = rel_updates(query, s); |
| 673 | if (!r) |
| 674 | return NULL; |
| 675 | res = exp_rel(sql, r); |
| 676 | } break; |
| 677 | default: |
| 678 | res = sql_error(sql, 01, SQLSTATE(42000) "Statement '%s' is not a valid flow control statement" , |
| 679 | token2string(s->token)); |
| 680 | } |
| 681 | if (!res && !reslist) { |
| 682 | l = NULL; |
| 683 | break; |
| 684 | } |
| 685 | if (res) |
| 686 | list_append(l, res); |
| 687 | else |
| 688 | list_merge(l, reslist, NULL); |
| 689 | } |
| 690 | stack_pop_frame(sql); |
| 691 | return l; |
| 692 | } |
| 693 | |
| 694 | static int |
| 695 | arg_cmp(void *A, void *N) |
| 696 | { |
| 697 | sql_arg *a = A; |
| 698 | char *name = N; |
| 699 | return strcmp(a->name, name); |
| 700 | } |
| 701 | |
| 702 | static list * |
| 703 | result_type(mvc *sql, symbol *res) |
| 704 | { |
| 705 | if (res->token == SQL_TYPE) { |
| 706 | sql_subtype *st = &res->data.lval->h->data.typeval; |
| 707 | sql_arg *a = sql_create_arg(sql->sa, "result" , st, ARG_OUT); |
| 708 | |
| 709 | return list_append(sa_list(sql->sa), a); |
| 710 | } else if (res->token == SQL_TABLE) { |
| 711 | sql_arg *a; |
| 712 | dnode *n = res->data.lval->h; |
| 713 | list *types = sa_list(sql->sa); |
| 714 | |
| 715 | for(;n; n = n->next->next) { |
| 716 | sql_subtype *ct = &n->next->data.typeval; |
| 717 | |
| 718 | if (list_find(types, n->data.sval, &arg_cmp) != NULL) |
| 719 | return sql_error(sql, ERR_AMBIGUOUS, SQLSTATE(42000) "CREATE FUNC: identifier '%s' ambiguous" , n->data.sval); |
| 720 | |
| 721 | a = sql_create_arg(sql->sa, n->data.sval, ct, ARG_OUT); |
| 722 | list_append(types, a); |
| 723 | } |
| 724 | return types; |
| 725 | } |
| 726 | return NULL; |
| 727 | } |
| 728 | |
| 729 | static list * |
| 730 | create_type_list(mvc *sql, dlist *params, int param) |
| 731 | { |
| 732 | sql_subtype *par_subtype; |
| 733 | list * type_list = sa_list(sql->sa); |
| 734 | dnode * n = NULL; |
| 735 | |
| 736 | if (params) { |
| 737 | for (n = params->h; n; n = n->next) { |
| 738 | dnode *an = n; |
| 739 | |
| 740 | if (param) { |
| 741 | an = n->data.lval->h; |
| 742 | par_subtype = &an->next->data.typeval; |
| 743 | if (par_subtype && !par_subtype->type) /* var arg */ |
| 744 | return type_list; |
| 745 | list_append(type_list, par_subtype); |
| 746 | } else { |
| 747 | par_subtype = &an->data.typeval; |
| 748 | list_prepend(type_list, par_subtype); |
| 749 | } |
| 750 | } |
| 751 | } |
| 752 | return type_list; |
| 753 | } |
| 754 | |
| 755 | static sql_rel* |
| 756 | rel_create_function(sql_allocator *sa, const char *sname, sql_func *f) |
| 757 | { |
| 758 | sql_rel *rel = rel_create(sa); |
| 759 | list *exps = new_exp_list(sa); |
| 760 | if(!rel || !exps) |
| 761 | return NULL; |
| 762 | |
| 763 | append(exps, exp_atom_clob(sa, sname)); |
| 764 | if (f) |
| 765 | append(exps, exp_atom_clob(sa, f->base.name)); |
| 766 | append(exps, exp_atom_ptr(sa, f)); |
| 767 | rel->l = NULL; |
| 768 | rel->r = NULL; |
| 769 | rel->op = op_ddl; |
| 770 | rel->flag = ddl_create_function; |
| 771 | rel->exps = exps; |
| 772 | rel->card = 0; |
| 773 | rel->nrcols = 0; |
| 774 | return rel; |
| 775 | } |
| 776 | |
| 777 | static sql_rel * |
| 778 | rel_create_func(sql_query *query, dlist *qname, dlist *params, symbol *res, dlist *ext_name, dlist *body, sql_ftype type, sql_flang lang, int replace) |
| 779 | { |
| 780 | mvc *sql = query->sql; |
| 781 | const char *fname = qname_table(qname); |
| 782 | const char *sname = qname_schema(qname); |
| 783 | sql_schema *s = NULL; |
| 784 | sql_func *f = NULL; |
| 785 | sql_subfunc *sf; |
| 786 | dnode *n; |
| 787 | list *type_list = NULL, *restype = NULL; |
| 788 | int instantiate = (sql->emode == m_instantiate); |
| 789 | int deps = (sql->emode == m_deps); |
| 790 | int create = (!instantiate && !deps); |
| 791 | bit vararg = FALSE; |
| 792 | |
| 793 | char is_table = (res && res->token == SQL_TABLE); |
| 794 | char is_aggr = (type == F_AGGR); |
| 795 | char is_func = (type != F_PROC); |
| 796 | char is_loader = (type == F_LOADER); |
| 797 | |
| 798 | char *F = is_loader?"LOADER" :(is_aggr?"AGGREGATE" :(is_func?"FUNCTION" :"PROCEDURE" )); |
| 799 | char *fn = is_loader?"loader" :(is_aggr ? "aggregate" : (is_func ? "function" : "procedure" )); |
| 800 | char *KF = type==F_FILT?"FILTER " : type==F_UNION?"UNION " : "" ; |
| 801 | char *kf = type == F_FILT ? "filter " : type == F_UNION ? "union " : "" ; |
| 802 | |
| 803 | assert(res || type == F_PROC || type == F_FILT || type == F_LOADER); |
| 804 | |
| 805 | if (is_table) |
| 806 | type = F_UNION; |
| 807 | |
| 808 | if (STORE_READONLY && create) |
| 809 | return sql_error(sql, 06, SQLSTATE(42000) "Schema statements cannot be executed on a readonly database." ); |
| 810 | |
| 811 | if (sname && !(s = mvc_bind_schema(sql, sname))) |
| 812 | return sql_error(sql, 02, SQLSTATE(3F000) "CREATE %s%s: no such schema '%s'" , KF, F, sname); |
| 813 | if (s == NULL) |
| 814 | s = cur_schema(sql); |
| 815 | |
| 816 | type_list = create_type_list(sql, params, 1); |
| 817 | if ((sf = sql_bind_func_(sql->sa, s, fname, type_list, type)) != NULL && create) { |
| 818 | if (replace) { |
| 819 | sql_func *func = sf->func; |
| 820 | if (!mvc_schema_privs(sql, s)) |
| 821 | return sql_error(sql, 02, SQLSTATE(42000) "CREATE OR REPLACE %s%s: access denied for %s to schema '%s'" , KF, F, stack_get_string(sql, "current_user" ), s->base.name); |
| 822 | if (mvc_check_dependency(sql, func->base.id, !IS_PROC(func) ? FUNC_DEPENDENCY : PROC_DEPENDENCY, NULL)) |
| 823 | return sql_error(sql, 02, SQLSTATE(42000) "CREATE OR REPLACE %s%s: there are database objects dependent on %s%s %s;" , KF, F, kf, fn, func->base.name); |
| 824 | if (!func->s) |
| 825 | return sql_error(sql, 02, SQLSTATE(42000) "CREATE OR REPLACE %s%s: not allowed to replace system %s%s %s;" , KF, F, kf, fn, func->base.name); |
| 826 | if (mvc_drop_func(sql, s, func, 0)) |
| 827 | return sql_error(sql, 02, SQLSTATE(HY001) MAL_MALLOC_FAIL); |
| 828 | sf = NULL; |
| 829 | } else { |
| 830 | if (params) { |
| 831 | char *arg_list = NULL; |
| 832 | node *n; |
| 833 | |
| 834 | for (n = type_list->h; n; n = n->next) { |
| 835 | char *tpe = subtype2string((sql_subtype *) n->data); |
| 836 | |
| 837 | if (arg_list) { |
| 838 | char *t = arg_list; |
| 839 | arg_list = sql_message("%s, %s" , arg_list, tpe); |
| 840 | _DELETE(t); |
| 841 | _DELETE(tpe); |
| 842 | } else { |
| 843 | arg_list = tpe; |
| 844 | } |
| 845 | } |
| 846 | (void)sql_error(sql, 02, SQLSTATE(42000) "CREATE %s%s: name '%s' (%s) already in use" , KF, F, fname, arg_list ? arg_list : "" ); |
| 847 | _DELETE(arg_list); |
| 848 | list_destroy(type_list); |
| 849 | return NULL; |
| 850 | } else { |
| 851 | list_destroy(type_list); |
| 852 | return sql_error(sql, 02, SQLSTATE(42000) "CREATE %s%s: name '%s' already in use" , KF, F, fname); |
| 853 | } |
| 854 | } |
| 855 | } |
| 856 | list_destroy(type_list); |
| 857 | if (create && !mvc_schema_privs(sql, s)) { |
| 858 | return sql_error(sql, 02, SQLSTATE(42000) "CREATE %s%s: insufficient privileges for user '%s' in schema '%s'" , KF, F, |
| 859 | stack_get_string(sql, "current_user" ), s->base.name); |
| 860 | } else { |
| 861 | char *q = QUERY(sql->scanner); |
| 862 | list *l = NULL; |
| 863 | |
| 864 | if (params) { |
| 865 | for (n = params->h; n; n = n->next) { |
| 866 | dnode *an = n->data.lval->h; |
| 867 | sql_add_param(sql, an->data.sval, &an->next->data.typeval); |
| 868 | } |
| 869 | l = sql->params; |
| 870 | if (l && list_length(l) == 1) { |
| 871 | sql_arg *a = l->h->data; |
| 872 | |
| 873 | if (strcmp(a->name, "*" ) == 0) { |
| 874 | l = NULL; |
| 875 | vararg = TRUE; |
| 876 | } |
| 877 | } |
| 878 | } |
| 879 | if (!l) |
| 880 | l = sa_list(sql->sa); |
| 881 | if (res) { |
| 882 | restype = result_type(sql, res); |
| 883 | if (!restype) |
| 884 | return sql_error(sql, 01, SQLSTATE(42000) "CREATE %s%s: failed to get restype" , KF, F); |
| 885 | } |
| 886 | if (body && LANG_EXT(lang)) { |
| 887 | char *lang_body = body->h->data.sval, *mod = NULL, *slang = NULL; |
| 888 | switch (lang) { |
| 889 | case FUNC_LANG_R: |
| 890 | mod = "rapi" ; |
| 891 | slang = "R" ; |
| 892 | break; |
| 893 | case FUNC_LANG_C: |
| 894 | mod = "capi" ; |
| 895 | slang = "C" ; |
| 896 | break; |
| 897 | case FUNC_LANG_CPP: |
| 898 | mod = "capi" ; |
| 899 | slang = "CPP" ; |
| 900 | break; |
| 901 | case FUNC_LANG_J: |
| 902 | mod = "japi" ; |
| 903 | slang = "Javascript" ; |
| 904 | break; |
| 905 | case FUNC_LANG_PY: |
| 906 | mod = "pyapi" ; |
| 907 | slang = "Python" ; |
| 908 | break; |
| 909 | case FUNC_LANG_MAP_PY: |
| 910 | mod = "pyapimap" ; |
| 911 | slang = "Python" ; |
| 912 | break; |
| 913 | default: |
| 914 | assert(0); |
| 915 | } |
| 916 | sql->params = NULL; |
| 917 | if (create) { |
| 918 | f = mvc_create_func(sql, sql->sa, s, fname, l, restype, type, lang, mod, fname, lang_body, (type == F_LOADER)?TRUE:FALSE, vararg, FALSE); |
| 919 | } else if (!sf) { |
| 920 | return sql_error(sql, 01, SQLSTATE(42000) "CREATE %s%s: %s function %s.%s not bound" , KF, F, slang, s->base.name, fname); |
| 921 | } |
| 922 | } else if (body) { /* SQL implementation */ |
| 923 | sql_arg *ra = (restype && !is_table)?restype->h->data:NULL; |
| 924 | list *b = NULL; |
| 925 | sql_schema *old_schema = cur_schema(sql); |
| 926 | |
| 927 | if (create) { /* needed for recursive functions */ |
| 928 | q = query_cleaned(q); |
| 929 | sql->forward = f = mvc_create_func(sql, sql->sa, s, fname, l, restype, type, lang, "user" , q, q, FALSE, vararg, FALSE); |
| 930 | GDKfree(q); |
| 931 | } |
| 932 | sql->session->schema = s; |
| 933 | b = sequential_block(query, (ra)?&ra->type:NULL, ra?NULL:restype, body, NULL, is_func); |
| 934 | sql->forward = NULL; |
| 935 | sql->session->schema = old_schema; |
| 936 | sql->params = NULL; |
| 937 | if (!b) |
| 938 | return NULL; |
| 939 | |
| 940 | /* check if we have a return statement */ |
| 941 | if (is_func && restype && !has_return(b)) |
| 942 | return sql_error(sql, 01, SQLSTATE(42000) "CREATE %s%s: missing return statement" , KF, F); |
| 943 | if (!is_func && !restype && has_return(b)) |
| 944 | return sql_error(sql, 01, SQLSTATE(42000) "CREATE %s%s: procedures cannot have return statements" , KF, F); |
| 945 | /* in execute mode we instantiate the function */ |
| 946 | if (instantiate || deps) |
| 947 | return rel_psm_block(sql->sa, b); |
| 948 | } else { /* MAL implementation */ |
| 949 | char *fmod = qname_module(ext_name); |
| 950 | char *fnme = qname_fname(ext_name); |
| 951 | |
| 952 | if (!fmod || !fnme) |
| 953 | return NULL; |
| 954 | sql->params = NULL; |
| 955 | if (create) { |
| 956 | q = query_cleaned(q); |
| 957 | f = mvc_create_func(sql, sql->sa, s, fname, l, restype, type, lang, fmod, fnme, q, FALSE, vararg, FALSE); |
| 958 | GDKfree(q); |
| 959 | } else if (!sf) { |
| 960 | return sql_error(sql, 01, SQLSTATE(42000) "CREATE %s%s: external name %s.%s not bound (%s.%s)" , KF, F, fmod, fnme, s->base.name, fname ); |
| 961 | } else { |
| 962 | sql_func *f = sf->func; |
| 963 | if (!f->mod || strcmp(f->mod, fmod)) |
| 964 | f->mod = _STRDUP(fmod); |
| 965 | if (!f->imp || strcmp(f->imp, fnme)) |
| 966 | f->imp = (f->sa)?sa_strdup(f->sa, fnme):_STRDUP(fnme); |
| 967 | if (!f->mod || !f->imp) { |
| 968 | _DELETE(f->mod); |
| 969 | _DELETE(f->imp); |
| 970 | return sql_error(sql, 02, SQLSTATE(HY001) "CREATE %s%s: could not allocate space" , KF, F); |
| 971 | } |
| 972 | f->sql = 0; /* native */ |
| 973 | f->lang = FUNC_LANG_INT; |
| 974 | } |
| 975 | if (!f) |
| 976 | f = sf->func; |
| 977 | assert(f); |
| 978 | if (!backend_resolve_function(sql, f)) |
| 979 | return sql_error(sql, 01, SQLSTATE(3F000) "CREATE %s%s: external name %s.%s not bound (%s.%s)" , KF, F, fmod, fnme, s->base.name, fname ); |
| 980 | } |
| 981 | } |
| 982 | return rel_create_function(sql->sa, s->base.name, f); |
| 983 | } |
| 984 | |
| 985 | static sql_rel* |
| 986 | rel_drop_function(sql_allocator *sa, const char *sname, const char *name, int nr, sql_ftype type, int action) |
| 987 | { |
| 988 | sql_rel *rel = rel_create(sa); |
| 989 | list *exps = new_exp_list(sa); |
| 990 | if(!rel || !exps) |
| 991 | return NULL; |
| 992 | |
| 993 | append(exps, exp_atom_clob(sa, sname)); |
| 994 | append(exps, exp_atom_clob(sa, name)); |
| 995 | append(exps, exp_atom_int(sa, nr)); |
| 996 | append(exps, exp_atom_int(sa, (int) type)); |
| 997 | append(exps, exp_atom_int(sa, action)); |
| 998 | rel->l = NULL; |
| 999 | rel->r = NULL; |
| 1000 | rel->op = op_ddl; |
| 1001 | rel->flag = ddl_drop_function; |
| 1002 | rel->exps = exps; |
| 1003 | rel->card = 0; |
| 1004 | rel->nrcols = 0; |
| 1005 | return rel; |
| 1006 | } |
| 1007 | |
| 1008 | sql_func * |
| 1009 | resolve_func( mvc *sql, sql_schema *s, const char *name, dlist *typelist, sql_ftype type, char *op, int if_exists) |
| 1010 | { |
| 1011 | sql_func *func = NULL; |
| 1012 | list *list_func = NULL, *type_list = NULL; |
| 1013 | char is_aggr = (type == F_AGGR); |
| 1014 | char is_func = (type != F_PROC && type != F_LOADER); |
| 1015 | char *F = is_aggr?"AGGREGATE" :(is_func?"FUNCTION" :"PROCEDURE" ); |
| 1016 | char *f = is_aggr?"aggregate" :(is_func?"function" :"procedure" ); |
| 1017 | char *KF = type==F_FILT?"FILTER " : type==F_UNION?"UNION " : "" ; |
| 1018 | char *kf = type==F_FILT?"filter " : type==F_UNION?"union " : "" ; |
| 1019 | |
| 1020 | if (typelist) { |
| 1021 | sql_subfunc *sub_func; |
| 1022 | |
| 1023 | type_list = create_type_list(sql, typelist, 0); |
| 1024 | sub_func = sql_bind_func_(sql->sa, s, name, type_list, type); |
| 1025 | if (!sub_func && type == F_FUNC) { |
| 1026 | sub_func = sql_bind_func_(sql->sa, s, name, type_list, F_UNION); |
| 1027 | type = sub_func?F_UNION:F_FUNC; |
| 1028 | } |
| 1029 | if ( sub_func && sub_func->func->type == type) |
| 1030 | func = sub_func->func; |
| 1031 | } else { |
| 1032 | list_func = schema_bind_func(sql, s, name, type); |
| 1033 | if (!list_func && type == F_FUNC) |
| 1034 | list_func = schema_bind_func(sql,s,name, F_UNION); |
| 1035 | if (list_func && list_func->cnt > 1) { |
| 1036 | list_destroy(list_func); |
| 1037 | return sql_error(sql, 02, SQLSTATE(42000) "%s %s%s: there are more than one %s%s called '%s', please use the full signature" , op, KF, F, kf, f,name); |
| 1038 | } |
| 1039 | if (list_func && list_func->cnt == 1) |
| 1040 | func = (sql_func*) list_func->h->data; |
| 1041 | } |
| 1042 | |
| 1043 | if (!func) { |
| 1044 | void *e = NULL; |
| 1045 | if (typelist) { |
| 1046 | char *arg_list = NULL; |
| 1047 | node *n; |
| 1048 | |
| 1049 | if (type_list->cnt > 0) { |
| 1050 | for (n = type_list->h; n; n = n->next) { |
| 1051 | char *tpe = subtype2string((sql_subtype *) n->data); |
| 1052 | |
| 1053 | if (arg_list) { |
| 1054 | char *t = arg_list; |
| 1055 | arg_list = sql_message("%s, %s" , arg_list, tpe); |
| 1056 | _DELETE(tpe); |
| 1057 | _DELETE(t); |
| 1058 | } else { |
| 1059 | arg_list = tpe; |
| 1060 | } |
| 1061 | } |
| 1062 | list_destroy(list_func); |
| 1063 | list_destroy(type_list); |
| 1064 | if(!if_exists) |
| 1065 | e = sql_error(sql, 02, SQLSTATE(42000) "%s %s%s: no such %s%s '%s' (%s)" , op, KF, F, kf, f, name, arg_list); |
| 1066 | _DELETE(arg_list); |
| 1067 | return e; |
| 1068 | } |
| 1069 | list_destroy(list_func); |
| 1070 | list_destroy(type_list); |
| 1071 | if(!if_exists) |
| 1072 | e = sql_error(sql, 02, SQLSTATE(42000) "%s %s%s: no such %s%s '%s' ()" , op, KF, F, kf, f, name); |
| 1073 | return e; |
| 1074 | |
| 1075 | } else { |
| 1076 | if(!if_exists) |
| 1077 | e = sql_error(sql, 02, SQLSTATE(42000) "%s %s%s: no such %s%s '%s'" , op, KF, F, kf, f, name); |
| 1078 | return e; |
| 1079 | } |
| 1080 | } else if (((is_func && type != F_FILT) && !func->res) || |
| 1081 | (!is_func && func->res)) { |
| 1082 | list_destroy(list_func); |
| 1083 | list_destroy(type_list); |
| 1084 | return sql_error(sql, 02, SQLSTATE(42000) "%s %s%s: cannot drop %s '%s'" , KF, F, is_func?"procedure" :"function" , op, name); |
| 1085 | } |
| 1086 | |
| 1087 | list_destroy(list_func); |
| 1088 | list_destroy(type_list); |
| 1089 | return func; |
| 1090 | } |
| 1091 | |
| 1092 | static sql_rel* |
| 1093 | rel_drop_func(mvc *sql, dlist *qname, dlist *typelist, int drop_action, sql_ftype type, int if_exists) |
| 1094 | { |
| 1095 | const char *name = qname_table(qname); |
| 1096 | const char *sname = qname_schema(qname); |
| 1097 | sql_schema *s = NULL; |
| 1098 | sql_func *func = NULL; |
| 1099 | |
| 1100 | char is_aggr = (type == F_AGGR); |
| 1101 | char is_func = (type != F_PROC); |
| 1102 | char *F = is_aggr?"AGGREGATE" :(is_func?"FUNCTION" :"PROCEDURE" ); |
| 1103 | char *KF = type==F_FILT?"FILTER " : type==F_UNION?"UNION " : "" ; |
| 1104 | |
| 1105 | if (sname && !(s = mvc_bind_schema(sql, sname))) |
| 1106 | return sql_error(sql, 02, SQLSTATE(3F000) "DROP %s%s: no such schema '%s'" , KF, F, sname); |
| 1107 | |
| 1108 | if (s == NULL) |
| 1109 | s = cur_schema(sql); |
| 1110 | |
| 1111 | func = resolve_func(sql, s, name, typelist, type, "DROP" , if_exists); |
| 1112 | if (!func && !sname) { |
| 1113 | s = tmp_schema(sql); |
| 1114 | func = resolve_func(sql, s, name, typelist, type, "DROP" , if_exists); |
| 1115 | } |
| 1116 | if (func) |
| 1117 | return rel_drop_function(sql->sa, s->base.name, name, func->base.id, type, drop_action); |
| 1118 | else if(if_exists && !sql->session->status) |
| 1119 | return rel_drop_function(sql->sa, s->base.name, name, -2, type, drop_action); |
| 1120 | return NULL; |
| 1121 | } |
| 1122 | |
| 1123 | static sql_rel* |
| 1124 | rel_drop_all_func(mvc *sql, dlist *qname, int drop_action, sql_ftype type) |
| 1125 | { |
| 1126 | const char *name = qname_table(qname); |
| 1127 | const char *sname = qname_schema(qname); |
| 1128 | sql_schema *s = NULL; |
| 1129 | list * list_func = NULL; |
| 1130 | |
| 1131 | char is_aggr = (type == F_AGGR); |
| 1132 | char is_func = (type != F_PROC); |
| 1133 | char *F = is_aggr?"AGGREGATE" :(is_func?"FUNCTION" :"PROCEDURE" ); |
| 1134 | char *f = is_aggr?"aggregate" :(is_func?"function" :"procedure" ); |
| 1135 | char *KF = type==F_FILT?"FILTER " : type==F_UNION?"UNION " : "" ; |
| 1136 | char *kf = type==F_FILT?"filter " : type==F_UNION?"union " : "" ; |
| 1137 | |
| 1138 | if (sname && !(s = mvc_bind_schema(sql, sname))) |
| 1139 | return sql_error(sql, 02, SQLSTATE(3F000) "DROP %s%s: no such schema '%s'" , KF, F, sname); |
| 1140 | |
| 1141 | if (s == NULL) |
| 1142 | s = cur_schema(sql); |
| 1143 | |
| 1144 | list_func = schema_bind_func(sql, s, name, type); |
| 1145 | if (!list_func) |
| 1146 | return sql_error(sql, 02, SQLSTATE(3F000) "DROP ALL %s%s: no such %s%s '%s'" , KF, F, kf, f, name); |
| 1147 | list_destroy(list_func); |
| 1148 | return rel_drop_function(sql->sa, s->base.name, name, -1, type, drop_action); |
| 1149 | } |
| 1150 | |
| 1151 | static sql_rel * |
| 1152 | rel_create_trigger(mvc *sql, const char *sname, const char *tname, const char *triggername, int time, int orientation, int event, const char *old_name, const char *new_name, symbol *condition, const char *query) |
| 1153 | { |
| 1154 | sql_rel *rel = rel_create(sql->sa); |
| 1155 | list *exps = new_exp_list(sql->sa); |
| 1156 | if(!rel || !exps) |
| 1157 | return NULL; |
| 1158 | |
| 1159 | append(exps, exp_atom_str(sql->sa, sname, sql_bind_localtype("str" ) )); |
| 1160 | append(exps, exp_atom_str(sql->sa, tname, sql_bind_localtype("str" ) )); |
| 1161 | append(exps, exp_atom_str(sql->sa, triggername, sql_bind_localtype("str" ) )); |
| 1162 | append(exps, exp_atom_int(sql->sa, time)); |
| 1163 | append(exps, exp_atom_int(sql->sa, orientation)); |
| 1164 | append(exps, exp_atom_int(sql->sa, event)); |
| 1165 | append(exps, exp_atom_str(sql->sa, old_name, sql_bind_localtype("str" ) )); |
| 1166 | append(exps, exp_atom_str(sql->sa, new_name, sql_bind_localtype("str" ) )); |
| 1167 | (void)condition; |
| 1168 | append(exps, exp_atom_str(sql->sa, NULL, sql_bind_localtype("str" ) )); |
| 1169 | append(exps, exp_atom_str(sql->sa, query, sql_bind_localtype("str" ) )); |
| 1170 | rel->l = NULL; |
| 1171 | rel->r = NULL; |
| 1172 | rel->op = op_ddl; |
| 1173 | rel->flag = ddl_create_trigger; |
| 1174 | rel->exps = exps; |
| 1175 | rel->card = CARD_MULTI; |
| 1176 | rel->nrcols = 0; |
| 1177 | return rel; |
| 1178 | } |
| 1179 | |
| 1180 | static sql_var* |
| 1181 | _stack_push_table(mvc *sql, const char *tname, sql_table *t) |
| 1182 | { |
| 1183 | sql_rel *r = rel_basetable(sql, t, tname ); |
| 1184 | return stack_push_rel_view(sql, tname, r); |
| 1185 | } |
| 1186 | |
| 1187 | static sql_rel * |
| 1188 | create_trigger(sql_query *query, dlist *qname, int time, symbol *trigger_event, dlist *tqname, dlist *opt_ref, dlist *triggered_action, int replace) |
| 1189 | { |
| 1190 | mvc *sql = query->sql; |
| 1191 | const char *triggerschema = qname_schema(qname); |
| 1192 | const char *triggername = qname_table(qname); |
| 1193 | const char *sname = qname_schema(tqname); |
| 1194 | const char *tname = qname_table(tqname); |
| 1195 | sql_schema *ss = cur_schema(sql); |
| 1196 | sql_table *t = NULL; |
| 1197 | sql_trigger *st = NULL; |
| 1198 | int instantiate = (sql->emode == m_instantiate); |
| 1199 | int create = (!instantiate && sql->emode != m_deps), event, orientation; |
| 1200 | list *sq = NULL; |
| 1201 | sql_rel *r = NULL; |
| 1202 | char *q, *base = replace ? "CREATE OR REPLACE" : "CREATE" ; |
| 1203 | |
| 1204 | dlist *columns = trigger_event->data.lval; |
| 1205 | const char *old_name = NULL, *new_name = NULL; |
| 1206 | dlist *stmts = triggered_action->h->next->next->data.lval; |
| 1207 | symbol *condition = triggered_action->h->next->data.sym; |
| 1208 | |
| 1209 | if (!sname) |
| 1210 | sname = ss->base.name; |
| 1211 | |
| 1212 | if (sname && !(ss = mvc_bind_schema(sql, sname))) |
| 1213 | return sql_error(sql, 02, SQLSTATE(3F000) "%s TRIGGER: no such schema '%s'" , base, sname); |
| 1214 | |
| 1215 | if (opt_ref) { |
| 1216 | dnode *dl = opt_ref->h; |
| 1217 | for ( ; dl; dl = dl->next) { |
| 1218 | /* list (new(1)/old(0)), char */ |
| 1219 | char *n = dl->data.lval->h->next->data.sval; |
| 1220 | |
| 1221 | assert(dl->data.lval->h->type == type_int); |
| 1222 | if (!dl->data.lval->h->data.i_val) /*?l_val?*/ |
| 1223 | old_name = n; |
| 1224 | else |
| 1225 | new_name = n; |
| 1226 | } |
| 1227 | } |
| 1228 | |
| 1229 | if (create && !mvc_schema_privs(sql, ss)) |
| 1230 | return sql_error(sql, 02, SQLSTATE(42000) "%s TRIGGER: access denied for %s to schema '%s'" , base, stack_get_string(sql, "current_user" ), ss->base.name); |
| 1231 | if (create && !(t = mvc_bind_table(sql, ss, tname))) |
| 1232 | return sql_error(sql, 02, SQLSTATE(42000) "%s TRIGGER: unknown table '%s'" , base, tname); |
| 1233 | if (create && isView(t)) |
| 1234 | return sql_error(sql, 02, SQLSTATE(42000) "%s TRIGGER: cannot create trigger on view '%s'" , base, tname); |
| 1235 | if (triggerschema && strcmp(triggerschema, sname) != 0) |
| 1236 | return sql_error(sql, 02, SQLSTATE(42000) "%s TRIGGER: trigger and respective table must belong to the same schema" , base); |
| 1237 | if (create && (st = mvc_bind_trigger(sql, ss, triggername)) != NULL) { |
| 1238 | if (replace) { |
| 1239 | if(mvc_drop_trigger(sql, ss, st)) |
| 1240 | return sql_error(sql, 02, SQLSTATE(HY001) "%s TRIGGER: %s" , base, MAL_MALLOC_FAIL); |
| 1241 | } else { |
| 1242 | return sql_error(sql, 02, SQLSTATE(42000) "%s TRIGGER: name '%s' already in use" , base, triggername); |
| 1243 | } |
| 1244 | } |
| 1245 | |
| 1246 | if (create) { |
| 1247 | switch (trigger_event->token) { |
| 1248 | case SQL_INSERT: |
| 1249 | event = 0; |
| 1250 | break; |
| 1251 | case SQL_DELETE: |
| 1252 | event = 1; |
| 1253 | break; |
| 1254 | case SQL_TRUNCATE: |
| 1255 | event = 3; |
| 1256 | break; |
| 1257 | default: |
| 1258 | event = 2; |
| 1259 | break; |
| 1260 | } |
| 1261 | orientation = triggered_action->h->data.i_val; |
| 1262 | q = query_cleaned(QUERY(sql->scanner)); |
| 1263 | |
| 1264 | assert(triggered_action->h->type == type_int); |
| 1265 | r = rel_create_trigger(sql, t->s->base.name, t->base.name, triggername, time, orientation, event, old_name, new_name, condition, q); |
| 1266 | GDKfree(q); |
| 1267 | return r; |
| 1268 | } |
| 1269 | |
| 1270 | if (!instantiate) { |
| 1271 | t = mvc_bind_table(sql, ss, tname); |
| 1272 | if (!stack_push_frame(sql, "OLD-NEW" )) |
| 1273 | return sql_error(sql, 02, SQLSTATE(HY001) MAL_MALLOC_FAIL); |
| 1274 | /* we need to add the old and new tables */ |
| 1275 | if (new_name && !_stack_push_table(sql, new_name, t)) { |
| 1276 | stack_pop_frame(sql); |
| 1277 | return sql_error(sql, 02, SQLSTATE(HY001) MAL_MALLOC_FAIL); |
| 1278 | } |
| 1279 | if (old_name && !_stack_push_table(sql, old_name, t)) { |
| 1280 | stack_pop_frame(sql); |
| 1281 | return sql_error(sql, 02, SQLSTATE(HY001) MAL_MALLOC_FAIL); |
| 1282 | } |
| 1283 | } |
| 1284 | if (condition) { |
| 1285 | sql_rel *rel = NULL; |
| 1286 | |
| 1287 | if (new_name) /* in case of updates same relations is available via both names */ |
| 1288 | rel = stack_find_rel_view(sql, new_name); |
| 1289 | if (!rel && old_name) |
| 1290 | rel = stack_find_rel_view(sql, old_name); |
| 1291 | if (rel) |
| 1292 | rel = rel_logical_exp(query, rel, condition, sql_where); |
| 1293 | if (!rel) { |
| 1294 | if (!instantiate) |
| 1295 | stack_pop_frame(sql); |
| 1296 | return NULL; |
| 1297 | } |
| 1298 | /* transition tables */ |
| 1299 | /* insert: rel_select(table [new], searchcondition) */ |
| 1300 | /* delete: rel_select(table [old], searchcondition) */ |
| 1301 | /* update: rel_select(table [old,new]), searchcondition) */ |
| 1302 | if (new_name) |
| 1303 | stack_update_rel_view(sql, new_name, rel); |
| 1304 | if (old_name) |
| 1305 | stack_update_rel_view(sql, old_name, new_name?rel_dup(rel):rel); |
| 1306 | } |
| 1307 | sq = sequential_block(query, NULL, NULL, stmts, NULL, 1); |
| 1308 | r = rel_psm_block(sql->sa, sq); |
| 1309 | |
| 1310 | if (!instantiate) |
| 1311 | stack_pop_frame(sql); |
| 1312 | /* todo trigger_columns */ |
| 1313 | (void)columns; |
| 1314 | return r; |
| 1315 | } |
| 1316 | |
| 1317 | static sql_rel * |
| 1318 | rel_drop_trigger(mvc *sql, const char *sname, const char *tname, int if_exists) |
| 1319 | { |
| 1320 | sql_rel *rel = rel_create(sql->sa); |
| 1321 | list *exps = new_exp_list(sql->sa); |
| 1322 | if(!rel || !exps) |
| 1323 | return NULL; |
| 1324 | |
| 1325 | append(exps, exp_atom_str(sql->sa, sname, sql_bind_localtype("str" ) )); |
| 1326 | append(exps, exp_atom_str(sql->sa, tname, sql_bind_localtype("str" ) )); |
| 1327 | append(exps, exp_atom_int(sql->sa, if_exists)); |
| 1328 | rel->l = NULL; |
| 1329 | rel->r = NULL; |
| 1330 | rel->op = op_ddl; |
| 1331 | rel->flag = ddl_drop_trigger; |
| 1332 | rel->exps = exps; |
| 1333 | rel->card = CARD_MULTI; |
| 1334 | rel->nrcols = 0; |
| 1335 | return rel; |
| 1336 | } |
| 1337 | |
| 1338 | static sql_rel * |
| 1339 | drop_trigger(mvc *sql, dlist *qname, int if_exists) |
| 1340 | { |
| 1341 | const char *sname = qname_schema(qname); |
| 1342 | const char *tname = qname_table(qname); |
| 1343 | sql_schema *ss = cur_schema(sql); |
| 1344 | |
| 1345 | if (!sname) |
| 1346 | sname = ss->base.name; |
| 1347 | |
| 1348 | if (sname && !(ss = mvc_bind_schema(sql, sname))) |
| 1349 | return sql_error(sql, 02, SQLSTATE(3F000) "DROP TRIGGER: no such schema '%s'" , sname); |
| 1350 | |
| 1351 | if (!mvc_schema_privs(sql, ss)) |
| 1352 | return sql_error(sql, 02, SQLSTATE(3F000) "DROP TRIGGER: access denied for %s to schema '%s'" , stack_get_string(sql, "current_user" ), ss->base.name); |
| 1353 | return rel_drop_trigger(sql, ss->base.name, tname, if_exists); |
| 1354 | } |
| 1355 | |
| 1356 | static sql_rel * |
| 1357 | psm_analyze(sql_query *query, char *analyzeType, dlist *qname, dlist *columns, symbol *sample, int minmax ) |
| 1358 | { |
| 1359 | mvc *sql = query->sql; |
| 1360 | exp_kind ek = {type_value, card_value, FALSE}; |
| 1361 | sql_exp *sample_exp = NULL, *call, *mm_exp = NULL; |
| 1362 | const char *sname = NULL, *tname = NULL; |
| 1363 | list *tl = sa_list(sql->sa); |
| 1364 | list *exps = sa_list(sql->sa), *analyze_calls = sa_list(sql->sa); |
| 1365 | sql_subfunc *f = NULL; |
| 1366 | |
| 1367 | append(exps, mm_exp = exp_atom_int(sql->sa, minmax)); |
| 1368 | append(tl, exp_subtype(mm_exp)); |
| 1369 | if (sample) { |
| 1370 | sql_subtype *tpe = sql_bind_localtype("lng" ); |
| 1371 | dlist* sample_parameters = sample->data.lval; |
| 1372 | |
| 1373 | if (sample_parameters->cnt == 1 && (sample_exp = rel_value_exp(query, NULL, sample_parameters->h->data.sym, 0, ek))) |
| 1374 | sample_exp = rel_check_type(sql, tpe, NULL, sample_exp, type_cast); |
| 1375 | else |
| 1376 | return sql_error(sql, 01, SQLSTATE(42000) "Analyze sample size incorrect" ); |
| 1377 | } else { |
| 1378 | sample_exp = exp_atom_lng(sql->sa, 0); |
| 1379 | } |
| 1380 | append(exps, sample_exp); |
| 1381 | append(tl, exp_subtype(sample_exp)); |
| 1382 | |
| 1383 | assert(qname); |
| 1384 | if (qname) { |
| 1385 | if (qname->h->next) |
| 1386 | sname = qname_schema(qname); |
| 1387 | else |
| 1388 | sname = qname_table(qname); |
| 1389 | if (!sname) |
| 1390 | sname = cur_schema(sql)->base.name; |
| 1391 | if (qname->h->next) |
| 1392 | tname = qname_table(qname); |
| 1393 | } |
| 1394 | /* call analyze( [schema, [ table ]], opt_sample_size, opt_minmax ) */ |
| 1395 | if (sname) { |
| 1396 | sql_exp *sname_exp = exp_atom_clob(sql->sa, sname); |
| 1397 | |
| 1398 | append(exps, sname_exp); |
| 1399 | append(tl, exp_subtype(sname_exp)); |
| 1400 | } |
| 1401 | if (tname) { |
| 1402 | sql_exp *tname_exp = exp_atom_clob(sql->sa, tname); |
| 1403 | |
| 1404 | append(exps, tname_exp); |
| 1405 | append(tl, exp_subtype(tname_exp)); |
| 1406 | |
| 1407 | if (columns) |
| 1408 | append(tl, exp_subtype(tname_exp)); |
| 1409 | } |
| 1410 | if (!columns) { |
| 1411 | f = sql_bind_func_(sql->sa, mvc_bind_schema(sql, "sys" ), analyzeType, tl, F_PROC); |
| 1412 | if (!f) |
| 1413 | return sql_error(sql, 01, SQLSTATE(42000) "Analyze procedure missing" ); |
| 1414 | call = exp_op(sql->sa, exps, f); |
| 1415 | append(analyze_calls, call); |
| 1416 | } else { |
| 1417 | dnode *n; |
| 1418 | |
| 1419 | if (!sname || !tname) |
| 1420 | return sql_error(sql, 01, SQLSTATE(42000) "Analyze schema or table name missing" ); |
| 1421 | f = sql_bind_func_(sql->sa, mvc_bind_schema(sql, "sys" ), analyzeType, tl, F_PROC); |
| 1422 | if (!f) |
| 1423 | return sql_error(sql, 01, SQLSTATE(42000) "Analyze procedure missing" ); |
| 1424 | for( n = columns->h; n; n = n->next) { |
| 1425 | const char *cname = n->data.sval; |
| 1426 | list *nexps = list_dup(exps, NULL); |
| 1427 | sql_exp *cname_exp = exp_atom_clob(sql->sa, cname); |
| 1428 | |
| 1429 | append(nexps, cname_exp); |
| 1430 | /* call analyze( opt_minmax, opt_sample_size, sname, tname, cname) */ |
| 1431 | call = exp_op(sql->sa, nexps, f); |
| 1432 | append(analyze_calls, call); |
| 1433 | } |
| 1434 | } |
| 1435 | return rel_psm_block(sql->sa, analyze_calls); |
| 1436 | } |
| 1437 | |
| 1438 | static sql_rel* |
| 1439 | create_table_from_loader(sql_query *query, dlist *qname, symbol *fcall) |
| 1440 | { |
| 1441 | mvc *sql = query->sql; |
| 1442 | sql_schema *s = NULL; |
| 1443 | char *sname = qname_schema(qname); |
| 1444 | char *tname = qname_table(qname); |
| 1445 | sql_subfunc *loader = NULL; |
| 1446 | sql_rel* rel = NULL; |
| 1447 | |
| 1448 | if (sname && !(s = mvc_bind_schema(sql, sname))) |
| 1449 | return sql_error(sql, 02, SQLSTATE(3F000) "CREATE TABLE: no such schema '%s'" , sname); |
| 1450 | |
| 1451 | if (mvc_bind_table(sql, s, tname)) { |
| 1452 | return sql_error(sql, 02, SQLSTATE(42S01) "CREATE TABLE: name '%s' already in use" , tname); |
| 1453 | } else if (!mvc_schema_privs(sql, s)){ |
| 1454 | return sql_error(sql, 02, SQLSTATE(42000) "CREATE TABLE: insufficient privileges for user '%s' in schema '%s'" , stack_get_string(sql, "current_user" ), s->base.name); |
| 1455 | } |
| 1456 | |
| 1457 | rel = rel_loader_function(query, fcall, new_exp_list(sql->sa), &loader); |
| 1458 | if (!rel || !loader) { |
| 1459 | return NULL; |
| 1460 | } |
| 1461 | loader->sname = sname ? sa_zalloc(sql->sa, strlen(sname) + 1) : NULL; |
| 1462 | loader->tname = tname ? sa_zalloc(sql->sa, strlen(tname) + 1) : NULL; |
| 1463 | |
| 1464 | if (sname) strcpy(loader->sname, sname); |
| 1465 | if (tname) strcpy(loader->tname, tname); |
| 1466 | |
| 1467 | return rel; |
| 1468 | } |
| 1469 | |
| 1470 | sql_rel * |
| 1471 | rel_psm(sql_query *query, symbol *s) |
| 1472 | { |
| 1473 | mvc *sql = query->sql; |
| 1474 | sql_rel *ret = NULL; |
| 1475 | |
| 1476 | switch (s->token) { |
| 1477 | case SQL_CREATE_FUNC: |
| 1478 | { |
| 1479 | dlist *l = s->data.lval; |
| 1480 | sql_ftype type = (sql_ftype) l->h->next->next->next->next->next->data.i_val; |
| 1481 | sql_flang lang = (sql_flang) l->h->next->next->next->next->next->next->data.i_val; |
| 1482 | int repl = l->h->next->next->next->next->next->next->next->data.i_val; |
| 1483 | |
| 1484 | ret = rel_create_func(query, l->h->data.lval, l->h->next->data.lval, l->h->next->next->data.sym, l->h->next->next->next->data.lval, l->h->next->next->next->next->data.lval, type, lang, repl); |
| 1485 | sql->type = Q_SCHEMA; |
| 1486 | } break; |
| 1487 | case SQL_DROP_FUNC: |
| 1488 | { |
| 1489 | dlist *l = s->data.lval; |
| 1490 | dlist *qname = l->h->data.lval; |
| 1491 | dlist *typelist = l->h->next->data.lval; |
| 1492 | sql_ftype type = (sql_ftype) l->h->next->next->data.i_val; |
| 1493 | int if_exists = l->h->next->next->next->data.i_val; |
| 1494 | int all = l->h->next->next->next->next->data.i_val; |
| 1495 | int drop_action = l->h->next->next->next->next->next->data.i_val; |
| 1496 | |
| 1497 | if (STORE_READONLY) |
| 1498 | return sql_error(sql, 06, SQLSTATE(42000) "Schema statements cannot be executed on a readonly database." ); |
| 1499 | |
| 1500 | if (all) |
| 1501 | ret = rel_drop_all_func(sql, qname, drop_action, type); |
| 1502 | else { |
| 1503 | ret = rel_drop_func(sql, qname, typelist, drop_action, type, if_exists); |
| 1504 | } |
| 1505 | |
| 1506 | sql->type = Q_SCHEMA; |
| 1507 | } break; |
| 1508 | case SQL_SET: |
| 1509 | ret = rel_psm_stmt(sql->sa, psm_set_exp(query, s->data.lval->h)); |
| 1510 | sql->type = Q_SCHEMA; |
| 1511 | break; |
| 1512 | case SQL_DECLARE: |
| 1513 | ret = rel_psm_block(sql->sa, rel_psm_declare(sql, s->data.lval->h)); |
| 1514 | sql->type = Q_SCHEMA; |
| 1515 | break; |
| 1516 | case SQL_CALL: |
| 1517 | ret = rel_psm_stmt(sql->sa, rel_psm_call(query, s->data.sym)); |
| 1518 | sql->type = Q_UPDATE; |
| 1519 | break; |
| 1520 | case SQL_CREATE_TABLE_LOADER: |
| 1521 | { |
| 1522 | dlist *l = s->data.lval; |
| 1523 | dlist *qname = l->h->data.lval; |
| 1524 | symbol *sym = l->h->next->data.sym; |
| 1525 | |
| 1526 | ret = create_table_from_loader(query, qname, sym); |
| 1527 | if (ret == NULL) |
| 1528 | return NULL; |
| 1529 | ret = rel_psm_stmt(sql->sa, exp_rel(sql, ret)); |
| 1530 | sql->type = Q_SCHEMA; |
| 1531 | } break; |
| 1532 | case SQL_CREATE_TRIGGER: |
| 1533 | { |
| 1534 | dlist *l = s->data.lval; |
| 1535 | |
| 1536 | assert(l->h->next->type == type_int); |
| 1537 | ret = create_trigger(query, l->h->data.lval, l->h->next->data.i_val, l->h->next->next->data.sym, l->h->next->next->next->data.lval, l->h->next->next->next->next->data.lval, l->h->next->next->next->next->next->data.lval, l->h->next->next->next->next->next->next->data.i_val); |
| 1538 | sql->type = Q_SCHEMA; |
| 1539 | } |
| 1540 | break; |
| 1541 | |
| 1542 | case SQL_DROP_TRIGGER: |
| 1543 | { |
| 1544 | dlist *l = s->data.lval; |
| 1545 | dlist *qname = l->h->data.lval; |
| 1546 | int if_exists = l->h->next->data.i_val; |
| 1547 | |
| 1548 | ret = drop_trigger(sql, qname, if_exists); |
| 1549 | sql->type = Q_SCHEMA; |
| 1550 | } |
| 1551 | break; |
| 1552 | |
| 1553 | case SQL_ANALYZE: { |
| 1554 | dlist *l = s->data.lval; |
| 1555 | |
| 1556 | ret = psm_analyze(query, "analyze" , l->h->data.lval /* qualified table name */, l->h->next->data.lval /* opt list of column */, l->h->next->next->data.sym /* opt_sample_size */, l->h->next->next->next->data.i_val); |
| 1557 | sql->type = Q_UPDATE; |
| 1558 | } break; |
| 1559 | default: |
| 1560 | return sql_error(sql, 01, SQLSTATE(42000) "Schema statement unknown symbol(%p)->token = %s" , s, token2string(s->token)); |
| 1561 | } |
| 1562 | return ret; |
| 1563 | } |
| 1564 | |