[Commits] 2606b87: MDEV-9117: Client Server capability negotiation for MariaDB specific functionality

sanja at mariadb.com sanja at mariadb.com
Fri Nov 20 19:23:56 EET 2015


revision-id: 2606b8744404f352b44c85ee23d41b12cddc3470 (mariadb-10.1.8-51-g2606b87)
parent(s): 81e4ce5e31ba0753d7acfab28bc6c3d83bfad1c6
committer: Oleksandr Byelkin
timestamp: 2015-11-20 18:23:52 +0100
message:

MDEV-9117: Client Server capability negotiation for MariaDB specific functionality

New capability flags space.
Moved progress flag
fixed mysql_client_test.c

---
 client/mysql.cc           | 10 +++++-----
 include/mysql.h           |  2 +-
 include/mysql.h.pp        |  2 +-
 include/mysql_com.h       | 13 ++++++++++---
 sql-common/client.c       | 40 ++++++++++++++++++++++++++++++++++------
 sql/sql_acl.cc            | 36 ++++++++++++++++++++++++++++--------
 sql/sql_class.cc          |  2 +-
 sql/sql_class.h           |  6 +++---
 sql/sql_parse.cc          |  2 +-
 tests/mysql_client_fw.c   |  3 ++-
 tests/mysql_client_test.c | 13 +++++++++----
 11 files changed, 95 insertions(+), 34 deletions(-)

diff --git a/client/mysql.cc b/client/mysql.cc
index 92324c6..e242c25 100644
--- a/client/mysql.cc
+++ b/client/mysql.cc
@@ -152,7 +152,7 @@ static ulong opt_max_allowed_packet, opt_net_buffer_length;
 static uint verbose=0,opt_silent=0,opt_mysql_port=0, opt_local_infile=0;
 static uint my_end_arg;
 static char * opt_mysql_unix_port=0;
-static int connect_flag=CLIENT_INTERACTIVE;
+static ulong long connect_flag=CLIENT_INTERACTIVE;
 static my_bool opt_binary_mode= FALSE;
 static int interrupted_query= 0;
 static char *current_host,*current_db,*current_user=0,*opt_password=0,
@@ -1921,7 +1921,7 @@ static int get_options(int argc, char **argv)
     connect_flag|= CLIENT_IGNORE_SPACE;
 
   if (opt_progress_reports)
-    connect_flag|= CLIENT_PROGRESS;
+    connect_flag|= MARIADB_CLIENT_PROGRESS;
 
   return(0);
 }
