static int keyword_or_ident(mvc * c, int cur) { struct scanner *lc = &c->scanner; keyword *k = NULL; int s; lc->started = 1; utf8_putchar(lc, cur); s = lc->yycur; lc->yyval = IDENT; while ((cur = scanner_getc(lc)) != EOF) { if (!iswalnum(cur) && cur != '_') { utf8_putchar(lc, cur); (void)scanner_token(lc, IDENT); k = find_keyword_bs(lc,s); if (k) lc->yyval = k->token; /* find keyword in SELECT/JOIN/UNION FUNCTIONS */ else if (sql_find_func(c->sa, cur_schema(c), lc->rs->buf+lc->rs->pos+s, -1, F_FILT, NULL)) lc->yyval = FILTER_FUNC; return lc->yyval; } } (void)scanner_token(lc, IDENT); k = find_keyword_bs(lc,s); if (k) lc->yyval = k->token; /* find keyword in SELECT/JOIN/UNION FUNCTIONS */ else if (sql_find_func(c->sa, cur_schema(c), lc->rs->buf+lc->rs->pos+s, -1, F_FILT, NULL)) lc->yyval = FILTER_FUNC; return lc->yyval; }
static sql_rel* rel_drop_all_func(mvc *sql, dlist *qname, int drop_action, int type) { char *name = qname_table(qname); char *sname = qname_schema(qname); sql_schema *s = NULL; list * list_func = NULL; char is_aggr = (type == F_AGGR); char is_func = (type != F_PROC); char *F = is_aggr?"AGGREGATE":(is_func?"FUNCTION":"PROCEDURE"); char *f = is_aggr?"aggregate":(is_func?"function":"procedure"); char *KF = type==F_FILT?"FILTER ": type==F_UNION?"UNION ": ""; char *kf = type==F_FILT?"filter ": type==F_UNION?"union ": ""; if (sname && !(s = mvc_bind_schema(sql, sname))) return sql_error(sql, 02, "3F000!DROP %s%s: no such schema '%s'", KF, F, sname); if (s == NULL) s = cur_schema(sql); list_func = schema_bind_func(sql, s, name, type); if (!list_func) return sql_error(sql, 02, "DROP ALL %s%s: no such %s%s '%s'", KF, F, kf, f, name); list_destroy(list_func); return rel_drop_function(sql->sa, s->base.name, name, -1, type, drop_action); }
static sql_exp * rel_psm_declare_table(mvc *sql, dnode *n) { sql_rel *rel = NULL, *baset = NULL; dlist *qname = n->next->data.lval; const char *name = qname_table(qname); const char *sname = qname_schema(qname); sql_table *t; if (sname) /* not allowed here */ return sql_error(sql, 02, SQLSTATE(42000) "DECLARE TABLE: qualified name not allowed"); if (frame_find_var(sql, name)) return sql_error(sql, 01, SQLSTATE(42000) "Variable '%s' already declared", name); assert(n->next->next->next->type == type_int); rel = rel_create_table(sql, cur_schema(sql), SQL_DECLARED_TABLE, NULL, name, n->next->next->data.sym, n->next->next->next->data.i_val, NULL, NULL, NULL, false, NULL, 0); if (!rel) return NULL; if(rel->op == op_ddl) { baset = rel; } else if(rel->op == op_insert) { baset = rel->l; } else { return NULL; } if(baset->flag != DDL_CREATE_TABLE) return NULL; t = (sql_table*)((atom*)((sql_exp*)baset->exps->t->data)->l)->data.val.pval; if(!stack_push_table(sql, name, baset, t)) return sql_error(sql, 02, SQLSTATE(HY001) MAL_MALLOC_FAIL); return exp_table(sql->sa, sa_strdup(sql->sa, name), t, sql->frame); }
static sql_exp * rel_psm_declare_table(mvc *sql, dnode *n) { sql_rel *rel = NULL; dlist *qname = n->next->data.lval; char *name = qname_table(qname); char *sname = qname_schema(qname); sql_table *t; if (sname) /* not allowed here */ return sql_error(sql, 02, "DECLARE TABLE: qualified name not allowed"); if (frame_find_var(sql, name)) return sql_error(sql, 01, "Variable '%s' already declared", name); assert(n->next->next->next->type == type_int); rel = rel_create_table(sql, cur_schema(sql), SQL_DECLARED_TABLE, NULL, name, n->next->next->data.sym, n->next->next->next->data.i_val, NULL); if (!rel || rel->op != op_ddl || rel->flag != DDL_CREATE_TABLE) return NULL; t = (sql_table*)((atom*)((sql_exp*)rel->exps->t->data)->l)->data.val.pval; stack_push_table(sql, name, rel, t); return exp_table(sql->sa, sa_strdup(sql->sa, name), t, sql->frame); }
static sql_rel* rel_drop_func(mvc *sql, dlist *qname, dlist *typelist, int drop_action, int type, int if_exists) { const char *name = qname_table(qname); const char *sname = qname_schema(qname); sql_schema *s = NULL; sql_func *func = NULL; char is_aggr = (type == F_AGGR); char is_func = (type != F_PROC); char *F = is_aggr?"AGGREGATE":(is_func?"FUNCTION":"PROCEDURE"); char *KF = type==F_FILT?"FILTER ": type==F_UNION?"UNION ": ""; if (sname && !(s = mvc_bind_schema(sql, sname))) return sql_error(sql, 02, SQLSTATE(3F000) "DROP %s%s: no such schema '%s'", KF, F, sname); if (s == NULL) s = cur_schema(sql); func = resolve_func(sql, s, name, typelist, type, "DROP", if_exists); if (!func && !sname) { s = tmp_schema(sql); func = resolve_func(sql, s, name, typelist, type, "DROP", if_exists); } if (func) return rel_drop_function(sql->sa, s->base.name, name, func->base.id, type, drop_action); else if(if_exists && !sql->session->status) return rel_drop_function(sql->sa, s->base.name, name, -2, type, drop_action); return NULL; }
static sql_rel * drop_trigger(mvc *sql, dlist *qname) { char *tname = qname_table(qname); sql_schema *ss = cur_schema(sql); if (!schema_privs(sql->role_id, ss)) return sql_error(sql, 02, "DROP TRIGGER: access denied for %s to schema ;'%s'", stack_get_string(sql, "current_user"), ss->base.name); return rel_drop_trigger(sql, ss->base.name, tname); }
static sql_rel * drop_trigger(mvc *sql, dlist *qname, int if_exists) { const char *sname = qname_schema(qname); const char *tname = qname_table(qname); sql_schema *ss = cur_schema(sql); if (!sname) sname = ss->base.name; if (sname && !(ss = mvc_bind_schema(sql, sname))) return sql_error(sql, 02, SQLSTATE(3F000) "DROP TRIGGER: no such schema '%s'", sname); if (!mvc_schema_privs(sql, ss)) 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); return rel_drop_trigger(sql, ss->base.name, tname, if_exists); }
static sql_rel* rel_drop_func(mvc *sql, dlist *qname, dlist *typelist, int drop_action, int type) { char *name = qname_table(qname); char *sname = qname_schema(qname); sql_schema *s = NULL; list * list_func = NULL, *type_list = NULL; sql_subfunc *sub_func = NULL; sql_func *func = NULL; char is_aggr = (type == F_AGGR); char is_func = (type != F_PROC); char *F = is_aggr?"AGGREGATE":(is_func?"FUNCTION":"PROCEDURE"); char *f = is_aggr?"aggregate":(is_func?"function":"procedure"); char *KF = type==F_FILT?"FILTER ": type==F_UNION?"UNION ": ""; char *kf = type==F_FILT?"filter ": type==F_UNION?"union ": ""; if (sname && !(s = mvc_bind_schema(sql, sname))) return sql_error(sql, 02, "3F000!DROP %s%s: no such schema '%s'", KF, F, sname); if (s == NULL) s = cur_schema(sql); if (typelist) { type_list = create_type_list(sql, typelist, 0); sub_func = sql_bind_func_(sql->sa, s, name, type_list, type); if (!sub_func && type == F_FUNC) { sub_func = sql_bind_func_(sql->sa, s, name, type_list, F_UNION); type = sub_func?F_UNION:F_FUNC; } if (!sub_func && !sname) { s = tmp_schema(sql); sub_func = sql_bind_func_(sql->sa, s, name, type_list, type); if (!sub_func && type == F_FUNC) { sub_func = sql_bind_func_(sql->sa, s, name, type_list, F_UNION); type = sub_func?F_UNION:F_FUNC; } } if ( sub_func && sub_func->func->type == type) func = sub_func->func; } else { list_func = schema_bind_func(sql,s,name, type); if (!list_func && type == F_FUNC) list_func = schema_bind_func(sql,s,name, F_UNION); if (list_func && list_func->cnt > 1) { list_destroy(list_func); return sql_error(sql, 02, "DROP %s%s: there are more than one %s%s called '%s', please use the full signature", KF, F, kf, f,name); } if (list_func && list_func->cnt == 1) func = (sql_func*) list_func->h->data; } if (!func) { if (typelist) { char *arg_list = NULL; node *n; if (type_list->cnt > 0) { for (n = type_list->h; n; n = n->next) { char *tpe = subtype2string((sql_subtype *) n->data); if (arg_list) { arg_list = sql_message("%s, %s", arg_list, tpe); _DELETE(tpe); } else { arg_list = tpe; } } list_destroy(list_func); list_destroy(type_list); return sql_error(sql, 02, "DROP %s%s: no such %s%s '%s' (%s)", KF, F, kf, f, name, arg_list); } list_destroy(list_func); list_destroy(type_list); return sql_error(sql, 02, "DROP %s%s: no such %s%s '%s' ()", KF, F, kf, f, name); } else { return sql_error(sql, 02, "DROP %s%s: no such %s%s '%s'", KF, F, kf, f, name); } } else if (((is_func && type != F_FILT) && !func->res) || (!is_func && func->res)) { list_destroy(list_func); list_destroy(type_list); return sql_error(sql, 02, "DROP %s%s: cannot drop %s '%s'", KF, F, is_func?"procedure":"function", name); } list_destroy(list_func); list_destroy(type_list); return rel_drop_function(sql->sa, s->base.name, name, func->base.id, type, drop_action); }
static sql_rel * rel_create_func(mvc *sql, dlist *qname, dlist *params, symbol *res, dlist *ext_name, dlist *body, int type, int lang) { char *fname = qname_table(qname); char *sname = qname_schema(qname); sql_schema *s = NULL; sql_func *f = NULL; sql_subfunc *sf; dnode *n; list *type_list = NULL, *restype = NULL; int instantiate = (sql->emode == m_instantiate); int deps = (sql->emode == m_deps); int create = (!instantiate && !deps); bit vararg = FALSE; char is_table = (res && res->token == SQL_TABLE); char is_aggr = (type == F_AGGR); char is_func = (type != F_PROC); char *F = is_aggr?"AGGREGATE":(is_func?"FUNCTION":"PROCEDURE"); char *KF = type==F_FILT?"FILTER ": type==F_UNION?"UNION ": ""; assert(res || type == F_PROC || type == F_FILT); if (is_table) type = F_UNION; if (STORE_READONLY && create) return sql_error(sql, 06, "schema statements cannot be executed on a readonly database."); if (sname && !(s = mvc_bind_schema(sql, sname))) return sql_error(sql, 02, "3F000!CREATE %s%s: no such schema '%s'", KF, F, sname); if (s == NULL) s = cur_schema(sql); type_list = create_type_list(sql, params, 1); if ((sf = sql_bind_func_(sql->sa, s, fname, type_list, type)) != NULL && create) { if (params) { char *arg_list = NULL; node *n; for (n = type_list->h; n; n = n->next) { char *tpe = subtype2string((sql_subtype *) n->data); if (arg_list) { arg_list = sql_message("%s, %s", arg_list, tpe); _DELETE(tpe); } else { arg_list = tpe; } } (void)sql_error(sql, 02, "CREATE %s%s: name '%s' (%s) already in use", KF, F, fname, arg_list); _DELETE(arg_list); list_destroy(type_list); return NULL; } else { list_destroy(type_list); return sql_error(sql, 02, "CREATE %s%s: name '%s' already in use", KF, F, fname); } } else { list_destroy(type_list); if (create && !schema_privs(sql->role_id, s)) { return sql_error(sql, 02, "CREATE %s%s: insufficient privileges " "for user '%s' in schema '%s'", KF, F, stack_get_string(sql, "current_user"), s->base.name); } else { char *q = QUERY(sql->scanner); list *l = NULL; if (params) { for (n = params->h; n; n = n->next) { dnode *an = n->data.lval->h; sql_add_param(sql, an->data.sval, &an->next->data.typeval); } l = sql->params; if (l && list_length(l) == 1) { sql_arg *a = l->h->data; if (strcmp(a->name, "*") == 0) { l = NULL; vararg = TRUE; } } } if (!l) l = sa_list(sql->sa); if (res) { restype = result_type(sql, res); if (!restype) return sql_error(sql, 01, "CREATE %s%s: failed to get restype", KF, F); } if (body && lang > FUNC_LANG_SQL) { char *lang_body = body->h->data.sval; char *mod = (lang == FUNC_LANG_R)?"rapi": (lang == FUNC_LANG_C)?"capi": (lang == FUNC_LANG_J)?"japi":"unknown"; sql->params = NULL; if (create) { f = mvc_create_func(sql, sql->sa, s, fname, l, restype, type, lang, mod, fname, lang_body, FALSE, vararg); } else if (!sf) { return sql_error(sql, 01, "CREATE %s%s: R function %s.%s not bound", KF, F, s->base.name, fname ); } else { sql_func *f = sf->func; f->mod = _STRDUP("rapi"); f->imp = _STRDUP("eval"); if (res && restype) f->res = restype; f->sql = 0; /* native */ f->lang = FUNC_LANG_INT; } } else if (body) { sql_arg *ra = (restype && !is_table)?restype->h->data:NULL; list *b = NULL; sql_schema *old_schema = cur_schema(sql); sql->session->schema = s; b = sequential_block(sql, (ra)?&ra->type:NULL, ra?NULL:restype, body, NULL, is_func); sql->session->schema = old_schema; sql->params = NULL; if (!b) return NULL; /* check if we have a return statement */ if (is_func && restype && !has_return(b)) { return sql_error(sql, 01, "CREATE %s%s: missing return statement", KF, F); } if (!is_func && !restype && has_return(b)) { return sql_error(sql, 01, "CREATE %s%s: procedures " "cannot have return statements", KF, F); } /* in execute mode we instantiate the function */ if (instantiate || deps) { return rel_psm_block(sql->sa, b); } else if (create) { f = mvc_create_func(sql, sql->sa, s, fname, l, restype, type, lang, "user", q, q, FALSE, vararg); } } else { char *fmod = qname_module(ext_name); char *fnme = qname_fname(ext_name); if (!fmod || !fnme) return NULL; sql->params = NULL; if (create) { f = mvc_create_func(sql, sql->sa, s, fname, l, restype, type, lang, fmod, fnme, q, FALSE, vararg); } else if (!sf) { return sql_error(sql, 01, "CREATE %s%s: external name %s.%s not bound (%s,%s)", KF, F, fmod, fnme, s->base.name, fname ); } else { sql_func *f = sf->func; f->mod = _STRDUP(fmod); f->imp = _STRDUP(fnme); f->sql = 0; /* native */ f->lang = FUNC_LANG_INT; } } } } return rel_create_function(sql->sa, s->base.name, f); }
static sql_rel * psm_analyze(mvc *sql, dlist *qname, dlist *columns, symbol *sample ) { exp_kind ek = {type_value, card_value, FALSE}; sql_exp *sample_exp = NULL, *call; char *sname = NULL, *tname = NULL; list *tl = sa_list(sql->sa); list *exps = sa_list(sql->sa), *analyze_calls = sa_list(sql->sa); sql_subfunc *f = NULL; if (sample) { sql_subtype *tpe = sql_bind_localtype("lng"); sample_exp = rel_value_exp( sql, NULL, sample, 0, ek); if (sample_exp) sample_exp = rel_check_type(sql, tpe, sample_exp, type_cast); } if (qname) { if (qname->h->next) sname = qname_schema(qname); else sname = qname_table(qname); if (!sname) sname = cur_schema(sql)->base.name; if (qname->h->next) tname = qname_table(qname); } /* call analyze( [schema, [ table ]], opt_sample_size ) */ if (sname) { sql_exp *sname_exp = exp_atom_clob(sql->sa, sname); append(exps, sname_exp); append(tl, exp_subtype(sname_exp)); } if (tname) { sql_exp *tname_exp = exp_atom_clob(sql->sa, tname); append(exps, tname_exp); append(tl, exp_subtype(tname_exp)); if (columns) append(tl, exp_subtype(tname_exp)); } if (!columns) { if (sample_exp) { append(exps, sample_exp); append(tl, exp_subtype(sample_exp)); } f = sql_bind_func_(sql->sa, mvc_bind_schema(sql, "sys"), "analyze", tl, F_PROC); if (!f) return sql_error(sql, 01, "Analyze procedure missing"); call = exp_op(sql->sa, exps, f); append(analyze_calls, call); } else { dnode *n; if (sample_exp) append(tl, exp_subtype(sample_exp)); f = sql_bind_func_(sql->sa, mvc_bind_schema(sql, "sys"), "analyze", tl, F_PROC); if (!f) return sql_error(sql, 01, "Analyze procedure missing"); for( n = columns->h; n; n = n->next) { char *cname = n->data.sval; list *nexps = list_dup(exps, NULL); sql_exp *cname_exp = exp_atom_clob(sql->sa, cname); append(nexps, cname_exp); if (sample_exp) append(nexps, sample_exp); /* call analyze( sname, tname, cname, opt_sample_size ) */ call = exp_op(sql->sa, nexps, f); append(analyze_calls, call); } } return rel_psm_block(sql->sa, analyze_calls); }
static sql_rel * create_trigger(mvc *sql, dlist *qname, int time, symbol *trigger_event, char *table_name, dlist *opt_ref, dlist *triggered_action) { char *tname = qname_table(qname); sql_schema *ss = cur_schema(sql); sql_table *t = NULL; int instantiate = (sql->emode == m_instantiate); int create = (!instantiate && sql->emode != m_deps); list *sq = NULL; sql_rel *r = NULL; dlist *columns = trigger_event->data.lval; char *old_name = NULL, *new_name = NULL; dlist *stmts = triggered_action->h->next->next->data.lval; if (opt_ref) { dnode *dl = opt_ref->h; for ( ; dl; dl = dl->next) { /* list (new(1)/old(0)), char */ char *n = dl->data.lval->h->next->data.sval; assert(dl->data.lval->h->type == type_int); if (!dl->data.lval->h->data.i_val) /*?l_val?*/ old_name = n; else new_name = n; } } if (create && !schema_privs(sql->role_id, ss)) return sql_error(sql, 02, "CREATE TRIGGER: access denied for %s to schema ;'%s'", stack_get_string(sql, "current_user"), ss->base.name); if (create && mvc_bind_trigger(sql, ss, tname) != NULL) return sql_error(sql, 02, "CREATE TRIGGER: name '%s' already in use", tname); if (create && !(t = mvc_bind_table(sql, ss, table_name))) return sql_error(sql, 02, "CREATE TRIGGER: unknown table '%s'", table_name); if (create && isView(t)) return sql_error(sql, 02, "CREATE TRIGGER: cannot create trigger on view '%s'", table_name); if (create) { int event = (trigger_event->token == SQL_INSERT)?0: (trigger_event->token == SQL_DELETE)?1:2; int orientation = triggered_action->h->data.i_val; char *condition = triggered_action->h->next->data.sval; char *q = QUERY(sql->scanner); assert(triggered_action->h->type == type_int); return rel_create_trigger(sql, t->s->base.name, t->base.name, tname, time, orientation, event, old_name, new_name, condition, q); } t = mvc_bind_table(sql, ss, table_name); stack_push_frame(sql, "OLD-NEW"); /* we need to add the old and new tables */ if (new_name) _stack_push_table(sql, new_name, t); if (old_name) _stack_push_table(sql, old_name, t); sq = sequential_block(sql, NULL, NULL, stmts, NULL, 1); r = rel_psm_block(sql->sa, sq); /* todo trigger_columns */ (void)columns; return r; }
static sql_rel * rel_create_func(mvc *sql, dlist *qname, dlist *params, symbol *res, dlist *ext_name, dlist *body, int type, int lang, int replace) { const char *fname = qname_table(qname); const char *sname = qname_schema(qname); sql_schema *s = NULL; sql_func *f = NULL; sql_subfunc *sf; dnode *n; list *type_list = NULL, *restype = NULL; int instantiate = (sql->emode == m_instantiate); int deps = (sql->emode == m_deps); int create = (!instantiate && !deps); bit vararg = FALSE; char is_table = (res && res->token == SQL_TABLE); char is_aggr = (type == F_AGGR); char is_func = (type != F_PROC); char is_loader = (type == F_LOADER); char *F = is_loader?"LOADER":(is_aggr?"AGGREGATE":(is_func?"FUNCTION":"PROCEDURE")); char *fn = is_loader?"loader":(is_aggr ? "aggregate" : (is_func ? "function" : "procedure")); char *KF = type==F_FILT?"FILTER ": type==F_UNION?"UNION ": ""; char *kf = type == F_FILT ? "filter " : type == F_UNION ? "union " : ""; assert(res || type == F_PROC || type == F_FILT || type == F_LOADER); if (is_table) type = F_UNION; if (STORE_READONLY && create) return sql_error(sql, 06, SQLSTATE(42000) "Schema statements cannot be executed on a readonly database."); if (sname && !(s = mvc_bind_schema(sql, sname))) return sql_error(sql, 02, SQLSTATE(3F000) "CREATE %s%s: no such schema '%s'", KF, F, sname); if (s == NULL) s = cur_schema(sql); type_list = create_type_list(sql, params, 1); if ((sf = sql_bind_func_(sql->sa, s, fname, type_list, type)) != NULL && create) { if (replace) { sql_func *func = sf->func; int action = 0; if (!mvc_schema_privs(sql, s)) { 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); } if (mvc_check_dependency(sql, func->base.id, !IS_PROC(func) ? FUNC_DEPENDENCY : PROC_DEPENDENCY, NULL)) 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); if (!func->s) { 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); } if(mvc_drop_func(sql, s, func, action)) return sql_error(sql, 02, SQLSTATE(HY001) MAL_MALLOC_FAIL); sf = NULL; } else { if (params) { char *arg_list = NULL; node *n; for (n = type_list->h; n; n = n->next) { char *tpe = subtype2string((sql_subtype *) n->data); if (arg_list) { char *t = arg_list; arg_list = sql_message("%s, %s", arg_list, tpe); _DELETE(t); _DELETE(tpe); } else { arg_list = tpe; } } (void)sql_error(sql, 02, SQLSTATE(42000) "CREATE %s%s: name '%s' (%s) already in use", KF, F, fname, arg_list); _DELETE(arg_list); list_destroy(type_list); return NULL; } else { list_destroy(type_list); return sql_error(sql, 02, SQLSTATE(42000) "CREATE %s%s: name '%s' already in use", KF, F, fname); } } } list_destroy(type_list); if (create && !mvc_schema_privs(sql, s)) { return sql_error(sql, 02, SQLSTATE(42000) "CREATE %s%s: insufficient privileges " "for user '%s' in schema '%s'", KF, F, stack_get_string(sql, "current_user"), s->base.name); } else { char *q = QUERY(sql->scanner); list *l = NULL; if (params) { for (n = params->h; n; n = n->next) { dnode *an = n->data.lval->h; sql_add_param(sql, an->data.sval, &an->next->data.typeval); } l = sql->params; if (l && list_length(l) == 1) { sql_arg *a = l->h->data; if (strcmp(a->name, "*") == 0) { l = NULL; vararg = TRUE; } } } if (!l) l = sa_list(sql->sa); if (res) { restype = result_type(sql, res); if (!restype) return sql_error(sql, 01, SQLSTATE(42000) "CREATE %s%s: failed to get restype", KF, F); } if (body && lang > FUNC_LANG_SQL) { char *lang_body = body->h->data.sval; char *mod = (lang == FUNC_LANG_R)?"rapi": (lang == FUNC_LANG_C || lang == FUNC_LANG_CPP)?"capi": (lang == FUNC_LANG_J)?"japi": (lang == FUNC_LANG_PY)?"pyapi": (lang == FUNC_LANG_MAP_PY)?"pyapimap":"unknown"; sql->params = NULL; if (create) { f = mvc_create_func(sql, sql->sa, s, fname, l, restype, type, lang, mod, fname, lang_body, (type == F_LOADER)?TRUE:FALSE, vararg, FALSE); } else if (!sf) { return sql_error(sql, 01, SQLSTATE(42000) "CREATE %s%s: R function %s.%s not bound", KF, F, s->base.name, fname ); } /*else { sql_func *f = sf->func; f->mod = _STRDUP("rapi"); f->imp = _STRDUP("eval"); if (res && restype) f->res = restype; f->sql = 0; f->lang = FUNC_LANG_INT; }*/ } else if (body) { sql_arg *ra = (restype && !is_table)?restype->h->data:NULL; list *b = NULL; sql_schema *old_schema = cur_schema(sql); if (create) { /* needed for recursive functions */ q = query_cleaned(q); sql->forward = f = mvc_create_func(sql, sql->sa, s, fname, l, restype, type, lang, "user", q, q, FALSE, vararg, FALSE); GDKfree(q); } sql->session->schema = s; b = sequential_block(sql, (ra)?&ra->type:NULL, ra?NULL:restype, body, NULL, is_func); sql->forward = NULL; sql->session->schema = old_schema; sql->params = NULL; if (!b) return NULL; /* check if we have a return statement */ if (is_func && restype && !has_return(b)) { return sql_error(sql, 01, SQLSTATE(42000) "CREATE %s%s: missing return statement", KF, F); } if (!is_func && !restype && has_return(b)) { return sql_error(sql, 01, SQLSTATE(42000) "CREATE %s%s: procedures " "cannot have return statements", KF, F); } /* in execute mode we instantiate the function */ if (instantiate || deps) { return rel_psm_block(sql->sa, b); } } else { char *fmod = qname_module(ext_name); char *fnme = qname_fname(ext_name); if (!fmod || !fnme) return NULL; sql->params = NULL; if (create) { q = query_cleaned(q); f = mvc_create_func(sql, sql->sa, s, fname, l, restype, type, lang, fmod, fnme, q, FALSE, vararg, FALSE); GDKfree(q); } else if (!sf) { 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 ); } else { sql_func *f = sf->func; if (!f->mod || strcmp(f->mod, fmod)) f->mod = _STRDUP(fmod); if (!f->imp || strcmp(f->imp, fnme)) f->imp = (f->sa)?sa_strdup(f->sa, fnme):_STRDUP(fnme); if(!f->mod || !f->imp) { _DELETE(f->mod); _DELETE(f->imp); return sql_error(sql, 02, SQLSTATE(HY001) "CREATE %s%s: could not allocate space", KF, F); } f->sql = 0; /* native */ f->lang = FUNC_LANG_INT; } } } return rel_create_function(sql->sa, s->base.name, f); }
static sql_rel * create_trigger(mvc *sql, dlist *qname, int time, symbol *trigger_event, dlist *tqname, dlist *opt_ref, dlist *triggered_action, int replace) { const char *triggerschema = qname_schema(qname); const char *triggername = qname_table(qname); const char *sname = qname_schema(tqname); const char *tname = qname_table(tqname); sql_schema *ss = cur_schema(sql); sql_table *t = NULL; sql_trigger *st = NULL; int instantiate = (sql->emode == m_instantiate); int create = (!instantiate && sql->emode != m_deps), event, orientation; list *sq = NULL; sql_rel *r = NULL; char *q, *base = replace ? "CREATE OR REPLACE" : "CREATE"; dlist *columns = trigger_event->data.lval; const char *old_name = NULL, *new_name = NULL; dlist *stmts = triggered_action->h->next->next->data.lval; symbol *condition = triggered_action->h->next->data.sym; if (!sname) sname = ss->base.name; if (sname && !(ss = mvc_bind_schema(sql, sname))) return sql_error(sql, 02, SQLSTATE(3F000) "%s TRIGGER: no such schema '%s'", base, sname); if (opt_ref) { dnode *dl = opt_ref->h; for ( ; dl; dl = dl->next) { /* list (new(1)/old(0)), char */ char *n = dl->data.lval->h->next->data.sval; assert(dl->data.lval->h->type == type_int); if (!dl->data.lval->h->data.i_val) /*?l_val?*/ old_name = n; else new_name = n; } } if (create && !mvc_schema_privs(sql, ss)) 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); if (create && !(t = mvc_bind_table(sql, ss, tname))) return sql_error(sql, 02, SQLSTATE(42000) "%s TRIGGER: unknown table '%s'", base, tname); if (create && isView(t)) return sql_error(sql, 02, SQLSTATE(42000) "%s TRIGGER: cannot create trigger on view '%s'", base, tname); if (triggerschema && strcmp(triggerschema, sname) != 0) return sql_error(sql, 02, SQLSTATE(42000) "%s TRIGGER: trigger and respective table must belong to the same schema", base); if (create && (st = mvc_bind_trigger(sql, ss, triggername)) != NULL) { if (replace) { if(mvc_drop_trigger(sql, ss, st)) return sql_error(sql, 02, SQLSTATE(HY001) "%s TRIGGER: %s", base, MAL_MALLOC_FAIL); } else { return sql_error(sql, 02, SQLSTATE(42000) "%s TRIGGER: name '%s' already in use", base, triggername); } } if (create) { switch (trigger_event->token) { case SQL_INSERT: event = 0; break; case SQL_DELETE: event = 1; break; case SQL_TRUNCATE: event = 3; break; default: event = 2; break; } orientation = triggered_action->h->data.i_val; q = query_cleaned(QUERY(sql->scanner)); assert(triggered_action->h->type == type_int); r = rel_create_trigger(sql, t->s->base.name, t->base.name, triggername, time, orientation, event, old_name, new_name, condition, q); GDKfree(q); return r; } if (!instantiate) { t = mvc_bind_table(sql, ss, tname); if(!stack_push_frame(sql, "OLD-NEW")) return sql_error(sql, 02, SQLSTATE(HY001) MAL_MALLOC_FAIL); /* we need to add the old and new tables */ if (!instantiate && new_name) { if(!_stack_push_table(sql, new_name, t)) return sql_error(sql, 02, SQLSTATE(HY001) MAL_MALLOC_FAIL); } if (!instantiate && old_name) { if(!_stack_push_table(sql, old_name, t)) return sql_error(sql, 02, SQLSTATE(HY001) MAL_MALLOC_FAIL); } } if (condition) { sql_rel *rel = NULL; if (new_name) /* in case of updates same relations is available via both names */ rel = stack_find_rel_view(sql, new_name); if (!rel && old_name) rel = stack_find_rel_view(sql, old_name); if (rel) rel = rel_logical_exp(sql, rel, condition, sql_where); if (!rel) return NULL; /* transition tables */ /* insert: rel_select(table [new], searchcondition) */ /* delete: rel_select(table [old], searchcondition) */ /* update: rel_select(table [old,new]), searchcondition) */ if (new_name) stack_update_rel_view(sql, new_name, rel); if (old_name) stack_update_rel_view(sql, old_name, new_name?rel_dup(rel):rel); } sq = sequential_block(sql, NULL, NULL, stmts, NULL, 1); r = rel_psm_block(sql->sa, sq); /* todo trigger_columns */ (void)columns; return r; }