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); }
char * sql_revoke_table_privs( mvc *sql, char *grantee, int privs, char *sname, char *tname, char *cname, int grant, int grantor) { sql_schema *s = NULL; sql_table *t = NULL; sql_column *c = NULL; int allowed, grantee_id; int all = PRIV_SELECT | PRIV_UPDATE | PRIV_INSERT | PRIV_DELETE; if (sname) s = mvc_bind_schema(sql, sname); if (s) t = mvc_bind_table(sql, s, tname); if (!t) return sql_message("42S02!REVOKE: no such table '%s'", tname); allowed = schema_privs(grantor, t->s); if (!allowed) allowed = sql_grantable(sql, grantor, t->base.id, all, 0); if (!allowed) return sql_message("0L000!REVOKE: grantor '%s' is not allowed to revoke privileges for table '%s'", stack_get_string(sql,"current_user"), tname); if (cname) { c = mvc_bind_column(sql, t, cname); if (!c) return sql_message("42S22!REVOKE: table %s has no column %s", tname, cname); /* allowed on column */ if (!allowed) allowed = sql_grantable(sql, grantor, c->base.id, privs, 0); if (!allowed) return sql_message("0L000!REVOKE: grantor %s is not allowed to revoke privilege %s for table %s", stack_get_string(sql, "current_user"), priv2string(privs), tname); } grantee_id = sql_find_auth(sql, grantee); if (grantee_id <= 0) return sql_message("42M32!REVOKE: user/role '%s' unknown", grantee); if (privs == all) { sql_delete_priv(sql, grantee_id, t->base.id, PRIV_SELECT, grantor, grant); sql_delete_priv(sql, grantee_id, t->base.id, PRIV_UPDATE, grantor, grant); sql_delete_priv(sql, grantee_id, t->base.id, PRIV_INSERT, grantor, grant); sql_delete_priv(sql, grantee_id, t->base.id, PRIV_DELETE, grantor, grant); } else if (!c) sql_insert_priv(sql, grantee_id, t->base.id, privs, grantor, grant); else sql_insert_priv(sql, grantee_id, c->base.id, privs, grantor, grant); return NULL; }
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 * 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; }