List:Commits« Previous MessageNext Message »
From:Patrick Galbraith Date:February 10 2007 3:03pm
Subject:bk commit into 5.1 tree (patg:1.2391) BUG#26257
View as plain text  
Below is the list of changes that have just been committed into a local
5.1 repository of patg. When patg does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet@stripped, 2007-02-10 09:03:46-05:00, patg@stripped +4 -0
  BUG #26257
      
      New Federated Server Functionality Doesn't support differently named tables
      
      * Added method tmp_clone_server to allocate a new server to use for 
        get_server_by_name when creating a federated table
      
      * Now using MEM_ROOT allocation (mark and sweep) to account for meta 
        data parameters being allocated properly, particularly with regards to
        SERVER object. Also cleans up code allocating share.
      * Added the ability to specify connection name _AND_ tablename per review
        of first attempt patch from Brian Aker
  
  This patch was possible with code from Antony Curtis. All code has been 
  run with --valgrind flag and passed.

  sql/sql_servers.cc@stripped, 2007-02-10 09:03:15-05:00, patg@stripped +42 -3
    BUG #26257
    
    New Federated Server Functionality Doesn't support differently named tables
    
    * Added method tmp_clone_server to allocate a new server to use for 
      get_server_by_name when creating a federated table

  sql/sql_servers.h@stripped, 2007-02-10 09:03:15-05:00, patg@stripped +1 -0
    BUG #26257
    
    New Federated Server Functionality Doesn't support differently named tables
    
    * Added method tmp_clone_server to allocate a new server to use for 
      get_server_by_name when creating a federated table

  storage/federated/ha_federated.cc@stripped, 2007-02-10 09:03:15-05:00, patg@stripped +145 -90
    BUG #26257
    
    New Federated Server Functionality Doesn't support differently named tables
    
    * Now using MEM_ROOT allocation (mark and sweep) to account for meta 
      data parameters being allocated properly, particularly with regards to
      SERVER object. Also cleans up code allocating share.
    * Added the ability to specify connection name _AND_ tablename per review
      of first attempt patch from Brian Aker

  storage/federated/ha_federated.h@stripped, 2007-02-10 09:03:15-05:00, patg@stripped +3 -0
    BUG #26257
    
    New Federated Server Functionality Doesn't support differently named tables
    
    * Now using MEM_ROOT allocation (mark and sweep) to account for meta 
      data parameters being allocated properly, particularly with regards to
      SERVER object. Also cleans up code allocating share.
    * Added the ability to specify connection name _AND_ tablename per review
      of first attempt patch from Brian Aker

# This is a BitKeeper patch.  What follows are the unified diffs for the
# set of deltas contained in the patch.  The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User:	patg
# Host:	ishvara.patg.net
# Root:	/home/patg/mysql-build/mysql-5.1-bkbits

--- 1.95/storage/federated/ha_federated.cc	2007-02-10 09:03:51 -05:00
+++ 1.96/storage/federated/ha_federated.cc	2007-02-10 09:03:51 -05:00
@@ -43,23 +43,59 @@
   The create table will simply create the .frm file, and within the
   "CREATE TABLE" SQL, there SHALL be any of the following :
 
-  comment=scheme://username:password@hostname:port/database/tablename
-  comment=scheme://username@hostname/database/tablename
-  comment=scheme://username:password@hostname/database/tablename
-  comment=scheme://username:password@hostname/database/tablename
+  connection=scheme://username:password@hostname:port/database/tablename
+  connection=scheme://username@hostname/database/tablename
+  connection=scheme://username:password@hostname/database/tablename
+  connection=scheme://username:password@hostname/database/tablename
+
+  - OR -
+
+  As of 5.1 (See worklog #3031), federated now allows you to use a non-url
+  format, taking advantage of mysql.servers:
+
+  connection="connection_one"
+  connection="connection_one/table_foo"
 
   An example would be:
 
-  comment=mysql://username:password@hostname:port/database/tablename
+  connection=mysql://username:password@hostname:port/database/tablename
 
-  ***IMPORTANT***
+  or, if we had:
+
+  create server 'server_one' foreign data wrapper 'mysql' options
+  (HOST '127.0.0.1',
+  DATABASE 'db1',
+  USER 'root',
+  PASSWORD '',
+  PORT 3306,
+  SOCKET '',
+  OWNER 'root');
+
+  CREATE TABLE federated.t1 (
+    `id` int(20) NOT NULL,
+    `name` varchar(64) NOT NULL default ''
+    )
+  ENGINE="FEDERATED" DEFAULT CHARSET=latin1
+  CONNECTION='server_one';
+
+  So, this will have been the equivalent of
 
-  This is a first release, conceptual release
-  Only 'mysql://' is supported at this release.
+  CONNECTION="mysql://root@stripped:3306/db1/t1"
 
+  Then, we can also change the server to point to a new schema:
 
-  This comment connection string is necessary for the handler to be
-  able to connect to the foreign server.
+  ALTER SERVER 'server_one' options(DATABASE 'db2');
+
+  then (YOU MUST DO THIS!): 
+
+  flush tables;
+
+  All subsequent calls will now be against db2.t1! Guess what? You don't
+  have to perform an alter table!
+
+  This connecton="connection string" is necessary for the handler to be
+  able to connect to the foreign server, either by URL, or by server
+  name. 
 
 
   The basic flow is this:
@@ -166,7 +202,7 @@
       KEY other_key (other))
        ENGINE="FEDERATED"
        DEFAULT CHARSET=latin1
