mySQL 5.0.11 sources for tomato
[tomato.git] / release / src / router / mysql / sql / sql_servers.cc
blob2dd27c2b2176dc3c1035656ececc5fc8522122e8
1 /*
2 Copyright (c) 2006-2008 MySQL AB, 2009, 2010 Sun Microsystems, Inc.
3 Use is subject to license terms.
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; version 2 of the License.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 The servers are saved in the system table "servers"
23 Currently, when the user performs an ALTER SERVER or a DROP SERVER
24 operation, it will cause all open tables which refer to the named
25 server connection to be flushed. This may cause some undesirable
26 behaviour with regard to currently running transactions. It is
27 expected that the DBA knows what s/he is doing when s/he performs
28 the ALTER SERVER or DROP SERVER operation.
30 TODO:
31 It is desirable for us to implement a callback mechanism instead where
32 callbacks can be registered for specific server protocols. The callback
33 will be fired when such a server name has been created/altered/dropped
34 or when statistics are to be gathered such as how many actual connections.
35 Storage engines etc will be able to make use of the callback so that
36 currently running transactions etc will not be disrupted.
39 #include "mysql_priv.h"
40 #include "hash_filo.h"
41 #include <m_ctype.h>
42 #include <stdarg.h>
43 #include "sp_head.h"
44 #include "sp.h"
47 We only use 1 mutex to guard the data structures - THR_LOCK_servers.
48 Read locked when only reading data and write-locked for all other access.
51 static HASH servers_cache;
52 static MEM_ROOT mem;
53 static rw_lock_t THR_LOCK_servers;
55 static bool get_server_from_table_to_cache(TABLE *table);
57 /* insert functions */
58 static int insert_server(THD *thd, FOREIGN_SERVER *server_options);
59 static int insert_server_record(TABLE *table, FOREIGN_SERVER *server);
60 static int insert_server_record_into_cache(FOREIGN_SERVER *server);
61 static FOREIGN_SERVER *
62 prepare_server_struct_for_insert(LEX_SERVER_OPTIONS *server_options);
63 /* drop functions */
64 static int delete_server_record(TABLE *table,
65 char *server_name,
66 size_t server_name_length);
67 static int delete_server_record_in_cache(LEX_SERVER_OPTIONS *server_options);
69 /* update functions */
70 static void prepare_server_struct_for_update(LEX_SERVER_OPTIONS *server_options,
71 FOREIGN_SERVER *existing,
72 FOREIGN_SERVER *altered);
73 static int update_server(THD *thd, FOREIGN_SERVER *existing,
74 FOREIGN_SERVER *altered);
75 static int update_server_record(TABLE *table, FOREIGN_SERVER *server);
76 static int update_server_record_in_cache(FOREIGN_SERVER *existing,
77 FOREIGN_SERVER *altered);
78 /* utility functions */
79 static void merge_server_struct(FOREIGN_SERVER *from, FOREIGN_SERVER *to);
83 static uchar *servers_cache_get_key(FOREIGN_SERVER *server, size_t *length,
84 my_bool not_used __attribute__((unused)))
86 DBUG_ENTER("servers_cache_get_key");
87 DBUG_PRINT("info", ("server_name_length %d server_name %s",
88 server->server_name_length,
89 server->server_name));
91 *length= (uint) server->server_name_length;
92 DBUG_RETURN((uchar*) server->server_name);
97 Initialize structures responsible for servers used in federated
98 server scheme information for them from the server
99 table in the 'mysql' database.
101 SYNOPSIS
102 servers_init()
103 dont_read_server_table TRUE if we want to skip loading data from
104 server table and disable privilege checking.
106 NOTES
107 This function is mostly responsible for preparatory steps, main work
108 on initialization and grants loading is done in servers_reload().
110 RETURN VALUES
111 0 ok
112 1 Could not initialize servers
115 bool servers_init(bool dont_read_servers_table)
117 THD *thd;
118 bool return_val= FALSE;
119 DBUG_ENTER("servers_init");
121 /* init the mutex */
122 if (my_rwlock_init(&THR_LOCK_servers, NULL))
123 DBUG_RETURN(TRUE);
125 /* initialise our servers cache */
126 if (hash_init(&servers_cache, system_charset_info, 32, 0, 0,
127 (hash_get_key) servers_cache_get_key, 0, 0))
129 return_val= TRUE; /* we failed, out of memory? */
130 goto end;
133 /* Initialize the mem root for data */
134 init_alloc_root(&mem, ACL_ALLOC_BLOCK_SIZE, 0);
136 if (dont_read_servers_table)
137 goto end;
140 To be able to run this from boot, we allocate a temporary THD
142 if (!(thd=new THD))
143 DBUG_RETURN(TRUE);
144 thd->thread_stack= (char*) &thd;
145 thd->store_globals();
146 lex_start(thd);
148 It is safe to call servers_reload() since servers_* arrays and hashes which
149 will be freed there are global static objects and thus are initialized
150 by zeros at startup.
152 return_val= servers_reload(thd);
153 delete thd;
154 /* Remember that we don't have a THD */
155 my_pthread_setspecific_ptr(THR_THD, 0);
157 end:
158 DBUG_RETURN(return_val);
162 Initialize server structures
164 SYNOPSIS
165 servers_load()
166 thd Current thread
167 tables List containing open "mysql.servers"
169 RETURN VALUES
170 FALSE Success
171 TRUE Error
173 TODO
174 Revert back to old list if we failed to load new one.
177 static bool servers_load(THD *thd, TABLE_LIST *tables)
179 TABLE *table;
180 READ_RECORD read_record_info;
181 bool return_val= TRUE;
182 DBUG_ENTER("servers_load");
184 my_hash_reset(&servers_cache);
185 free_root(&mem, MYF(0));
186 init_alloc_root(&mem, ACL_ALLOC_BLOCK_SIZE, 0);
188 init_read_record(&read_record_info,thd,table=tables[0].table,NULL,1,0,
189 FALSE);
190 while (!(read_record_info.read_record(&read_record_info)))
192 /* return_val is already TRUE, so no need to set */
193 if ((get_server_from_table_to_cache(table)))
194 goto end;
197 return_val= FALSE;
199 end:
200 end_read_record(&read_record_info);
201 DBUG_RETURN(return_val);
206 Forget current servers cache and read new servers
207 from the conneciton table.
209 SYNOPSIS
210 servers_reload()
211 thd Current thread
213 NOTE
214 All tables of calling thread which were open and locked by LOCK TABLES
215 statement will be unlocked and closed.
216 This function is also used for initialization of structures responsible
217 for user/db-level privilege checking.
219 RETURN VALUE
220 FALSE Success
221 TRUE Failure
224 bool servers_reload(THD *thd)
226 TABLE_LIST tables[1];
227 bool return_val= TRUE;
228 DBUG_ENTER("servers_reload");
230 if (thd->locked_tables)
231 { // Can't have locked tables here
232 thd->lock=thd->locked_tables;
233 thd->locked_tables=0;
234 close_thread_tables(thd);
237 DBUG_PRINT("info", ("locking servers_cache"));
238 rw_wrlock(&THR_LOCK_servers);
240 bzero((char*) tables, sizeof(tables));
241 tables[0].alias= tables[0].table_name= (char*) "servers";
242 tables[0].db= (char*) "mysql";
243 tables[0].lock_type= TL_READ;
245 if (simple_open_n_lock_tables(thd, tables))
248 Execution might have been interrupted; only print the error message
249 if an error condition has been raised.
251 if (thd->main_da.is_error())
252 sql_print_error("Can't open and lock privilege tables: %s",
253 thd->main_da.message());
254 return_val= FALSE;
255 goto end;
258 if ((return_val= servers_load(thd, tables)))
259 { // Error. Revert to old list
260 /* blast, for now, we have no servers, discuss later way to preserve */
262 DBUG_PRINT("error",("Reverting to old privileges"));
263 servers_free();
266 end:
267 close_thread_tables(thd);
268 DBUG_PRINT("info", ("unlocking servers_cache"));
269 rw_unlock(&THR_LOCK_servers);
270 DBUG_RETURN(return_val);
275 Initialize structures responsible for servers used in federated
276 server scheme information for them from the server
277 table in the 'mysql' database.
279 SYNOPSIS
280 get_server_from_table_to_cache()
281 TABLE *table open table pointer
284 NOTES
285 This function takes a TABLE pointer (pointing to an opened
286 table). With this open table, a FOREIGN_SERVER struct pointer
287 is allocated into root memory, then each member of the FOREIGN_SERVER
288 struct is populated. A char pointer takes the return value of get_field
289 for each column we're interested in obtaining, and if that pointer
290 isn't 0x0, the FOREIGN_SERVER member is set to that value, otherwise,
291 is set to the value of an empty string, since get_field would set it to
292 0x0 if the column's value is empty, even if the default value for that
293 column is NOT NULL.
295 RETURN VALUES
296 0 ok
297 1 could not insert server struct into global servers cache
300 static bool
301 get_server_from_table_to_cache(TABLE *table)
303 /* alloc a server struct */
304 char *ptr;
305 char * const blank= (char*)"";
306 FOREIGN_SERVER *server= (FOREIGN_SERVER *)alloc_root(&mem,
307 sizeof(FOREIGN_SERVER));
308 DBUG_ENTER("get_server_from_table_to_cache");
309 table->use_all_columns();
311 /* get each field into the server struct ptr */
312 server->server_name= get_field(&mem, table->field[0]);
313 server->server_name_length= (uint) strlen(server->server_name);
314 ptr= get_field(&mem, table->field[1]);
315 server->host= ptr ? ptr : blank;
316 ptr= get_field(&mem, table->field[2]);
317 server->db= ptr ? ptr : blank;
318 ptr= get_field(&mem, table->field[3]);
319 server->username= ptr ? ptr : blank;
320 ptr= get_field(&mem, table->field[4]);
321 server->password= ptr ? ptr : blank;
322 ptr= get_field(&mem, table->field[5]);
323 server->sport= ptr ? ptr : blank;
325 server->port= server->sport ? atoi(server->sport) : 0;
327 ptr= get_field(&mem, table->field[6]);
328 server->socket= ptr && strlen(ptr) ? ptr : blank;
329 ptr= get_field(&mem, table->field[7]);
330 server->scheme= ptr ? ptr : blank;
331 ptr= get_field(&mem, table->field[8]);
332 server->owner= ptr ? ptr : blank;
333 DBUG_PRINT("info", ("server->server_name %s", server->server_name));
334 DBUG_PRINT("info", ("server->host %s", server->host));
335 DBUG_PRINT("info", ("server->db %s", server->db));
336 DBUG_PRINT("info", ("server->username %s", server->username));
337 DBUG_PRINT("info", ("server->password %s", server->password));
338 DBUG_PRINT("info", ("server->socket %s", server->socket));
339 if (my_hash_insert(&servers_cache, (uchar*) server))
341 DBUG_PRINT("info", ("had a problem inserting server %s at %lx",
342 server->server_name, (long unsigned int) server));
343 // error handling needed here
344 DBUG_RETURN(TRUE);
346 DBUG_RETURN(FALSE);
351 SYNOPSIS
352 insert_server()
353 THD *thd - thread pointer
354 FOREIGN_SERVER *server - pointer to prepared FOREIGN_SERVER struct
356 NOTES
357 This function takes a server object that is has all members properly
358 prepared, ready to be inserted both into the mysql.servers table and
359 the servers cache.
361 THR_LOCK_servers must be write locked.
363 RETURN VALUES
364 0 - no error
365 other - error code
368 static int
369 insert_server(THD *thd, FOREIGN_SERVER *server)
371 int error= -1;
372 TABLE_LIST tables;
373 TABLE *table;
375 DBUG_ENTER("insert_server");
377 bzero((char*) &tables, sizeof(tables));
378 tables.db= (char*) "mysql";
379 tables.alias= tables.table_name= (char*) "servers";
381 /* need to open before acquiring THR_LOCK_plugin or it will deadlock */
382 if (! (table= open_ltable(thd, &tables, TL_WRITE, 0)))
383 goto end;
385 /* insert the server into the table */
386 if ((error= insert_server_record(table, server)))
387 goto end;
389 /* insert the server into the cache */
390 if ((error= insert_server_record_into_cache(server)))
391 goto end;
393 end:
394 DBUG_RETURN(error);
399 SYNOPSIS
400 int insert_server_record_into_cache()
401 FOREIGN_SERVER *server
403 NOTES
404 This function takes a FOREIGN_SERVER pointer to an allocated (root mem)
405 and inserts it into the global servers cache
407 THR_LOCK_servers must be write locked.
409 RETURN VALUE
410 0 - no error
411 >0 - error code
415 static int
416 insert_server_record_into_cache(FOREIGN_SERVER *server)
418 int error=0;
419 DBUG_ENTER("insert_server_record_into_cache");
421 We succeded in insertion of the server to the table, now insert
422 the server to the cache
424 DBUG_PRINT("info", ("inserting server %s at %lx, length %d",
425 server->server_name, (long unsigned int) server,
426 server->server_name_length));
427 if (my_hash_insert(&servers_cache, (uchar*) server))
429 DBUG_PRINT("info", ("had a problem inserting server %s at %lx",
430 server->server_name, (long unsigned int) server));
431 // error handling needed here
432 error= 1;
434 DBUG_RETURN(error);
439 SYNOPSIS
440 store_server_fields()
441 TABLE *table
442 FOREIGN_SERVER *server
444 NOTES
445 This function takes an opened table object, and a pointer to an
446 allocated FOREIGN_SERVER struct, and then stores each member of
447 the FOREIGN_SERVER to the appropriate fields in the table, in
448 advance of insertion into the mysql.servers table
450 RETURN VALUE
451 VOID
455 static void
456 store_server_fields(TABLE *table, FOREIGN_SERVER *server)
459 table->use_all_columns();
461 "server" has already been prepped by prepare_server_struct_for_<>
462 so, all we need to do is check if the value is set (> -1 for port)
464 If this happens to be an update, only the server members that
465 have changed will be set. If an insert, then all will be set,
466 even if with empty strings
468 if (server->host)
469 table->field[1]->store(server->host,
470 (uint) strlen(server->host), system_charset_info);
471 if (server->db)
472 table->field[2]->store(server->db,
473 (uint) strlen(server->db), system_charset_info);
474 if (server->username)
475 table->field[3]->store(server->username,
476 (uint) strlen(server->username), system_charset_info);
477 if (server->password)
478 table->field[4]->store(server->password,
479 (uint) strlen(server->password), system_charset_info);
480 if (server->port > -1)
481 table->field[5]->store(server->port);
483 if (server->socket)
484 table->field[6]->store(server->socket,
485 (uint) strlen(server->socket), system_charset_info);
486 if (server->scheme)
487 table->field[7]->store(server->scheme,
488 (uint) strlen(server->scheme), system_charset_info);
489 if (server->owner)
490 table->field[8]->store(server->owner,
491 (uint) strlen(server->owner), system_charset_info);
495 SYNOPSIS
496 insert_server_record()
497 TABLE *table
498 FOREIGN_SERVER *server
500 NOTES
501 This function takes the arguments of an open table object and a pointer
502 to an allocated FOREIGN_SERVER struct. It stores the server_name into
503 the first field of the table (the primary key, server_name column). With
504 this, index_read_idx is called, if the record is found, an error is set
505 to ER_FOREIGN_SERVER_EXISTS (the server with that server name exists in the
506 table), if not, then store_server_fields stores all fields of the
507 FOREIGN_SERVER to the table, then ha_write_row is inserted. If an error
508 is encountered in either index_read_idx or ha_write_row, then that error
509 is returned
511 RETURN VALUE
512 0 - no errors
513 >0 - error code
517 static
518 int insert_server_record(TABLE *table, FOREIGN_SERVER *server)
520 int error;
521 DBUG_ENTER("insert_server_record");
522 table->use_all_columns();
524 empty_record(table);
526 /* set the field that's the PK to the value we're looking for */
527 table->field[0]->store(server->server_name,
528 server->server_name_length,
529 system_charset_info);
531 /* read index until record is that specified in server_name */
532 if ((error= table->file->index_read_idx_map(table->record[0], 0,
533 (uchar *)table->field[0]->ptr,
534 HA_WHOLE_KEY,
535 HA_READ_KEY_EXACT)))
537 /* if not found, err */
538 if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
540 table->file->print_error(error, MYF(0));
541 error= 1;
543 /* store each field to be inserted */
544 store_server_fields(table, server);
546 DBUG_PRINT("info",("record for server '%s' not found!",
547 server->server_name));
548 /* write/insert the new server */
549 if ((error=table->file->ha_write_row(table->record[0])))
551 table->file->print_error(error, MYF(0));
553 else
554 error= 0;
556 else
557 error= ER_FOREIGN_SERVER_EXISTS;
558 DBUG_RETURN(error);
562 SYNOPSIS
563 drop_server()
564 THD *thd
565 LEX_SERVER_OPTIONS *server_options
567 NOTES
568 This function takes as its arguments a THD object pointer and a pointer
569 to a LEX_SERVER_OPTIONS struct from the parser. The member 'server_name'
570 of this LEX_SERVER_OPTIONS struct contains the value of the server to be
571 deleted. The mysql.servers table is opened via open_ltable, a table object
572 returned, the servers cache mutex locked, then delete_server_record is
573 called with this table object and LEX_SERVER_OPTIONS server_name and
574 server_name_length passed, containing the name of the server to be
575 dropped/deleted, then delete_server_record_in_cache is called to delete
576 the server from the servers cache.
578 RETURN VALUE
579 0 - no error
580 > 0 - error code
583 int drop_server(THD *thd, LEX_SERVER_OPTIONS *server_options)
585 int error;
586 TABLE_LIST tables;
587 TABLE *table;
588 LEX_STRING name= { server_options->server_name,
589 server_options->server_name_length };
591 DBUG_ENTER("drop_server");
592 DBUG_PRINT("info", ("server name server->server_name %s",
593 server_options->server_name));
595 bzero((char*) &tables, sizeof(tables));
596 tables.db= (char*) "mysql";
597 tables.alias= tables.table_name= (char*) "servers";
599 rw_wrlock(&THR_LOCK_servers);
601 /* hit the memory hit first */
602 if ((error= delete_server_record_in_cache(server_options)))
603 goto end;
605 if (! (table= open_ltable(thd, &tables, TL_WRITE, 0)))
607 error= my_errno;
608 goto end;
611 error= delete_server_record(table, name.str, name.length);
613 /* close the servers table before we call closed_cached_connection_tables */
614 close_thread_tables(thd);
616 if (close_cached_connection_tables(thd, TRUE, &name))
618 push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
619 ER_UNKNOWN_ERROR, "Server connection in use");
622 end:
623 rw_unlock(&THR_LOCK_servers);
624 DBUG_RETURN(error);
630 SYNOPSIS
631 delete_server_record_in_cache()
632 LEX_SERVER_OPTIONS *server_options
634 NOTES
635 This function's argument is a LEX_SERVER_OPTIONS struct pointer. This
636 function uses the "server_name" and "server_name_length" members of the
637 lex->server_options to search for the server in the servers_cache. Upon
638 returned the server (pointer to a FOREIGN_SERVER struct), it then deletes
639 that server from the servers_cache hash.
641 RETURN VALUE
642 0 - no error
646 static int
647 delete_server_record_in_cache(LEX_SERVER_OPTIONS *server_options)
649 int error= ER_FOREIGN_SERVER_DOESNT_EXIST;
650 FOREIGN_SERVER *server;
651 DBUG_ENTER("delete_server_record_in_cache");
653 DBUG_PRINT("info",("trying to obtain server name %s length %d",
654 server_options->server_name,
655 server_options->server_name_length));
658 if (!(server= (FOREIGN_SERVER *) hash_search(&servers_cache,
659 (uchar*) server_options->server_name,
660 server_options->server_name_length)))
662 DBUG_PRINT("info", ("server_name %s length %d not found!",
663 server_options->server_name,
664 server_options->server_name_length));
665 goto end;
668 We succeded in deletion of the server to the table, now delete
669 the server from the cache
671 DBUG_PRINT("info",("deleting server %s length %d",
672 server->server_name,
673 server->server_name_length));
675 VOID(hash_delete(&servers_cache, (uchar*) server));
677 error= 0;
679 end:
680 DBUG_RETURN(error);
686 SYNOPSIS
687 update_server()
688 THD *thd
689 FOREIGN_SERVER *existing
690 FOREIGN_SERVER *altered
692 NOTES
693 This function takes as arguments a THD object pointer, and two pointers,
694 one pointing to the existing FOREIGN_SERVER struct "existing" (which is
695 the current record as it is) and another pointer pointing to the
696 FOREIGN_SERVER struct with the members containing the modified/altered
697 values that need to be updated in both the mysql.servers table and the
698 servers_cache. It opens a table, passes the table and the altered
699 FOREIGN_SERVER pointer, which will be used to update the mysql.servers
700 table for the particular server via the call to update_server_record,
701 and in the servers_cache via update_server_record_in_cache.
703 THR_LOCK_servers must be write locked.
705 RETURN VALUE
706 0 - no error
707 >0 - error code
711 int update_server(THD *thd, FOREIGN_SERVER *existing, FOREIGN_SERVER *altered)
713 int error;
714 TABLE *table;
715 TABLE_LIST tables;
716 DBUG_ENTER("update_server");
718 bzero((char*) &tables, sizeof(tables));
719 tables.db= (char*)"mysql";
720 tables.alias= tables.table_name= (char*)"servers";
722 if (!(table= open_ltable(thd, &tables, TL_WRITE, 0)))
724 error= my_errno;
725 goto end;
728 if ((error= update_server_record(table, altered)))
729 goto end;
731 error= update_server_record_in_cache(existing, altered);
734 Perform a reload so we don't have a 'hole' in our mem_root
736 servers_load(thd, &tables);
738 end:
739 DBUG_RETURN(error);
745 SYNOPSIS
746 update_server_record_in_cache()
747 FOREIGN_SERVER *existing
748 FOREIGN_SERVER *altered
750 NOTES
751 This function takes as an argument the FOREIGN_SERVER structi pointer
752 for the existing server and the FOREIGN_SERVER struct populated with only
753 the members which have been updated. It then "merges" the "altered" struct
754 members to the existing server, the existing server then represents an
755 updated server. Then, the existing record is deleted from the servers_cache
756 HASH, then the updated record inserted, in essence replacing the old
757 record.
759 THR_LOCK_servers must be write locked.
761 RETURN VALUE
762 0 - no error
763 1 - error
767 int update_server_record_in_cache(FOREIGN_SERVER *existing,
768 FOREIGN_SERVER *altered)
770 int error= 0;
771 DBUG_ENTER("update_server_record_in_cache");
774 update the members that haven't been change in the altered server struct
775 with the values of the existing server struct
777 merge_server_struct(existing, altered);
780 delete the existing server struct from the server cache
782 VOID(hash_delete(&servers_cache, (uchar*)existing));
785 Insert the altered server struct into the server cache
787 if (my_hash_insert(&servers_cache, (uchar*)altered))
789 DBUG_PRINT("info", ("had a problem inserting server %s at %lx",
790 altered->server_name, (long unsigned int) altered));
791 error= ER_OUT_OF_RESOURCES;
794 DBUG_RETURN(error);
800 SYNOPSIS
801 merge_server_struct()
802 FOREIGN_SERVER *from
803 FOREIGN_SERVER *to
805 NOTES
806 This function takes as its arguments two pointers each to an allocated
807 FOREIGN_SERVER struct. The first FOREIGN_SERVER struct represents the struct
808 that we will obtain values from (hence the name "from"), the second
809 FOREIGN_SERVER struct represents which FOREIGN_SERVER struct we will be
810 "copying" any members that have a value to (hence the name "to")
812 RETURN VALUE
813 VOID
817 void merge_server_struct(FOREIGN_SERVER *from, FOREIGN_SERVER *to)
819 DBUG_ENTER("merge_server_struct");
820 if (!to->host)
821 to->host= strdup_root(&mem, from->host);
822 if (!to->db)
823 to->db= strdup_root(&mem, from->db);
824 if (!to->username)
825 to->username= strdup_root(&mem, from->username);
826 if (!to->password)
827 to->password= strdup_root(&mem, from->password);
828 if (to->port == -1)
829 to->port= from->port;
830 if (!to->socket && from->socket)
831 to->socket= strdup_root(&mem, from->socket);
832 if (!to->scheme && from->scheme)
833 to->scheme= strdup_root(&mem, from->scheme);
834 if (!to->owner)
835 to->owner= strdup_root(&mem, from->owner);
837 DBUG_VOID_RETURN;
843 SYNOPSIS
844 update_server_record()
845 TABLE *table
846 FOREIGN_SERVER *server
848 NOTES
849 This function takes as its arguments an open TABLE pointer, and a pointer
850 to an allocated FOREIGN_SERVER structure representing an updated record
851 which needs to be inserted. The primary key, server_name is stored to field
852 0, then index_read_idx is called to read the index to that record, the
853 record then being ready to be updated, if found. If not found an error is
854 set and error message printed. If the record is found, store_record is
855 called, then store_server_fields stores each field from the the members of
856 the updated FOREIGN_SERVER struct.
858 RETURN VALUE
859 0 - no error
864 static int
865 update_server_record(TABLE *table, FOREIGN_SERVER *server)
867 int error=0;
868 DBUG_ENTER("update_server_record");
869 table->use_all_columns();
870 /* set the field that's the PK to the value we're looking for */
871 table->field[0]->store(server->server_name,
872 server->server_name_length,
873 system_charset_info);
875 if ((error= table->file->index_read_idx_map(table->record[0], 0,
876 (uchar *)table->field[0]->ptr,
877 ~(longlong)0,
878 HA_READ_KEY_EXACT)))
880 if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
881 table->file->print_error(error, MYF(0));
882 DBUG_PRINT("info",("server not found!"));
883 error= ER_FOREIGN_SERVER_DOESNT_EXIST;
885 else
887 /* ok, so we can update since the record exists in the table */
888 store_record(table,record[1]);
889 store_server_fields(table, server);
890 if ((error=table->file->ha_update_row(table->record[1],
891 table->record[0])) &&
892 error != HA_ERR_RECORD_IS_THE_SAME)
894 DBUG_PRINT("info",("problems with ha_update_row %d", error));
895 goto end;
897 else
898 error= 0;
901 end:
902 DBUG_RETURN(error);
908 SYNOPSIS
909 delete_server_record()
910 TABLE *table
911 char *server_name
912 int server_name_length
914 NOTES
916 RETURN VALUE
917 0 - no error
921 static int
922 delete_server_record(TABLE *table,
923 char *server_name, size_t server_name_length)
925 int error;
926 DBUG_ENTER("delete_server_record");
927 table->use_all_columns();
929 /* set the field that's the PK to the value we're looking for */
930 table->field[0]->store(server_name, server_name_length, system_charset_info);
932 if ((error= table->file->index_read_idx_map(table->record[0], 0,
933 (uchar *)table->field[0]->ptr,
934 HA_WHOLE_KEY,
935 HA_READ_KEY_EXACT)))
937 if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
938 table->file->print_error(error, MYF(0));
939 DBUG_PRINT("info",("server not found!"));
940 error= ER_FOREIGN_SERVER_DOESNT_EXIST;
942 else
944 if ((error= table->file->ha_delete_row(table->record[0])))
945 table->file->print_error(error, MYF(0));
948 DBUG_RETURN(error);
953 SYNOPSIS
954 create_server()
955 THD *thd
956 LEX_SERVER_OPTIONS *server_options
958 NOTES
960 RETURN VALUE
961 0 - no error
965 int create_server(THD *thd, LEX_SERVER_OPTIONS *server_options)
967 int error= ER_FOREIGN_SERVER_EXISTS;
968 FOREIGN_SERVER *server;
970 DBUG_ENTER("create_server");
971 DBUG_PRINT("info", ("server_options->server_name %s",
972 server_options->server_name));
974 rw_wrlock(&THR_LOCK_servers);
976 /* hit the memory first */
977 if (hash_search(&servers_cache, (uchar*) server_options->server_name,
978 server_options->server_name_length))
979 goto end;
982 if (!(server= prepare_server_struct_for_insert(server_options)))
984 /* purecov: begin inspected */
985 error= ER_OUT_OF_RESOURCES;
986 goto end;
987 /* purecov: end */
990 error= insert_server(thd, server);
992 DBUG_PRINT("info", ("error returned %d", error));
994 end:
995 rw_unlock(&THR_LOCK_servers);
996 DBUG_RETURN(error);
1002 SYNOPSIS
1003 alter_server()
1004 THD *thd
1005 LEX_SERVER_OPTIONS *server_options
1007 NOTES
1009 RETURN VALUE
1010 0 - no error
1014 int alter_server(THD *thd, LEX_SERVER_OPTIONS *server_options)
1016 int error= ER_FOREIGN_SERVER_DOESNT_EXIST;
1017 FOREIGN_SERVER *altered, *existing;
1018 LEX_STRING name= { server_options->server_name,
1019 server_options->server_name_length };
1020 DBUG_ENTER("alter_server");
1021 DBUG_PRINT("info", ("server_options->server_name %s",
1022 server_options->server_name));
1024 rw_wrlock(&THR_LOCK_servers);
1026 if (!(existing= (FOREIGN_SERVER *) hash_search(&servers_cache,
1027 (uchar*) name.str,
1028 name.length)))
1029 goto end;
1031 altered= (FOREIGN_SERVER *)alloc_root(&mem,
1032 sizeof(FOREIGN_SERVER));
1034 prepare_server_struct_for_update(server_options, existing, altered);
1036 error= update_server(thd, existing, altered);
1038 /* close the servers table before we call closed_cached_connection_tables */
1039 close_thread_tables(thd);
1041 if (close_cached_connection_tables(thd, FALSE, &name))
1043 push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
1044 ER_UNKNOWN_ERROR, "Server connection in use");
1047 end:
1048 DBUG_PRINT("info", ("error returned %d", error));
1049 rw_unlock(&THR_LOCK_servers);
1050 DBUG_RETURN(error);
1056 SYNOPSIS
1057 prepare_server_struct_for_insert()
1058 LEX_SERVER_OPTIONS *server_options
1060 NOTES
1061 As FOREIGN_SERVER members are allocated on mem_root, we do not need to
1062 free them in case of error.
1064 RETURN VALUE
1065 On success filled FOREIGN_SERVER, or NULL in case out of memory.
1069 static FOREIGN_SERVER *
1070 prepare_server_struct_for_insert(LEX_SERVER_OPTIONS *server_options)
1072 char *unset_ptr= (char*)"";
1073 FOREIGN_SERVER *server;
1074 DBUG_ENTER("prepare_server_struct");
1076 if (!(server= (FOREIGN_SERVER *)alloc_root(&mem, sizeof(FOREIGN_SERVER))))
1077 DBUG_RETURN(NULL); /* purecov: inspected */
1079 /* these two MUST be set */
1080 if (!(server->server_name= strdup_root(&mem, server_options->server_name)))
1081 DBUG_RETURN(NULL); /* purecov: inspected */
1082 server->server_name_length= server_options->server_name_length;
1084 if (!(server->host= server_options->host ?
1085 strdup_root(&mem, server_options->host) : unset_ptr))
1086 DBUG_RETURN(NULL); /* purecov: inspected */
1088 if (!(server->db= server_options->db ?
1089 strdup_root(&mem, server_options->db) : unset_ptr))
1090 DBUG_RETURN(NULL); /* purecov: inspected */
1092 if (!(server->username= server_options->username ?
1093 strdup_root(&mem, server_options->username) : unset_ptr))
1094 DBUG_RETURN(NULL); /* purecov: inspected */
1096 if (!(server->password= server_options->password ?
1097 strdup_root(&mem, server_options->password) : unset_ptr))
1098 DBUG_RETURN(NULL); /* purecov: inspected */
1100 /* set to 0 if not specified */
1101 server->port= server_options->port > -1 ?
1102 server_options->port : 0;
1104 if (!(server->socket= server_options->socket ?
1105 strdup_root(&mem, server_options->socket) : unset_ptr))
1106 DBUG_RETURN(NULL); /* purecov: inspected */
1108 if (!(server->scheme= server_options->scheme ?
1109 strdup_root(&mem, server_options->scheme) : unset_ptr))
1110 DBUG_RETURN(NULL); /* purecov: inspected */
1112 if (!(server->owner= server_options->owner ?
1113 strdup_root(&mem, server_options->owner) : unset_ptr))
1114 DBUG_RETURN(NULL); /* purecov: inspected */
1116 DBUG_RETURN(server);
1121 SYNOPSIS
1122 prepare_server_struct_for_update()
1123 LEX_SERVER_OPTIONS *server_options
1125 NOTES
1127 RETURN VALUE
1128 0 - no error
1132 static void
1133 prepare_server_struct_for_update(LEX_SERVER_OPTIONS *server_options,
1134 FOREIGN_SERVER *existing,
1135 FOREIGN_SERVER *altered)
1137 DBUG_ENTER("prepare_server_struct_for_update");
1139 altered->server_name= strdup_root(&mem, server_options->server_name);
1140 altered->server_name_length= server_options->server_name_length;
1141 DBUG_PRINT("info", ("existing name %s altered name %s",
1142 existing->server_name, altered->server_name));
1145 The logic here is this: is this value set AND is it different
1146 than the existing value?
1148 altered->host=
1149 (server_options->host && (strcmp(server_options->host, existing->host))) ?
1150 strdup_root(&mem, server_options->host) : 0;
1152 altered->db=
1153 (server_options->db && (strcmp(server_options->db, existing->db))) ?
1154 strdup_root(&mem, server_options->db) : 0;
1156 altered->username=
1157 (server_options->username &&
1158 (strcmp(server_options->username, existing->username))) ?
1159 strdup_root(&mem, server_options->username) : 0;
1161 altered->password=
1162 (server_options->password &&
1163 (strcmp(server_options->password, existing->password))) ?
1164 strdup_root(&mem, server_options->password) : 0;
1167 port is initialised to -1, so if unset, it will be -1
1169 altered->port= (server_options->port > -1 &&
1170 server_options->port != existing->port) ?
1171 server_options->port : -1;
1173 altered->socket=
1174 (server_options->socket &&
1175 (strcmp(server_options->socket, existing->socket))) ?
1176 strdup_root(&mem, server_options->socket) : 0;
1178 altered->scheme=
1179 (server_options->scheme &&
1180 (strcmp(server_options->scheme, existing->scheme))) ?
1181 strdup_root(&mem, server_options->scheme) : 0;
1183 altered->owner=
1184 (server_options->owner &&
1185 (strcmp(server_options->owner, existing->owner))) ?
1186 strdup_root(&mem, server_options->owner) : 0;
1188 DBUG_VOID_RETURN;
1193 SYNOPSIS
1194 servers_free()
1195 bool end
1197 NOTES
1199 RETURN VALUE
1200 void
1204 void servers_free(bool end)
1206 DBUG_ENTER("servers_free");
1207 if (!hash_inited(&servers_cache))
1208 DBUG_VOID_RETURN;
1209 if (!end)
1211 free_root(&mem, MYF(MY_MARK_BLOCKS_FREE));
1212 my_hash_reset(&servers_cache);
1213 DBUG_VOID_RETURN;
1215 rwlock_destroy(&THR_LOCK_servers);
1216 free_root(&mem,MYF(0));
1217 hash_free(&servers_cache);
1218 DBUG_VOID_RETURN;
1223 SYNOPSIS
1225 clone_server(MEM_ROOT *mem_root, FOREIGN_SERVER *orig, FOREIGN_SERVER *buff)
1227 Create a clone of FOREIGN_SERVER. If the supplied mem_root is of
1228 thd->mem_root then the copy is automatically disposed at end of statement.
1230 NOTES
1232 ARGS
1233 MEM_ROOT pointer (strings are copied into this mem root)
1234 FOREIGN_SERVER pointer (made a copy of)
1235 FOREIGN_SERVER buffer (if not-NULL, this pointer is returned)
1237 RETURN VALUE
1238 FOREIGN_SEVER pointer (copy of one supplied FOREIGN_SERVER)
1241 static FOREIGN_SERVER *clone_server(MEM_ROOT *mem, const FOREIGN_SERVER *server,
1242 FOREIGN_SERVER *buffer)
1244 DBUG_ENTER("sql_server.cc:clone_server");
1246 if (!buffer)
1247 buffer= (FOREIGN_SERVER *) alloc_root(mem, sizeof(FOREIGN_SERVER));
1249 buffer->server_name= strmake_root(mem, server->server_name,
1250 server->server_name_length);
1251 buffer->port= server->port;
1252 buffer->server_name_length= server->server_name_length;
1254 /* TODO: We need to examine which of these can really be NULL */
1255 buffer->db= server->db ? strdup_root(mem, server->db) : NULL;
1256 buffer->scheme= server->scheme ? strdup_root(mem, server->scheme) : NULL;
1257 buffer->username= server->username? strdup_root(mem, server->username): NULL;
1258 buffer->password= server->password? strdup_root(mem, server->password): NULL;
1259 buffer->socket= server->socket ? strdup_root(mem, server->socket) : NULL;
1260 buffer->owner= server->owner ? strdup_root(mem, server->owner) : NULL;
1261 buffer->host= server->host ? strdup_root(mem, server->host) : NULL;
1263 DBUG_RETURN(buffer);
1269 SYNOPSIS
1270 get_server_by_name()
1271 const char *server_name
1273 NOTES
1275 RETURN VALUE
1276 FOREIGN_SERVER *
1280 FOREIGN_SERVER *get_server_by_name(MEM_ROOT *mem, const char *server_name,
1281 FOREIGN_SERVER *buff)
1283 size_t server_name_length;
1284 FOREIGN_SERVER *server;
1285 DBUG_ENTER("get_server_by_name");
1286 DBUG_PRINT("info", ("server_name %s", server_name));
1288 server_name_length= strlen(server_name);
1290 if (! server_name || !strlen(server_name))
1292 DBUG_PRINT("info", ("server_name not defined!"));
1293 DBUG_RETURN((FOREIGN_SERVER *)NULL);
1296 DBUG_PRINT("info", ("locking servers_cache"));
1297 rw_rdlock(&THR_LOCK_servers);
1298 if (!(server= (FOREIGN_SERVER *) hash_search(&servers_cache,
1299 (uchar*) server_name,
1300 server_name_length)))
1302 DBUG_PRINT("info", ("server_name %s length %u not found!",
1303 server_name, (unsigned) server_name_length));
1304 server= (FOREIGN_SERVER *) NULL;
1306 /* otherwise, make copy of server */
1307 else
1308 server= clone_server(mem, server, buff);
1310 DBUG_PRINT("info", ("unlocking servers_cache"));
1311 rw_unlock(&THR_LOCK_servers);
1312 DBUG_RETURN(server);