1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-30 16:24:05 +03:00

MDEV-33783 CREATE SERVER segfaults on wrong mysql.servers

Do basic checking of mysql.servers compatibility.
This commit is contained in:
Aleksey Midenkov
2024-12-03 13:49:43 +03:00
parent 27c25ceedb
commit 13f93da1f6
3 changed files with 80 additions and 26 deletions

View File

@ -24,3 +24,17 @@ SELECT * FROM mysql.servers;
Server_name Host Db Username Password Port Socket Wrapper Owner Server_name Host Db Username Password Port Socket Wrapper Owner
s1 3306 bar mysql s1 3306 bar mysql
DROP SERVER s1; DROP SERVER s1;
#
# MDEV-33783 CREATE SERVER segfaults on wrong mysql.servers
#
create server s1 foreign data wrapper foo options(user 'a');
alter server s1 options(host 'server.example.org');
rename table mysql.servers to mysql.servers_save;
create table mysql.servers (x int);
alter server s1 options(host 'server.example.org');
ERROR HY000: The foreign server name you are trying to reference does not exist. Data source error: s1
create server s2 foreign data wrapper foo options(user 'a');
ERROR HY000: Can't read record in system table
drop table mysql.servers;
rename table mysql.servers_save to mysql.servers;
drop server s1;

View File

@ -22,3 +22,18 @@ DROP SERVER s1;
CREATE SERVER s1 FOREIGN DATA WRAPPER mysql OPTIONS(SOCKET 'bar'); CREATE SERVER s1 FOREIGN DATA WRAPPER mysql OPTIONS(SOCKET 'bar');
SELECT * FROM mysql.servers; SELECT * FROM mysql.servers;
DROP SERVER s1; DROP SERVER s1;
--echo #
--echo # MDEV-33783 CREATE SERVER segfaults on wrong mysql.servers
--echo #
create server s1 foreign data wrapper foo options(user 'a');
alter server s1 options(host 'server.example.org');
rename table mysql.servers to mysql.servers_save;
create table mysql.servers (x int);
--error ER_FOREIGN_SERVER_DOESNT_EXIST
alter server s1 options(host 'server.example.org');
--error ER_CANT_FIND_SYSTEM_REC
create server s2 foreign data wrapper foo options(user 'a');
drop table mysql.servers;
rename table mysql.servers_save to mysql.servers;
drop server s1;

View File

