MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
sql_servers.cc
1 /* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
2 
3  This program is free software; you can redistribute it and/or modify
4  it under the terms of the GNU General Public License as published by
5  the Free Software Foundation; version 2 of the License.
6 
7  This program is distributed in the hope that it will be useful,
8  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  GNU General Public License for more details.
11 
12  You should have received a copy of the GNU General Public License
13  along with this program; if not, write to the Free Software Foundation,
14  51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
15 
16 
17 /*
18  The servers are saved in the system table "servers"
19 
20  Currently, when the user performs an ALTER SERVER or a DROP SERVER
21  operation, it will cause all open tables which refer to the named
22  server connection to be flushed. This may cause some undesirable
23  behaviour with regard to currently running transactions. It is
24  expected that the DBA knows what s/he is doing when s/he performs
25  the ALTER SERVER or DROP SERVER operation.
26 
27  TODO:
28  It is desirable for us to implement a callback mechanism instead where
29  callbacks can be registered for specific server protocols. The callback
30  will be fired when such a server name has been created/altered/dropped
31  or when statistics are to be gathered such as how many actual connections.
32  Storage engines etc will be able to make use of the callback so that
33  currently running transactions etc will not be disrupted.
34 */
35 
36 #include "sql_priv.h"
37 #include "sql_servers.h"
38 #include "unireg.h"
39 #include "sql_base.h" // close_mysql_tables
40 #include "records.h" // init_read_record, end_read_record
41 #include "hash_filo.h"
42 #include <m_ctype.h>
43 #include <stdarg.h>
44 #include "sp_head.h"
45 #include "sp.h"
46 #include "transaction.h"
47 #include "lock.h" // MYSQL_LOCK_IGNORE_TIMEOUT
48 
49 /*
50  We only use 1 mutex to guard the data structures - THR_LOCK_servers.
51  Read locked when only reading data and write-locked for all other access.
52 */
53 
54 static HASH servers_cache;
55 static MEM_ROOT mem;
56 static mysql_rwlock_t THR_LOCK_servers;
57 
58 static bool get_server_from_table_to_cache(TABLE *table);
59 
60 /* insert functions */
61 static bool insert_server(THD *thd, FOREIGN_SERVER *server_options);
62 static bool insert_server_record(TABLE *table, FOREIGN_SERVER *server);
63 static bool insert_server_record_into_cache(FOREIGN_SERVER *server);
64 static FOREIGN_SERVER *
65 prepare_server_struct_for_insert(LEX_SERVER_OPTIONS *server_options);
66 /* drop functions */
67 static bool delete_server_record(TABLE *table,
68  char *server_name,
69  size_t server_name_length,
70  bool if_exists);
71 static bool delete_server_record_in_cache(LEX_SERVER_OPTIONS *server_options,
72  bool if_exists);
73 
74 /* update functions */
75 static void prepare_server_struct_for_update(LEX_SERVER_OPTIONS *server_options,
76  FOREIGN_SERVER *existing,
77  FOREIGN_SERVER *altered);
78 static bool update_server(THD *thd, FOREIGN_SERVER *existing,
79  FOREIGN_SERVER *altered);
80 static bool update_server_record(TABLE *table, FOREIGN_SERVER *server);
81 static bool update_server_record_in_cache(FOREIGN_SERVER *existing,
82  FOREIGN_SERVER *altered);
83 /* utility functions */
84 static void merge_server_struct(FOREIGN_SERVER *from, FOREIGN_SERVER *to);
85 
86 
87 
88 static uchar *servers_cache_get_key(FOREIGN_SERVER *server, size_t *length,
89  my_bool not_used __attribute__((unused)))
90 {
91  DBUG_ENTER("servers_cache_get_key");
92  DBUG_PRINT("info", ("server_name_length %d server_name %s",
93  server->server_name_length,
94  server->server_name));
95 
96  *length= (uint) server->server_name_length;
97  DBUG_RETURN((uchar*) server->server_name);
98 }
99 
100 #ifdef HAVE_PSI_INTERFACE
101 static PSI_rwlock_key key_rwlock_THR_LOCK_servers;
102 
103 static PSI_rwlock_info all_servers_cache_rwlocks[]=
104 {
105  { &key_rwlock_THR_LOCK_servers, "THR_LOCK_servers", PSI_FLAG_GLOBAL}
106 };
107 
108 static void init_servers_cache_psi_keys(void)
109 {
110  const char* category= "sql";
111  int count;
112 
113  count= array_elements(all_servers_cache_rwlocks);
114  mysql_rwlock_register(category, all_servers_cache_rwlocks, count);
115 }
116 #endif /* HAVE_PSI_INTERFACE */
117 
118 /*
119  Initialize structures responsible for servers used in federated
120  server scheme information for them from the server
121  table in the 'mysql' database.
122 
123  SYNOPSIS
124  servers_init()
125  dont_read_server_table TRUE if we want to skip loading data from
126  server table and disable privilege checking.
127 
128  NOTES
129  This function is mostly responsible for preparatory steps, main work
130  on initialization and grants loading is done in servers_reload().
131 
132  RETURN VALUES
133  0 ok
134  1 Could not initialize servers
135 */
136 
137 bool servers_init(bool dont_read_servers_table)
138 {
139  THD *thd;
140  bool return_val= FALSE;
141  DBUG_ENTER("servers_init");
142 
143 #ifdef HAVE_PSI_INTERFACE
144  init_servers_cache_psi_keys();
145 #endif
146 
147  /* init the mutex */
148  if (mysql_rwlock_init(key_rwlock_THR_LOCK_servers, &THR_LOCK_servers))
149  DBUG_RETURN(TRUE);
150 
151  /* initialise our servers cache */
152  if (my_hash_init(&servers_cache, system_charset_info, 32, 0, 0,
153  (my_hash_get_key) servers_cache_get_key, 0, 0))
154  {
155  return_val= TRUE; /* we failed, out of memory? */
156  goto end;
157  }
158 
159  /* Initialize the mem root for data */
160  init_sql_alloc(&mem, ACL_ALLOC_BLOCK_SIZE, 0);
161 
162  if (dont_read_servers_table)
163  goto end;
164 
165  /*
166  To be able to run this from boot, we allocate a temporary THD
167  */
168  if (!(thd=new THD))
169  DBUG_RETURN(TRUE);
170  thd->thread_stack= (char*) &thd;
171  thd->store_globals();
172  /*
173  It is safe to call servers_reload() since servers_* arrays and hashes which
174  will be freed there are global static objects and thus are initialized
175  by zeros at startup.
176  */
177  return_val= servers_reload(thd);
178  delete thd;
179  /* Remember that we don't have a THD */
180  my_pthread_setspecific_ptr(THR_THD, 0);
181 
182 end:
183  DBUG_RETURN(return_val);
184 }
185 
186 /*
187  Initialize server structures
188 
189  SYNOPSIS
190  servers_load()
191  thd Current thread
192  tables List containing open "mysql.servers"
193 
194  RETURN VALUES
195  FALSE Success
196  TRUE Error
197 
198  TODO
199  Revert back to old list if we failed to load new one.
200 */
201 
202 static bool servers_load(THD *thd, TABLE_LIST *tables)
203 {
204  TABLE *table;
205  READ_RECORD read_record_info;
206  bool return_val= TRUE;
207  DBUG_ENTER("servers_load");
208 
209  my_hash_reset(&servers_cache);
210  free_root(&mem, MYF(0));
211  init_sql_alloc(&mem, ACL_ALLOC_BLOCK_SIZE, 0);
212 
213  if (init_read_record(&read_record_info, thd, table=tables[0].table,
214  NULL, 1, 1, FALSE))
215  DBUG_RETURN(TRUE);
216 
217  while (!(read_record_info.read_record(&read_record_info)))
218  {
219  /* return_val is already TRUE, so no need to set */
220  if ((get_server_from_table_to_cache(table)))
221  goto end;
222  }
223 
224  return_val= FALSE;
225 
226 end:
227  end_read_record(&read_record_info);
228  DBUG_RETURN(return_val);
229 }
230 
231 
232 /*
233  Forget current servers cache and read new servers
234  from the conneciton table.
235 
236  SYNOPSIS
237  servers_reload()
238  thd Current thread
239 
240  NOTE
241  All tables of calling thread which were open and locked by LOCK TABLES
242  statement will be unlocked and closed.
243  This function is also used for initialization of structures responsible
244  for user/db-level privilege checking.
245 
246  RETURN VALUE
247  FALSE Success
248  TRUE Failure
249 */
250 
251 bool servers_reload(THD *thd)
252 {
253  TABLE_LIST tables[1];
254  bool return_val= TRUE;
255  DBUG_ENTER("servers_reload");
256 
257  DBUG_PRINT("info", ("locking servers_cache"));
258  mysql_rwlock_wrlock(&THR_LOCK_servers);
259 
260  tables[0].init_one_table("mysql", 5, "servers", 7, "servers", TL_READ);
261 
262  if (open_and_lock_tables(thd, tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT))
263  {
264  /*
265  Execution might have been interrupted; only print the error message
266  if an error condition has been raised.
267  */
268  if (thd->get_stmt_da()->is_error())
269  sql_print_error("Can't open and lock privilege tables: %s",
270  thd->get_stmt_da()->message());
271  return_val= FALSE;
272  goto end;
273  }
274 
275  if ((return_val= servers_load(thd, tables)))
276  { // Error. Revert to old list
277  /* blast, for now, we have no servers, discuss later way to preserve */
278 
279  DBUG_PRINT("error",("Reverting to old privileges"));
280  servers_free();
281  }
282 
283 end:
284  close_mysql_tables(thd);
285  DBUG_PRINT("info", ("unlocking servers_cache"));
286  mysql_rwlock_unlock(&THR_LOCK_servers);
287  DBUG_RETURN(return_val);
288 }
289 
290 
291 /*
292  Initialize structures responsible for servers used in federated
293  server scheme information for them from the server
294  table in the 'mysql' database.
295 
296  SYNOPSIS
297  get_server_from_table_to_cache()
298  TABLE *table open table pointer
299 
300 
301  NOTES
302  This function takes a TABLE pointer (pointing to an opened
303  table). With this open table, a FOREIGN_SERVER struct pointer
304  is allocated into root memory, then each member of the FOREIGN_SERVER
305  struct is populated. A char pointer takes the return value of get_field
306  for each column we're interested in obtaining, and if that pointer
307  isn't 0x0, the FOREIGN_SERVER member is set to that value, otherwise,
308  is set to the value of an empty string, since get_field would set it to
309  0x0 if the column's value is empty, even if the default value for that
310  column is NOT NULL.
311 
312  RETURN VALUES
313  0 ok
314  1 could not insert server struct into global servers cache
315 */
316 
317 static bool
318 get_server_from_table_to_cache(TABLE *table)
319 {
320  /* alloc a server struct */
321  char *ptr;
322  char * const blank= (char*)"";
323  FOREIGN_SERVER *server= (FOREIGN_SERVER *)alloc_root(&mem,
324  sizeof(FOREIGN_SERVER));
325  DBUG_ENTER("get_server_from_table_to_cache");
326  table->use_all_columns();
327 
328  /* get each field into the server struct ptr */
329  ptr= get_field(&mem, table->field[0]);
330  server->server_name= ptr ? ptr : blank;
331  server->server_name_length= (uint) strlen(server->server_name);
332  ptr= get_field(&mem, table->field[1]);
333  server->host= ptr ? ptr : blank;
334  ptr= get_field(&mem, table->field[2]);
335  server->db= ptr ? ptr : blank;
336  ptr= get_field(&mem, table->field[3]);
337  server->username= ptr ? ptr : blank;
338  ptr= get_field(&mem, table->field[4]);
339  server->password= ptr ? ptr : blank;
340  ptr= get_field(&mem, table->field[5]);
341  server->sport= ptr ? ptr : blank;
342 
343  server->port= server->sport ? atoi(server->sport) : 0;
344 
345  ptr= get_field(&mem, table->field[6]);
346  server->socket= ptr && strlen(ptr) ? ptr : blank;
347  ptr= get_field(&mem, table->field[7]);
348  server->scheme= ptr ? ptr : blank;
349  ptr= get_field(&mem, table->field[8]);
350  server->owner= ptr ? ptr : blank;
351  DBUG_PRINT("info", ("server->server_name %s", server->server_name));
352  DBUG_PRINT("info", ("server->host %s", server->host));
353  DBUG_PRINT("info", ("server->db %s", server->db));
354  DBUG_PRINT("info", ("server->username %s", server->username));
355  DBUG_PRINT("info", ("server->password %s", server->password));
356  DBUG_PRINT("info", ("server->socket %s", server->socket));
357  if (my_hash_insert(&servers_cache, (uchar*) server))
358  {
359  DBUG_PRINT("info", ("had a problem inserting server %s at %lx",
360  server->server_name, (long unsigned int) server));
361  // error handling needed here
362  DBUG_RETURN(TRUE);
363  }
364  DBUG_RETURN(FALSE);
365 }
366 
367 
382 static bool insert_server(THD *thd, FOREIGN_SERVER *server)
383 {
384  DBUG_ENTER("insert_server");
385 
386  TABLE_LIST tables;
387  tables.init_one_table("mysql", 5, "servers", 7, "servers", TL_WRITE);
388 
389  /* need to open before acquiring THR_LOCK_plugin or it will deadlock */
390  TABLE *table= open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT);
391  if (!table)
392  DBUG_RETURN(true);
393 
394  /* insert the server into the table and the cache */
395  bool error= (insert_server_record(table, server) ||
396  insert_server_record_into_cache(server));
397 
398  close_mysql_tables(thd);
399 
400  DBUG_RETURN(error);
401 }
402 
403 
416 static bool insert_server_record_into_cache(FOREIGN_SERVER *server)
417 {
418  DBUG_ENTER("insert_server_record_into_cache");
419  /*
420  We succeded in insertion of the server to the table, now insert
421  the server to the cache
422  */
423  DBUG_PRINT("info", ("inserting server %s at %lx, length %d",
424  server->server_name, (long unsigned int) server,
425  server->server_name_length));
426  if (my_hash_insert(&servers_cache, (uchar*) server))
427  {
428  DBUG_PRINT("info", ("had a problem inserting server %s at %lx",
429  server->server_name, (long unsigned int) server));
430  my_error(ER_OUT_OF_RESOURCES, MYF(0));
431  DBUG_RETURN(true);
432  }
433 
434  DBUG_RETURN(false);
435 }
436 
437 
438 /*
439  SYNOPSIS
440  store_server_fields()
441  TABLE *table
442  FOREIGN_SERVER *server
443 
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
449 
450  RETURN VALUE
451  VOID
452 
453 */
454 
455 static void
456 store_server_fields(TABLE *table, FOREIGN_SERVER *server)
457 {
458 
459  table->use_all_columns();
460  /*
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)
463 
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
467  */
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);
482 
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);
492 }
493 
512 static bool insert_server_record(TABLE *table, FOREIGN_SERVER *server)
513 {
514  int error;
515  DBUG_ENTER("insert_server_record");
516  tmp_disable_binlog(table->in_use);
517  table->use_all_columns();
518 
519  empty_record(table);
520 
521  /* set the field that's the PK to the value we're looking for */
522  table->field[0]->store(server->server_name,
523  server->server_name_length,
524  system_charset_info);
525 
526  /* read index until record is that specified in server_name */
527  error= table->file->ha_index_read_idx_map(table->record[0], 0,
528  (uchar *)table->field[0]->ptr,
529  HA_WHOLE_KEY,
530  HA_READ_KEY_EXACT);
531  if (error)
532  {
533  /* if not found, err */
534  if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
535  table->file->print_error(error, MYF(0));
536 
537  /* store each field to be inserted */
538  store_server_fields(table, server);
539 
540  DBUG_PRINT("info",("record for server '%s' not found!",
541  server->server_name));
542  /* write/insert the new server */
543  if ((error=table->file->ha_write_row(table->record[0])))
544  table->file->print_error(error, MYF(0));
545  }
546  else
547  {
548  my_error(ER_FOREIGN_SERVER_EXISTS, MYF(0), server->server_name);
549  error= 1;
550  }
551 
552  reenable_binlog(table->in_use);
553  DBUG_RETURN(error != 0);
554 }
555 
556 
576 bool drop_server(THD *thd, LEX_SERVER_OPTIONS *server_options, bool if_exists)
577 {
578  DBUG_ENTER("drop_server");
579  DBUG_PRINT("info", ("server name server->server_name %s",
580  server_options->server_name));
581 
582  TABLE_LIST tables;
583  tables.init_one_table("mysql", 5, "servers", 7, "servers", TL_WRITE);
584 
585  mysql_rwlock_wrlock(&THR_LOCK_servers);
586 
587  TABLE *table= open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT);
588  if (!table)
589  {
590  mysql_rwlock_unlock(&THR_LOCK_servers);
591  DBUG_RETURN(true);
592  }
593 
594  LEX_STRING name= { server_options->server_name,
595  server_options->server_name_length };
596 
597  bool error= (delete_server_record_in_cache(server_options, if_exists) ||
598  delete_server_record(table, name.str, name.length, if_exists));
599 
600  /* close the servers table before we call closed_cached_connection_tables */
601  close_mysql_tables(thd);
602 
603  if (close_cached_connection_tables(thd, &name))
604  {
605  push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
606  ER_UNKNOWN_ERROR, "Server connection in use");
607  }
608 
609  mysql_rwlock_unlock(&THR_LOCK_servers);
610  DBUG_RETURN(error || thd->killed);
611 }
612 
613 
628 static bool delete_server_record_in_cache(LEX_SERVER_OPTIONS *server_options,
629  bool if_exists)
630 {
631  DBUG_ENTER("delete_server_record_in_cache");
632  DBUG_PRINT("info",("trying to obtain server name %s length %d",
633  server_options->server_name,
634  server_options->server_name_length));
635 
636  FOREIGN_SERVER *server=
637  (FOREIGN_SERVER *)my_hash_search(&servers_cache,
638  (uchar*) server_options->server_name,
639  server_options->server_name_length);
640  if (!server)
641  {
642  DBUG_PRINT("info", ("server_name %s length %d not found!",
643  server_options->server_name,
644  server_options->server_name_length));
645  if (!if_exists)
646  my_error(ER_FOREIGN_SERVER_DOESNT_EXIST, MYF(0),
647  server_options->server_name);
648  DBUG_RETURN(true);
649  }
650  /*
651  We succeded in deletion of the server to the table, now delete
652  the server from the cache
653  */
654  DBUG_PRINT("info",("deleting server %s length %d",
655  server->server_name,
656  server->server_name_length));
657 
658  my_hash_delete(&servers_cache, (uchar*) server);
659 
660  DBUG_RETURN(false);
661 }
662 
663 
685 bool update_server(THD *thd, FOREIGN_SERVER *existing, FOREIGN_SERVER *altered)
686 {
687  DBUG_ENTER("update_server");
688 
689  TABLE_LIST tables;
690  tables.init_one_table("mysql", 5, "servers", 7, "servers", TL_WRITE);
691 
692  TABLE *table= open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT);
693  if (!table)
694  DBUG_RETURN(true);
695 
696  bool error= (update_server_record(table, altered) ||
697  update_server_record_in_cache(existing, altered));
698 
699  /* Perform a reload so we don't have a 'hole' in our mem_root */
700  servers_load(thd, &tables);
701 
702  close_mysql_tables(thd);
703 
704  DBUG_RETURN(error);
705 }
706 
707 
726 bool update_server_record_in_cache(FOREIGN_SERVER *existing,
727  FOREIGN_SERVER *altered)
728 {
729  DBUG_ENTER("update_server_record_in_cache");
730 
731  /*
732  update the members that haven't been change in the altered server struct
733  with the values of the existing server struct
734  */
735  merge_server_struct(existing, altered);
736 
737  /* delete the existing server struct from the server cache */
738  my_hash_delete(&servers_cache, (uchar*)existing);
739 
740  /* Insert the altered server struct into the server cache */
741  if (my_hash_insert(&servers_cache, (uchar*)altered))
742  {
743  DBUG_PRINT("info", ("had a problem inserting server %s at %lx",
744  altered->server_name, (long unsigned int) altered));
745  my_error(ER_OUT_OF_RESOURCES, MYF(0));
746  DBUG_RETURN(true);
747  }
748 
749  DBUG_RETURN(false);
750 }
751 
752 
753 /*
754 
755  SYNOPSIS
756  merge_server_struct()
757  FOREIGN_SERVER *from
758  FOREIGN_SERVER *to
759 
760  NOTES
761  This function takes as its arguments two pointers each to an allocated
762  FOREIGN_SERVER struct. The first FOREIGN_SERVER struct represents the struct
763  that we will obtain values from (hence the name "from"), the second
764  FOREIGN_SERVER struct represents which FOREIGN_SERVER struct we will be
765  "copying" any members that have a value to (hence the name "to")
766 
767  RETURN VALUE
768  VOID
769 
770 */
771 
772 void merge_server_struct(FOREIGN_SERVER *from, FOREIGN_SERVER *to)
773 {
774  DBUG_ENTER("merge_server_struct");
775  if (!to->host)
776  to->host= strdup_root(&mem, from->host);
777  if (!to->db)
778  to->db= strdup_root(&mem, from->db);
779  if (!to->username)
780  to->username= strdup_root(&mem, from->username);
781  if (!to->password)
782  to->password= strdup_root(&mem, from->password);
783  if (to->port == -1)
784  to->port= from->port;
785  if (!to->socket && from->socket)
786  to->socket= strdup_root(&mem, from->socket);
787  if (!to->scheme && from->scheme)
788  to->scheme= strdup_root(&mem, from->scheme);
789  if (!to->owner)
790  to->owner= strdup_root(&mem, from->owner);
791 
792  DBUG_VOID_RETURN;
793 }
794 
795 
814 static bool update_server_record(TABLE *table, FOREIGN_SERVER *server)
815 {
816  int error;
817  DBUG_ENTER("update_server_record");
818  tmp_disable_binlog(table->in_use);
819  table->use_all_columns();
820  /* set the field that's the PK to the value we're looking for */
821  table->field[0]->store(server->server_name,
822  server->server_name_length,
823  system_charset_info);
824 
825  error= table->file->ha_index_read_idx_map(table->record[0], 0,
826  (uchar *)table->field[0]->ptr,
827  ~(longlong)0,
828  HA_READ_KEY_EXACT);
829  if (error)
830  {
831  if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
832  table->file->print_error(error, MYF(0));
833  DBUG_PRINT("info",("server not found!"));
834  my_error(ER_FOREIGN_SERVER_DOESNT_EXIST, MYF(0), server->server_name);
835  }
836  else
837  {
838  /* ok, so we can update since the record exists in the table */
839  store_record(table,record[1]);
840  store_server_fields(table, server);
841  if ((error=table->file->ha_update_row(table->record[1],
842  table->record[0])) &&
843  error != HA_ERR_RECORD_IS_THE_SAME)
844  {
845  table->file->print_error(error, MYF(0));
846  DBUG_PRINT("info",("problems with ha_update_row %d", error));
847  }
848  else
849  error= 0;
850  }
851 
852  reenable_binlog(table->in_use);
853  DBUG_RETURN(error != 0);
854 }
855 
856 
867 static bool delete_server_record(TABLE *table, char *server_name,
868  size_t server_name_length, bool if_exists)
869 {
870  int error;
871  DBUG_ENTER("delete_server_record");
872  tmp_disable_binlog(table->in_use);
873  table->use_all_columns();
874 
875  /* set the field that's the PK to the value we're looking for */
876  table->field[0]->store(server_name, server_name_length, system_charset_info);
877 
878  error= table->file->ha_index_read_idx_map(table->record[0], 0,
879  (uchar *)table->field[0]->ptr,
880  HA_WHOLE_KEY,
881  HA_READ_KEY_EXACT);
882  if (error)
883  {
884  if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
885  table->file->print_error(error, MYF(0));
886  DBUG_PRINT("info",("server not found!"));
887  if (!if_exists)
888  my_error(ER_FOREIGN_SERVER_DOESNT_EXIST, MYF(0), server_name);
889  }
890  else
891  {
892  if ((error= table->file->ha_delete_row(table->record[0])))
893  table->file->print_error(error, MYF(0));
894  }
895 
896  reenable_binlog(table->in_use);
897  DBUG_RETURN(error != 0);
898 }
899 
900 
909 bool create_server(THD *thd, LEX_SERVER_OPTIONS *server_options)
910 {
911  bool error= true;
912  FOREIGN_SERVER *server;
913 
914  DBUG_ENTER("create_server");
915  DBUG_PRINT("info", ("server_options->server_name %s",
916  server_options->server_name));
917 
918  mysql_rwlock_wrlock(&THR_LOCK_servers);
919 
920  /* hit the memory first */
921  if (my_hash_search(&servers_cache, (uchar*) server_options->server_name,
922  server_options->server_name_length))
923  {
924  my_error(ER_FOREIGN_SERVER_EXISTS, MYF(0), server_options->server_name);
925  goto end;
926  }
927 
928  server= prepare_server_struct_for_insert(server_options);
929  if (!server)
930  {
931  my_error(ER_OUT_OF_RESOURCES, MYF(0));
932  goto end;
933  }
934 
935  error= insert_server(thd, server);
936 
937 end:
938  mysql_rwlock_unlock(&THR_LOCK_servers);
939  DBUG_RETURN(error || thd->killed);
940 }
941 
942 
951 bool alter_server(THD *thd, LEX_SERVER_OPTIONS *server_options)
952 {
953  bool error= true;
954  FOREIGN_SERVER *altered, *existing;
955  LEX_STRING name= { server_options->server_name,
956  server_options->server_name_length };
957 
958  DBUG_ENTER("alter_server");
959  DBUG_PRINT("info", ("server_options->server_name %s",
960  server_options->server_name));
961 
962  mysql_rwlock_wrlock(&THR_LOCK_servers);
963 
964  existing= (FOREIGN_SERVER *) my_hash_search(&servers_cache,
965  (uchar*) name.str,
966  name.length);
967  if (!existing)
968  {
969  my_error(ER_FOREIGN_SERVER_DOESNT_EXIST, MYF(0), name.str);
970  goto end;
971  }
972 
973  altered= (FOREIGN_SERVER *)alloc_root(&mem, sizeof(FOREIGN_SERVER));
974 
975  prepare_server_struct_for_update(server_options, existing, altered);
976 
977  error= update_server(thd, existing, altered);
978 
979  if (close_cached_connection_tables(thd, &name))
980  {
981  push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
982  ER_UNKNOWN_ERROR, "Server connection in use");
983  }
984 
985 end:
986  mysql_rwlock_unlock(&THR_LOCK_servers);
987  DBUG_RETURN(error || thd->killed);
988 }
989 
990 
991 /*
992 
993  SYNOPSIS
994  prepare_server_struct_for_insert()
995  LEX_SERVER_OPTIONS *server_options
996 
997  NOTES
998  As FOREIGN_SERVER members are allocated on mem_root, we do not need to
999  free them in case of error.
1000 
1001  RETURN VALUE
1002  On success filled FOREIGN_SERVER, or NULL in case out of memory.
1003 
1004 */
1005 
1006 static FOREIGN_SERVER *
1007 prepare_server_struct_for_insert(LEX_SERVER_OPTIONS *server_options)
1008 {
1009  char *unset_ptr= (char*)"";
1010  FOREIGN_SERVER *server;
1011  DBUG_ENTER("prepare_server_struct");
1012 
1013  if (!(server= (FOREIGN_SERVER *)alloc_root(&mem, sizeof(FOREIGN_SERVER))))
1014  DBUG_RETURN(NULL); /* purecov: inspected */
1015 
1016  /* these two MUST be set */
1017  if (!(server->server_name= strdup_root(&mem, server_options->server_name)))
1018  DBUG_RETURN(NULL); /* purecov: inspected */
1019  server->server_name_length= server_options->server_name_length;
1020 
1021  if (!(server->host= server_options->host ?
1022  strdup_root(&mem, server_options->host) : unset_ptr))
1023  DBUG_RETURN(NULL); /* purecov: inspected */
1024 
1025  if (!(server->db= server_options->db ?
1026  strdup_root(&mem, server_options->db) : unset_ptr))
1027  DBUG_RETURN(NULL); /* purecov: inspected */
1028 
1029  if (!(server->username= server_options->username ?
1030  strdup_root(&mem, server_options->username) : unset_ptr))
1031  DBUG_RETURN(NULL); /* purecov: inspected */
1032 
1033  if (!(server->password= server_options->password ?
1034  strdup_root(&mem, server_options->password) : unset_ptr))
1035  DBUG_RETURN(NULL); /* purecov: inspected */
1036 
1037  /* set to 0 if not specified */
1038  server->port= server_options->port > -1 ?
1039  server_options->port : 0;
1040 
1041  if (!(server->socket= server_options->socket ?
1042  strdup_root(&mem, server_options->socket) : unset_ptr))
1043  DBUG_RETURN(NULL); /* purecov: inspected */
1044 
1045  if (!(server->scheme= server_options->scheme ?
1046  strdup_root(&mem, server_options->scheme) : unset_ptr))
1047  DBUG_RETURN(NULL); /* purecov: inspected */
1048 
1049  if (!(server->owner= server_options->owner ?
1050  strdup_root(&mem, server_options->owner) : unset_ptr))
1051  DBUG_RETURN(NULL); /* purecov: inspected */
1052 
1053  DBUG_RETURN(server);
1054 }
1055 
1056 /*
1057 
1058  SYNOPSIS
1059  prepare_server_struct_for_update()
1060  LEX_SERVER_OPTIONS *server_options
1061 
1062  NOTES
1063 
1064  RETURN VALUE
1065  0 - no error
1066 
1067 */
1068 
1069 static void
1070 prepare_server_struct_for_update(LEX_SERVER_OPTIONS *server_options,
1071  FOREIGN_SERVER *existing,
1072  FOREIGN_SERVER *altered)
1073 {
1074  DBUG_ENTER("prepare_server_struct_for_update");
1075 
1076  altered->server_name= strdup_root(&mem, server_options->server_name);
1077  altered->server_name_length= server_options->server_name_length;
1078  DBUG_PRINT("info", ("existing name %s altered name %s",
1079  existing->server_name, altered->server_name));
1080 
1081  /*
1082  The logic here is this: is this value set AND is it different
1083  than the existing value?
1084  */
1085  altered->host=
1086  (server_options->host && (strcmp(server_options->host, existing->host))) ?
1087  strdup_root(&mem, server_options->host) : 0;
1088 
1089  altered->db=
1090  (server_options->db && (strcmp(server_options->db, existing->db))) ?
1091  strdup_root(&mem, server_options->db) : 0;
1092 
1093  altered->username=
1094  (server_options->username &&
1095  (strcmp(server_options->username, existing->username))) ?
1096  strdup_root(&mem, server_options->username) : 0;
1097 
1098  altered->password=
1099  (server_options->password &&
1100  (strcmp(server_options->password, existing->password))) ?
1101  strdup_root(&mem, server_options->password) : 0;
1102 
1103  /*
1104  port is initialised to -1, so if unset, it will be -1
1105  */
1106  altered->port= (server_options->port > -1 &&
1107  server_options->port != existing->port) ?
1108  server_options->port : -1;
1109 
1110  altered->socket=
1111  (server_options->socket &&
1112  (strcmp(server_options->socket, existing->socket))) ?
1113  strdup_root(&mem, server_options->socket) : 0;
1114 
1115  altered->scheme=
1116  (server_options->scheme &&
1117  (strcmp(server_options->scheme, existing->scheme))) ?
1118  strdup_root(&mem, server_options->scheme) : 0;
1119 
1120  altered->owner=
1121  (server_options->owner &&
1122  (strcmp(server_options->owner, existing->owner))) ?
1123  strdup_root(&mem, server_options->owner) : 0;
1124 
1125  DBUG_VOID_RETURN;
1126 }
1127 
1128 /*
1129 
1130  SYNOPSIS
1131  servers_free()
1132  bool end
1133 
1134  NOTES
1135 
1136  RETURN VALUE
1137  void
1138 
1139 */
1140 
1141 void servers_free(bool end)
1142 {
1143  DBUG_ENTER("servers_free");
1144  if (!my_hash_inited(&servers_cache))
1145  DBUG_VOID_RETURN;
1146  if (!end)
1147  {
1148  free_root(&mem, MYF(MY_MARK_BLOCKS_FREE));
1149  my_hash_reset(&servers_cache);
1150  DBUG_VOID_RETURN;
1151  }
1152  mysql_rwlock_destroy(&THR_LOCK_servers);
1153  free_root(&mem,MYF(0));
1154  my_hash_free(&servers_cache);
1155  DBUG_VOID_RETURN;
1156 }
1157 
1158 
1159 /*
1160  SYNOPSIS
1161 
1162  clone_server(MEM_ROOT *mem_root, FOREIGN_SERVER *orig, FOREIGN_SERVER *buff)
1163 
1164  Create a clone of FOREIGN_SERVER. If the supplied mem_root is of
1165  thd->mem_root then the copy is automatically disposed at end of statement.
1166 
1167  NOTES
1168 
1169  ARGS
1170  MEM_ROOT pointer (strings are copied into this mem root)
1171  FOREIGN_SERVER pointer (made a copy of)
1172  FOREIGN_SERVER buffer (if not-NULL, this pointer is returned)
1173 
1174  RETURN VALUE
1175  FOREIGN_SEVER pointer (copy of one supplied FOREIGN_SERVER)
1176 */
1177 
1178 static FOREIGN_SERVER *clone_server(MEM_ROOT *mem, const FOREIGN_SERVER *server,
1179  FOREIGN_SERVER *buffer)
1180 {
1181  DBUG_ENTER("sql_server.cc:clone_server");
1182 
1183  if (!buffer)
1184  buffer= (FOREIGN_SERVER *) alloc_root(mem, sizeof(FOREIGN_SERVER));
1185 
1186  buffer->server_name= strmake_root(mem, server->server_name,
1187  server->server_name_length);
1188  buffer->port= server->port;
1189  buffer->server_name_length= server->server_name_length;
1190 
1191  /* TODO: We need to examine which of these can really be NULL */
1192  buffer->db= server->db ? strdup_root(mem, server->db) : NULL;
1193  buffer->scheme= server->scheme ? strdup_root(mem, server->scheme) : NULL;
1194  buffer->username= server->username? strdup_root(mem, server->username): NULL;
1195  buffer->password= server->password? strdup_root(mem, server->password): NULL;
1196  buffer->socket= server->socket ? strdup_root(mem, server->socket) : NULL;
1197  buffer->owner= server->owner ? strdup_root(mem, server->owner) : NULL;
1198  buffer->host= server->host ? strdup_root(mem, server->host) : NULL;
1199 
1200  DBUG_RETURN(buffer);
1201 }
1202 
1203 
1204 /*
1205 
1206  SYNOPSIS
1207  get_server_by_name()
1208  const char *server_name
1209 
1210  NOTES
1211 
1212  RETURN VALUE
1213  FOREIGN_SERVER *
1214 
1215 */
1216 
1217 FOREIGN_SERVER *get_server_by_name(MEM_ROOT *mem, const char *server_name,
1218  FOREIGN_SERVER *buff)
1219 {
1220  size_t server_name_length;
1221  FOREIGN_SERVER *server;
1222  DBUG_ENTER("get_server_by_name");
1223  DBUG_PRINT("info", ("server_name %s", server_name));
1224 
1225  server_name_length= strlen(server_name);
1226 
1227  if (! server_name || !strlen(server_name))
1228  {
1229  DBUG_PRINT("info", ("server_name not defined!"));
1230  DBUG_RETURN((FOREIGN_SERVER *)NULL);
1231  }
1232 
1233  DBUG_PRINT("info", ("locking servers_cache"));
1234  mysql_rwlock_rdlock(&THR_LOCK_servers);
1235  if (!(server= (FOREIGN_SERVER *) my_hash_search(&servers_cache,
1236  (uchar*) server_name,
1237  server_name_length)))
1238  {
1239  DBUG_PRINT("info", ("server_name %s length %u not found!",
1240  server_name, (unsigned) server_name_length));
1241  server= (FOREIGN_SERVER *) NULL;
1242  }
1243  /* otherwise, make copy of server */
1244  else
1245  server= clone_server(mem, server, buff);
1246 
1247  DBUG_PRINT("info", ("unlocking servers_cache"));
1248  mysql_rwlock_unlock(&THR_LOCK_servers);
1249  DBUG_RETURN(server);
1250 
1251 }