-       COMMENT='root@stripped:9306/federated/test_federated';
+       CONNECTION='mysql://root@stripped:9306/federated/test_federated';
 
    Notice the "COMMENT" and "ENGINE" field? This is where you
    respectively set the engine type, "FEDERATED" and foreign
@@ -263,7 +299,7 @@
     To run these tests, go into ./mysql-test (based in the directory you
     built the server in)
 
-    ./mysql-test-run federatedd
+    ./mysql-test-run federated
 
     To run the test, or if you want to run the test and have debug info:
 
@@ -311,7 +347,7 @@
     -------------
 
     These were the files that were modified or created for this
-    Federated handler to work:
+    Federated handler to work, in 5.0:
 
     ./configure.in
     ./sql/Makefile.am
@@ -329,6 +365,13 @@
     ./sql/ha_federated.cc
     ./sql/ha_federated.h
 
+    In 5.1
+
+    my:~/mysql-build/mysql-5.1-bkbits patg$ ls storage/federated/
+    CMakeLists.txt                  Makefile.in                     ha_federated.h                  plug.in
+    Makefile                        SCCS                            libfederated.a
+    Makefile.am                     ha_federated.cc                 libfederated_a-ha_federated.o
+
 */
 
 
@@ -548,27 +591,19 @@
   int buf_len;
   DBUG_ENTER("ha_federated parse_url_error");
 
-  if (share->connection_string)
-  {
-    DBUG_PRINT("info",
-               ("error: parse_url. Returning error code %d \
-                freeing share->connection_string %lx",
-                error_num, (long unsigned int) share->connection_string));
-    my_free((gptr) share->connection_string, MYF(0));
-    share->connection_string= 0;
-  }
   buf_len= min(table->s->connect_string.length,
                FEDERATED_QUERY_BUFFER_SIZE-1);
   strmake(buf, table->s->connect_string.str, buf_len);
   my_error(error_num, MYF(0), buf);
   DBUG_RETURN(error_num);
 }
+
 /*
   retrieve server object which contains server meta-data 
   from the system table given a server's name, set share
   connection parameter members
 */