@@ -4639,10 +4639,10 @@ sql_real_connect(char *host,char *database,char *user,char *password,
   mysql.reconnect= debug_info_flag; // We want to know if this happens
 
   /*
-    CLIENT_PROGRESS is set only if we requsted it in mysql_real_connect()
-    and the server also supports it
+    MARIADB_CLIENT_PROGRESS is set only if we requsted it in
+    mysql_real_connect() and the server also supports it
   */
-  if (mysql.client_flag & CLIENT_PROGRESS)
+  if (mysql.client_flag & MARIADB_CLIENT_PROGRESS)
     mysql_options(&mysql, MYSQL_PROGRESS_CALLBACK, (void*) report_progress);
 #else
   mysql.reconnect= 1;
diff --git a/include/mysql.h b/include/mysql.h
index f088ad6..d398734 100644
--- a/include/mysql.h
+++ b/include/mysql.h
@@ -270,7 +270,7 @@ typedef struct st_mysql
   unsigned long thread_id;		/* Id for connection in server */
   unsigned long packet_length;
   unsigned int	port;
-  unsigned long client_flag,server_capabilities;
+  unsigned long long client_flag,server_capabilities;
   unsigned int	protocol_version;
   unsigned int	field_count;
   unsigned int 	server_status;
diff --git a/include/mysql.h.pp b/include/mysql.h.pp
index 5c3a921..78a640f 100644
--- a/include/mysql.h.pp
+++ b/include/mysql.h.pp
@@ -341,7 +341,7 @@ typedef struct st_mysql
   unsigned long thread_id;
   unsigned long packet_length;
   unsigned int port;
-  unsigned long client_flag,server_capabilities;
+  unsigned long long client_flag,server_capabilities;
   unsigned int protocol_version;
   unsigned int field_count;
   unsigned int server_status;
diff --git a/include/mysql_com.h b/include/mysql_com.h
index a226c59..b36e30c 100644
--- a/include/mysql_com.h
+++ b/include/mysql_com.h
@@ -218,7 +218,7 @@ enum enum_server_command
 /* Don't close the connection for a connection with expired password. */
 #define CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS (1UL << 22)
 
-#define CLIENT_PROGRESS  (1UL << 29)   /* Client support progress indicator */
+#define CLIENT_PROGRESS_OBSOLETE  (1UL << 29)
 #define CLIENT_SSL_VERIFY_SERVER_CERT (1UL << 30)
 /*
   It used to be that if mysql_real_connect() failed, it would delete any
@@ -231,6 +231,13 @@ enum enum_server_command
 */
 #define CLIENT_REMEMBER_OPTIONS (1UL << 31)
 
+/* MariaDB extended capability flags */
+#define MARIADB_CLIENT_FLAGS_MASK 0xffffffff00000000ULL
+/* Client support progress indicator */
+#define MARIADB_CLIENT_PROGRESS (1ULL << 32)
+/* Client support mariaDB extended flags */
+#define MARIADB_CLIENT_EXTENDED_FLAGS (1ULL << 63)
+
 #ifdef HAVE_COMPRESS
 #define CAN_CLIENT_COMPRESS CLIENT_COMPRESS
 #else
@@ -238,7 +245,7 @@ enum enum_server_command
 #endif
 
 /* Gather all possible capabilites (flags) supported by the server */
-#define CLIENT_ALL_FLAGS  (CLIENT_LONG_PASSWORD | \
+#define CLIENT_ALL_FLAGS  ( \
                            CLIENT_FOUND_ROWS | \
                            CLIENT_LONG_FLAG | \
                            CLIENT_CONNECT_WITH_DB | \
@@ -259,7 +266,7 @@ enum enum_server_command
                            CLIENT_PS_MULTI_RESULTS | \
                            CLIENT_SSL_VERIFY_SERVER_CERT | \
                            CLIENT_REMEMBER_OPTIONS | \
-                           CLIENT_PROGRESS | \
+                           MARIADB_CLIENT_PROGRESS | \
                            CLIENT_PLUGIN_AUTH | \
                            CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA | \
                            CLIENT_CONNECT_ATTRS)
