Changeset: b12d8cb111aa for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB/rev/b12d8cb111aa
Added Files:
        sql/test/BugTracker-2026/Tests/7700-alter-user-optimizer.test
Modified Files:
        ChangeLog
        clients/Tests/MAL-signatures-hge.test
        clients/Tests/MAL-signatures.test
        sql/backends/monet5/sql.c
        sql/backends/monet5/sql_cat.c
        sql/backends/monet5/sql_user.c
        sql/common/sql_backend.c
        sql/common/sql_backend.h
        sql/server/rel_schema.c
        sql/server/rel_semantic.c
        sql/server/sql_parser.y
        sql/server/sql_privileges.c
        sql/server/sql_privileges.h
        sql/test/BugTracker-2026/Tests/All
Branch: default
Log Message:

Implement request #7700
Add capability to change the default OPTIMIZER for a USER via:
ALTER USER user_id OPTIMIZER 'minimal_pipe';


diffs (truncated from 342 to 300 lines):

diff --git a/ChangeLog b/ChangeLog
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,10 @@
 # ChangeLog file for devel
 # This file is updated with Maddlog
 
+* Wed May  6 2026 Martin van Dinther <[email protected]>
+- Added capability to change the OPTIMIZER setting for a USER via:
+  ALTER USER user_id OPTIMIZER 'minimal_pipe';
+
 * Sat May  2 2026 Lucas Pereira <[email protected]>
 - Set default to 'no' of monetdbd discovery property.
 
diff --git a/clients/Tests/MAL-signatures-hge.test 
b/clients/Tests/MAL-signatures-hge.test
--- a/clients/Tests/MAL-signatures-hge.test
+++ b/clients/Tests/MAL-signatures-hge.test
@@ -50890,7 +50890,7 @@ SQLalter_table
 Catalog operation alter_table
 sqlcatalog
 alter_user
-pattern sqlcatalog.alter_user(X_0:str, X_1:str, X_2:int, X_3:str, X_4:str, 
X_5:str, X_6:str, X_7:lng, X_8:int):void
+pattern sqlcatalog.alter_user(X_0:str, X_1:str, X_2:int, X_3:str, X_4:str, 
X_5:str, X_6:str, X_7:lng, X_8:int, X_9:str):void
 SQLalter_user
 Catalog operation alter_user
 sqlcatalog
diff --git a/clients/Tests/MAL-signatures.test 
b/clients/Tests/MAL-signatures.test
--- a/clients/Tests/MAL-signatures.test
+++ b/clients/Tests/MAL-signatures.test
@@ -39270,7 +39270,7 @@ SQLalter_table
 Catalog operation alter_table
 sqlcatalog
 alter_user
-pattern sqlcatalog.alter_user(X_0:str, X_1:str, X_2:int, X_3:str, X_4:str, 
X_5:str, X_6:str, X_7:lng, X_8:int):void
+pattern sqlcatalog.alter_user(X_0:str, X_1:str, X_2:int, X_3:str, X_4:str, 
X_5:str, X_6:str, X_7:lng, X_8:int, X_9:str):void
 SQLalter_user
 Catalog operation alter_user
 sqlcatalog