-int get_connection(FEDERATED_SHARE *share)
+int get_connection(MEM_ROOT *mem_root, FEDERATED_SHARE *share)
 {
   int error_num= ER_FOREIGN_SERVER_DOESNT_EXIST;
   char error_buffer[FEDERATED_QUERY_BUFFER_SIZE];
@@ -597,27 +632,18 @@
   */
   if (server->server_name)
     share->server_name= server->server_name;
-  share->server_name_length= server->server_name_length ?
-    server->server_name_length : 0;
-  if (server->username)
-    share->username= server->username;
-  if (server->password)
-    share->password= server->password;
-  if (server->db)
-    share->database= server->db;
-
+  share->server_name= strmake_root(mem_root, server->server_name,
+        (share->server_name_length= server->server_name_length));
+  share->username= server->username ? strdup_root(mem_root, server->username) : NULL;
+  share->password= server->password ? strdup_root(mem_root, server->password) : NULL;
+  share->database= server->db ? strdup_root(mem_root, server->db) : NULL;
   share->port= server->port ? (ushort) server->port : MYSQL_PORT;
-
-  if (server->host)
-    share->hostname= server->host;
+  share->hostname= server->host ? strdup_root(mem_root, server->host) : NULL;
   if (server->socket)
-    share->socket= server->socket;
+    share->socket= strdup_root(mem_root, server->socket);
   else if (strcmp(share->hostname, my_localhost) == 0)
-    share->socket= my_strdup(MYSQL_UNIX_ADDR, MYF(0));
-  if (server->scheme)
-    share->scheme= server->scheme;
-  else
-    share->scheme= NULL;
+    share->socket= strdup_root(mem_root, MYSQL_UNIX_ADDR);
+  share->scheme= server->scheme ? strdup_root(mem_root, server->scheme) : NULL;
 
   DBUG_PRINT("info", ("share->username %s", share->username));
   DBUG_PRINT("info", ("share->password %s", share->password));
@@ -640,6 +666,7 @@
 
   SYNOPSIS
     parse_url()
+    mem_root            MEM_ROOT pointer for memory allocation
     share               pointer to FEDERATED share
     table               pointer to current TABLE class
     table_create_flag   determines what error to throw
@@ -689,7 +716,7 @@
 
 */
 
-static int parse_url(FEDERATED_SHARE *share, TABLE *table,
+static int parse_url(MEM_ROOT *mem_root, FEDERATED_SHARE *share, TABLE *table,
                      uint table_create_flag)
 {
   uint error_num= (table_create_flag ?
@@ -703,9 +730,8 @@
   DBUG_PRINT("info", ("Length: %d", table->s->connect_string.length));
   DBUG_PRINT("info", ("String: '%.*s'", table->s->connect_string.length,
                       table->s->connect_string.str));
-  share->connection_string= my_strndup(table->s->connect_string.str,
-                                       table->s->connect_string.length,
-                                       MYF(0));
+  share->connection_string= strmake_root(mem_root, table->s->connect_string.str,
+                                       table->s->connect_string.length);
 
   // Add a null for later termination of table name
   share->connection_string[table->s->connect_string.length]= 0;
@@ -713,10 +739,12 @@
                      (long unsigned int) share->connection_string));
 
   DBUG_PRINT("info",("share->connection_string %s",share->connection_string));
-  /* No delimiters, must be a straight connection name */
-  if ( (!strchr(share->connection_string, '/')) &&
-       (!strchr(share->connection_string, '@')) &&
-       (!strchr(share->connection_string, ';')))
+  /*
+    No :// or @ in connection string. Must be a straight connection name of
+    either "servername" or "servername/tablename"
+  */
+  if ( (!strstr(share->connection_string, "://") &&
+       (!strchr(share->connection_string, '@'))))
   {
 
     DBUG_PRINT("info",
@@ -725,17 +753,51 @@
                 share->connection_string,
                 (long unsigned int) share->connection_string));
 
+    /* ok, so we do a little parsing, but not completely! */
     share->parsed= FALSE;
-    if ((error_num= get_connection(share)))
-      goto error;
+    /*
+      If there is a single '/' in the connection string, this means the user is
+      specifying a table name
+    */
 
+    if ((share->table_name= strchr(share->connection_string, '/')))
+    {
+      share->connection_string[share->table_name - share->connection_string]= '\0';
+      share->table_name++;
+      share->table_name_length= strlen(share->table_name);
+
+      DBUG_PRINT("info", 
+                 ("internal format, parsed table_name share->connection_string \
+                  %s share->table_name %s", 
+                  share->connection_string, share->table_name));
+
+      /*
+        there better not be any more '/'s !
+      */
+      if (strchr(share->table_name, '/'))
+        goto error;
+
+    }
     /*
-      connection specifies everything but, resort to
-      expecting remote and foreign table names to match
+      otherwise, straight server name, use tablename of federated table
+      as remote table name
     */
-    share->table_name= table->s->table_name.str;
-    share->table_name_length= table->s->table_name.length;
-    share->table_name[share->table_name_length]= '\0';
+    else
+    {
+      /*
+        connection specifies everything but, resort to
+        expecting remote and foreign table names to match
+      */
+      share->table_name= strmake_root(mem_root, table->s->table_name.str,
+                                      (share->table_name_length= table->s->table_name.length));
+      DBUG_PRINT("info", 
+                 ("internal format, default table_name share->connection_string \
+                  %s share->table_name %s", 
+                  share->connection_string, share->table_name));
+    }
+
+    if ((error_num= get_connection(mem_root, share)))
+      goto error;
   }
   else
   {
@@ -821,7 +883,8 @@
   if (!share->port)
   {
     if (strcmp(share->hostname, my_localhost) == 0)
-      share->socket= my_strdup(MYSQL_UNIX_ADDR, MYF(0));
+      /* why are we duplicating a const string? */
+      share->socket= strdup_root(mem_root, MYSQL_UNIX_ADDR);
     else
       share->port= MYSQL_PORT;
   }
@@ -1430,17 +1493,22 @@
   Field **field;
   String query(query_buffer, sizeof(query_buffer), &my_charset_bin);
   FEDERATED_SHARE *share= NULL, tmp_share;
+  MEM_ROOT mem_root;
+  DBUG_ENTER("ha_federated.cc::get_share");
+
   /*
     In order to use this string, we must first zero it's length,
     or it will contain garbage
   */
   query.length(0);
 
+  init_alloc_root(&mem_root, 256, 0);
+
   pthread_mutex_lock(&federated_mutex);
 
   tmp_share.share_key= table_name;
   tmp_share.share_key_length= strlen(table_name);
-  if (parse_url(&tmp_share, table, 0))
+  if (parse_url(&mem_root, &tmp_share, table, 0))
     goto error;
 
   /* TODO: change tmp_share.scheme to LEX_STRING object */
@@ -1461,24 +1529,17 @@
     query.length(query.length() - sizeof_trailing_comma);
 
     query.append(STRING_WITH_LEN(" FROM `"));
+    query.append(tmp_share.table_name, tmp_share.table_name_length);
+    query.append(STRING_WITH_LEN("`"));
+    DBUG_PRINT("info", ("calling alloc_root"));
 
-    if (!(share= (FEDERATED_SHARE *)
-          my_multi_malloc(MYF(MY_WME),
-                          &share, sizeof(*share),
-                          &select_query,
-                          query.length()+table->s->connect_string.length+1,
-                          NullS)))
+    if (!(share= (FEDERATED_SHARE *) memdup_root(&mem_root, (char*)&tmp_share, sizeof(*share))) ||
+        !(share->select_query= (char*) strmake_root(&mem_root, query.ptr(), query.length())))
       goto error;
 
-    memcpy(share, &tmp_share, sizeof(tmp_share));
-
-    share->table_name_length= strlen(share->table_name);
-    /* TODO: share->table_name to LEX_STRING object */
-    query.append(share->table_name, share->table_name_length);
-    query.append(STRING_WITH_LEN("`"));
-    share->select_query= select_query;
-    strmov(share->select_query, query.ptr());
     share->use_count= 0;
+    share->mem_root= mem_root;
+
     DBUG_PRINT("info",
                ("share->select_query %s", share->select_query));
 
@@ -1487,17 +1548,18 @@
     thr_lock_init(&share->lock);
     pthread_mutex_init(&share->mutex, MY_MUTEX_INIT_FAST);
   }
+  else
+    free_root(&mem_root, MYF(0)); /* prevents memory leak */
+
   share->use_count++;
   pthread_mutex_unlock(&federated_mutex);
 
-  return share;
+  DBUG_RETURN(share);
 
 error:
   pthread_mutex_unlock(&federated_mutex);
-  my_free((gptr) tmp_share.connection_string, MYF(MY_ALLOW_ZERO_PTR));
-  tmp_share.connection_string= 0;
-  my_free((gptr) share, MYF(MY_ALLOW_ZERO_PTR));
-  return NULL;
+  free_root(&mem_root, MYF(0));
+  DBUG_RETURN(NULL);
 }
 
 
