Beispiel #1
0
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;
}
Beispiel #2
0
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;
}
Beispiel #3
0
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;
}
Beispiel #4
0
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;
}
Beispiel #5
0
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);
}
Beispiel #6
0
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;
}
Beispiel #7
0
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;

}
Beispiel #8
0
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;
}
Beispiel #9
0
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;
}
Beispiel #10
0
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;
}
Beispiel #11
0
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);
}
Beispiel #12
0
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);
}
Beispiel #13
0
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;
}
Beispiel #14
0
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);
}
Beispiel #15
0
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;
}