Changeset: df7bf5ceb480 for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB/rev/df7bf5ceb480
Modified Files:
sql/server/rel_unnest.c
sql/server/sql_parser.y
sql/test/BugTracker-2025/Tests/All
Branch: default
Log Message:
merged with mar2025
diffs (287 lines):
diff --git a/sql/server/rel_unnest.c b/sql/server/rel_unnest.c
--- a/sql/server/rel_unnest.c
+++ b/sql/server/rel_unnest.c
@@ -2557,6 +2557,7 @@ rel_set_type(visitor *v, sql_rel *rel)
if (!rel)
return rel;
if (is_project(rel->op) && rel->l) {
+ bool clear_hash = false;
if (is_set(rel->op)) {
sql_rel *l = rel->l, *r = rel->r;
list *exps = l->exps;
@@ -2565,13 +2566,18 @@ rel_set_type(visitor *v, sql_rel *rel)
sql_exp *e = n->data;
sql_subtype *t = exp_subtype(e);
- if (t && !t->type->localtype)
+ if (t && !t->type->localtype) {
n->data = exp_set_type(v->sql,
m->data, e);
+ clear_hash = true;
+ }
}
+ if (clear_hash)
+ list_hash_clear(exps);
if (exps != r->exps)
exps = r->exps;
else
exps = NULL;
+ clear_hash = false;
}
} else if (is_munion(rel->op)) {
list *l = rel->l;
@@ -2582,9 +2588,13 @@ rel_set_type(visitor *v, sql_rel *rel)
sql_exp *e = n->data;
sql_subtype *t = exp_subtype(e);
- if (t && !t->type->localtype)
+ if (t && !t->type->localtype) {
n->data = exp_set_type(v->sql,
m->data, e);
+ clear_hash = true;
+ }
}
+ if (clear_hash)
+ list_hash_clear(exps);
}
} else if ((is_simple_project(rel->op) || is_groupby(rel->op))
&& rel->l) {
list *exps = rel->exps;
@@ -2615,6 +2625,7 @@ rel_set_type(visitor *v, sql_rel *rel)
int label = e->alias.label;
n->data = e = exp_convert(v->sql, e, t, exp_subtype(te));
e->alias.label = label;
+
list_hash_clear(l->exps);
break;
}
}
diff --git a/sql/server/sql_parser.y b/sql/server/sql_parser.y
--- a/sql/server/sql_parser.y
+++ b/sql/server/sql_parser.y
@@ -1033,7 +1033,7 @@ set_statement:
{ dlist *l = L();
sql_subtype t;
sql_find_subtype(&t, "char", UTF8_strlen($5), 0 );
- append_list(l, append_string(append_string(L(), sa_strdup(SA,
"sys")), sa_strdup(SA, "current_user")));
+ append_list(l, append_string(append_string(L(), sa_strdup(SA,
"sys")), sa_strdup(SA, "current_role")));
append_symbol(l, _newAtomNode( _atom_string(&t, $5)) );
$$ = _symbol_create_list( SQL_SET, l); }
| set session_schema ident
@@ -1047,7 +1047,7 @@ set_statement:
{ dlist *l = L();
sql_subtype t;
sql_find_subtype(&t, "char", UTF8_strlen($4), 0 );
- append_list(l, append_string(append_string(L(), sa_strdup(SA,
"sys")), sa_strdup(SA, "current_user")));
+ append_list(l, append_string(append_string(L(), sa_strdup(SA,
"sys")), sa_strdup(SA, "current_role")));
append_symbol(l, _newAtomNode( _atom_string(&t, $4)) );
$$ = _symbol_create_list( SQL_SET, l); }
| set ROLE ident
diff --git a/sql/server/sql_privileges.c b/sql/server/sql_privileges.c
--- a/sql/server/sql_privileges.c
+++ b/sql/server/sql_privileges.c
@@ -405,6 +405,24 @@ sql_create_auth_id(mvc *m, sqlid id, str
return true;
}
+static bool
+role_granting_privs(mvc *m, oid role_rid, sqlid role_id, sqlid grantor_id)
+{
+ sql_schema *sys = find_sql_schema(m->session->tr, "sys");
+ sql_table *auths = find_sql_table(m->session->tr, sys, "auths");
+ sql_column *auths_grantor = find_sql_column(auths, "grantor");
+ sqlid owner_id;
+ sqlstore *store = m->session->tr->store;
+
+ owner_id = store->table_api.column_find_sqlid(m->session->tr,
auths_grantor, role_rid);
+ if (owner_id == grantor_id)
+ return true;
+ if (sql_privilege(m, grantor_id, role_id, PRIV_ROLE_ADMIN) ==
PRIV_ROLE_ADMIN)
+ return true;
+ /* check for grant rights in the privs table */
+ return false;
+}
+
str
sql_create_role(mvc *m, str auth, sqlid grantor)
{
@@ -443,6 +461,16 @@ sql_drop_role(mvc *m, str auth)
rid = store->table_api.column_find_row(tr, find_sql_column(auths,
"name"), auth, NULL);
if (is_oid_nil(rid))
throw(SQL, "sql.drop_role", SQLSTATE(0P000) "DROP ROLE: no such
role '%s'", auth);
+
+ if (!admin_privs(m->user_id) &&
+ !admin_privs(m->role_id) &&
+ !role_granting_privs(m, rid, role_id, m->user_id) &&
+ !role_granting_privs(m, rid, role_id, m->role_id))
+ throw(SQL,"sql.drop_role", SQLSTATE(0P000) "Insufficient
privileges to drop role '%s'", auth);
+
+ if (!is_oid_nil(backend_find_user(m, auth)))
+ throw(SQL,"sql.drop_role", SQLSTATE(M1M05) "DROP: '%s' is a
USER not a ROLE", auth);
+
if ((log_res = store->table_api.table_delete(m->session->tr, auths,
rid)) != LOG_OK)
throw(SQL, "sql.drop_role", SQLSTATE(42000) "DROP ROLE:
failed%s", log_res == LOG_CONFLICT ? " due to conflict with another
transaction" : "");
@@ -555,21 +583,15 @@ execute_priv(mvc *m, sql_func *f)
}
static bool
-role_granting_privs(mvc *m, oid role_rid, sqlid role_id, sqlid grantor_id)
+sql_user_has_role(mvc *m, sqlid user_id, sqlid role_id)
{
+ if (user_id == role_id)
+ return true;
sql_schema *sys = find_sql_schema(m->session->tr, "sys");
- sql_table *auths = find_sql_table(m->session->tr, sys, "auths");
- sql_column *auths_grantor = find_sql_column(auths, "grantor");
- sqlid owner_id;
+ sql_table *roles = find_sql_table(m->session->tr, sys, "user_role");
sqlstore *store = m->session->tr->store;
-
- owner_id = store->table_api.column_find_sqlid(m->session->tr,
auths_grantor, role_rid);
- if (owner_id == grantor_id)
- return true;
- if (sql_privilege(m, grantor_id, role_id, PRIV_ROLE_ADMIN) ==
PRIV_ROLE_ADMIN)
- return true;
- /* check for grant rights in the privs table */
- return false;
+ oid rid = store->table_api.column_find_row(m->session->tr,
find_sql_column(roles, "login_id"), &user_id, find_sql_column(roles,
"role_id"), &role_id, NULL);
+ return (!is_oid_nil(rid));
}
char *
@@ -877,6 +899,7 @@ sql_drop_granted_users(mvc *sql, sqlid u
if (!list_find(deleted_users, &user_id, (fcmp) &id_cmp)) {
if (mvc_check_dependency(sql, user_id, OWNER_DEPENDENCY, NULL))
throw(SQL,"sql.drop_user",SQLSTATE(M1M05) "DROP USER:
'%s' owns a schema", user);
+
if (backend_drop_user(sql, user) == FALSE)
throw(SQL,"sql.drop_user",SQLSTATE(M0M27) "%s",
sql->errstr);
@@ -947,10 +970,22 @@ sql_drop_granted_users(mvc *sql, sqlid u
char *
sql_drop_user(mvc *sql, char *user)
{
- sqlid user_id = sql_find_auth(sql, user);
list *deleted = list_create(NULL);
str msg = NULL;
+ sqlid user_id = sql_find_auth(sql, user);
+ sql_schema *sys = find_sql_schema(sql->session->tr, "sys");
+ sql_table *auths = find_sql_table(sql->session->tr, sys, "auths");
+ sql_trans *tr = sql->session->tr;
+ sqlstore *store = sql->session->tr->store;
+ oid rid = store->table_api.column_find_row(tr, find_sql_column(auths,
"name"), user, NULL);
+
+ if (!admin_privs(sql->user_id) &&
+ !admin_privs(sql->role_id) &&
+ !role_granting_privs(sql, rid, user_id, sql->user_id) &&
+ !role_granting_privs(sql, rid, user_id, sql->role_id))
+ throw(SQL,"sql.drop_role", SQLSTATE(0P000) "Insufficient
privileges to drop user '%s'", user);
+
if (!deleted)
throw(SQL, "sql.drop_user", SQLSTATE(HY013) MAL_MALLOC_FAIL);
msg = sql_drop_granted_users(sql, user_id, user, deleted);
@@ -983,6 +1018,12 @@ sql_alter_user(mvc *sql, char *user, cha
if (user != NULL && is_oid_nil(backend_find_user(sql, user)))
throw(SQL,"sql.alter_user", SQLSTATE(42M32) "ALTER USER: no
such user '%s'", user);
+
+ sqlid user_id = !user ? sql->user_id : sql_find_auth(sql, user);
+ bool has_role = role_id && sql_user_has_role(sql, user_id, role_id);
+ if (!admin_privs(sql->user_id) && !admin_privs(sql->role_id) && role_id
&& !has_role)
+ throw(SQL,"sql.alter_user", SQLSTATE(M1M05) "User has not been
granted the role '%s'", role);
+
if (schema) {
if (!(s = find_sql_schema(sql->session->tr, schema)))
throw(SQL,"sql.alter_user", SQLSTATE(3F000) "ALTER
USER: no such schema '%s'", schema);
@@ -992,6 +1033,18 @@ sql_alter_user(mvc *sql, char *user, cha
}
if (backend_alter_user(sql, user, passwd, enc, schema_id, schema_path,
oldpasswd, role_id, max_memory, max_workers) == FALSE)
throw(SQL,"sql.alter_user", SQLSTATE(M0M27) "%s", sql->errstr);
+
+ /* the default role must explicitly granted to the new user */
+ if (role_id && !has_role) {
+ str r;
+ /* - we don't grant the default role WITH ADMIN OPTION hence
admin=0
+ * - we should use sql->role_id instead of sql->user_id
otherwise a user with high privs
+ * (e.g. sysadmin) might not be able to GRANT the DEFAULT ROLE
(see sql_grant_role() impl)
+ */
+ if ((r = sql_grant_role(sql, user, role, sql->role_id, 0)))
+ return r;
+ }
+
return NULL;
}
diff --git a/sql/test/BugTracker-2025/Tests/7662-drop-role-user.test
b/sql/test/BugTracker-2025/Tests/7662-drop-role-user.test
new file mode 100644
--- /dev/null
+++ b/sql/test/BugTracker-2025/Tests/7662-drop-role-user.test
@@ -0,0 +1,19 @@
+statement ok
+CREATE USER test WITH PASSWORD 'test' NAME 'test'
+
+statement ok
+CREATE USER alice WITH PASSWORD 'alice' NAME 'alice' SCHEMA sys
+
+@connection(id=test, username=test, password=test)
+query T
+select CURRENT_ROLE
+----
+test
+
+@connection(id=test)
+statement error
+DROP ROLE alice
+
+@connection(id=test)
+statement error
+DROP USER alice
diff --git a/sql/test/BugTracker-2025/Tests/7663-alter-user-role.test
b/sql/test/BugTracker-2025/Tests/7663-alter-user-role.test
new file mode 100644
--- /dev/null
+++ b/sql/test/BugTracker-2025/Tests/7663-alter-user-role.test
@@ -0,0 +1,14 @@
+statement ok
+CREATE USER test WITH PASSWORD 'test' NAME 'test'
+
+@connection(id=test, username=test, password=test)
+statement ok
+SET SCHEMA sys
+
+@connection(id=test)
+statement error 42000!CREATE TABLE: insufficient privileges for user 'test' in
schema 'sys'
+CREATE TABLE x (y INT)
+
+@connection(id=test)
+statement error M1M05!User has not been granted the role 'monetdb'
+ALTER USER test DEFAULT ROLE monetdb;
diff --git a/sql/test/BugTracker-2025/Tests/7664-session-user.test
b/sql/test/BugTracker-2025/Tests/7664-session-user.test
new file mode 100644
--- /dev/null
+++ b/sql/test/BugTracker-2025/Tests/7664-session-user.test
@@ -0,0 +1,14 @@
+statement ok
+CREATE USER test WITH PASSWORD 'test' NAME 'test';
+
+@connection(id=test, username=test, password=test)
+statement error M1M05!Insufficient privileges to change user 'monetdb'
+ALTER USER monetdb MAX_WORKERS 10
+
+@connection(id=test)
+statement error HY009!Role (monetdb) missing
+SET SESSION AUTHORIZATION monetdb;
+
+@connection(id=test)
+statement error M1M05!Insufficient privileges to change user 'monetdb'
+ALTER USER monetdb MAX_WORKERS 10;
diff --git a/sql/test/BugTracker-2025/Tests/All
b/sql/test/BugTracker-2025/Tests/All
--- a/sql/test/BugTracker-2025/Tests/All
+++ b/sql/test/BugTracker-2025/Tests/All
@@ -24,6 +24,9 @@ 7654_non_monetdb_user_remote_table_exec
7656_incorrect_error
7659_trigger_crashes
7661_trigger_crash
+7662-drop-role-user
+7663-alter-user-role
+7664-session-user
7671-lag-over-empty-bat
7674-rel_find_designated_index_crash
7680-union-all
_______________________________________________
checkin-list mailing list -- [email protected]
To unsubscribe send an email to [email protected]