diff --git a/sql-common/client.c b/sql-common/client.c
index 609eef5..e108c4b 100644
--- a/sql-common/client.c
+++ b/sql-common/client.c
@@ -787,7 +787,7 @@ cli_safe_read(MYSQL *mysql)
       uint last_errno=uint2korr(pos);
 
       if (last_errno == 65535 &&
-          (mysql->server_capabilities & CLIENT_PROGRESS))
+          (mysql->server_capabilities & MARIADB_CLIENT_PROGRESS))
       {
         if (cli_report_progress(mysql, pos+2, (uint) (len-3)))
         {
@@ -2614,7 +2614,8 @@ static int send_change_user_packet(MCPVIO_EXT *mpvio,
     4           client capabilities
     4           max packet size
     1           charset number
-    23          reserved (always 0)
+    19          reserved (always 0)
+    4           client capabilities high bits (mariadb extension)
     n           user name, \0-terminated
     n           plugin auth data (e.g. scramble), length encoded
     n           database name, \0-terminated
@@ -2672,15 +2673,26 @@ static int send_client_reply_packet(MCPVIO_EXT *mpvio,
   if (mysql->client_flag & CLIENT_PROTOCOL_41)
   {
     /* 4.1 server and 4.1 client has a 32 byte option flag */
-    int4store(buff,mysql->client_flag);
+    bzero(buff+9, 32-9);
+    if (mysql->server_capabilities & MARIADB_CLIENT_EXTENDED_FLAGS)
+    {
+      DBUG_ASSERT(mysql->client_flag & CLIENT_LONG_PASSWORD);
+      /*
+        first part of bytes - CLIENT_LONG_PASSWORD to signal mariadb extensions
+      */
+      mysql->client_flag|= MARIADB_CLIENT_EXTENDED_FLAGS;
+      int4store(buff, (mysql->client_flag & (~CLIENT_LONG_PASSWORD)));
+      int4store(buff + 28, (mysql->client_flag >> 32));
+    }
+    else
+      int4store(buff, mysql->client_flag);
     int4store(buff+4, net->max_packet_size);
     buff[8]= (char) mysql->charset->number;
-    bzero(buff+9, 32-9);
     end= buff+32;
   }
   else
   {
-    int2store(buff, mysql->client_flag);
+    int2store(buff, (mysql->client_flag & 0xffff));
     int3store(buff+2, net->max_packet_size);
     end= buff+5;
   }
@@ -2768,7 +2780,8 @@ static int send_client_reply_packet(MCPVIO_EXT *mpvio,
   }
 #endif /* HAVE_OPENSSL */
 
-  DBUG_PRINT("info",("Server version = '%s'  capabilites: %lu  status: %u  client_flag: %lu",
+  DBUG_PRINT("info",("Server version = '%s'  capabilites: %llu  "
+                     "status: %u  client_flag: %llu",
 		     mysql->server_version, mysql->server_capabilities,
 		     mysql->server_status, mysql->client_flag));
 
@@ -3231,6 +3244,7 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
 		       uint port, const char *unix_socket,ulong client_flag)
 {
   char		buff[NAME_LEN+USERNAME_LENGTH+100];
+  ulonglong     ext_server_capabilities= 0;
   int           scramble_data_len, UNINIT_VAR(pkt_scramble_len);
   char          *end,*host_info= 0, *server_version_end, *pkt_end;
   char          *scramble_data;
@@ -3631,6 +3645,7 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
     mysql->server_language=end[2];
     mysql->server_status=uint2korr(end+3);
     mysql->server_capabilities|= uint2korr(end+5) << 16;
+    ext_server_capabilities|= ((ulonglong)uint4korr(end + 14)) << 32;
     pkt_scramble_len= end[7];
     if (pkt_scramble_len < 0)
     {
@@ -3682,7 +3697,20 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
   if ((mysql->server_capabilities & CLIENT_PLUGIN_AUTH) &&
       strncmp(mysql->server_version, RPL_VERSION_HACK,
               sizeof(RPL_VERSION_HACK) - 1) == 0)
+  {
     mysql->server_version+= sizeof(RPL_VERSION_HACK) - 1;
+    mysql->server_capabilities|= ext_server_capabilities;
+    if (!(mysql->server_capabilities & MARIADB_CLIENT_EXTENDED_FLAGS) &&
+        (mysql->client_flag & MARIADB_CLIENT_PROGRESS))
+    {
+      /* old mariadb fix progress flag */
+      mysql->client_flag|= CLIENT_PROGRESS_OBSOLETE;
+      if (mysql->server_capabilities & CLIENT_PROGRESS_OBSOLETE)
+      {
+        mysql->server_capabilities|= MARIADB_CLIENT_PROGRESS;
+      }
+    }
+  }
 
   if (pkt_end >= end + SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323 + 1)
   {
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 679bd15..0fbfbd8 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -11244,7 +11244,8 @@ static bool send_server_handshake_packet(MPVIO_EXT *mpvio,
 
   *end++= protocol_version;
 
-  thd->client_capabilities= CLIENT_BASIC_FLAGS;
+  thd->client_capabilities=
+    (CLIENT_BASIC_FLAGS | MARIADB_CLIENT_EXTENDED_FLAGS);
 
   if (opt_using_transactions)
     thd->client_capabilities|= CLIENT_TRANSACTIONS;
@@ -11312,7 +11313,8 @@ static bool send_server_handshake_packet(MPVIO_EXT *mpvio,
   int2store(end+5, thd->client_capabilities >> 16);
   end[7]= data_len;
   DBUG_EXECUTE_IF("poison_srv_handshake_scramble_len", end[7]= -100;);
-  bzero(end + 8, 10);
+  bzero(end + 8, 6);
+  int4store(end + 14, thd->client_capabilities >> 32);
   end+= 18;
   /* write scramble tail */
   end= (char*) memcpy(end, data + SCRAMBLE_LENGTH_323,
@@ -11728,18 +11730,38 @@ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio,
   */
   DBUG_ASSERT(net->read_pos[pkt_len] == 0);
 
-  ulong client_capabilities= uint2korr(net->read_pos);
+  ulonglong client_capabilities= uint2korr(net->read_pos);
+  compile_time_assert(sizeof(client_capabilities) >= 8);
   if (client_capabilities & CLIENT_PROTOCOL_41)
   {
-    if (pkt_len < 4)
+    if (pkt_len < 32)
       return packet_error;
     client_capabilities|= ((ulong) uint2korr(net->read_pos+2)) << 16;
+    if (!(client_capabilities & CLIENT_LONG_PASSWORD))
+    {
+      // it is client with mariadb extensions
+      client_capabilities|= CLIENT_LONG_PASSWORD;
+      ulonglong ext_client_capabilities=
+        (((ulonglong)uint4korr(net->read_pos + 28)) << 32);
+      if (ext_client_capabilities & MARIADB_CLIENT_EXTENDED_FLAGS)
+        client_capabilities|= ext_client_capabilities;
+      else
+      {
+        DBUG_PRINT("error", ("CLIENT_PROTOCOL_41: on, "
+                             "CLIENT_LONG_PASSWORD off, "
+                             "but MARIADB_CLIENT_EXTENDED_FLAGS is off. "
+                             "flags: %llx ext flags %llx",
+                             client_capabilities, ext_client_capabilities));
+        return packet_error;
+      }
+    }
   }
 
   /* Disable those bits which are not supported by the client. */
+  compile_time_assert(sizeof(thd->client_capabilities) >= 8);
   thd->client_capabilities&= client_capabilities;
 
-  DBUG_PRINT("info", ("client capabilities: %lu", thd->client_capabilities));
+  DBUG_PRINT("info", ("client capabilities 1: %llu", thd->client_capabilities));
   if (thd->client_capabilities & CLIENT_SSL)
   {
     unsigned long errptr __attribute__((unused));
@@ -11767,8 +11789,6 @@ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio,
 
   if (client_capabilities & CLIENT_PROTOCOL_41)
   {
-    if (pkt_len < 32)
-      return packet_error;
     thd->max_client_packet_length= uint4korr(net->read_pos+4);
     DBUG_PRINT("info", ("client_character_set: %d", (uint) net->read_pos[8]));
     if (thd_init_client_charset(thd, (uint) net->read_pos[8]))
@@ -12545,7 +12565,7 @@ bool acl_authenticate(THD *thd, uint com_change_user_pkt_len)
   }
 
   DBUG_PRINT("info",
-             ("Capabilities: %lu  packet_length: %ld  Host: '%s'  "
+             ("Capabilities: %llu  packet_length: %ld  Host: '%s'  "
               "Login user: '%s' Priv_user: '%s'  Using password: %s "
               "Access: %lu  db: '%s'",
               thd->client_capabilities, thd->max_client_packet_length,
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 1bf4892..6ebbab9 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -4331,7 +4331,7 @@ extern "C" void thd_progress_init(MYSQL_THD thd, uint max_stage)
     is a high level command (like ALTER TABLE) and we are not in a
     stored procedure
   */
-  thd->progress.report= ((thd->client_capabilities & CLIENT_PROGRESS) &&
+  thd->progress.report= ((thd->client_capabilities & MARIADB_CLIENT_PROGRESS) &&
                          thd->progress.report_to_client &&
                          !thd->in_sub_stmt);
   thd->progress.next_report_time= 0;
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 2b62c46..453aec0 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1412,7 +1412,7 @@ class Sub_statement_state
   Discrete_intervals_list auto_inc_intervals_forced;
   ulonglong limit_found_rows;
   ha_rows    cuted_fields, sent_row_count, examined_row_count;
-  ulong client_capabilities;
+  ulonglong client_capabilities;
   ulong query_plan_flags; 
   uint in_sub_stmt;
   bool enable_slow_log;
@@ -2045,7 +2045,7 @@ class THD :public Statement,
   /* Needed by MariaDB semi sync replication */
   Trans_binlog_info *semisync_info;
 
-  ulong client_capabilities;		/* What the client supports */
+  ulonglong client_capabilities;  /* What the client supports */
   ulong max_client_packet_length;
 
   HASH		handler_tables_hash;
@@ -2087,7 +2087,7 @@ class THD :public Statement,
     bool       report_to_client;
     /*
       true, if we will send progress report packets to a client
-      (client has requested them, see CLIENT_PROGRESS; report_to_client
+      (client has requested them, see MARIADB_CLIENT_PROGRESS; report_to_client
       is true; not in sub-statement)
     */
     bool       report;
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index d6e5082..8f223e4 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -638,7 +638,7 @@ void execute_init_command(THD *thd, LEX_STRING *init_command,
                           mysql_rwlock_t *var_lock)
 {
   Vio* save_vio;
-  ulong save_client_capabilities;
+  ulonglong save_client_capabilities;
 
   mysql_rwlock_rdlock(var_lock);
   if (!init_command->length)
diff --git a/tests/mysql_client_fw.c b/tests/mysql_client_fw.c
index 990fdb1..f26de62 100644
--- a/tests/mysql_client_fw.c
+++ b/tests/mysql_client_fw.c
@@ -326,7 +326,8 @@ mysql_simple_prepare(MYSQL *mysql_arg, const char *query)
    
    @return pointer to initialized and connected MYSQL object
 */
-static MYSQL* client_connect(ulong flag, uint protocol, my_bool auto_reconnect)
+static MYSQL* client_connect(ulonglong flag, uint protocol,
+                             my_bool auto_reconnect)
 {
   MYSQL* mysql;
   int  rc;
diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c
index 98f42ff..255ac25 100644
--- a/tests/mysql_client_test.c
+++ b/tests/mysql_client_test.c
@@ -15336,7 +15336,7 @@ static void test_mysql_insert_id()
 
   myheader("test_mysql_insert_id");
 
-  rc= mysql_query(mysql, "drop table if exists t1");
+  rc= mysql_query(mysql, "drop table if exists t1,t2");
   myquery(rc);
   /* table without auto_increment column */
   rc= mysql_query(mysql, "create table t1 (f1 int, f2 varchar(255), key(f1))");
@@ -16186,6 +16186,10 @@ static void test_change_user()
   sprintf(buff, "drop database if exists %s", db);
   rc= mysql_query(mysql, buff);
   myquery(rc);
+  sprintf(buff, "set local sql_mode=''");
+  rc= mysql_query(mysql, buff);
+  myquery(rc);
+
 
   sprintf(buff, "create database %s", db);
   rc= mysql_query(mysql, buff);
@@ -18671,7 +18675,7 @@ static void test_bug56976()
 }
 
 /*
-  Test that CLIENT_PROGRESS works.
+  Test that MARIADB_CLIENT_PROGRESS works.
 */
 
 uint progress_stage, progress_max_stage, progress_count;
@@ -18699,8 +18703,8 @@ static void test_progress_reporting()
 
   myheader("test_progress_reporting");
 
-  conn= client_connect(CLIENT_PROGRESS, MYSQL_PROTOCOL_TCP, 0);
-  DIE_UNLESS(conn->client_flag & CLIENT_PROGRESS);
+  conn= client_connect(MARIADB_CLIENT_PROGRESS, MYSQL_PROTOCOL_TCP, 0);
+  DIE_UNLESS(conn->client_flag & MARIADB_CLIENT_PROGRESS);
 
   mysql_options(conn, MYSQL_PROGRESS_CALLBACK, (void*) report_progress);
   rc= mysql_query(conn, "set @save=@@global.progress_report_time");
@@ -19390,6 +19394,7 @@ static void test_big_packet()
 
 
 static struct my_tests_st my_tests[]= {
+  { "test_change_user", test_change_user },
   { "disable_query_logs", disable_query_logs },
   { "test_view_sp_list_fields", test_view_sp_list_fields },
   { "client_query", client_query },


More information about the commits mailing list