commit 923e6199b9d98c0d947c827ec6b2e0ba29d1f07a
Author: Oleksandr Byelkin <sanja@mariadb.com>
Date:   Fri Oct 14 14:03:01 2016 +0200

    MDEV-10340: support COM_RESET_CONNECTION

diff --git a/include/mariadb_com.h b/include/mariadb_com.h
index 29b5de5..0cc0c70 100644
--- a/include/mariadb_com.h
+++ b/include/mariadb_com.h
@@ -90,7 +90,9 @@ enum enum_server_command
   COM_STMT_RESET = 26,
   COM_SET_OPTION = 27,
   COM_STMT_FETCH = 28,
-  COM_DAEMON,
+  COM_DAEMON = 29,
+  COM_UNSUPPORTED = 30,
+  COM_RESET_CONNECTION = 31,
   COM_MULTI = 254,
   COM_END
 };
diff --git a/include/mysql.h b/include/mysql.h
index 8c8e60e..3b6cd61 100644
--- a/include/mysql.h
+++ b/include/mysql.h
@@ -523,6 +523,7 @@ int		STDCALL mysql_refresh(MYSQL *mysql,
 				     unsigned int refresh_options);
 int		STDCALL mysql_kill(MYSQL *mysql,unsigned long pid);
 int		STDCALL mysql_ping(MYSQL *mysql);
+int		STDCALL mysql_reset_connection(MYSQL *mysql);
 char *		STDCALL mysql_stat(MYSQL *mysql);
 char *		STDCALL mysql_get_server_info(MYSQL *mysql);
 unsigned long   STDCALL mysql_get_server_version(MYSQL *mysql);
@@ -662,6 +663,8 @@ int             STDCALL mysql_set_server_option_cont(int *ret, MYSQL *mysql,
                                                      int status);
 int             STDCALL mysql_ping_start(int *ret, MYSQL *mysql);
 int             STDCALL mysql_ping_cont(int *ret, MYSQL *mysql, int status);
+int             STDCALL mysql_reset_connection_start(int *ret, MYSQL *mysql);
+int             STDCALL mysql_reset_connection_cont(int *ret, MYSQL *mysql, int status);
 int             STDCALL mysql_stat_start(const char **ret, MYSQL *mysql);
 int             STDCALL mysql_stat_cont(const char **ret, MYSQL *mysql,
                                         int status);
@@ -815,8 +818,9 @@ struct st_mariadb_api {
   int (STDCALL *mysql_stmt_next_result)(MYSQL_STMT *stmt);
   my_bool (STDCALL *mysql_stmt_more_results)(MYSQL_STMT *stmt);
   int (STDCALL *mariadb_stmt_execute_direct)(MYSQL_STMT *stmt, const char *stmtstr, size_t length);
+  int (STDCALL *mysql_reset_connection)(MYSQL *mysql);
 };
-  
+
 /* these methods can be overwritten by db plugins */
 struct st_mariadb_methods {
   MYSQL *(*db_connect)(MYSQL *mysql, const char *host, const char *user, const char *passwd,
diff --git a/libmariadb/CMakeLists.txt b/libmariadb/CMakeLists.txt
index c45a47b..1d978c0 100644
--- a/libmariadb/CMakeLists.txt
+++ b/libmariadb/CMakeLists.txt
@@ -143,7 +143,8 @@ SET(MARIADB_LIB_SYMBOLS
  mysql_thread_init
  mysql_thread_safe
  mysql_use_result
- mysql_warning_count)
+ mysql_warning_count
+ mysql_reset_connection)
 IF(WITH_SSL)
   SET(MARIADB_LIB_SYMBOLS ${MARIADB_LIB_SYMBOLS} mariadb_deinitialize_ssl)
 ENDIF()
@@ -245,6 +246,8 @@ SET(MARIADB_NONBLOCK_SYMBOLS
  mysql_stmt_store_result_start
  mysql_store_result_cont
  mysql_store_result_start
+ mysql_reset_connection_start
+ mysql_reset_connection_cont
 )
 
 
diff --git a/libmariadb/mariadb_async.c b/libmariadb/mariadb_async.c
index 2929e73..0ba80b7 100644
--- a/libmariadb/mariadb_async.c
+++ b/libmariadb/mariadb_async.c
@@ -1054,6 +1054,42 @@ MK_ASYNC_CONT_BODY(
   1,
   r_int)
 }
+/* Structure used to pass parameters from mysql_ping_start(). */
+struct mysql_reset_connection_params {
+  MYSQL *mysql;
+};
+static void
+mysql_reset_connection_start_internal(void *d)
+{
+MK_ASYNC_INTERNAL_BODY(
+  mysql_reset_connection,
+  (parms->mysql),
+  parms->mysql,
+  int,
+  r_int)
+}
+int STDCALL
+mysql_reset_connection_start(int *ret, MYSQL *mysql)
+{
+MK_ASYNC_START_BODY(
+  mysql_reset_connection,
+  mysql,
+  {
+    WIN_SET_NONBLOCKING(mysql)
+    parms.mysql= mysql;
+  },
+  1,
+  r_int,
+  /* Nothing */)
+}
+int STDCALL
+mysql_reset_connection_cont(int *ret, MYSQL *mysql, int ready_status)
+{
+MK_ASYNC_CONT_BODY(
+  mysql,
+  1,
+  r_int)
+}
 
 /* Structure used to pass parameters from mysql_stat_start(). */
 struct mysql_stat_params {
diff --git a/libmariadb/mariadb_lib.c b/libmariadb/mariadb_lib.c
index c1b42e0..9aecce3 100644
--- a/libmariadb/mariadb_lib.c
+++ b/libmariadb/mariadb_lib.c
@@ -2480,6 +2480,34 @@ mysql_ping(MYSQL *mysql)
   return rc;
 }
 