@@ -1509,23 +1571,16 @@
 
 static int free_share(FEDERATED_SHARE *share)
 {
+  MEM_ROOT mem_root= share->mem_root;
   DBUG_ENTER("free_share");
 
   pthread_mutex_lock(&federated_mutex);
   if (!--share->use_count)
   {
     hash_delete(&federated_open_tables, (byte*) share);
-    if (share->parsed)
-      my_free((gptr) share->socket, MYF(MY_ALLOW_ZERO_PTR));
-    /*if (share->connection_string)
-    {
-    */
-      my_free((gptr) share->connection_string, MYF(MY_ALLOW_ZERO_PTR));
-      share->connection_string= 0;
-      /*}*/
     thr_lock_delete(&share->lock);
     VOID(pthread_mutex_destroy(&share->mutex));
-    my_free((gptr) share, MYF(0));
+    free_root(&mem_root, MYF(0));
   }
   pthread_mutex_unlock(&federated_mutex);
 
@@ -1594,6 +1649,8 @@
   mysql_options(mysql,MYSQL_SET_CHARSET_NAME,
                 this->table->s->table_charset->csname);
 
+  DBUG_PRINT("info", ("calling mysql_real_connect hostname %s user %s",
+			share->hostname, share->username));
   if (!mysql || !mysql_real_connect(mysql,
                                    share->hostname,
                                    share->username,
@@ -2836,15 +2893,13 @@
                          HA_CREATE_INFO *create_info)
 {
   int retval;
+  THD *thd= current_thd;
   FEDERATED_SHARE tmp_share; // Only a temporary share, to test the url
   DBUG_ENTER("ha_federated::create");
 
-  if (!(retval= parse_url(&tmp_share, table_arg, 1)))
+  if (!(retval= parse_url(thd->mem_root, &tmp_share, table_arg, 1)))
     retval= check_foreign_data_source(&tmp_share, 1);
 
-  /* free this because strdup created it in parse_url */
-  my_free((gptr) tmp_share.connection_string, MYF(MY_ALLOW_ZERO_PTR));
-  tmp_share.connection_string= 0;
   DBUG_RETURN(retval);
 
 }

--- 1.44/storage/federated/ha_federated.h	2007-02-10 09:03:51 -05:00
+++ 1.45/storage/federated/ha_federated.h	2007-02-10 09:03:51 -05:00
@@ -43,6 +43,8 @@
   The example implements the minimum of what you will probably need.
 */
 typedef struct st_federated_share {
+  MEM_ROOT mem_root;
+
   bool parsed;
   /* this key is unique db/tablename */
   const char *share_key;
@@ -67,6 +69,7 @@
   char *sport;
   int share_key_length;
   ushort port;
+
   uint table_name_length, server_name_length, connect_string_length, use_count;
   pthread_mutex_t mutex;
   THR_LOCK lock;

--- 1.4/sql/sql_servers.cc	2007-02-10 09:03:51 -05:00
+++ 1.5/sql/sql_servers.cc	2007-02-10 09:03:51 -05:00
@@ -216,9 +216,6 @@
   DBUG_PRINT("info", ("locking servers_cache"));
   VOID(pthread_mutex_lock(&servers_cache_mutex));
 
-  //old_servers_cache= servers_cache;
-  //old_mem=mem;
-
   if ((return_val= servers_load(thd, tables)))
   {					// Error. Revert to old list
     /* blast, for now, we have no servers, discuss later way to preserve */
@@ -1190,6 +1187,44 @@
   DBUG_VOID_RETURN;
 }
 
+/*
+  SYNOPSIS
+
+  tmp_clone_server(FOREIGN_SERVER *orig)
+
+  Create a temporary copy of FOREIGN_SERVER.
+  The copy is automatically disposed at end of statement
+
+  NOTES
+
+  ARGS
+   FOREIGN SERVER pointer (made a copy of)
+
+  RETURN VALUE
+   FOREIGN_SEVER pointer (copy of one supplied in ARGS)
+*/
+
+static FOREIGN_SERVER *tmp_clone_server(FOREIGN_SERVER *orig)
+{
+  THD *thd= current_thd;
+  FOREIGN_SERVER *server;
+
+  DBUG_ENTER("sql_server.cc:tmp_clone_server");
+  server= (FOREIGN_SERVER *) thd->alloc(sizeof(FOREIGN_SERVER));
+
+  server->server_name= thd->strmake(orig->server_name, orig->server_name_length);
+  server->port= orig->port;
+  server->server_name_length= orig->server_name_length;
+  server->db= orig->db ? thd->strdup(orig->db) : NULL;
+  server->scheme= orig->scheme ? thd->strdup(orig->scheme) : NULL;
+  server->username= orig->username ? thd->strdup(orig->username) : NULL;
+  server->password= orig->password ? thd->strdup(orig->password) : NULL;
+  server->socket= orig->socket ? thd->strdup(orig->password) : NULL;
+  server->owner= orig->owner ? thd->strdup(orig->owner) : NULL;
+  server->host= orig->host ? thd->strdup(orig->host) : NULL;
+
+  DBUG_RETURN(server);
+}
 
 
 /*
@@ -1232,6 +1267,10 @@
                         server_name, server_name_length));
     server= (FOREIGN_SERVER *) NULL;
   }
+  /* otherwise, make copy of server */
+  else
+    server= tmp_clone_server(server);
+
   DBUG_PRINT("info", ("unlocking servers_cache"));
   VOID(pthread_mutex_unlock(&servers_cache_mutex));
   DBUG_RETURN(server);

--- 1.3/sql/sql_servers.h	2007-02-10 09:03:51 -05:00
+++ 1.4/sql/sql_servers.h	2007-02-10 09:03:51 -05:00
@@ -63,3 +63,4 @@
 void merge_server_struct(FOREIGN_SERVER *from, FOREIGN_SERVER *to);
 FOREIGN_SERVER *get_server_by_name(const char *server_name);
 my_bool server_exists_in_table(THD *thd, char *server_name);
+static FOREIGN_SERVER *tmp_clone_server(FOREIGN_SERVER *orig);
Thread
bk commit into 5.1 tree (patg:1.2391) BUG#26257Patrick Galbraith10 Feb