diff --git a/sql/backends/monet5/sql.c b/sql/backends/monet5/sql.c
--- a/sql/backends/monet5/sql.c
+++ b/sql/backends/monet5/sql.c
@@ -6437,7 +6437,7 @@ static mel_func sql_init_funcs[] = {
  pattern("sqlcatalog", "create_user", SQLcreate_user, false, "Catalog 
operation create_user", args(0,10, 
arg("sname",str),arg("passwrd",str),arg("enc",int),arg("schema",str),arg("schemapath",str),arg("fullname",str),
 arg("max_memory", lng), arg("max_workers", int), arg("optimizer", str), 
arg("default_role", str))),
  pattern("sqlcatalog", "drop_user", SQLdrop_user, false, "Catalog operation 
drop_user", args(0,2, arg("sname",str),arg("action",int))),
  pattern("sqlcatalog", "drop_user", SQLdrop_user, false, "Catalog operation 
drop_user", args(0,3, arg("sname",str),arg("auth",str),arg("action",int))),
- pattern("sqlcatalog", "alter_user", SQLalter_user, false, "Catalog operation 
alter_user", args(0,9, 
arg("sname",str),arg("passwrd",str),arg("enc",int),arg("schema",str),arg("schemapath",str),arg("oldpasswrd",str),arg("role",str),arg("max_memory",lng),arg("max_workers",int))),
+ pattern("sqlcatalog", "alter_user", SQLalter_user, false, "Catalog operation 
alter_user", args(0,10, 
arg("sname",str),arg("passwrd",str),arg("enc",int),arg("schema",str),arg("schemapath",str),arg("oldpasswrd",str),arg("role",str),arg("max_memory",lng),arg("max_workers",int),arg("optimizer",str))),
  pattern("sqlcatalog", "rename_user", SQLrename_user, false, "Catalog 
operation rename_user", args(0,3, 
arg("sname",str),arg("newnme",str),arg("action",int))),
  pattern("sqlcatalog", "create_role", SQLcreate_role, false, "Catalog 
operation create_role", args(0,3, 
arg("sname",str),arg("role",str),arg("grator",int))),
  pattern("sqlcatalog", "drop_role", SQLdrop_role, false, "Catalog operation 
drop_role", args(0,3, arg("auth",str),arg("role",str),arg("action",int))),
diff --git a/sql/backends/monet5/sql_cat.c b/sql/backends/monet5/sql_cat.c
--- a/sql/backends/monet5/sql_cat.c
+++ b/sql/backends/monet5/sql_cat.c
@@ -1877,9 +1877,10 @@ SQLalter_user(Client cntxt, MalBlkPtr mb
        char *role = SaveArgReference(stk, pci, 7);
        lng max_memory = *getArgReference_lng(stk, pci, 8);
        int max_workers = *getArgReference_int(stk, pci, 9);
+       char *optimizer = SaveArgReference(stk, pci, 10);
 
        initcontext();
-       msg = sql_alter_user(sql, sname, passwd, enc, schema, schema_path, 
oldpasswd, role, max_memory, max_workers);
+       msg = sql_alter_user(sql, sname, passwd, enc, schema, schema_path, 
oldpasswd, role, max_memory, max_workers, optimizer);
 
        return msg;
 }
diff --git a/sql/backends/monet5/sql_user.c b/sql/backends/monet5/sql_user.c
--- a/sql/backends/monet5/sql_user.c
+++ b/sql/backends/monet5/sql_user.c
@@ -303,7 +303,7 @@ monet5_create_user(ptr _mvc, str user, s
        if (!optimizer)
                optimizer = default_optimizer;
        if (!isOptimizerPipe(optimizer)) {
-               throw(MAL, "sql.create_user", SQLSTATE(42000) "Optimizer pipe 
%s unknown", optimizer);
+               throw(MAL, "sql.create_user", SQLSTATE(42000) "Optimizer pipe 
'%s' unknown", optimizer);
        }
 
 
@@ -455,8 +455,8 @@ monet5_schema_has_user(ptr _mvc, sql_sch
 }
 
 static int
-monet5_alter_user(ptr _mvc, str user, str passwd, bool enc, sqlid schema_id, 
str schema_path, str oldpasswd, sqlid
-               role_id, lng max_memory, int max_workers)
+monet5_alter_user(ptr _mvc, str user, str passwd, bool enc, sqlid schema_id, 
str schema_path, str oldpasswd,
+               sqlid role_id, lng max_memory, int max_workers, str optimizer)
 {
        mvc *m = (mvc *) _mvc;
        Client c = MCgetClient(m->clientid);
@@ -469,7 +469,7 @@ monet5_alter_user(ptr _mvc, str user, st
        sql_table *info = find_sql_table(m->session->tr, sys, "db_user_info");
        sql_column *users_name = find_sql_column(info, "name");
 
-       if (schema_id || schema_path || role_id || max_memory > -1 || 
max_workers > -1) {
+       if (schema_id || schema_path || role_id || max_memory > -1 || 
max_workers > -1 || optimizer) {
                rid = store->table_api.column_find_row(m->session->tr, 
users_name, user, NULL);
                // user should be checked here since the way `ALTER USER ident 
...` stmt is
                if (is_oid_nil(rid)) {
@@ -613,6 +613,21 @@ monet5_alter_user(ptr _mvc, str user, st
                }
        }
 
+       if (optimizer) {
+               sql_column *users_optimizer = find_sql_column(info, 
"optimizer");
+
+               if (!isOptimizerPipe(optimizer)) {
+                       (void) sql_error(m, 02, SQLSTATE(42000) "ALTER USER: 
failed. Optimizer pipe '%s' unknown", optimizer);
+                       return FALSE;
+               }
+
+               if ((res = store->table_api.column_update_value(m->session->tr, 
users_optimizer, rid, optimizer))) {
+                       (void) sql_error(m, 02, SQLSTATE(42000) "ALTER USER: 
failed%s",
+                                                       res == LOG_CONFLICT ? " 
due to conflict with another transaction" : "");
+                       return FALSE;
+               }
+       }
+
        return TRUE;
 }
 
diff --git a/sql/common/sql_backend.c b/sql/common/sql_backend.c
--- a/sql/common/sql_backend.c
+++ b/sql/common/sql_backend.c
@@ -78,10 +78,10 @@ backend_schema_has_user(ptr mvc, sql_sch
 
 int
 backend_alter_user(ptr mvc, str user, str passwd, bool enc,
-                                  sqlid schema_id, char *schema_path, str 
oldpasswd, sqlid role_id, lng max_memory, int max_workers)
+                               sqlid schema_id, char *schema_path, str 
oldpasswd, sqlid role_id, lng max_memory, int max_workers, char *optimizer)
 {
        if (be_funcs.fauser != NULL)
-               return(be_funcs.fauser(mvc, user, passwd, enc, schema_id, 
schema_path, oldpasswd, role_id, max_memory, max_workers));
+               return(be_funcs.fauser(mvc, user, passwd, enc, schema_id, 
schema_path, oldpasswd, role_id, max_memory, max_workers, optimizer));
        return(FALSE);
 }
 
diff --git a/sql/common/sql_backend.h b/sql/common/sql_backend.h
--- a/sql/common/sql_backend.h
+++ b/sql/common/sql_backend.h
@@ -22,7 +22,7 @@ typedef int  (*drop_user_fptr) (ptr mvc,
 typedef oid  (*find_user_fptr) (ptr mvc, char *user);
 typedef void (*create_privileges_fptr) (ptr mvc, sql_schema *s, const char 
*initpasswd);
 typedef int  (*schema_has_user_fptr) (ptr mvc, sql_schema *s);
-typedef int  (*alter_user_fptr) (ptr mvc, str user, str passwd, bool enc, 
sqlid schema_id, char *schema_path, str oldpasswd, sqlid role_id, lng 
max_memory, int max_workers);
+typedef int  (*alter_user_fptr) (ptr mvc, str user, str passwd, bool enc, 
sqlid schema_id, char *schema_path, str oldpasswd, sqlid role_id, lng 
max_memory, int max_workers, str optimizer);
 typedef int  (*rename_user_fptr) (ptr mvc, str olduser, str newuser);
 typedef void*  (*schema_user_dependencies) (ptr mvc, int schema_id);
 typedef void  (*create_function) (ptr mvc, str name, sql_rel *rel, sql_table 
*t);
@@ -56,7 +56,7 @@ extern int  backend_drop_user(ptr mvc, c
 extern oid  backend_find_user(ptr mp, char *user);
 extern void backend_create_privileges(ptr mvc, sql_schema *s, const char 
*initpasswd);
 extern int  backend_schema_has_user(ptr mvc, sql_schema *s);
-extern int     backend_alter_user(ptr mvc, str user, str passwd, bool enc, 
sqlid schema_id, char *schema_path, str oldpasswd, sqlid role_id, lng 
max_memory, int max_workers);
+extern int     backend_alter_user(ptr mvc, str user, str passwd, bool enc, 
sqlid schema_id, char *schema_path, str oldpasswd, sqlid role_id, lng 
max_memory, int max_workers, char *optimizer);
 extern int     backend_rename_user(ptr mvc, str olduser, str newuser);
 extern void*   backend_schema_user_dependencies(ptr trans, sqlid schema_id);
 extern int     backend_resolve_function(ptr trans, sql_func *f, const char 
*fimp, bool *side_effect);
diff --git a/sql/server/rel_schema.c b/sql/server/rel_schema.c
--- a/sql/server/rel_schema.c
+++ b/sql/server/rel_schema.c
@@ -2589,7 +2589,7 @@ rel_create_user(allocator *sa, char *use
 }
 
 static sql_rel *
-rel_alter_user(allocator *sa, char *user, char *passwd, int enc, char *schema, 
char *schema_path, char *oldpasswd, char *role, lng max_memory, int max_workers)
+rel_alter_user(allocator *sa, char *user, char *passwd, int enc, char *schema, 
char *schema_path, char *oldpasswd, char *role, lng max_memory, int 
max_workers, char *optimizer)
 {
        sql_rel *rel = rel_create(sa);
        list *exps = new_exp_list(sa);
@@ -2605,6 +2605,7 @@ rel_alter_user(allocator *sa, char *user
        append(exps, exp_atom_clob(sa, role));
        append(exps, exp_atom_lng(sa, max_memory));
        append(exps, exp_atom_int(sa, max_workers));
+       append(exps, exp_atom_clob(sa, optimizer));
 
        rel->l = NULL;
        rel->r = NULL;
@@ -3303,7 +3304,7 @@ rel_schemas(sql_query *query, symbol *s)
                dlist *l = s->data.lval;
                char *username = l->h->data.sval;
                dnode *a = l->h->next->data.lval->h;
-               int if_exists = l->h->next->next->next->next->next->data.i_val;
+               int if_exists = 
l->h->next->next->next->next->next->next->data.i_val;
 
                if (if_exists == 1 && username != NULL && 
is_oid_nil(backend_find_user(sql, username))) {
                        /* user does not exist, but IF EXISTS is specified, so 
we are done */
@@ -3317,7 +3318,8 @@ rel_schemas(sql_query *query, symbol *s)
                                a->next->next->next->next->data.sval, /* old 
passwd */
                                l->h->next->next->data.sval, /* default role */
                                l->h->next->next->next->data.l_val, /* 
max_memory */
-                               l->h->next->next->next->next->data.i_val /* 
max_workers */
+                               l->h->next->next->next->next->data.i_val, /* 
max_workers */
+                               l->h->next->next->next->next->next->data.sval 
/* optimizer */
                        );
        }       break;
        case SQL_RENAME_USER: {
diff --git a/sql/server/rel_semantic.c b/sql/server/rel_semantic.c
--- a/sql/server/rel_semantic.c
+++ b/sql/server/rel_semantic.c
@@ -26,7 +26,8 @@ sql_rel *
 rel_parse(mvc *m, sql_schema *s, const char *query, char emode)
 {
        if (mvc_highwater(m))
-        return sql_error(m, 10, SQLSTATE(42000) "Query too complex: running 
out of stack space");
+               return sql_error(m, 10, SQLSTATE(42000) "Query too complex: 
running out of stack space");
+
        sql_rel *rel = NULL;
        buffer *b;
        bstream *bs;
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
@@ -1487,10 +1487,10 @@ alter_statement:
                        append_int(l, $3);
                        $$ = _symbol_create_list(SQL_SET_TABLE_SCHEMA, l );
                }
-       |       ALTER USER if_exists column_id opt_with_encrypted_password 
user_schema opt_schema_path opt_default_role opt_max_memory_max_workers
+       |       ALTER USER if_exists column_id opt_with_encrypted_password 
user_schema opt_schema_path opt_default_role opt_max_memory_max_workers 
opt_optimizer
                {
                        dlist *l = L(), *p = L();
-                       if (!$5 && !$6 && !$7 && !$8 && $9[0] < 0 && $9[1] < 0) 
{
+                       if (!$5 && !$6 && !$7 && !$8 && $9[0] < 0 && $9[1] < 0 
&& !$10) {
                                yyerror(m, "ALTER USER: At least one property 
should be updated");
                                YYABORT;
                        }
@@ -1504,6 +1504,7 @@ alter_statement:
                        append_string(l, $8);
                        append_lng(l, $9[0]);
                        append_int(l, (int)$9[1]);
+                       append_string(l, $10);
                        append_int(l, $3);
                        $$ = _symbol_create_list( SQL_ALTER_USER, l );
                }
@@ -1529,6 +1530,7 @@ alter_statement:
                        append_string(l, NULL);
                        append_lng(l, -1);
                        append_int(l, -1);
+                       append_string(l, NULL);
                        append_int(l, FALSE);
                        $$ = _symbol_create_list( SQL_ALTER_USER, l );
                }
@@ -3739,7 +3741,7 @@ assignment:
 
 opt_assignment_commalist:
                '(' assignment_commalist ')'    { $$ = $2; }
-       |       /* empty */                     { $$ = NULL; }
+       |       /* empty */                     { $$ = NULL; }
        ;
 
 opt_where_clause:
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
@@ -1015,7 +1015,7 @@ sql_drop_user(mvc *sql, char *user)
 }
 
 char *
-sql_alter_user(mvc *sql, char *user, char *passwd, bool enc, char *schema, 
char *schema_path, char *oldpasswd, char *role, lng max_memory, int max_workers)
+sql_alter_user(mvc *sql, char *user, char *passwd, bool enc, char *schema, 
char *schema_path, char *oldpasswd, char *role, lng max_memory, int 
max_workers, char *optimizer)
 {
        sql_schema *s = NULL;
        sqlid schema_id = 0;
@@ -1048,7 +1048,7 @@ sql_alter_user(mvc *sql, char *user, cha
                if (!isNew(s) && sql_trans_add_dependency(sql->session->tr, 
s->base.id, ddl) != LOG_OK)
                        throw(SQL, "sql.alter_user", SQLSTATE(HY013) 
MAL_MALLOC_FAIL);
        }
-       if (backend_alter_user(sql, user, passwd, enc, schema_id, schema_path, 
oldpasswd, role_id, max_memory, max_workers) == FALSE)
+       if (backend_alter_user(sql, user, passwd, enc, schema_id, schema_path, 
oldpasswd, role_id, max_memory, max_workers, optimizer) == FALSE)
                throw(SQL,"sql.alter_user", SQLSTATE(M0M27) "%s", sql->errstr);
 
        /* the default role must explicitly granted to the new user */
diff --git a/sql/server/sql_privileges.h b/sql/server/sql_privileges.h
--- a/sql/server/sql_privileges.h
+++ b/sql/server/sql_privileges.h
@@ -45,7 +45,7 @@ extern int sql_schema_has_user(mvc *m, s
 
 extern char * sql_create_user(mvc *sql, char *user, char *passwd, bool enc, 
char *fullname, char *schema, char *schema_path, lng max_memory, int 
max_workers, char *optimizer, char *default_role);
 extern char * sql_drop_user(mvc *sql, char *user);
-extern char * sql_alter_user(mvc *sql, char *user, char *passwd, bool enc, 
char *schema, char *schema_path, char *oldpasswd, char *role, lng max_memory, 
int max_workers);
+extern char * sql_alter_user(mvc *sql, char *user, char *passwd, bool enc, 
char *schema, char *schema_path, char *oldpasswd, char *role, lng max_memory, 
int max_workers, char *optimizer);
 extern char * sql_rename_user(mvc *sql, char *olduser, char *newuser);
 
 #endif /*_SQL_PRIV_H_ */
diff --git a/sql/test/BugTracker-2026/Tests/7700-alter-user-optimizer.test 
b/sql/test/BugTracker-2026/Tests/7700-alter-user-optimizer.test
new file mode 100644
--- /dev/null
+++ b/sql/test/BugTracker-2026/Tests/7700-alter-user-optimizer.test
@@ -0,0 +1,47 @@
+statement ok
+CREATE USER test WITH PASSWORD 'me' NAME 'tester' OPTIMIZER 'default_pipe'
+
+query TT nosort
+SELECT name, optimizer FROM sys.users WHERE name = 'test'
+----
+test
+default_pipe
+
+statement ok
+ALTER USER test OPTIMIZER 'minimal_pipe'
+
+query TT nosort
_______________________________________________
checkin-list mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to