+int STDCALL
+mysql_reset_connection(MYSQL *mysql)
+{
+  int rc;
+  rc= ma_simple_command(mysql, COM_RESET_CONNECTION,0,0,0,0);
+
+  /* if connection was terminated and reconnect is true, try again */
+  if (rc!=0  && mysql->options.reconnect)
+  {
+    /* There is no big sens in resetting but we need reconnect */
+    rc= ma_simple_command(mysql, COM_RESET_CONNECTION,0,0,0,0);
+  }
+
+  if (!rc)
+  {
+    /*
+      COM_RESET_CONNECTION always releases prepared statements,
+      so we need to invalidate them
+    */
+    ma_invalidate_stmts(mysql, "mysql_reset_connection()");
+    /* Some status should be "ready" without reading server responce */
+    mysql->insert_id= 0;
+    mysql->server_status= MYSQL_STATUS_READY;
+    mysql->affected_rows= ~(my_ulonglong) 0;
+  }
+  return rc;
+}
+
 char * STDCALL
 mysql_get_server_info(MYSQL *mysql)
 {
@@ -4003,7 +4031,8 @@ struct st_mariadb_api MARIADB_API=
   mysql_stmt_field_count,
   mysql_stmt_next_result,
   mysql_stmt_more_results,
-  mariadb_stmt_execute_direct
+  mariadb_stmt_execute_direct,
+  mysql_reset_connection
 };
 
 /*
diff --git a/unittest/libmariadb/misc.c b/unittest/libmariadb/misc.c
index befac8d..de2a372 100644
--- a/unittest/libmariadb/misc.c
+++ b/unittest/libmariadb/misc.c
@@ -1131,6 +1131,83 @@ static int test_zerofill(MYSQL *mysql)
   return OK;
 }
 
+
+static int test_wl6797(MYSQL *mysql)
+{
+  MYSQL_STMT *stmt;
+  int        rc;
+  const char *stmt_text;
+  my_ulonglong res;
+
+  if (mysql_get_server_version(mysql) < 50703 ||
+      (mariadb_connection(mysql) && mysql_get_server_version(mysql) < 100203))
+  {
+    fprintf(stdout, "Skipping test_wl6797: "
+            "tested feature does not exist in versions before MySQL 5.7.3\n");
+    return OK;
+  }
+  /* clean up the session */
+  rc= mysql_reset_connection(mysql);
+  FAIL_UNLESS(rc == 0, "");
+
+  /* do prepare of a query */
+  mysql_query(mysql, "use test");
+  mysql_query(mysql, "DROP TABLE IF EXISTS t1");
+  mysql_query(mysql, "CREATE TABLE t1 (a int)");
+
+  stmt= mysql_stmt_init(mysql);
+  stmt_text= "INSERT INTO t1 VALUES (1), (2)";
+
+  rc= mysql_stmt_prepare(stmt, stmt_text, (ulong)strlen(stmt_text));
+  check_mysql_rc(rc, mysql);
+
+  /* Execute the insert statement */
+  rc= mysql_stmt_execute(stmt);
+  check_mysql_rc(rc, mysql);
+
+  /*
+   clean the session this should remove the prepare statement
+   from the cache.
+  */
+  rc= mysql_reset_connection(mysql);
+  FAIL_UNLESS(rc == 0, "");
+
+  /* this below stmt should report error */
+  rc= mysql_stmt_execute(stmt);
+  FAIL_IF(rc == 0, "");
+
+  /*
+   bug#17653288: MYSQL_RESET_CONNECTION DOES NOT RESET LAST_INSERT_ID
+  */
+
+  mysql_query(mysql, "DROP TABLE IF EXISTS t2");
+  rc= mysql_query(mysql, "CREATE TABLE t2 (a int NOT NULL PRIMARY KEY"\
+                         " auto_increment)");
+  check_mysql_rc(rc, mysql);
+  rc= mysql_query(mysql, "INSERT INTO t2 VALUES (null)");
+  check_mysql_rc(rc, mysql);
+  res= mysql_insert_id(mysql);
+  FAIL_UNLESS(res == 1, "");
+  rc= mysql_reset_connection(mysql);
+  FAIL_UNLESS(rc == 0, "");
+  res= mysql_insert_id(mysql);
+  FAIL_UNLESS(res == 0, "");
+
+  rc= mysql_query(mysql, "INSERT INTO t2 VALUES (last_insert_id(100))");
+  check_mysql_rc(rc, mysql);
+  res= mysql_insert_id(mysql);
+  FAIL_UNLESS(res == 100, "");
+  rc= mysql_reset_connection(mysql);
+  FAIL_UNLESS(rc == 0, "");
+  res= mysql_insert_id(mysql);
+  FAIL_UNLESS(res == 0, "");
+
+  mysql_query(mysql, "DROP TABLE IF EXISTS t1");
+  mysql_query(mysql, "DROP TABLE IF EXISTS t2");
+  mysql_stmt_close(stmt);
+  return OK;
+}
+
 struct my_tests_st my_tests[] = {
   {"test_read_timeout", test_read_timeout, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
   {"test_zerofill", test_zerofill, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
@@ -1158,7 +1235,8 @@ struct my_tests_st my_tests[] = {
   {"test_ldi_path", test_ldi_path, TEST_CONNECTION_NEW, 0, NULL, NULL},
 #ifdef _WIN32
   {"test_conc44", test_conc44, TEST_CONNECTION_NEW, 0, NULL, NULL},
-#endif 
+#endif
+  {"test_wl6797", test_wl6797, TEST_CONNECTION_NEW, 0, NULL, NULL},
   {NULL, NULL, 0, 0, NULL, 0}
 };
 
