char * sql_revoke_role(mvc *m, str grantee, str auth) /* grantee no longer belongs the role (auth) */ { oid rid; sql_schema *sys = find_sql_schema(m->session->tr, "sys"); sql_table *auths = find_sql_table(sys, "auths"); sql_table *roles = find_sql_table(sys, "user_role"); sql_column *auths_name = find_sql_column(auths, "name"); sql_column *auths_id = find_sql_column(auths, "id"); sql_column *role_id = find_sql_column(roles, "role_id"); sql_column *login_id = find_sql_column(roles, "login_id"); void *auth_id, *grantee_id; rid = table_funcs.column_find_row(m->session->tr, auths_name, grantee, NULL); if (rid == oid_nil) return sql_message("42M32!REVOKE: no such role '%s' or grantee '%s'", auth, grantee); grantee_id = table_funcs.column_find_value(m->session->tr, auths_id, rid); rid = table_funcs.column_find_row(m->session->tr, auths_name, auth, NULL); if (rid == oid_nil) { _DELETE(grantee_id); return sql_message("42M32!REVOKE: no such role '%s' or grantee '%s'", auth, grantee); } auth_id = table_funcs.column_find_value(m->session->tr, auths_id, rid); rid = table_funcs.column_find_row(m->session->tr, login_id, grantee_id, role_id, auth_id, NULL); table_funcs.table_delete(m->session->tr, roles, rid); _DELETE(grantee_id); _DELETE(auth_id); return NULL; }
str sql_update_var(mvc *m, char *name, char *sval, lng sgn) { if (strcmp(name, "debug") == 0) { assert((lng) GDK_int_min <= sgn && sgn <= (lng) GDK_int_max); m->debug = (int) sgn; } else if (strcmp(name, "current_schema") == 0) { if (!mvc_set_schema(m, sval)) { return sql_message( "Schema (%s) missing\n", sval); } } else if (strcmp(name, "current_role") == 0) { if (!mvc_set_role(m, sval)) { return sql_message( "Role (%s) missing\n", sval); } } else if (strcmp(name, "current_timezone") == 0) { assert((lng) GDK_int_min <= sgn && sgn <= (lng) GDK_int_max); m->timezone = (int) sgn; } else if (strcmp(name, "cache") == 0) { assert((lng) GDK_int_min <= sgn && sgn <= (lng) GDK_int_max); m->cache = (int) sgn; } else if (strcmp(name, "history") == 0) { assert((lng) GDK_int_min <= sgn && sgn <= (lng) GDK_int_max); m->history = (sgn != 0); } return NULL; }
char * sql_create_user(mvc *sql, char *user, char *passwd, char enc, char *fullname, char *schema) { char *err; int schema_id = 0; if (backend_find_user(sql, user) >= 0) { return sql_message("42M31!CREATE USER: user '%s' already exists", user); } if ((schema_id = sql_find_schema(sql, schema)) < 0) { return sql_message("3F000!CREATE USER: no such schema '%s'", schema); } if ((err = backend_create_user(sql, user, passwd, enc, fullname, schema_id, sql->user_id)) != NULL) { /* strip off MAL exception decorations */ char *r; char *e = err; if ((e = strchr(e, ':')) == NULL) { e = err; } else if ((e = strchr(++e, ':')) == NULL) { e = err; } else { e++; } r = sql_message("M0M27!CREATE USER: %s", e); _DELETE(err); return r; } return NULL; }
char * sql_grant_role(mvc *m, str grantee, str auth /*, grantor?, admin? */ ) { oid rid; sql_schema *sys = find_sql_schema(m->session->tr, "sys"); sql_table *auths = find_sql_table(sys, "auths"); sql_table *roles = find_sql_table(sys, "user_role"); sql_column *auths_name = find_sql_column(auths, "name"); sql_column *auths_id = find_sql_column(auths, "id"); void *auth_id, *grantee_id; rid = table_funcs.column_find_row(m->session->tr, auths_name, grantee, NULL); if (rid == oid_nil) return sql_message("M1M05!GRANT: cannot grant ROLE '%s' to ROLE '%s'", grantee, auth ); grantee_id = table_funcs.column_find_value(m->session->tr, auths_id, rid); rid = table_funcs.column_find_row(m->session->tr, auths_name, auth, NULL); if (rid == oid_nil) { _DELETE(grantee_id); return sql_message("M1M05!GRANT: cannot grant ROLE '%s' to ROLE '%s'", grantee, auth ); } auth_id = table_funcs.column_find_value(m->session->tr, auths_id, rid); table_funcs.table_insert(m->session->tr, roles, grantee_id, auth_id); _DELETE(grantee_id); _DELETE(auth_id); return NULL; }
char * sql_drop_user(mvc *sql, char *user) { int user_id = sql_find_auth(sql, user); if (mvc_check_dependency(sql, user_id, OWNER_DEPENDENCY, NULL)) return sql_message("M1M05!DROP USER: '******' owns a schema", user); if (backend_drop_user(sql,user) == FALSE) return sql_message("M0M27!%s", sql->errstr); return sql_drop_role(sql, user); }
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; }
char * sql_rename_user(mvc *sql, char *olduser, char *newuser) { if (backend_find_user(sql, olduser) < 0) return sql_message("42M32!ALTER USER: no such user '%s'", olduser); if (backend_find_user(sql, newuser) >= 0) return sql_message("42M31!ALTER USER: user '%s' already exists", newuser); if (sql->user_id != USER_MONETDB && sql->role_id != ROLE_SYSADMIN) return sql_message("M1M05!ALTER USER: insufficient privileges to " "rename user '%s'", olduser); if (backend_rename_user(sql, olduser, newuser) == FALSE) return sql_message("M1M05!%s", sql->errstr); return NULL; }
char * sql_alter_user(mvc *sql, char *user, char *passwd, char enc, char *schema, char *oldpasswd) { sqlid schema_id = 0; /* we may be called from MAL (nil) */ if (user != NULL && strcmp(user, str_nil) == 0) user = NULL; /* USER == NULL -> current_user */ if (user != NULL && backend_find_user(sql, user) < 0) return sql_message("42M32!ALTER USER: no such user '%s'", user); if (sql->user_id != USER_MONETDB && sql->role_id != ROLE_SYSADMIN && user != NULL && strcmp(user, stack_get_string(sql, "current_user")) != 0) return sql_message("M1M05!ALTER USER: insufficient privileges to change user '%s'", user); if (schema && (schema_id = sql_find_schema(sql, schema)) < 0) { return sql_message("3F000!ALTER USER: no such schema '%s'", schema); } if (backend_alter_user(sql, user, passwd, enc, schema_id, oldpasswd) == FALSE) return sql_message("M0M27!%s", sql->errstr); return NULL; }
str sql_drop_role(mvc *m, str auth) { oid rid; sql_schema *sys = find_sql_schema(m->session->tr, "sys"); sql_table *auths = find_sql_table(sys, "auths"); sql_column *auth_name = find_sql_column(auths, "name"); rid = table_funcs.column_find_row(m->session->tr, auth_name, auth, NULL); if (rid == oid_nil) return sql_message("0P000!DROP ROLE: no such role '%s'", auth); table_funcs.table_delete(m->session->tr, auths, rid); return NULL; }
str sql_create_role(mvc *m, str auth, int grantor) { oid id; sql_schema *sys = find_sql_schema(m->session->tr, "sys"); sql_table *auths = find_sql_table(sys, "auths"); sql_column *auth_name = find_sql_column(auths, "name"); if (table_funcs.column_find_row(m->session->tr, auth_name, auth, NULL) != oid_nil) return sql_message("0P000!CREATE ROLE: role '%s' already exists", auth); id = store_next_oid(); table_funcs.table_insert(m->session->tr, auths, &id, auth, &grantor); return NULL; }
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); }
sql_func * resolve_func( mvc *sql, sql_schema *s, const char *name, dlist *typelist, int type, char *op, int if_exists) { sql_func *func = NULL; list *list_func = NULL, *type_list = NULL; char is_aggr = (type == F_AGGR); char is_func = (type != F_PROC && type != F_LOADER); 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 (typelist) { sql_subfunc *sub_func; 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 && 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, 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); } if (list_func && list_func->cnt == 1) func = (sql_func*) list_func->h->data; } if (!func) { void *e = NULL; 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) { char *t = arg_list; arg_list = sql_message("%s, %s", arg_list, tpe); _DELETE(tpe); _DELETE(t); } else { arg_list = tpe; } } list_destroy(list_func); list_destroy(type_list); if(!if_exists) e = sql_error(sql, 02, SQLSTATE(42000) "%s %s%s: no such %s%s '%s' (%s)", op, KF, F, kf, f, name, arg_list); _DELETE(arg_list); return e; } list_destroy(list_func); list_destroy(type_list); if(!if_exists) e = sql_error(sql, 02, SQLSTATE(42000) "%s %s%s: no such %s%s '%s' ()", op, KF, F, kf, f, name); return e; } else { if(!if_exists) e = sql_error(sql, 02, SQLSTATE(42000) "%s %s%s: no such %s%s '%s'", op, KF, F, kf, f, name); return e; } } 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, SQLSTATE(42000) "%s %s%s: cannot drop %s '%s'", KF, F, is_func?"procedure":"function", op, name); } list_destroy(list_func); list_destroy(type_list); return func; }
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); }
int mvc_commit(mvc *m, int chain, const char *name) { sql_trans *cur, *tr = m->session->tr; int ok = SQL_OK;//, wait = 0; assert(tr); assert(m->session->active); /* only commit an active transaction */ if (mvc_debug) fprintf(stderr, "#mvc_commit %s\n", (name) ? name : ""); if (m->session->status < 0) { (void)sql_error(m, 010, "40000!COMMIT: transaction is aborted, will ROLLBACK instead"); mvc_rollback(m, chain, name); return -1; } /* savepoint then simply make a copy of the current transaction */ if (name && name[0] != '\0') { sql_trans *tr = m->session->tr; if (mvc_debug) fprintf(stderr, "#mvc_savepoint\n"); store_lock(); m->session->tr = sql_trans_create(m->session->stk, tr, name); store_unlock(); m->type = Q_TRANS; if (m->qc) /* clean query cache, protect against concurrent access on the hash tables (when functions already exists, concurrent mal will build up the hash (not copied in the trans dup)) */ qc_clean(m->qc); m->session->schema = find_sql_schema(m->session->tr, m->session->schema_name); if (mvc_debug) fprintf(stderr, "#mvc_commit %s done\n", name); return 0; } /* first release all intermediate savepoints */ cur = tr; tr = tr->parent; if (tr->parent) { store_lock(); while (tr->parent != NULL && ok == SQL_OK) { tr = sql_trans_destroy(tr); } store_unlock(); } cur -> parent = tr; tr = cur; store_lock(); /* if there is nothing to commit reuse the current transaction */ if (tr->wtime == 0) { if (!chain) sql_trans_end(m->session); m->type = Q_TRANS; if (mvc_debug) fprintf(stderr, "#mvc_commit %s done\n", (name) ? name : ""); store_unlock(); return 0; } /* while (tr->schema_updates && store_nr_active > 1) { store_unlock(); MT_sleep_ms(100); wait += 100; if (wait > 1000) { (void)sql_error(m, 010, "40000!COMMIT: transaction is aborted because of DDL concurrency conflicts, will ROLLBACK instead"); mvc_rollback(m, chain, name); return -1; } store_lock(); } * */ /* validation phase */ if (sql_trans_validate(tr)) { if ((ok = sql_trans_commit(tr)) != SQL_OK) { char *msg = sql_message("40000!COMMIT: transaction commit failed (perhaps your disk is full?) exiting (kernel error: %s)", GDKerrbuf); GDKfatal("%s", msg); _DELETE(msg); } } else { store_unlock(); (void)sql_error(m, 010, "40000!COMMIT: transaction is aborted because of concurrency conflicts, will ROLLBACK instead"); mvc_rollback(m, chain, name); return -1; } sql_trans_end(m->session); if (chain) sql_trans_begin(m->session); store_unlock(); m->type = Q_TRANS; if (mvc_debug) fprintf(stderr, "#mvc_commit %s done\n", (name) ? name : ""); return ok; }