@ -462,7 +462,7 @@ get_server_from_table_to_cache(TABLE *table)
RETURN VALUES RETURN VALUES
0 - no error 0 - no error
other - error code other - ER_ error code
*/ */
static int static int
@ -546,15 +546,19 @@ insert_server_record_into_cache(FOREIGN_SERVER *server)
advance of insertion into the mysql.servers table advance of insertion into the mysql.servers table
RETURN VALUE RETURN VALUE
VOID 0 - no errors
>0 - ER_ error code
*/ */
static void static int
store_server_fields(TABLE *table, FOREIGN_SERVER *server) store_server_fields(TABLE *table, FOREIGN_SERVER *server)
{ {
table->use_all_columns(); table->use_all_columns();
if (table->s->fields < 9)
return ER_CANT_FIND_SYSTEM_REC;
/* /*
"server" has already been prepped by prepare_server_struct_for_<> "server" has already been prepped by prepare_server_struct_for_<>
so, all we need to do is check if the value is set (> -1 for port) so, all we need to do is check if the value is set (> -1 for port)
@ -563,30 +567,43 @@ store_server_fields(TABLE *table, FOREIGN_SERVER *server)
have changed will be set. If an insert, then all will be set, have changed will be set. If an insert, then all will be set,
even if with empty strings even if with empty strings
*/ */
if (server->host) if (server->host &&
table->field[1]->store(server->host, table->field[1]->store(server->host,
(uint) strlen(server->host), system_charset_info); (uint) strlen(server->host), system_charset_info))
if (server->db) goto err;
if (server->db &&
table->field[2]->store(server->db, table->field[2]->store(server->db,
(uint) strlen(server->db), system_charset_info); (uint) strlen(server->db), system_charset_info))
if (server->username) goto err;
if (server->username &&
table->field[3]->store(server->username, table->field[3]->store(server->username,
(uint) strlen(server->username), system_charset_info); (uint) strlen(server->username), system_charset_info))
if (server->password) goto err;
if (server->password &&
table->field[4]->store(server->password, table->field[4]->store(server->password,
(uint) strlen(server->password), system_charset_info); (uint) strlen(server->password), system_charset_info))
if (server->port > -1) goto err;
table->field[5]->store(server->port); if (server->port > -1 &&
table->field[5]->store(server->port))
if (server->socket) goto err;
if (server->socket &&
table->field[6]->store(server->socket, table->field[6]->store(server->socket,
(uint) strlen(server->socket), system_charset_info); (uint) strlen(server->socket), system_charset_info))
if (server->scheme) goto err;
if (server->scheme &&
table->field[7]->store(server->scheme, table->field[7]->store(server->scheme,
(uint) strlen(server->scheme), system_charset_info); (uint) strlen(server->scheme), system_charset_info))
if (server->owner) goto err;
if (server->owner &&
table->field[8]->store(server->owner, table->field[8]->store(server->owner,
(uint) strlen(server->owner), system_charset_info); (uint) strlen(server->owner), system_charset_info))
goto err;
return 0;
err:
THD *thd= table->in_use;
DBUG_ASSERT(thd->is_error());
return thd->get_stmt_da()->get_sql_errno();
} }
/* /*
@ -608,7 +625,7 @@ store_server_fields(TABLE *table, FOREIGN_SERVER *server)
RETURN VALUE RETURN VALUE
0 - no errors 0 - no errors
>0 - error code >0 - ER_ error code
*/ */
@ -642,7 +659,8 @@ int insert_server_record(TABLE *table, FOREIGN_SERVER *server)
error= 1; error= 1;
} }
/* store each field to be inserted */ /* store each field to be inserted */
store_server_fields(table, server); if ((error= store_server_fields(table, server)))
DBUG_RETURN(error);
DBUG_PRINT("info",("record for server '%s' not found!", DBUG_PRINT("info",("record for server '%s' not found!",
server->server_name)); server->server_name));
@ -972,9 +990,15 @@ update_server_record(TABLE *table, FOREIGN_SERVER *server)
table->use_all_columns(); table->use_all_columns();
/* set the field that's the PK to the value we're looking for */ /* set the field that's the PK to the value we're looking for */
table->field[0]->store(server->server_name, if (table->field[0]->store(server->server_name,
server->server_name_length, server->server_name_length,
system_charset_info); system_charset_info))
{
DBUG_ASSERT(0); /* Protected by servers_cache */
THD *thd= table->in_use;
DBUG_ASSERT(thd->is_error());
return thd->get_stmt_da()->get_sql_errno();
}
if (unlikely((error= if (unlikely((error=
table->file->ha_index_read_idx_map(table->record[0], 0, table->file->ha_index_read_idx_map(table->record[0], 0,
@ -992,7 +1016,8 @@ update_server_record(TABLE *table, FOREIGN_SERVER *server)
{ {
/* ok, so we can update since the record exists in the table */ /* ok, so we can update since the record exists in the table */
store_record(table,record[1]); store_record(table,record[1]);
store_server_fields(table, server); if ((error= store_server_fields(table, server)))
goto end;
if (unlikely((error=table->file->ha_update_row(table->record[1], if (unlikely((error=table->file->ha_update_row(table->record[1],
table->record[0])) && table->record[0])) &&
error != HA_ERR_RECORD_IS_THE_SAME)) error != HA_ERR_RECORD_IS_THE_SAME))