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 | |