/*
Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.

The MySQL Connector/C is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
MySQL Connectors. There are special exceptions to the terms and
conditions of the GPLv2 as it is applied to this software, see the
FLOSS License Exception
<http://www.mysql.com/about/legal/licensing/foss-exception.html>.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; version 2 of the License.

This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
*/
#include "my_test.h"
#include <math.h>

#define MY_INT64_NUM_DECIMAL_DIGITS 21
#define MAX_INDEXES 64

/* A workaround for Sun Forte 5.6 on Solaris x86 */

static int cmp_double(double *a, double *b)
{
  return *a == *b;
  return OK;
}

/* Test BUG#1115 (incorrect string parameter value allocation) */

static int test_conc67(MYSQL *mysql)
{
  MYSQL_STMT *stmt= mysql_stmt_init(mysql);
  const char *query= "SELECT a,b FROM conc67 WHERE a=?";
  int rc, i;
  MYSQL_BIND bind[2];
  char val[20];
  MYSQL_BIND rbind;
  MYSQL_RES *res;
  ulong prefetch_rows= 1000;
  ulong cursor_type= CURSOR_TYPE_READ_ONLY;

  // https://jira.mariadb.org/browse/XPT-266
  if (IS_XPAND()) {
    rc= mysql_query(mysql, "SET NAMES UTF8");
    check_mysql_rc(rc, mysql);
  }

  rc= mysql_query(mysql, "DROP TABLE IF EXISTS conc67");
  check_mysql_rc(rc, mysql);

  rc= mysql_query(mysql, "CREATE TABLE conc67 (a int, b text)");
  check_mysql_rc(rc, mysql);

  rc= mysql_query(mysql, "INSERT INTO conc67 VALUES (1, 'foo')");
  check_mysql_rc(rc, mysql);

  rc= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, &cursor_type);
  check_stmt_rc(rc, stmt);
  rc= mysql_stmt_attr_set(stmt, STMT_ATTR_PREFETCH_ROWS, &prefetch_rows);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_prepare(stmt, SL(query));
  check_stmt_rc(rc, stmt);

  memset(&rbind, 0, sizeof(MYSQL_BIND));
  i= 1;
  rbind.buffer_type= MYSQL_TYPE_LONG;
  rbind.buffer= &i;
  rbind.buffer_length= 4;
  mysql_stmt_bind_param(stmt, &rbind);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  res= mysql_stmt_result_metadata(stmt);
  mysql_free_result(res);

  memset(bind, 0, 2 * sizeof(MYSQL_BIND));

  i= 0;
  bind[0].buffer_type= MYSQL_TYPE_LONG;
  bind[0].buffer= &i;
  bind[0].buffer_length= 4;
  bind[1].buffer_type= MYSQL_TYPE_STRING;
  bind[1].buffer= &val;
  bind[1].buffer_length= 20;

  mysql_stmt_bind_result(stmt, bind);

  rc= mysql_stmt_fetch(stmt);
  check_stmt_rc(rc, stmt);

  FAIL_IF(i != 1, "expected value 1 for first row");

  rc= mysql_stmt_fetch(stmt);
  FAIL_IF(rc != MYSQL_NO_DATA, "Eof expected");

  mysql_stmt_close(stmt);
  rc= mysql_query(mysql, "DROP TABLE IF EXISTS conc67");
  check_mysql_rc(rc, mysql);
  return OK;
}

static int test_bug1115(MYSQL *mysql)
{
  MYSQL_STMT *stmt;
  int rc, rowcount;
  MYSQL_BIND my_bind[1];
  ulong length[1];
  char szData[11];
  char query[MAX_TEST_QUERY_LENGTH];

  rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_select");
  check_mysql_rc(rc, mysql);

  rc= mysql_query(mysql, "CREATE TABLE test_select(\
session_id  char(9) NOT NULL, \
    a       int(8) unsigned NOT NULL, \
    b        int(5) NOT NULL, \
    c      int(5) NOT NULL, \
    d  datetime NOT NULL)");
  check_mysql_rc(rc, mysql);
  rc= mysql_query(mysql, "INSERT INTO test_select VALUES "
                         "(\"abc\", 1, 2, 3, 2003-08-30), "
                         "(\"abd\", 1, 2, 3, 2003-08-30), "
                         "(\"abf\", 1, 2, 3, 2003-08-30), "
                         "(\"abg\", 1, 2, 3, 2003-08-30), "
                         "(\"abh\", 1, 2, 3, 2003-08-30), "
                         "(\"abj\", 1, 2, 3, 2003-08-30), "
                         "(\"abk\", 1, 2, 3, 2003-08-30), "
                         "(\"abl\", 1, 2, 3, 2003-08-30), "
                         "(\"abq\", 1, 2, 3, 2003-08-30) ");
  check_mysql_rc(rc, mysql);
  rc= mysql_query(mysql, "INSERT INTO test_select VALUES "
                         "(\"abw\", 1, 2, 3, 2003-08-30), "
                         "(\"abe\", 1, 2, 3, 2003-08-30), "
                         "(\"abr\", 1, 2, 3, 2003-08-30), "
                         "(\"abt\", 1, 2, 3, 2003-08-30), "
                         "(\"aby\", 1, 2, 3, 2003-08-30), "
                         "(\"abu\", 1, 2, 3, 2003-08-30), "
                         "(\"abi\", 1, 2, 3, 2003-08-30), "
                         "(\"abo\", 1, 2, 3, 2003-08-30), "
                         "(\"abp\", 1, 2, 3, 2003-08-30), "
                         "(\"abz\", 1, 2, 3, 2003-08-30), "
                         "(\"abx\", 1, 2, 3, 2003-08-30)");
  check_mysql_rc(rc, mysql);

  strcpy(query, "SELECT * FROM test_select WHERE "
                "CONVERT(session_id USING utf8)= ?");
  stmt= mysql_stmt_init(mysql);
  FAIL_IF(!stmt, mysql_error(mysql));
  rc= mysql_stmt_prepare(stmt, SL(query));
  check_stmt_rc(rc, stmt);

  FAIL_IF(mysql_stmt_param_count(stmt) != 1, "Paramcount != 1");

  memset(my_bind, '\0', sizeof(MYSQL_BIND));

  strcpy(szData, (char *)"abc");
  my_bind[0].buffer_type= MYSQL_TYPE_STRING;
  my_bind[0].buffer= (void *)szData;
  my_bind[0].buffer_length= 10;
  my_bind[0].length= &length[0];
  length[0]= 3;

  rc= mysql_stmt_bind_param(stmt, my_bind);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  rowcount= 0;
  while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
    rowcount++;
  FAIL_IF(rowcount != 1, "rowcount=%d != 1");

  strcpy(szData, (char *)"venu");
  my_bind[0].buffer_type= MYSQL_TYPE_STRING;
  my_bind[0].buffer= (void *)szData;
  my_bind[0].buffer_length= 10;
  my_bind[0].length= &length[0];
  length[0]= 4;
  my_bind[0].is_null= 0;

  rc= mysql_stmt_bind_param(stmt, my_bind);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  rowcount= 0;
  while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
    rowcount++;
  FAIL_IF(rowcount != 0, "rowcount != 0");

  strcpy(szData, (char *)"abc");
  my_bind[0].buffer_type= MYSQL_TYPE_STRING;
  my_bind[0].buffer= (void *)szData;
  my_bind[0].buffer_length= 10;
  my_bind[0].length= &length[0];
  length[0]= 3;
  my_bind[0].is_null= 0;

  rc= mysql_stmt_bind_param(stmt, my_bind);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  rowcount= 0;
  while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
    rowcount++;
  FAIL_IF(rowcount != 1, "rowcount != 1");

  mysql_stmt_close(stmt);
  rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_select");
  check_mysql_rc(rc, mysql);

  return OK;
}
/* Test BUG#1180 (optimized away part of WHERE clause) */

static int test_bug1180(MYSQL *mysql)
{
  MYSQL_STMT *stmt;
  int rc, rowcount;
  MYSQL_BIND my_bind[1];
  ulong length[1];
  char szData[11];
  char query[MAX_TEST_QUERY_LENGTH];

  // https://jira.mariadb.org/browse/XPT-266
  if (IS_XPAND()) {
    rc= mysql_query(mysql, "SET NAMES UTF8");
    check_mysql_rc(rc, mysql);
  }

  rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_select");
  check_mysql_rc(rc, mysql);

  rc= mysql_query(mysql, "CREATE TABLE test_select(session_id  char(9) NOT NULL)");
  check_mysql_rc(rc, mysql);
  rc= mysql_query(mysql, "INSERT INTO test_select VALUES (\"abc\")");
  check_mysql_rc(rc, mysql);

  strcpy(query, "SELECT * FROM test_select WHERE ?= \"1111\" and "
                "session_id= \"abc\"");
  stmt= mysql_stmt_init(mysql);
  FAIL_IF(!stmt, mysql_error(mysql));
  rc= mysql_stmt_prepare(stmt, SL(query));
  check_stmt_rc(rc, stmt);

  FAIL_IF(mysql_stmt_param_count(stmt) != 1, "Paramcount != 1");

  memset(my_bind, '\0', sizeof(MYSQL_BIND));

  strcpy(szData, (char *)"abc");
  my_bind[0].buffer_type= MYSQL_TYPE_STRING;
  my_bind[0].buffer= (void *)szData;
  my_bind[0].buffer_length= 10;
  my_bind[0].length= &length[0];
  length[0]= 3;
  my_bind[0].is_null= 0;

  rc= mysql_stmt_bind_param(stmt, my_bind);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);


  rowcount= 0;
  while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
    rowcount++;
  FAIL_IF(rowcount != 0, "rowcount != 0");

  strcpy(szData, (char *)"1111");
  my_bind[0].buffer_type= MYSQL_TYPE_STRING;
  my_bind[0].buffer= (void *)szData;
  my_bind[0].buffer_length= 10;
  my_bind[0].length= &length[0];
  length[0]= 4;
  my_bind[0].is_null= 0;

  rc= mysql_stmt_bind_param(stmt, my_bind);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  rowcount= 0;
  while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
    rowcount++;
  FAIL_IF(rowcount != 1, "rowcount != 1");

  strcpy(szData, (char *)"abc");
  my_bind[0].buffer_type= MYSQL_TYPE_STRING;
  my_bind[0].buffer= (void *)szData;
  my_bind[0].buffer_length= 10;
  my_bind[0].length= &length[0];
  length[0]= 3;
  my_bind[0].is_null= 0;

  rc= mysql_stmt_bind_param(stmt, my_bind);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  rowcount= 0;
  while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
    rowcount++;
  FAIL_IF(rowcount != 0, "rowcount != 0");

  mysql_stmt_close(stmt);
  rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_select");
  check_mysql_rc(rc, mysql);

  return OK;
}


/*
  Test BUG#1644 (Insertion of more than 3 NULL columns with parameter
  binding fails)
*/

static int test_bug1644(MYSQL *mysql)
{
  MYSQL_STMT *stmt;
  MYSQL_RES *result;
  MYSQL_ROW row;
  MYSQL_BIND my_bind[4];
  int num;
  my_bool isnull;
  int rc, i;
  char query[MAX_TEST_QUERY_LENGTH];

  rc= mysql_query(mysql, "DROP TABLE IF EXISTS foo_dfr");
  check_mysql_rc(rc, mysql);

  rc= mysql_query(mysql,
           "CREATE TABLE foo_dfr(col1 int, col2 int, col3 int, col4 int);");
  check_mysql_rc(rc, mysql);

  strcpy(query, "INSERT INTO foo_dfr VALUES (?, ?, ?, ? )");
  stmt= mysql_stmt_init(mysql);
  FAIL_IF(!stmt, mysql_error(mysql));
  rc= mysql_stmt_prepare(stmt, SL(query));
  check_stmt_rc(rc, stmt);

  FAIL_IF(mysql_stmt_param_count(stmt) != 4, "Paramcount != 4");

  memset(my_bind, '\0', sizeof(MYSQL_BIND) * 4);

  num= 22;
  isnull= 0;
  for (i= 0 ; i < 4 ; i++)
  {
    my_bind[i].buffer_type= MYSQL_TYPE_LONG;
    my_bind[i].buffer= (void *)&num;
    my_bind[i].is_null= &isnull;
  }

  rc= mysql_stmt_bind_param(stmt, my_bind);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  isnull= 1;
  for (i= 0 ; i < 4 ; i++)
    my_bind[i].is_null= &isnull;

  rc= mysql_stmt_bind_param(stmt, my_bind);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  isnull= 0;
  num= 88;
  for (i= 0 ; i < 4 ; i++)
    my_bind[i].is_null= &isnull;

  rc= mysql_stmt_bind_param(stmt, my_bind);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  mysql_stmt_close(stmt);

  rc= mysql_query(mysql, "SELECT * FROM foo_dfr");
  check_mysql_rc(rc, mysql);

  result= mysql_store_result(mysql);
  FAIL_IF(!result, "Invalid resultset");

  FAIL_IF(mysql_num_rows(result) != 3, "rowcount != 3");

  mysql_data_seek(result, 0);

  row= mysql_fetch_row(result);
  FAIL_IF(!row, "row = NULL");
  for (i= 0 ; i < 4 ; i++)
  {
    FAIL_UNLESS(strcmp(row[i], "22") == 0, "Wrong value");
  }
  row= mysql_fetch_row(result);
  FAIL_IF(!row, "Invalid row");
  for (i= 0 ; i < 4 ; i++)
  {
    FAIL_UNLESS(row[i] == 0, "row[i] != 0");
  }
  row= mysql_fetch_row(result);
  FAIL_IF(!row, "Invalid row");
  for (i= 0 ; i < 4 ; i++)
  {
    FAIL_UNLESS(strcmp(row[i], "88") == 0, "row[i] != 88");
  }
  row= mysql_fetch_row(result);
  FAIL_IF(row, "row != NULL");

  mysql_free_result(result);
  rc= mysql_query(mysql, "DROP TABLE IF EXISTS foo_dfr");
  check_mysql_rc(rc, mysql);

  return OK;
}

static int test_bug11037(MYSQL *mysql)
{
  MYSQL_STMT *stmt;
  int rc;
  const char *stmt_text;

  rc= mysql_query(mysql, "drop table if exists t1");
  check_mysql_rc(rc, mysql);

  rc= mysql_query(mysql, "create table t1 (id int not null)");
  check_mysql_rc(rc, mysql);

  rc= mysql_query(mysql, "insert into t1 values (1)");
  check_mysql_rc(rc, mysql);

  stmt_text= "select id FROM t1";
  stmt= mysql_stmt_init(mysql);
  FAIL_IF(!stmt, mysql_error(mysql));
  rc= mysql_stmt_prepare(stmt, SL(stmt_text));
  check_stmt_rc(rc, stmt);

  /* expected error */
  rc = mysql_stmt_fetch(stmt);
  FAIL_UNLESS(rc==1, "Error expected");

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_fetch(stmt);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_fetch(stmt);
  FAIL_UNLESS(rc==MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");

  rc= mysql_stmt_fetch(stmt);
  FAIL_UNLESS(rc==MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");

  mysql_stmt_close(stmt);
  rc= mysql_query(mysql, "drop table t1");
  check_mysql_rc(rc, mysql);

  return OK;
}

/* Bug#11183 "mysql_stmt_reset() doesn't reset information about error" */

static int test_bug11183(MYSQL *mysql)
{
  int rc;
  MYSQL_STMT *stmt;
  char bug_statement[]= "insert into t1 values (1)";

  rc= mysql_query(mysql, "drop table if exists t1");
  check_mysql_rc(rc, mysql);
  rc= mysql_query(mysql, "create table t1 (a int)");
  check_mysql_rc(rc, mysql);

  stmt= mysql_stmt_init(mysql);
  FAIL_IF(!stmt, mysql_error(mysql));

  rc= mysql_stmt_prepare(stmt, SL(bug_statement));
  check_stmt_rc(rc, stmt);

  rc= mysql_query(mysql, "drop table t1");
  check_mysql_rc(rc, mysql);

  /* Trying to execute statement that should fail on execute stage */
  rc= mysql_stmt_execute(stmt);
  FAIL_IF(!rc, "Error expected");

  mysql_stmt_reset(stmt);
  FAIL_IF(mysql_stmt_errno(stmt) != 0, "stmt->error != 0");

  rc= mysql_query(mysql, "create table t1 (a int)");
  check_mysql_rc(rc, mysql);

  /* Trying to execute statement that should pass ok */
  if (mysql_stmt_execute(stmt))
  {
    mysql_stmt_reset(stmt);
    FAIL_IF(mysql_stmt_errno(stmt) == 0, "stmt->error != 0");
  }

  mysql_stmt_close(stmt);

  rc= mysql_query(mysql, "drop table t1");
  check_mysql_rc(rc, mysql);

  return OK;
}

static int test_bug12744(MYSQL *mysql)
{
  MYSQL_STMT *stmt = NULL;
  int rc;

  SKIP_MAXSCALE;

  stmt = mysql_stmt_init(mysql);
  FAIL_IF(!stmt, mysql_error(mysql));
  rc= mysql_stmt_prepare(stmt, "SET @a:=1", 9);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  /* set reconnect, kill and ping to reconnect */
  rc= mysql_query(mysql, "SET @a:=1");
  check_mysql_rc(rc, mysql);
  rc= mysql_options(mysql, MYSQL_OPT_RECONNECT, "1");
  check_mysql_rc(rc, mysql);
  rc= mysql_kill(mysql, mysql_thread_id(mysql));

  rc= mysql_ping(mysql);
  check_mysql_rc(rc, mysql);

  rc= mysql_stmt_close(stmt);
  check_stmt_rc(rc, stmt);

  return OK;
}

static int test_bug1500(MYSQL *mysql)
{
  MYSQL_STMT *stmt;
  MYSQL_BIND my_bind[3];
  int        rc= 0;
  int32 int_data[3]= {2, 3, 4};
  const char *data;
  const char *query;

  // XPAND doesn't support AGAINST
  SKIP_XPAND

  rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_bg1500");
  check_mysql_rc(rc, mysql);

  rc= mysql_query(mysql, "CREATE TABLE test_bg1500 (i INT)");
  check_mysql_rc(rc, mysql);

  rc= mysql_query(mysql, "INSERT INTO test_bg1500 VALUES (1), (2)");
  check_mysql_rc(rc, mysql);

  rc= mysql_commit(mysql);
  check_mysql_rc(rc, mysql);

  query= "SELECT i FROM test_bg1500 WHERE i IN (?, ?, ?)";
  stmt= mysql_stmt_init(mysql);
  FAIL_IF(!stmt, mysql_error(mysql));
  rc= mysql_stmt_prepare(stmt, SL(query));
  check_stmt_rc(rc, stmt);

  FAIL_IF(mysql_stmt_param_count(stmt) != 3, "paramcount != 3");

  memset(my_bind, '\0', sizeof(my_bind));

  my_bind[0].buffer= (void *)int_data;
  my_bind[0].buffer_type= MYSQL_TYPE_LONG;
  my_bind[2]= my_bind[1]= my_bind[0];
  my_bind[1].buffer= (void *)(int_data + 1);
  my_bind[2].buffer= (void *)(int_data + 2);

  rc= mysql_stmt_bind_param(stmt, my_bind);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  rc= 0;
  while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
    rc++;
  FAIL_UNLESS(rc == 1, "rowcount != 1");

  mysql_stmt_close(stmt);

  rc= mysql_query(mysql, "DROP TABLE test_bg1500");
  check_mysql_rc(rc, mysql);

  rc= mysql_query(mysql, "CREATE TABLE test_bg1500 (s VARCHAR(25), FULLTEXT(s)) engine=MyISAM");
  check_mysql_rc(rc, mysql);

  rc= mysql_query(mysql,
        "INSERT INTO test_bg1500 VALUES ('Gravedigger'), ('Greed'), ('Hollow Dogs')");
  check_mysql_rc(rc, mysql);

  rc= mysql_commit(mysql);
  check_mysql_rc(rc, mysql);

  query= "SELECT s FROM test_bg1500 WHERE MATCH (s) AGAINST (?)";
  stmt= mysql_stmt_init(mysql);
  FAIL_IF(!stmt, mysql_error(mysql));
  rc= mysql_stmt_prepare(stmt, SL(query));
  check_stmt_rc(rc, stmt);

  FAIL_IF(mysql_stmt_param_count(stmt) != 1, "paramcount != 1");

  data= "Dogs";
  my_bind[0].buffer_type= MYSQL_TYPE_STRING;
  my_bind[0].buffer= (void *) data;
  my_bind[0].buffer_length= (unsigned long)strlen(data);
  my_bind[0].is_null= 0;
  my_bind[0].length= 0;

  rc= mysql_stmt_bind_param(stmt, my_bind);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  rc= 0;
  while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
    rc++;
  FAIL_UNLESS(rc == 1, "rowcount != 1");

  mysql_stmt_close(stmt);

  /* This should work too */
  query= "SELECT s FROM test_bg1500 WHERE MATCH (s) AGAINST (CONCAT(?, 'digger'))";
  stmt= mysql_stmt_init(mysql);
  FAIL_IF(!stmt, mysql_error(mysql));
  rc= mysql_stmt_prepare(stmt, SL(query));
  check_stmt_rc(rc, stmt);

  FAIL_IF(mysql_stmt_param_count(stmt) != 1, "paramcount != 1");

  data= "Grave";
  my_bind[0].buffer_type= MYSQL_TYPE_STRING;
  my_bind[0].buffer= (void *) data;
  my_bind[0].buffer_length= (unsigned long)strlen(data);

  rc= mysql_stmt_bind_param(stmt, my_bind);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  rc= 0;
  while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
    rc++;
  FAIL_UNLESS(rc == 1, "rowcount != 1");

  mysql_stmt_close(stmt);
  rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_bg1500");
  check_mysql_rc(rc, mysql);

  return OK;
}

static int test_bug15510(MYSQL *mysql)
{
  MYSQL_STMT *stmt;
  int rc;
  const char *query= "select 1 from dual where 1/0";

  SKIP_MYSQL(mysql);

  rc= mysql_query(mysql, "set @@sql_mode='ERROR_FOR_DIVISION_BY_ZERO'");
  check_mysql_rc(rc, mysql);

  stmt= mysql_stmt_init(mysql);

  rc= mysql_stmt_prepare(stmt, SL(query));
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_fetch(stmt);
  FAIL_UNLESS(mysql_warning_count(mysql), "Warning expected");

  /* Cleanup */
  mysql_stmt_close(stmt);
  rc= mysql_query(mysql, "set @@sql_mode=''");
  check_mysql_rc(rc, mysql);

  return OK;
}

/*
  Bug #15518 - Reusing a stmt that has failed during prepare
  does not clear error
*/

static int test_bug15518(MYSQL *mysql)
{
  MYSQL_STMT *stmt;
  int rc;

  stmt= mysql_stmt_init(mysql);

  /*
    The prepare of foo should fail with errno 1064 since
    it's not a valid query
  */
  rc= mysql_stmt_prepare(stmt, "foo", 3);
  FAIL_UNLESS(rc && mysql_stmt_errno(stmt) && mysql_errno(mysql), "Error expected");

  /*
    Use the same stmt and reprepare with another query that
    succeeds
  */
  rc= mysql_stmt_prepare(stmt, "SHOW STATUS", 12);
  FAIL_UNLESS(!rc || mysql_stmt_errno(stmt) || mysql_errno(mysql), "Error not expected");

  rc= mysql_stmt_close(stmt);
  check_mysql_rc(rc, mysql);
  /*
    part2, when connection to server has been closed
    after first prepare
  */
  stmt= mysql_stmt_init(mysql);
  rc= mysql_stmt_prepare(stmt, "foo", 3);
  FAIL_UNLESS(rc && mysql_stmt_errno(stmt) && mysql_errno(mysql), "Error expected");

  /* Close connection to server */
  mysql_close(mysql);

  /*
    Use the same stmt and reprepare with another query that
    succeeds. The prepare should fail with error 2013 since
    connection to server has been closed.
  */
  rc= mysql_stmt_prepare(stmt, "SHOW STATUS", 12);
  FAIL_UNLESS(rc && mysql_stmt_errno(stmt), "Error expected");

  mysql_stmt_close(stmt);

  return OK;
}

/*
  Bug #15613: "libmysqlclient API function mysql_stmt_prepare returns wrong
  field length"
*/

static int test_bug15613(MYSQL *mysql)
{
  MYSQL_STMT *stmt;
  const char *stmt_text;
  MYSQL_RES *metadata;
  MYSQL_FIELD *field;
  int rc;

  //https://jira.mariadb.org/browse/XPT-273
  SKIP_XPAND;

  /* I. Prepare the table */
  rc= mysql_query(mysql, "set names latin1");
  check_mysql_rc(rc, mysql);
  mysql_query(mysql, "drop table if exists t1");
  rc= mysql_query(mysql,
                  "create table t1 (t text character set utf8, "
                                   "tt tinytext character set utf8, "
                                   "mt mediumtext character set utf8, "
                                   "lt longtext character set utf8, "
                                   "vl varchar(255) character set latin1,"
                                   "vb varchar(255) character set binary,"
                                   "vu varchar(255) character set utf8)");
  check_mysql_rc(rc, mysql);

  stmt= mysql_stmt_init(mysql);

  /* II. Check SELECT metadata */
  stmt_text= ("select t, tt, mt, lt, vl, vb, vu from t1");
  rc= mysql_stmt_prepare(stmt, SL(stmt_text));
  metadata= mysql_stmt_result_metadata(stmt);
  field= mysql_fetch_fields(metadata);
  FAIL_UNLESS(field[0].length == 65535, "length != 65535");
  FAIL_UNLESS(field[1].length == 255, "length != 255");
  FAIL_UNLESS(field[2].length == 16777215, "length != 166777215");
  FAIL_UNLESS(field[3].length == 4294967295UL, "length != 4294967295UL");
  FAIL_UNLESS(field[4].length == 255, "length != 255");
  FAIL_UNLESS(field[5].length == 255, "length != 255");
  FAIL_UNLESS(field[6].length == 255, "length != 255");
  mysql_free_result(metadata);
  mysql_stmt_free_result(stmt);

  /* III. Cleanup */
  rc= mysql_query(mysql, "drop table t1");
  check_mysql_rc(rc, mysql);
  rc= mysql_query(mysql, "set names default");
  check_mysql_rc(rc, mysql);
  mysql_stmt_close(stmt);

  return OK;
}

static int test_bug16144(MYSQL *mysql)
{
  const my_bool flag_orig= (my_bool) 0xde;
  my_bool flag= flag_orig;
  MYSQL_STMT *stmt;

  /* Check that attr_get returns correct data on little and big endian CPUs */
  stmt= mysql_stmt_init(mysql);
  mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (const void*) &flag);
  mysql_stmt_attr_get(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (void*) &flag);
  FAIL_UNLESS(flag == flag_orig, "flag != flag_orig");

  mysql_stmt_close(stmt);

  return OK;
}

/*
  This tests for various mysql_stmt_send_long_data bugs described in #1664
*/

static int test_bug1664(MYSQL *mysql)
{
    MYSQL_STMT *stmt;
    int        rc, int_data;
    const char *data;
    const char *str_data= "Simple string";
    MYSQL_BIND my_bind[2];
    const char *query= "INSERT INTO test_long_data(col2, col1) VALUES(?, ?)";

    // https://jira.mariadb.org/browse/XPT-266
    if (IS_XPAND()) {
      rc= mysql_query(mysql, "SET NAMES UTF8");
      check_mysql_rc(rc, mysql);
    }

    rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_long_data");
    check_mysql_rc(rc, mysql);

    rc= mysql_query(mysql, "CREATE TABLE test_long_data(col1 int, col2 MEDIUMTEXT)");
    check_mysql_rc(rc, mysql);

    stmt= mysql_stmt_init(mysql);
    rc= mysql_stmt_prepare(stmt, SL(query));
    check_stmt_rc(rc, stmt);

    FAIL_IF(mysql_stmt_param_count(stmt) != 2, "Param count != 2");

    memset(my_bind, '\0', sizeof(my_bind));

    my_bind[0].buffer_type= MYSQL_TYPE_STRING;
    my_bind[0].buffer= (void *)str_data;
    my_bind[0].buffer_length= (unsigned long)strlen(str_data);

    my_bind[1].buffer= (void *)&int_data;
    my_bind[1].buffer_type= MYSQL_TYPE_LONG;

    rc= mysql_stmt_bind_param(stmt, my_bind);
    check_stmt_rc(rc, stmt);

    int_data= 1;

    /*
      Let us supply empty long_data. This should work and should
      not break following execution.
    */
    data= "";
    rc= mysql_stmt_send_long_data(stmt, 0, SL(data));
    check_stmt_rc(rc, stmt);

    rc= mysql_stmt_execute(stmt);
    check_stmt_rc(rc, stmt);
    if (verify_col_data(mysql, "test_long_data", "col1", "1"))
      goto error;
    if (verify_col_data(mysql, "test_long_data", "col2", ""))
      goto error;
    rc= mysql_query(mysql, "DELETE FROM test_long_data");
    check_mysql_rc(rc, mysql);

    /* This should pass OK */
    data= (char *)"Data";
    rc= mysql_stmt_send_long_data(stmt, 0, SL(data));
    check_stmt_rc(rc, stmt);

    rc= mysql_stmt_execute(stmt);
    check_stmt_rc(rc, stmt);

    if (verify_col_data(mysql, "test_long_data", "col1", "1"))
      goto error;
    if (verify_col_data(mysql, "test_long_data", "col2", "Data"))
      goto error;

    /* clean up */
    rc= mysql_query(mysql, "DELETE FROM test_long_data");
    check_mysql_rc(rc, mysql);

    /*
      Now we are changing int parameter and don't do anything
      with first parameter. Second mysql_stmt_execute() should run
      OK treating this first parameter as string parameter.
    */

    int_data= 2;
    /* execute */
    rc= mysql_stmt_execute(stmt);
    check_stmt_rc(rc, stmt);

    if (verify_col_data(mysql, "test_long_data", "col1", "2"))
      goto error;
    if (verify_col_data(mysql, "test_long_data", "col2", str_data))
      goto error;

    /* clean up */
    rc= mysql_query(mysql, "DELETE FROM test_long_data");
    check_mysql_rc(rc, mysql);

    /*
      Now we are sending other long data. It should not be
      concatenated to previous.
    */

    data= (char *)"SomeOtherData";
    rc= mysql_stmt_send_long_data(stmt, 0, SL(data));
    check_stmt_rc(rc, stmt);

    rc= mysql_stmt_execute(stmt);
    check_stmt_rc(rc, stmt);

    if (verify_col_data(mysql, "test_long_data", "col1", "2"))
      goto error;
    if (verify_col_data(mysql, "test_long_data", "col2", "SomeOtherData"))
      goto error;

    mysql_stmt_close(stmt);

    /* clean up */
    rc= mysql_query(mysql, "DELETE FROM test_long_data");
    check_mysql_rc(rc, mysql);

    /* Now let us test how mysql_stmt_reset works. */
    stmt= mysql_stmt_init(mysql);
    rc= mysql_stmt_prepare(stmt, SL(query));
    check_stmt_rc(rc, stmt);
    rc= mysql_stmt_bind_param(stmt, my_bind);
    check_stmt_rc(rc, stmt);

    data= (char *)"SomeData";
    rc= mysql_stmt_send_long_data(stmt, 0, SL(data));
    check_stmt_rc(rc, stmt);

    rc= mysql_stmt_reset(stmt);
    check_stmt_rc(rc, stmt);

    rc= mysql_stmt_execute(stmt);
    check_stmt_rc(rc, stmt);

    if (verify_col_data(mysql, "test_long_data", "col1", "2"))
      goto error;
    if (verify_col_data(mysql, "test_long_data", "col2", str_data))
      goto error;

    mysql_stmt_close(stmt);

    /* Final clean up */
    rc= mysql_query(mysql, "DROP TABLE test_long_data");
    check_mysql_rc(rc, mysql);

    return OK;

error:
    mysql_stmt_close(stmt);
    rc= mysql_query(mysql, "DROP TABLE test_long_data");
    return FAIL;
}
/* Test a misc bug */

static int test_ushort_bug(MYSQL *mysql)
{
  MYSQL_STMT *stmt;
  MYSQL_BIND my_bind[4];
  ushort     short_value;
  uint32     long_value;
  ulong      s_length, l_length, ll_length, t_length;
  ulonglong  longlong_value;
  int        rc;
  uchar      tiny_value;
  const char *query= "SELECT * FROM test_ushort";

  rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_ushort");
  check_mysql_rc(rc, mysql);

  rc= mysql_query(mysql, "CREATE TABLE test_ushort(a smallint unsigned, \
                                                  b smallint unsigned, \
                                                  c smallint unsigned, \
                                                  d smallint unsigned)");
  check_mysql_rc(rc, mysql);

  rc= mysql_query(mysql,
                  "INSERT INTO test_ushort VALUES(35999, 35999, 35999, 200)");
  check_mysql_rc(rc, mysql);

  stmt= mysql_stmt_init(mysql);
  FAIL_IF(!stmt, mysql_error(mysql));
  rc= mysql_stmt_prepare(stmt, SL(query));
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  memset(my_bind, '\0', sizeof(my_bind));
  my_bind[0].buffer_type= MYSQL_TYPE_SHORT;
  my_bind[0].buffer= (void *)&short_value;
  my_bind[0].is_unsigned= TRUE;
  my_bind[0].length= &s_length;

  my_bind[1].buffer_type= MYSQL_TYPE_LONG;
  my_bind[1].buffer= (void *)&long_value;
  my_bind[1].length= &l_length;

  my_bind[2].buffer_type= MYSQL_TYPE_LONGLONG;
  my_bind[2].buffer= (void *)&longlong_value;
  my_bind[2].length= &ll_length;

  my_bind[3].buffer_type= MYSQL_TYPE_TINY;
  my_bind[3].buffer= (void *)&tiny_value;
  my_bind[3].is_unsigned= TRUE;
  my_bind[3].length= &t_length;

  rc= mysql_stmt_bind_result(stmt, my_bind);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_fetch(stmt);
  check_stmt_rc(rc, stmt);

  FAIL_UNLESS(short_value == 35999, "short_value != 35999");
  FAIL_UNLESS(s_length == 2, "length != 2");

  FAIL_UNLESS(long_value == 35999, "long_value != 35999");
  FAIL_UNLESS(l_length == 4, "length != 4");

  FAIL_UNLESS(longlong_value == 35999, "longlong_value != 35999");
  FAIL_UNLESS(ll_length == 8, "length != 8");

  FAIL_UNLESS(tiny_value == 200, "tiny_value != 200");
  FAIL_UNLESS(t_length == 1, "length != 1");

  rc= mysql_stmt_fetch(stmt);
  FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");

  mysql_stmt_close(stmt);
  rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_ushort");
  check_mysql_rc(rc, mysql);

  return OK;
}

static int test_bug1946(MYSQL *mysql)
{
  MYSQL_STMT *stmt;
  int rc;
  const char *query= "INSERT INTO prepare_command VALUES (?)";


  rc= mysql_query(mysql, "DROP TABLE IF EXISTS prepare_command");
  check_mysql_rc(rc, mysql);

  rc= mysql_query(mysql, "CREATE TABLE prepare_command(ID INT)");
  check_mysql_rc(rc, mysql);

  stmt= mysql_stmt_init(mysql);
  FAIL_IF(!stmt, mysql_error(mysql));
  rc= mysql_stmt_prepare(stmt, SL(query));
  check_stmt_rc(rc, stmt);

  rc= mysql_real_query(mysql, SL(query));
  FAIL_IF(!rc, "Error expected");

  mysql_stmt_close(stmt);
  rc= mysql_query(mysql, "DROP TABLE prepare_command");
  check_mysql_rc(rc, mysql);
  return OK;
}

static int test_bug20152(MYSQL *mysql)
{
  MYSQL_BIND my_bind[1];
  MYSQL_STMT *stmt;
  MYSQL_TIME tm;
  int rc;
  const char *query= "INSERT INTO t1 (f1) VALUES (?)";


  memset(my_bind, '\0', sizeof(my_bind));
  my_bind[0].buffer_type= MYSQL_TYPE_DATE;
  my_bind[0].buffer= (void*)&tm;

  memset(&tm, 0, sizeof(MYSQL_TIME));

  tm.year = 2006;
  tm.month = 6;
  tm.day = 18;
  tm.hour = 14;
  tm.minute = 9;
  tm.second = 42;

  rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
  check_mysql_rc(rc, mysql);
  rc= mysql_query(mysql, "CREATE TABLE t1 (f1 DATE)");
  check_mysql_rc(rc, mysql);

  stmt= mysql_stmt_init(mysql);
  rc= mysql_stmt_prepare(stmt, SL(query));
  check_stmt_rc(rc, stmt);
  rc= mysql_stmt_bind_param(stmt, my_bind);
  check_stmt_rc(rc, stmt);
  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);
  rc= mysql_stmt_close(stmt);
  check_stmt_rc(rc, stmt);
  rc= mysql_query(mysql, "DROP TABLE t1");
  check_mysql_rc(rc, mysql);
  FAIL_UNLESS(tm.hour == 14 && tm.minute == 9 && tm.second == 42, "time != 14:09:42");
  return OK;
}

static int test_bug2247(MYSQL *mysql)
{
  MYSQL_STMT *stmt;
  MYSQL_RES *res;
  int rc;
  int i;
  const char *create= "CREATE TABLE bug2247(id INT UNIQUE AUTO_INCREMENT)";
  const char *insert= "INSERT INTO bug2247 VALUES (NULL)";
  const char *SELECT= "SELECT id FROM bug2247";
  const char *update= "UPDATE bug2247 SET id=id+10";
  const char *drop= "DROP TABLE IF EXISTS bug2247";
  ulonglong exp_count;
  enum { NUM_ROWS= 5 };


  /* create table and insert few rows */
  rc= mysql_query(mysql, drop);
  check_mysql_rc(rc, mysql);

  rc= mysql_query(mysql, create);
  check_mysql_rc(rc, mysql);

  stmt= mysql_stmt_init(mysql);
  FAIL_IF(!stmt, mysql_error(mysql));
  rc= mysql_stmt_prepare(stmt, SL(insert));
  check_stmt_rc(rc, stmt);
  for (i= 0; i < NUM_ROWS; ++i)
  {
    rc= mysql_stmt_execute(stmt);
    check_stmt_rc(rc, stmt);
  }
  exp_count= mysql_stmt_affected_rows(stmt);
  FAIL_UNLESS(exp_count == 1, "exp_count != 1");

  rc= mysql_query(mysql, SELECT);
  check_mysql_rc(rc, mysql);
  /*
    mysql_store_result overwrites mysql->affected_rows. Check that
    mysql_stmt_affected_rows() returns the same value, whereas
    mysql_affected_rows() value is correct.
  */
  res= mysql_store_result(mysql);
  FAIL_IF(!res, "Invalid result set");

  FAIL_UNLESS(mysql_affected_rows(mysql) == NUM_ROWS, "affected_rows != NUM_ROWS");
  FAIL_UNLESS(exp_count == mysql_stmt_affected_rows(stmt), "affected_rows != exp_count");

  rc= mysql_query(mysql, update);
  check_mysql_rc(rc, mysql);
  FAIL_UNLESS(mysql_affected_rows(mysql) == NUM_ROWS, "affected_rows != NUM_ROWS");
  FAIL_UNLESS(exp_count == mysql_stmt_affected_rows(stmt), "affected_rows != exp_count");

  mysql_free_result(res);
  mysql_stmt_close(stmt);

  /* check that mysql_stmt_store_result modifies mysql_stmt_affected_rows */
  stmt= mysql_stmt_init(mysql);
  FAIL_IF(!stmt, mysql_error(mysql));
  rc= mysql_stmt_prepare(stmt, SL(SELECT));
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);  rc= mysql_stmt_store_result(stmt);
  check_stmt_rc(rc, stmt);  exp_count= mysql_stmt_affected_rows(stmt);
  FAIL_UNLESS(exp_count == NUM_ROWS, "exp_count != NUM_ROWS");

  rc= mysql_query(mysql, insert);
  check_mysql_rc(rc, mysql);
  FAIL_UNLESS(mysql_affected_rows(mysql) == 1, "affected_rows != 1");
  FAIL_UNLESS(exp_count == mysql_stmt_affected_rows(stmt), "affected_rows != exp_count");

  mysql_stmt_close(stmt);
  rc= mysql_query(mysql, drop);
  check_mysql_rc(rc, mysql);
  return OK;
}

/*
  Test for bug#2248 "mysql_fetch without prior mysql_stmt_execute hangs"
*/

static int test_bug2248(MYSQL *mysql)
{
  MYSQL_STMT *stmt;
  int rc;
  const char *query1= "SELECT DATABASE()";
  const char *query2= "INSERT INTO test_bug2248 VALUES (10)";


  rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_bug2248");
  check_mysql_rc(rc, mysql);

  rc= mysql_query(mysql, "CREATE TABLE test_bug2248 (id int)");
  check_mysql_rc(rc, mysql);

  stmt= mysql_stmt_init(mysql);
  FAIL_IF(!stmt, mysql_error(mysql));
  rc= mysql_stmt_prepare(stmt, SL(query1));
  check_stmt_rc(rc, stmt);

  /* This should not hang */
  rc= mysql_stmt_fetch(stmt);
  FAIL_IF(!rc, "Error expected");

  /* And this too */
  rc= mysql_stmt_store_result(stmt);
  FAIL_IF(!rc, "Error expected");

  mysql_stmt_close(stmt);

  stmt= mysql_stmt_init(mysql);
  FAIL_IF(!stmt, mysql_error(mysql));
  rc= mysql_stmt_prepare(stmt, SL(query2));
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);
  /* This too should not hang but should return proper error */
  rc= mysql_stmt_fetch(stmt);
  FAIL_UNLESS(rc == 1, "rc != 1");

  /* This too should not hang but should not bark */
  rc= mysql_stmt_store_result(stmt);
  check_stmt_rc(rc, stmt);
  /* This should return proper error */
  rc= mysql_stmt_fetch(stmt);
  FAIL_UNLESS(rc == 1, "rc != 1");

  mysql_stmt_close(stmt);

  rc= mysql_query(mysql, "DROP TABLE test_bug2248");
  check_mysql_rc(rc, mysql);
  return OK;
}

/*
  BUG#23383: mysql_affected_rows() returns different values than
  mysql_stmt_affected_rows()

  Test that both mysql_affected_rows() and mysql_stmt_affected_rows()
  return -1 on error, 0 when no rows were affected, and (positive) row
  count when some rows were affected.
*/
static int test_bug23383(MYSQL *mysql)
{
  const char *insert_query= "INSERT INTO t1 VALUES (1), (2)";
  const char *update_query= "UPDATE t1 SET i= 4 WHERE i = 3";
  MYSQL_STMT *stmt;
  unsigned long long row_count;
  int rc;

  rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
  check_mysql_rc(rc, mysql);

  rc= mysql_query(mysql, "CREATE TABLE t1 (i INT UNIQUE)");
  check_mysql_rc(rc, mysql);

  rc= mysql_query(mysql, insert_query);
  check_mysql_rc(rc, mysql);
  row_count= mysql_affected_rows(mysql);
  FAIL_UNLESS(row_count == 2, "row_count != 2");

  rc= mysql_query(mysql, insert_query);
  FAIL_IF(!rc, "Error expected");
  row_count= mysql_affected_rows(mysql);
  FAIL_UNLESS(row_count == (unsigned long long)-1, "rowcount != -1");

  rc= mysql_query(mysql, update_query);
  check_mysql_rc(rc, mysql);
  row_count= mysql_affected_rows(mysql);
  FAIL_UNLESS(row_count == 0, "");

  rc= mysql_query(mysql, "DELETE FROM t1");
  check_mysql_rc(rc, mysql);

  stmt= mysql_stmt_init(mysql);
  FAIL_IF(!stmt, mysql_error(mysql));

  rc= mysql_stmt_prepare(stmt, SL(insert_query));
  check_stmt_rc(rc, stmt);
  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);
  row_count= mysql_stmt_affected_rows(stmt);
  FAIL_UNLESS(row_count == 2, "row_count != 2");

  rc= mysql_stmt_execute(stmt);
  FAIL_UNLESS(rc != 0, "");
  row_count= mysql_stmt_affected_rows(stmt);
  FAIL_UNLESS(row_count == (unsigned long long)-1, "rowcount != -1");

  rc= mysql_stmt_prepare(stmt, SL(update_query));
  check_stmt_rc(rc, stmt);
  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);
  row_count= mysql_stmt_affected_rows(stmt);
  FAIL_UNLESS(row_count == 0, "rowcount != 0");

  rc= mysql_stmt_close(stmt);
  check_stmt_rc(rc, stmt);
  rc= mysql_query(mysql, "DROP TABLE t1");
  check_mysql_rc(rc, mysql);

  return OK;
}

/*
  Bug#27592 (stack overrun when storing datetime value using prepared statements)
*/

static int test_bug27592(MYSQL *mysql)
{
  const int NUM_ITERATIONS= 40;
  int i;
  int rc;
  MYSQL_STMT *stmt= NULL;
  MYSQL_BIND bind[1];
  MYSQL_TIME time_val;

  mysql_query(mysql, "DROP TABLE IF EXISTS t1");
  mysql_query(mysql, "CREATE TABLE t1(c2 DATETIME)");

  stmt= mysql_stmt_init(mysql);
  FAIL_IF(!stmt, mysql_error(mysql));
  rc= mysql_stmt_prepare(stmt, SL("INSERT INTO t1 VALUES (?)"));
  check_stmt_rc(rc, stmt);

  memset(bind, '\0', sizeof(bind));

  bind[0].buffer_type= MYSQL_TYPE_DATETIME;
  bind[0].buffer= (char *) &time_val;
  bind[0].length= NULL;

  for (i= 0; i < NUM_ITERATIONS; i++)
  {
    time_val.year= 2007;
    time_val.month= 6;
    time_val.day= 7;
    time_val.hour= 18;
    time_val.minute= 41;
    time_val.second= 3;

    time_val.second_part=0;
    time_val.neg=0;

    rc= mysql_stmt_bind_param(stmt, bind);
    check_stmt_rc(rc, stmt);
    rc= mysql_stmt_execute(stmt);
    check_stmt_rc(rc, stmt);
  }

  mysql_stmt_close(stmt);
  mysql_query(mysql, "DROP TABLE IF EXISTS t1");

  return OK;
}

/*
  Bug#28934: server crash when receiving malformed com_execute packets
*/

static int test_bug28934(MYSQL *mysql)
{
  my_bool error= 0;
  MYSQL_BIND bind[5];
  MYSQL_STMT *stmt;
  int rc, cnt;

  rc= mysql_query(mysql, "drop table if exists t1");
  check_mysql_rc(rc, mysql);
  rc= mysql_query(mysql, "create table t1(id int)");
  check_mysql_rc(rc, mysql);

  rc= mysql_query(mysql, "insert into t1 values(1),(2),(3),(4),(5)");
  check_mysql_rc(rc, mysql);

  stmt= mysql_stmt_init(mysql);
  FAIL_IF(!stmt, mysql_error(mysql));
  rc= mysql_stmt_prepare(stmt, SL("select * from t1 where id in(?,?,?,?,?)"));
  check_stmt_rc(rc, stmt);

  memset (&bind, '\0', sizeof (bind));
  for (cnt= 0; cnt < 5; cnt++)
  {
    bind[cnt].buffer_type= MYSQL_TYPE_LONG;
    bind[cnt].buffer= (char*)&cnt;
    bind[cnt].buffer_length= 0;
  }
  rc= mysql_stmt_bind_param(stmt, bind);
  check_stmt_rc(rc, stmt);

  stmt->param_count=2;
  error= mysql_stmt_execute(stmt);
  FAIL_UNLESS(error != 0, "Error expected");
  mysql_stmt_close(stmt);

  rc= mysql_query(mysql, "drop table t1");
  check_mysql_rc(rc, mysql);
  return OK;
}

static int test_bug3035(MYSQL *mysql)
{
  MYSQL_STMT *stmt;
  int rc;
  MYSQL_BIND bind_array[12], *my_bind= bind_array, *bind_end= my_bind + 12;
  int8 int8_val;
  uint8 uint8_val;
  int16 int16_val;
  uint16 uint16_val;
  int32 int32_val;
  uint32 uint32_val;
  longlong int64_val;
  ulonglong uint64_val;
  double double_val, udouble_val, double_tmp;
  char longlong_as_string[22], ulonglong_as_string[22];

  /* mins and maxes */
  const int8 int8_min= -128;
  const int8 int8_max= 127;
  const uint8 uint8_min= 0;
  const uint8 uint8_max= 255;

  const int16 int16_min= -32768;
  const int16 int16_max= 32767;
  const uint16 uint16_min= 0;
  const uint16 uint16_max= 65535;

  const int32 int32_max= 2147483647L;
  const int32 int32_min= -int32_max - 1;
  const uint32 uint32_min= 0;
  const uint32 uint32_max= 4294967295U;

  /* it might not work okay everyplace */
  const longlong int64_max= 9223372036854775807LL;
  const longlong int64_min= -int64_max - 1;

  const ulonglong uint64_min= 0U;
  const ulonglong uint64_max= 18446744073709551615ULL;

  const char *stmt_text;


  stmt_text= "DROP TABLE IF EXISTS t1";
  rc= mysql_real_query(mysql, SL(stmt_text));
  check_mysql_rc(rc, mysql);

  stmt_text= "CREATE TABLE t1 (i8 TINYINT, ui8 TINYINT UNSIGNED, "
                              "i16 SMALLINT, ui16 SMALLINT UNSIGNED, "
                              "i32 INT, ui32 INT UNSIGNED, "
                              "i64 BIGINT, ui64 BIGINT UNSIGNED, "
                              "id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT)";
  rc= mysql_real_query(mysql, SL(stmt_text));
  check_mysql_rc(rc, mysql);

  memset(bind_array, '\0', sizeof(bind_array));
  for (my_bind= bind_array; my_bind < bind_end; my_bind++)
    my_bind->error= &my_bind->error_value;

  bind_array[0].buffer_type= MYSQL_TYPE_TINY;
  bind_array[0].buffer= (void *) &int8_val;

  bind_array[1].buffer_type= MYSQL_TYPE_TINY;
  bind_array[1].buffer= (void *) &uint8_val;
  bind_array[1].is_unsigned= 1;

  bind_array[2].buffer_type= MYSQL_TYPE_SHORT;
  bind_array[2].buffer= (void *) &int16_val;

  bind_array[3].buffer_type= MYSQL_TYPE_SHORT;
  bind_array[3].buffer= (void *) &uint16_val;
  bind_array[3].is_unsigned= 1;

  bind_array[4].buffer_type= MYSQL_TYPE_LONG;
  bind_array[4].buffer= (void *) &int32_val;

  bind_array[5].buffer_type= MYSQL_TYPE_LONG;
  bind_array[5].buffer= (void *) &uint32_val;
  bind_array[5].is_unsigned= 1;

  bind_array[6].buffer_type= MYSQL_TYPE_LONGLONG;
  bind_array[6].buffer= (void *) &int64_val;

  bind_array[7].buffer_type= MYSQL_TYPE_LONGLONG;
  bind_array[7].buffer= (void *) &uint64_val;
  bind_array[7].is_unsigned= 1;

  stmt= mysql_stmt_init(mysql);
  check_stmt_rc(rc, stmt);

  stmt_text= "INSERT INTO t1 (i8, ui8, i16, ui16, i32, ui32, i64, ui64) "
                     "VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
  rc= mysql_stmt_prepare(stmt, SL(stmt_text));
  check_stmt_rc(rc, stmt);
  mysql_stmt_bind_param(stmt, bind_array);

  int8_val= int8_min;
  uint8_val= uint8_min;
  int16_val= int16_min;
  uint16_val= uint16_min;
  int32_val= int32_min;
  uint32_val= uint32_min;
  int64_val= int64_min;
  uint64_val= uint64_min;

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);
  int8_val= int8_max;
  uint8_val= uint8_max;
  int16_val= int16_max;
  uint16_val= uint16_max;
  int32_val= int32_max;
  uint32_val= uint32_max;
  int64_val= int64_max;
  uint64_val= uint64_max;

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);
  stmt_text= "SELECT i8, ui8, i16, ui16, i32, ui32, i64, ui64, ui64, "
             "cast(ui64 as signed), ui64, cast(ui64 as signed)"
             "FROM t1 ORDER BY id ASC";

  rc= mysql_stmt_prepare(stmt, SL(stmt_text));
  check_stmt_rc(rc, stmt);
  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);
  bind_array[8].buffer_type= MYSQL_TYPE_DOUBLE;
  bind_array[8].buffer= (void *) &udouble_val;

  bind_array[9].buffer_type= MYSQL_TYPE_DOUBLE;
  bind_array[9].buffer= (void *) &double_val;

  bind_array[10].buffer_type= MYSQL_TYPE_STRING;
  bind_array[10].buffer= (void *) &ulonglong_as_string;
  bind_array[10].buffer_length= sizeof(ulonglong_as_string);

  bind_array[11].buffer_type= MYSQL_TYPE_STRING;
  bind_array[11].buffer= (void *) &longlong_as_string;
  bind_array[11].buffer_length= sizeof(longlong_as_string);

  mysql_stmt_bind_result(stmt, bind_array);

  rc= mysql_stmt_fetch(stmt);
  check_stmt_rc(rc, stmt);
  FAIL_UNLESS(int8_val == int8_min, "int8_val != int8_min");
  FAIL_UNLESS(uint8_val == uint8_min, "uint8_val != uint8_min");
  FAIL_UNLESS(int16_val == int16_min, "int16_val != int16_min");
  FAIL_UNLESS(uint16_val == uint16_min, "uint16_val != uint16_min");
  FAIL_UNLESS(int32_val == int32_min, "int32_val != int32_min");
  FAIL_UNLESS(uint32_val == uint32_min, "uint32_val != uint32_min");
  FAIL_UNLESS(int64_val == int64_min, "int64_val != int64_min");
  FAIL_UNLESS(uint64_val == uint64_min, "uint64_val != uint64_min");
  FAIL_UNLESS(double_val == (longlong) uint64_min, "double_val != uint64_min");
  double_tmp= ulonglong2double(uint64_val);
  FAIL_UNLESS(cmp_double(&udouble_val,&double_tmp), "udouble_val != double_tmp");
  FAIL_UNLESS(!strcmp(longlong_as_string, "0"), "longlong_as_string != '0'");
  FAIL_UNLESS(!strcmp(ulonglong_as_string, "0"), "ulonglong_as_string != '0'");

  rc= mysql_stmt_fetch(stmt);

  FAIL_UNLESS(rc == MYSQL_DATA_TRUNCATED || rc == 0, "rc != 0,MYSQL_DATA_TRUNCATED");

  FAIL_UNLESS(int8_val == int8_max, "int8_val != int8_max");
  FAIL_UNLESS(uint8_val == uint8_max, "uint8_val != uint8_max");
  FAIL_UNLESS(int16_val == int16_max, "int16_val != int16_max");
  FAIL_UNLESS(uint16_val == uint16_max, "uint16_val != uint16_max");
  FAIL_UNLESS(int32_val == int32_max, "int32_val != int32_max");
  FAIL_UNLESS(uint32_val == uint32_max, "uint32_val != uint32_max");
  FAIL_UNLESS(int64_val == int64_max, "int64_val != int64_max");
  FAIL_UNLESS(uint64_val == uint64_max, "uint64_val != uint64_max");
  FAIL_UNLESS(double_val == (longlong) uint64_val, "double_val != uint64_val");
  double_tmp= ulonglong2double(uint64_val);
  FAIL_UNLESS(cmp_double(&udouble_val,&double_tmp), "udouble_val != double_tmp");
  FAIL_UNLESS(!strcmp(longlong_as_string, "-1"), "longlong_as_string != '-1'");
  FAIL_UNLESS(!strcmp(ulonglong_as_string, "18446744073709551615"), "ulonglong_as_string != '18446744073709551615'");

  rc= mysql_stmt_fetch(stmt);
  FAIL_UNLESS(rc == MYSQL_NO_DATA, "");

  mysql_stmt_close(stmt);

  stmt_text= "DROP TABLE t1";
  mysql_real_query(mysql, SL(stmt_text));
  return OK;
}

/*
  Test for BUG#3420 ("select id1, value1 from t where id= ? or value= ?"
  returns all rows in the table)
*/

static int test_ps_conj_select(MYSQL *mysql)
{
  MYSQL_STMT *stmt;
  int        rc;
  MYSQL_BIND my_bind[2];
  int32      int_data;
  char       str_data[32];
  unsigned long str_length;
  char query[MAX_TEST_QUERY_LENGTH];

  // https://jira.mariadb.org/browse/XPT-266
  if (IS_XPAND()) {
    rc= mysql_query(mysql, "SET NAMES UTF8");
    check_mysql_rc(rc, mysql);
  }

  rc= mysql_query(mysql, "drop table if exists t1");
  check_mysql_rc(rc, mysql);

  rc= mysql_query(mysql, "create table t1 (id1 int(11) NOT NULL default '0', "
                         "value2 varchar(100), value1 varchar(100))");
  check_mysql_rc(rc, mysql);

  rc= mysql_query(mysql, "insert into t1 values (1, 'hh', 'hh'), "
                          "(2, 'hh', 'hh'), (1, 'ii', 'ii'), (2, 'ii', 'ii')");
  check_mysql_rc(rc, mysql);

  strcpy(query, "select id1, value1 from t1 where id1= ? or "
                "CONVERT(value1 USING utf8)= ?");
  stmt= mysql_stmt_init(mysql);
  FAIL_IF(!stmt, mysql_error(mysql));
  rc= mysql_stmt_prepare(stmt, SL(query));
  check_stmt_rc(rc, stmt);

  FAIL_IF(mysql_stmt_param_count(stmt) != 2, "param_count != 2");

  /* Always bzero all members of bind parameter */
  memset(my_bind, '\0', sizeof(my_bind));
  my_bind[0].buffer_type= MYSQL_TYPE_LONG;
  my_bind[0].buffer= (void *)&int_data;

  my_bind[1].buffer_type= MYSQL_TYPE_VAR_STRING;
  my_bind[1].buffer= (void *)str_data;
  my_bind[1].buffer_length= array_elements(str_data);
  my_bind[1].length= &str_length;

  rc= mysql_stmt_bind_param(stmt, my_bind);
  check_stmt_rc(rc, stmt);
  int_data= 1;
  strcpy(str_data, "hh");
  str_length= (unsigned long)strlen(str_data);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  rc=0;
  while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
   rc++;
  FAIL_UNLESS(rc == 3, "rc != 3");

  mysql_stmt_close(stmt);
  rc= mysql_query(mysql, "drop table if exists t1");
  check_mysql_rc(rc, mysql);
  return OK;
}

/* Test for NULL as PS parameter (BUG#3367, BUG#3371) */

static int test_ps_null_param(MYSQL *mysql)
{
  MYSQL_STMT *stmt;
  int        rc;

  MYSQL_BIND in_bind;
  my_bool    in_is_null;
  long int   in_long;

  MYSQL_BIND out_bind;
  ulong      out_length;
  my_bool    out_is_null;
  char       out_str_data[20];

  const char *queries[]= {"select ?", "select ?+1",
                    "select col1 from test_ps_nulls where col1 <=> ?",
                    NULL
                    };
  const char **cur_query= queries;


  rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_ps_nulls");
  check_mysql_rc(rc, mysql);

  rc= mysql_query(mysql, "CREATE TABLE test_ps_nulls(col1 int)");
  check_mysql_rc(rc, mysql);

  rc= mysql_query(mysql, "INSERT INTO test_ps_nulls values (1), (null)");
  check_mysql_rc(rc, mysql);

  /* Always bzero all members of bind parameter */
  memset(&in_bind, '\0', sizeof(in_bind));
  memset(&out_bind, '\0', sizeof(out_bind));
  in_bind.buffer_type= MYSQL_TYPE_LONG;
  in_bind.is_null= &in_is_null;
  in_bind.length= 0;
  in_bind.buffer= (void *)&in_long;
  in_is_null= 1;
  in_long= 1;

  out_bind.buffer_type= MYSQL_TYPE_STRING;
  out_bind.is_null= &out_is_null;
  out_bind.length= &out_length;
  out_bind.buffer= out_str_data;
  out_bind.buffer_length= array_elements(out_str_data);

  /* Execute several queries, all returning NULL in result. */
  for(cur_query= queries; *cur_query; cur_query++)
  {
    char query[MAX_TEST_QUERY_LENGTH];
    strcpy(query, *cur_query);
    stmt= mysql_stmt_init(mysql);
    FAIL_IF(!stmt, mysql_error(mysql));
    rc= mysql_stmt_prepare(stmt, SL(query));
    diag("statement: %s", query);
    check_stmt_rc(rc, stmt);
    FAIL_IF(mysql_stmt_param_count(stmt) != 1, "param_count != 1");

    rc= mysql_stmt_bind_param(stmt, &in_bind);
    check_stmt_rc(rc, stmt);
    rc= mysql_stmt_bind_result(stmt, &out_bind);
    check_stmt_rc(rc, stmt);
    rc= mysql_stmt_execute(stmt);
    check_stmt_rc(rc, stmt);
    rc= mysql_stmt_fetch(stmt);
    FAIL_UNLESS(rc != MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
    FAIL_UNLESS(out_is_null, "!out_is_null");
    rc= mysql_stmt_fetch(stmt);
    FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
    mysql_stmt_close(stmt);
  }
  rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_ps_nulls");
  check_mysql_rc(rc, mysql);
  return OK;
}

/*
  utility for the next test; expects 3 rows in the result from a SELECT,
  compares each row/field with an expected value.
 */
#define test_ps_query_cache_result(i1,s1,l1,i2,s2,l2,i3,s3,l3)    \
  r_metadata= mysql_stmt_result_metadata(stmt);                   \
  FAIL_UNLESS(r_metadata != NULL, "");                            \
  rc= mysql_stmt_fetch(stmt);                                     \
  check_stmt_rc(rc,stmt);                                         \
  FAIL_UNLESS((r_int_data == i1) && (r_str_length == l1) &&       \
             (strcmp(r_str_data, s1) == 0), "test_ps_query_cache_result failure"); \
  rc= mysql_stmt_fetch(stmt);                                     \
  check_stmt_rc(rc,stmt);                                         \
  FAIL_UNLESS((r_int_data == i2) && (r_str_length == l2) &&       \
             (strcmp(r_str_data, s2) == 0), "test_ps_query_cache_result failure"); \
  rc= mysql_stmt_fetch(stmt);                                     \
  check_stmt_rc(rc,stmt);                                         \
  FAIL_UNLESS((r_int_data == i3) && (r_str_length == l3) &&       \
             (strcmp(r_str_data, s3) == 0), "test_ps_query_cache_result failure"); \
  rc= mysql_stmt_fetch(stmt);                                     \
  FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");        \
  mysql_free_result(r_metadata);

/* reads Qcache_hits from server and returns its value */
static int query_cache_hits(MYSQL *mysql)
{
  MYSQL_RES *res;
  MYSQL_ROW row;
  int rc;
  uint result;

  rc= mysql_query(mysql, "show status like 'qcache_hits'");
  check_mysql_rc(rc, mysql);
  res= mysql_use_result(mysql);

  row= mysql_fetch_row(res);

  result= atoi(row[1]);
  mysql_free_result(res);
  return result;
}


/*
  Test that prepared statements make use of the query cache just as normal
  statements (BUG#735).
*/
static int test_ps_query_cache(MYSQL *mysql)
{
  MYSQL      *lmysql= mysql;
  MYSQL_STMT *stmt;
  int        rc;
  MYSQL_BIND p_bind[2],r_bind[2]; /* p: param bind; r: result bind */
  int32      p_int_data, r_int_data;
  char       p_str_data[32], r_str_data[32];
  unsigned long p_str_length, r_str_length;
  MYSQL_RES  *r_metadata;
  char       query[MAX_TEST_QUERY_LENGTH];
  uint       hits1, hits2;
  enum enum_test_ps_query_cache
  {
    /*
      We iterate the same prepare/executes block, but have iterations where
      we vary the query cache conditions.
    */
    /* the query cache is enabled for the duration of prep&execs: */
    TEST_QCACHE_ON= 0,
    /*
      same but using a new connection (to see if qcache serves results from
      the previous connection as it should):
    */
    TEST_QCACHE_ON_WITH_OTHER_CONN,
    /*
      First border case: disables the query cache before prepare and
      re-enables it before execution (to test if we have no bug then):
    */
    TEST_QCACHE_OFF_ON,
    /*
      Second border case: enables the query cache before prepare and
      disables it before execution:
    */
    TEST_QCACHE_ON_OFF
  };
  enum enum_test_ps_query_cache iteration;

  diag("test needs to be fixed");
  return SKIP;
  /* prepare the table */

  rc= mysql_query(mysql, "drop table if exists t1");
  check_mysql_rc(rc, mysql);

  rc= mysql_query(mysql, "create table t1 (id1 int(11) NOT NULL default '0', "
                         "value2 varchar(100), value1 varchar(100))");
  check_mysql_rc(rc, mysql);

  rc= mysql_query(mysql, "insert into t1 values (1, 'hh', 'hh'), "
                          "(2, 'hh', 'hh'), (1, 'ii', 'ii'), (2, 'ii', 'ii')");
  check_mysql_rc(rc, mysql);

  for (iteration= TEST_QCACHE_ON; iteration <= TEST_QCACHE_ON_OFF; iteration++)
  {
    switch (iteration) {
    case TEST_QCACHE_ON:
    case TEST_QCACHE_ON_OFF:
      rc= mysql_query(lmysql, "set global query_cache_size=1000000");
      check_mysql_rc(rc, mysql);
      break;
    case TEST_QCACHE_OFF_ON:
      rc= mysql_query(lmysql, "set global query_cache_size=0");
      check_mysql_rc(rc, mysql);
      break;
    case TEST_QCACHE_ON_WITH_OTHER_CONN:
      lmysql= test_connect(NULL);
      FAIL_IF(!lmysql, "Opening new connection failed");
      break;
    }

    strcpy(query, "select id1, value1 from t1 where id1= ? or "
           "CONVERT(value1 USING utf8)= ?");
    stmt= mysql_stmt_init(lmysql);
    FAIL_IF(!stmt, mysql_error(lmysql));
    rc= mysql_stmt_prepare(stmt, SL(query));
    check_stmt_rc(rc, stmt);

    FAIL_IF(mysql_stmt_param_count(stmt) != 2, "param_count != 2");

    switch (iteration) {
    case TEST_QCACHE_OFF_ON:
      rc= mysql_query(lmysql, "set global query_cache_size=1000000");
      check_mysql_rc(rc, mysql);
      break;
    case TEST_QCACHE_ON_OFF:
      rc= mysql_query(lmysql, "set global query_cache_size=0");
      check_mysql_rc(rc, mysql);
    default:
      break;
    }

    memset(p_bind, '\0', sizeof(p_bind));
    p_bind[0].buffer_type= MYSQL_TYPE_LONG;
    p_bind[0].buffer= (void *)&p_int_data;
    p_bind[1].buffer_type= MYSQL_TYPE_VAR_STRING;
    p_bind[1].buffer= (void *)p_str_data;
    p_bind[1].buffer_length= array_elements(p_str_data);
    p_bind[1].length= &p_str_length;

    rc= mysql_stmt_bind_param(stmt, p_bind);
    check_stmt_rc(rc, stmt);
    p_int_data= 1;
    strcpy(p_str_data, "hh");
    p_str_length= (unsigned long)strlen(p_str_data);

    memset(r_bind, '\0', sizeof(r_bind));
    r_bind[0].buffer_type= MYSQL_TYPE_LONG;
    r_bind[0].buffer= (void *)&r_int_data;
    r_bind[1].buffer_type= MYSQL_TYPE_VAR_STRING;
    r_bind[1].buffer= (void *)r_str_data;
    r_bind[1].buffer_length= array_elements(r_str_data);
    r_bind[1].length= &r_str_length;

    rc= mysql_stmt_bind_result(stmt, r_bind);
    check_stmt_rc(rc, stmt);
    rc= mysql_stmt_execute(stmt);
    check_stmt_rc(rc, stmt);
    test_ps_query_cache_result(1, "hh", 2, 2, "hh", 2, 1, "ii", 2);
  r_metadata= mysql_stmt_result_metadata(stmt);
  FAIL_UNLESS(r_metadata != NULL, "");
  rc= mysql_stmt_fetch(stmt);
  check_stmt_rc(rc,stmt);
  FAIL_UNLESS((r_int_data == 1) && (r_str_length == 2) &&
             (strcmp(r_str_data, "hh") == 0), "test_ps_query_cache_result failure"); \
  rc= mysql_stmt_fetch(stmt);
  check_stmt_rc(rc,stmt);
  FAIL_UNLESS((r_int_data == 2) && (r_str_length == 2) &&
             (strcmp(r_str_data, "hh") == 0), "test_ps_query_cache_result failure"); \
  rc= mysql_stmt_fetch(stmt);
  check_stmt_rc(rc,stmt);
  FAIL_UNLESS((r_int_data == 1) && (r_str_length == 2) &&
             (strcmp(r_str_data, "ii") == 0), "test_ps_query_cache_result failure"); \
  rc= mysql_stmt_fetch(stmt);
  FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
  mysql_free_result(r_metadata);


    /* now retry with the same parameter values and see qcache hits */
    hits1= query_cache_hits(lmysql);
    rc= mysql_stmt_execute(stmt);
    check_stmt_rc(rc, stmt);    test_ps_query_cache_result(1, "hh", 2, 2, "hh", 2, 1, "ii", 2);
    hits2= query_cache_hits(lmysql);
    switch(iteration) {
    case TEST_QCACHE_ON_WITH_OTHER_CONN:
    case TEST_QCACHE_ON:                 /* should have hit */
      FAIL_UNLESS(hits2-hits1 == 1, "hits2 != hits1 + 1");
      break;
    case TEST_QCACHE_OFF_ON:
    case TEST_QCACHE_ON_OFF:             /* should not have hit */
      FAIL_UNLESS(hits2-hits1 == 0, "hits2 != hits1");
      break;
    }

    /* now modify parameter values and see qcache hits */
    strcpy(p_str_data, "ii");
    p_str_length= (unsigned long)strlen(p_str_data);
    rc= mysql_stmt_execute(stmt);
    check_stmt_rc(rc, stmt);
    test_ps_query_cache_result(1, "hh", 2, 1, "ii", 2, 2, "ii", 2);
    hits1= query_cache_hits(lmysql);

    switch(iteration) {
    case TEST_QCACHE_ON:
    case TEST_QCACHE_OFF_ON:
    case TEST_QCACHE_ON_OFF:             /* should not have hit */
      FAIL_UNLESS(hits2-hits1 == 0, "hits2 != hits1");
      break;
    case TEST_QCACHE_ON_WITH_OTHER_CONN: /* should have hit */
      FAIL_UNLESS(hits1-hits2 == 1, "hits2 != hits1+1");
      break;
    }

    rc= mysql_stmt_execute(stmt);
    check_stmt_rc(rc, stmt);
    test_ps_query_cache_result(1, "hh", 2, 1, "ii", 2, 2, "ii", 2);
    hits2= query_cache_hits(lmysql);

    mysql_stmt_close(stmt);

    switch(iteration) {
    case TEST_QCACHE_ON:                 /* should have hit */
      FAIL_UNLESS(hits2-hits1 == 1, "hits2 != hits1+1");
      break;
    case TEST_QCACHE_OFF_ON:
    case TEST_QCACHE_ON_OFF:             /* should not have hit */
      FAIL_UNLESS(hits2-hits1 == 0, "hits2 != hits1");
      break;
    case TEST_QCACHE_ON_WITH_OTHER_CONN: /* should have hit */
      FAIL_UNLESS(hits2-hits1 == 1, "hits2 != hits1+1");
      break;
    }

  } /* for(iteration=...) */

  if (lmysql != mysql)
    mysql_close(lmysql);

  rc= mysql_query(mysql, "set global query_cache_size=0");
  check_mysql_rc(rc, mysql);
  return OK;
}

static int test_bug3117(MYSQL *mysql)
{
  MYSQL_STMT *stmt;
  MYSQL_BIND buffer;
  longlong lii;
  ulong length;
  my_bool is_null;
  int rc;

  rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
  check_mysql_rc(rc, mysql);

  rc= mysql_query(mysql, "CREATE TABLE t1 (id int auto_increment primary key)");
  check_mysql_rc(rc, mysql);

  stmt= mysql_stmt_init(mysql);
  FAIL_IF(!stmt, mysql_error(mysql));
  rc= mysql_stmt_prepare(stmt, SL("SELECT LAST_INSERT_ID()"));
  check_stmt_rc(rc, stmt);

  rc= mysql_query(mysql, "INSERT INTO t1 VALUES (NULL)");
  check_mysql_rc(rc, mysql);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);
  memset(&buffer, '\0', sizeof(buffer));
  buffer.buffer_type= MYSQL_TYPE_LONGLONG;
  buffer.buffer_length= sizeof(lii);
  buffer.buffer= (void *)&lii;
  buffer.length= &length;
  buffer.is_null= &is_null;

  rc= mysql_stmt_bind_result(stmt, &buffer);
  check_stmt_rc(rc, stmt);
  rc= mysql_stmt_store_result(stmt);
  check_stmt_rc(rc, stmt);
  rc= mysql_stmt_fetch(stmt);
  check_stmt_rc(rc, stmt);
  FAIL_UNLESS(is_null == 0 && lii == 1, "is_null != 0 || lii != 1");

  rc= mysql_query(mysql, "INSERT INTO t1 VALUES (NULL)");
  check_mysql_rc(rc, mysql);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);
  rc= mysql_stmt_fetch(stmt);
  check_stmt_rc(rc, stmt);
  FAIL_UNLESS(is_null == 0 && lii == 2, "is_null != 0 || lii != 2");

  mysql_stmt_close(stmt);

  rc= mysql_query(mysql, "DROP TABLE t1");
  check_mysql_rc(rc, mysql);
  return OK;
}

/**
  Bug#36004 mysql_stmt_prepare resets the list of warnings
*/

static int test_bug36004(MYSQL *mysql)
{
  int rc, warning_count= 0;
  MYSQL_STMT *stmt;
  SKIP_MAXSCALE;
  SKIP_MYSQL(mysql); // don't send expected warnings

  if (mysql_get_server_version(mysql) < 60000) {
    diag("Test requires MySQL Server version 6.0 or above");
    return SKIP;
  }

  rc= mysql_query(mysql, "drop table if exists inexistant");
  check_mysql_rc(rc, mysql);

  FAIL_UNLESS(mysql_warning_count(mysql) == 1, "");
  query_int_variable(mysql, "@@warning_count", &warning_count);
  FAIL_UNLESS(warning_count, "Warning expected");

  stmt= mysql_stmt_init(mysql);
  FAIL_IF(!stmt, mysql_error(mysql));
  rc= mysql_stmt_prepare(stmt, SL("select 1"));
  check_stmt_rc(rc, stmt);

  FAIL_UNLESS(mysql_warning_count(mysql) == 0, "No warning expected");
  query_int_variable(mysql, "@@warning_count", &warning_count);
  FAIL_UNLESS(warning_count, "warning expected");

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);
  FAIL_UNLESS(mysql_warning_count(mysql) == 0, "No warning expected");
  mysql_stmt_close(stmt);

  query_int_variable(mysql, "@@warning_count", &warning_count);
  FAIL_UNLESS(warning_count, "Warning expected");

  stmt= mysql_stmt_init(mysql);
  FAIL_IF(!stmt, mysql_error(mysql));
  rc= mysql_stmt_prepare(stmt, SL("drop table if exists inexistant"));
  check_stmt_rc(rc, stmt);

  query_int_variable(mysql, "@@warning_count", &warning_count);
  FAIL_UNLESS(warning_count == 0, "No warning expected");
  mysql_stmt_close(stmt);

  return OK;
}

static int test_bug3796(MYSQL *mysql)
{
  MYSQL_STMT *stmt;
  MYSQL_BIND my_bind[1];
  const char *concat_arg0= "concat_with_";
  enum { OUT_BUFF_SIZE= 30 };
  char out_buff[OUT_BUFF_SIZE];
  char canonical_buff[OUT_BUFF_SIZE];
  ulong out_length;
  const char *stmt_text;
  int rc;

  // https://jira.mariadb.org/browse/XPT-266
  if (IS_XPAND()) {
    rc= mysql_query(mysql, "SET NAMES UTF8");
    check_mysql_rc(rc, mysql);
  }

  /* Create and fill test table */
  stmt_text= "DROP TABLE IF EXISTS t1";
  rc= mysql_real_query(mysql, SL(stmt_text));
  check_mysql_rc(rc, mysql);

  stmt_text= "CREATE TABLE t1 (a INT, b VARCHAR(30))";
  rc= mysql_real_query(mysql, SL(stmt_text));
  check_mysql_rc(rc, mysql);

  stmt_text= "INSERT INTO t1 VALUES(1, 'ONE'), (2, 'TWO')";
  rc= mysql_real_query(mysql, SL(stmt_text));
  check_mysql_rc(rc, mysql);

  /* Create statement handle and prepare it with select */
  stmt= mysql_stmt_init(mysql);
  stmt_text= "SELECT concat(?, b) FROM t1";

  rc= mysql_stmt_prepare(stmt, SL(stmt_text));
  check_stmt_rc(rc, stmt);
  /* Bind input buffers */
  memset(my_bind, '\0', sizeof(my_bind));
  my_bind[0].buffer_type= MYSQL_TYPE_STRING;
  my_bind[0].buffer= (void *) concat_arg0;
  my_bind[0].buffer_length= (unsigned long)strlen(concat_arg0);

  mysql_stmt_bind_param(stmt, my_bind);

  /* Execute the select statement */
  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);
  my_bind[0].buffer= (void *) out_buff;
  my_bind[0].buffer_length= OUT_BUFF_SIZE;
  my_bind[0].length= &out_length;

  mysql_stmt_bind_result(stmt, my_bind);

  rc= mysql_stmt_fetch(stmt);
  check_stmt_rc(rc, stmt);
  strcpy(canonical_buff, concat_arg0);
  strcat(canonical_buff, "ONE");
  FAIL_UNLESS(strlen(canonical_buff) == out_length &&
         strncmp(out_buff, canonical_buff, out_length) == 0, "");

  rc= mysql_stmt_fetch(stmt);
  check_stmt_rc(rc, stmt);
  strcpy(canonical_buff + strlen(concat_arg0), "TWO");
  FAIL_UNLESS(strlen(canonical_buff) == out_length &&
         strncmp(out_buff, canonical_buff, out_length) == 0, "");

  rc= mysql_stmt_fetch(stmt);
  FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");

  mysql_stmt_close(stmt);

  stmt_text= "DROP TABLE IF EXISTS t1";
  rc= mysql_real_query(mysql, SL(stmt_text));
  check_mysql_rc(rc, mysql);
  return OK;
}

static int test_bug4026(MYSQL *mysql)
{
  MYSQL_STMT *stmt;
  MYSQL_BIND my_bind[2];
  MYSQL_TIME time_in, time_out;
  MYSQL_TIME datetime_in, datetime_out;
  const char *stmt_text;
  int rc;


  /* Check that microseconds are inserted and selected successfully */

  /* Create a statement handle and prepare it with select */
  stmt= mysql_stmt_init(mysql);
  stmt_text= "SELECT ?, ?";

  rc= mysql_stmt_prepare(stmt, SL(stmt_text));
  check_stmt_rc(rc, stmt);
  /* Bind input buffers */
  memset(my_bind, '\0', sizeof(MYSQL_BIND) * 2);
  memset(&time_in, '\0', sizeof(MYSQL_TIME));
  memset(&time_out, '\0', sizeof(MYSQL_TIME));
  memset(&datetime_in, '\0', sizeof(MYSQL_TIME));
  memset(&datetime_out, '\0', sizeof(MYSQL_TIME));
  my_bind[0].buffer_type= MYSQL_TYPE_TIME;
  my_bind[0].buffer= (void *) &time_in;
  my_bind[1].buffer_type= MYSQL_TYPE_DATETIME;
  my_bind[1].buffer= (void *) &datetime_in;

  time_in.hour= 23;
  time_in.minute= 59;
  time_in.second= 59;
  time_in.second_part= 123456;
  /*
    This is not necessary, just to make DIE_UNLESS below work: this field
    is filled in when time is received from server
  */
  time_in.time_type= MYSQL_TIMESTAMP_TIME;

  datetime_in= time_in;
  datetime_in.year= 2003;
  datetime_in.month= 12;
  datetime_in.day= 31;
  datetime_in.time_type= MYSQL_TIMESTAMP_DATETIME;

  mysql_stmt_bind_param(stmt, my_bind);

  /* Execute the select statement */
  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);
  my_bind[0].buffer= (void *) &time_out;
  my_bind[1].buffer= (void *) &datetime_out;

  mysql_stmt_bind_result(stmt, my_bind);

  rc= mysql_stmt_fetch(stmt);
  FAIL_UNLESS(rc == 0, "rc != 0");
  FAIL_UNLESS(memcmp(&time_in, &time_out, sizeof(time_in)) == 0, "time_in != time_out");
  FAIL_UNLESS(memcmp(&datetime_in, &datetime_out, sizeof(datetime_in)) == 0, "datetime_in != datetime_out");
  mysql_stmt_close(stmt);

  return OK;
}

static int test_bug4030(MYSQL *mysql)
{
  MYSQL_STMT *stmt;
  MYSQL_BIND my_bind[3];
  MYSQL_TIME time_canonical, time_out;
  MYSQL_TIME date_canonical, date_out;
  MYSQL_TIME datetime_canonical, datetime_out;
  const char *stmt_text;
  int rc;


  /* Check that microseconds are inserted and selected successfully */

  /* Execute a query with time values in prepared mode */
  stmt= mysql_stmt_init(mysql);
  stmt_text= "SELECT '23:59:59.123456', '2003-12-31', "
             "'2003-12-31 23:59:59.123456'";
  rc= mysql_stmt_prepare(stmt, SL(stmt_text));
  check_stmt_rc(rc, stmt);
  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);
  /* Bind output buffers */
  memset(my_bind, '\0', sizeof(my_bind));
  memset(&time_canonical, '\0', sizeof(time_canonical));
  memset(&time_out, '\0', sizeof(time_out));
  memset(&date_canonical, '\0', sizeof(date_canonical));
  memset(&date_out, '\0', sizeof(date_out));
  memset(&datetime_canonical, '\0', sizeof(datetime_canonical));
  memset(&datetime_out, '\0', sizeof(datetime_out));
  my_bind[0].buffer_type= MYSQL_TYPE_TIME;
  my_bind[0].buffer= (void *) &time_out;
  my_bind[1].buffer_type= MYSQL_TYPE_DATE;
  my_bind[1].buffer= (void *) &date_out;
  my_bind[2].buffer_type= MYSQL_TYPE_DATETIME;
  my_bind[2].buffer= (void *) &datetime_out;

  time_canonical.hour= 23;
  time_canonical.minute= 59;
  time_canonical.second= 59;
  time_canonical.second_part= 123456;
  time_canonical.time_type= MYSQL_TIMESTAMP_TIME;

  date_canonical.year= 2003;
  date_canonical.month= 12;
  date_canonical.day= 31;
  date_canonical.time_type= MYSQL_TIMESTAMP_DATE;

  datetime_canonical= time_canonical;
  datetime_canonical.year= 2003;
  datetime_canonical.month= 12;
  datetime_canonical.day= 31;
  datetime_canonical.time_type= MYSQL_TIMESTAMP_DATETIME;

  mysql_stmt_bind_result(stmt, my_bind);

  rc= mysql_stmt_fetch(stmt);
  FAIL_UNLESS(rc == 0, "rc != 0");
  FAIL_UNLESS(memcmp(&time_canonical, &time_out, sizeof(time_out)) == 0, "time_canonical != time_out");
  FAIL_UNLESS(memcmp(&date_canonical, &date_out, sizeof(date_out)) == 0, "date_canonical != date_out");
  FAIL_UNLESS(memcmp(&datetime_canonical, &datetime_out, sizeof(datetime_out)) == 0, "datetime_canonical != datetime_out");
  mysql_stmt_close(stmt);
  return OK;
}

static int test_bug4079(MYSQL *mysql)
{
  MYSQL_STMT *stmt;
  MYSQL_BIND my_bind[1];
  const char *stmt_text;
  uint32 res;
  int rc;

  /* Create and fill table */
  mysql_query(mysql, "DROP TABLE IF EXISTS t1");
  mysql_query(mysql, "CREATE TABLE t1 (a int)");
  mysql_query(mysql, "INSERT INTO t1 VALUES (1), (2)");

  /* Prepare erroneous statement */
  stmt= mysql_stmt_init(mysql);
  stmt_text= "SELECT 1 < (SELECT a FROM t1)";

  rc= mysql_stmt_prepare(stmt, SL(stmt_text));
  check_stmt_rc(rc, stmt);
  /* Execute the select statement */
  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);
  /* Bind input buffers */
  memset(my_bind, '\0', sizeof(my_bind));
  my_bind[0].buffer_type= MYSQL_TYPE_LONG;
  my_bind[0].buffer= (void *) &res;

  mysql_stmt_bind_result(stmt, my_bind);

  rc= mysql_stmt_fetch(stmt);
  FAIL_UNLESS(rc == 1, "rc != 1");
  /* buggy version of libmysql hanged up here */
  mysql_stmt_close(stmt);
  return OK;
}

static int test_bug4172(MYSQL *mysql)
{
  MYSQL_STMT *stmt;
  MYSQL_BIND my_bind[3];
  const char *stmt_text;
  MYSQL_RES *res;
  MYSQL_ROW row;
  int rc;
  char f[100], d[100], e[100];
  ulong f_len, d_len, e_len;

  mysql_query(mysql, "DROP TABLE IF EXISTS t1");
  mysql_query(mysql, "CREATE TABLE t1 (f float, d double, e decimal(10,4))");
  mysql_query(mysql, "INSERT INTO t1 VALUES (12345.1234, 123456.123456, "
                                            "123456.1234)");

  stmt= mysql_stmt_init(mysql);
  stmt_text= "SELECT f, d, e FROM t1";

  rc= mysql_stmt_prepare(stmt, SL(stmt_text));
  check_stmt_rc(rc, stmt);  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);
  memset(my_bind, '\0', sizeof(my_bind));  my_bind[0].buffer_type= MYSQL_TYPE_STRING;
  my_bind[0].buffer= f;
  my_bind[0].buffer_length= sizeof(f);
  my_bind[0].length= &f_len;
  my_bind[1].buffer_type= MYSQL_TYPE_STRING;
  my_bind[1].buffer= d;
  my_bind[1].buffer_length= sizeof(d);
  my_bind[1].length= &d_len;
  my_bind[2].buffer_type= MYSQL_TYPE_STRING;
  my_bind[2].buffer= e;
  my_bind[2].buffer_length= sizeof(e);
  my_bind[2].length= &e_len;

  mysql_stmt_bind_result(stmt, my_bind);

  mysql_stmt_store_result(stmt);
  rc= mysql_stmt_fetch(stmt);
  check_stmt_rc(rc, stmt);
  rc= mysql_real_query(mysql, SL(stmt_text));
  check_mysql_rc(rc, mysql);
  res= mysql_store_result(mysql);
  row= mysql_fetch_row(res);

  diag("expected %s %s %s", row[0], row[1], row[2]);
  diag("fetched %s %s %s", f, d, e);
  FAIL_UNLESS(!strcmp(f, row[0]) && !strcmp(d, row[1]) && !strcmp(e, row[2]), "");

  mysql_free_result(res);
  mysql_stmt_close(stmt);
  return OK;
}

static int test_bug4231(MYSQL *mysql)
{
  MYSQL_STMT *stmt;
  MYSQL_BIND my_bind[2];
  MYSQL_TIME tm[2];
  const char *stmt_text;
  int rc;


  stmt_text= "DROP TABLE IF EXISTS t1";
  rc= mysql_real_query(mysql, SL(stmt_text));
  check_mysql_rc(rc, mysql);

  stmt_text= "CREATE TABLE t1 (a int)";
  rc= mysql_real_query(mysql, SL(stmt_text));
  check_mysql_rc(rc, mysql);

  stmt_text= "INSERT INTO t1 VALUES (1)";
  rc= mysql_real_query(mysql, SL(stmt_text));
  check_mysql_rc(rc, mysql);

  stmt= mysql_stmt_init(mysql);
  stmt_text= "SELECT a FROM t1 WHERE ? = ?";
  rc= mysql_stmt_prepare(stmt, SL(stmt_text));
  check_stmt_rc(rc, stmt);
  /* Bind input buffers */
  memset(my_bind, '\0', sizeof(my_bind));  memset(tm, '\0', sizeof(tm));
  my_bind[0].buffer_type= MYSQL_TYPE_DATE;
  my_bind[0].buffer= &tm[0];
  my_bind[1].buffer_type= MYSQL_TYPE_DATE;
  my_bind[1].buffer= &tm[1];

  mysql_stmt_bind_param(stmt, my_bind);
  check_stmt_rc(rc, stmt);
  /*
    First set server-side params to some non-zero non-equal values:
    then we will check that they are not used when client sends
    new (zero) times.
  */
  tm[0].time_type = MYSQL_TIMESTAMP_DATE;
  tm[0].year = 2000;
  tm[0].month = 1;
  tm[0].day = 1;
  tm[1]= tm[0];
  --tm[1].year;                                 /* tm[0] != tm[1] */

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);
  rc= mysql_stmt_fetch(stmt);

  /* binds are unequal, no rows should be returned */
  FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");

  /* Set one of the dates to zero */
  tm[0].year= tm[0].month= tm[0].day= 0;
  tm[1]= tm[0];
  mysql_stmt_execute(stmt);
  rc= mysql_stmt_fetch(stmt);
  FAIL_UNLESS(rc == 0, "rc != 0");

  mysql_stmt_close(stmt);
  stmt_text= "DROP TABLE t1";
  rc= mysql_real_query(mysql, SL(stmt_text));
  check_mysql_rc(rc, mysql);
  return OK;
}

static int test_bug4236(MYSQL *mysql)
{
  MYSQL_STMT *stmt;
  const char *stmt_text;
  int rc;
  MYSQL_STMT backup;

  stmt= mysql_stmt_init(mysql);

  /* mysql_stmt_execute() of statement with statement id= 0 crashed server */
  stmt_text= "SELECT 1";
  /* We need to prepare statement to pass by possible check in libmysql */
  rc= mysql_stmt_prepare(stmt, SL(stmt_text));
  check_stmt_rc(rc, stmt);  /* Hack to check that server works OK if statement wasn't found */
  backup.stmt_id= stmt->stmt_id;
  stmt->stmt_id= 0;
  rc= mysql_stmt_execute(stmt);
  FAIL_IF(!rc, "Error expected");

  /* Restore original statement id to be able to reprepare it */
  stmt->stmt_id= backup.stmt_id;

  mysql_stmt_close(stmt);
  return OK;
}

static int test_bug5126(MYSQL *mysql)
{
  MYSQL_STMT *stmt;
  MYSQL_BIND my_bind[2];
  int32 c1, c2;
  const char *stmt_text;
  int rc;


  stmt_text= "DROP TABLE IF EXISTS t1";
  rc= mysql_real_query(mysql, SL(stmt_text));
  check_mysql_rc(rc, mysql);

  stmt_text= "CREATE TABLE t1 (a mediumint, b int)";
  rc= mysql_real_query(mysql, SL(stmt_text));
  check_mysql_rc(rc, mysql);

  stmt_text= "INSERT INTO t1 VALUES (8386608, 1)";
  rc= mysql_real_query(mysql, SL(stmt_text));
  check_mysql_rc(rc, mysql);

  stmt= mysql_stmt_init(mysql);
  stmt_text= "SELECT a, b FROM t1";
  rc= mysql_stmt_prepare(stmt, SL(stmt_text));
  check_stmt_rc(rc, stmt);
  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);
  /* Bind output buffers */
  memset(my_bind, '\0', sizeof(my_bind));
  my_bind[0].buffer_type= MYSQL_TYPE_LONG;
  my_bind[0].buffer= &c1;
  my_bind[1].buffer_type= MYSQL_TYPE_LONG;
  my_bind[1].buffer= &c2;

  mysql_stmt_bind_result(stmt, my_bind);

  rc= mysql_stmt_fetch(stmt);
  FAIL_UNLESS(rc == 0, "rc != 0");
  FAIL_UNLESS(c1 == 8386608 && c2 == 1, "c1 != 8386608 || c2 != 1");
  mysql_stmt_close(stmt);
  return OK;
}

static int test_bug5194(MYSQL *mysql)
{
  MYSQL_STMT *stmt;
  MYSQL_BIND *my_bind;
  char *query;
  char *param_str;
  int param_str_length;
  const char *stmt_text;
  int rc;
  float float_array[250] =
  {
    0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,
    0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,
    0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,
    0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,
    0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,
    0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,
    0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,
    0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,
    0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,
    0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,
    0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,
    0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,
    0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,
    0.25,  0.25,  0.25,  0.25,  0.25,  0.25,  0.25,  0.25,  0.25,  0.25,
    0.25,  0.25,  0.25,  0.25,  0.25,  0.25,  0.25,  0.25,  0.25,  0.25,
    0.25,  0.25,  0.25,  0.25,  0.25,  0.25,  0.25,  0.25,  0.25,  0.25,
    0.25,  0.25,  0.25,  0.25,  0.25,  0.25,  0.25,  0.25,  0.25,  0.25,
    0.25,  0.25,  0.25,  0.25,  0.25,  0.25,  0.25,  0.25,  0.25,  0.25,
    0.25,  0.25,  0.25,  0.25,  0.25,  0.25,  0.25,  0.25,  0.25,  0.25,
    0.25,  0.25,  0.25,  0.25,  0.25,  0.25,  0.25,  0.25,  0.25,  0.25,
    0.25,  0.25,  0.25,  0.25,  0.25,  0.25,  0.25,  0.25,  0.25,  0.25,
    0.25,  0.25,  0.25,  0.25,  0.25,  0.25,  0.25,  0.25,  0.25,  0.25,
    0.25,  0.25,  0.25,  0.25,  0.25,  0.25,  0.25,  0.25,  0.25,  0.25,
    0.25,  0.25,  0.25,  0.25,  0.25,  0.25,  0.25,  0.25,  0.25,  0.25,
    0.25,  0.25,  0.25,  0.25,  0.25,  0.25,  0.25,  0.25,  0.25,  0.25
  };
  float *fa_ptr= float_array;
  /* Number of columns per row */
  const int COLUMN_COUNT= sizeof(float_array)/sizeof(*float_array);
  /* Number of rows per bulk insert to start with */
  const int MIN_ROWS_PER_INSERT= 262;
  /* Max number of rows per bulk insert to end with */
  const int MAX_ROWS_PER_INSERT= 300;
  const int MAX_PARAM_COUNT= COLUMN_COUNT*MAX_ROWS_PER_INSERT;
  const char *query_template= "insert into t1 values %s";
  const int CHARS_PER_PARAM= 5; /* space needed to place ", ?" in the query */
  const int uint16_max= 65535;
  int nrows, i;

  SKIP_MAXSCALE;

  stmt_text= "drop table if exists t1";
  rc= mysql_real_query(mysql, SL(stmt_text));

  stmt_text= "create table if not exists t1"
   "(c1 float, c2 float, c3 float, c4 float, c5 float, c6 float, "
   "c7 float, c8 float, c9 float, c10 float, c11 float, c12 float, "
   "c13 float, c14 float, c15 float, c16 float, c17 float, c18 float, "
   "c19 float, c20 float, c21 float, c22 float, c23 float, c24 float, "
   "c25 float, c26 float, c27 float, c28 float, c29 float, c30 float, "
   "c31 float, c32 float, c33 float, c34 float, c35 float, c36 float, "
   "c37 float, c38 float, c39 float, c40 float, c41 float, c42 float, "
   "c43 float, c44 float, c45 float, c46 float, c47 float, c48 float, "
   "c49 float, c50 float, c51 float, c52 float, c53 float, c54 float, "
   "c55 float, c56 float, c57 float, c58 float, c59 float, c60 float, "
   "c61 float, c62 float, c63 float, c64 float, c65 float, c66 float, "
   "c67 float, c68 float, c69 float, c70 float, c71 float, c72 float, "
   "c73 float, c74 float, c75 float, c76 float, c77 float, c78 float, "
   "c79 float, c80 float, c81 float, c82 float, c83 float, c84 float, "
   "c85 float, c86 float, c87 float, c88 float, c89 float, c90 float, "
   "c91 float, c92 float, c93 float, c94 float, c95 float, c96 float, "
   "c97 float, c98 float, c99 float, c100 float, c101 float, c102 float, "
   "c103 float, c104 float, c105 float, c106 float, c107 float, c108 float, "
   "c109 float, c110 float, c111 float, c112 float, c113 float, c114 float, "
   "c115 float, c116 float, c117 float, c118 float, c119 float, c120 float, "
   "c121 float, c122 float, c123 float, c124 float, c125 float, c126 float, "
   "c127 float, c128 float, c129 float, c130 float, c131 float, c132 float, "
   "c133 float, c134 float, c135 float, c136 float, c137 float, c138 float, "
   "c139 float, c140 float, c141 float, c142 float, c143 float, c144 float, "
   "c145 float, c146 float, c147 float, c148 float, c149 float, c150 float, "
   "c151 float, c152 float, c153 float, c154 float, c155 float, c156 float, "
   "c157 float, c158 float, c159 float, c160 float, c161 float, c162 float, "
   "c163 float, c164 float, c165 float, c166 float, c167 float, c168 float, "
   "c169 float, c170 float, c171 float, c172 float, c173 float, c174 float, "
   "c175 float, c176 float, c177 float, c178 float, c179 float, c180 float, "
   "c181 float, c182 float, c183 float, c184 float, c185 float, c186 float, "
   "c187 float, c188 float, c189 float, c190 float, c191 float, c192 float, "
   "c193 float, c194 float, c195 float, c196 float, c197 float, c198 float, "
   "c199 float, c200 float, c201 float, c202 float, c203 float, c204 float, "
   "c205 float, c206 float, c207 float, c208 float, c209 float, c210 float, "
   "c211 float, c212 float, c213 float, c214 float, c215 float, c216 float, "
   "c217 float, c218 float, c219 float, c220 float, c221 float, c222 float, "
   "c223 float, c224 float, c225 float, c226 float, c227 float, c228 float, "
   "c229 float, c230 float, c231 float, c232 float, c233 float, c234 float, "
   "c235 float, c236 float, c237 float, c238 float, c239 float, c240 float, "
   "c241 float, c242 float, c243 float, c244 float, c245 float, c246 float, "
   "c247 float, c248 float, c249 float, c250 float)";
  rc= mysql_real_query(mysql, SL(stmt_text));
  check_mysql_rc(rc, mysql);

  my_bind= (MYSQL_BIND*) malloc(MAX_PARAM_COUNT * sizeof(MYSQL_BIND));
  FAIL_UNLESS(my_bind, "Not enough memory");
  query= (char*) malloc(strlen(query_template) +
                        MAX_PARAM_COUNT * CHARS_PER_PARAM + 1);
  if(!query)
    free(my_bind);
  FAIL_UNLESS(query, "Not enough memory");
  param_str= (char*) malloc(COLUMN_COUNT * CHARS_PER_PARAM);
  if(!param_str)
  {
    free(my_bind);
    free(query);
  }
  FAIL_UNLESS(param_str, "Not enough memory");

  stmt= mysql_stmt_init(mysql);

  /* setup a template for one row of parameters */
  sprintf(param_str, "(");
  for (i= 1; i < COLUMN_COUNT; ++i)
    strcat(param_str, "?, ");
  strcat(param_str, "?)");
  param_str_length= (int)strlen(param_str);

  /* setup bind array */
  memset(my_bind, '\0', MAX_PARAM_COUNT * sizeof(MYSQL_BIND));
  for (i= 0; i < MAX_PARAM_COUNT; ++i)
  {
    my_bind[i].buffer_type= MYSQL_TYPE_FLOAT;
    my_bind[i].buffer= fa_ptr;
    if (++fa_ptr == float_array + COLUMN_COUNT)
      fa_ptr= float_array;
  }

  /*
    Test each number of rows per bulk insert, so that we can see where
    MySQL fails.
  */
  for (nrows= MIN_ROWS_PER_INSERT; nrows <= MAX_ROWS_PER_INSERT; ++nrows)
  {
    char *query_ptr;
    /* Create statement text for current number of rows */
    sprintf(query, query_template, param_str);
    query_ptr= query + (unsigned long)strlen(query);
    for (i= 1; i < nrows; ++i)
    {
      memcpy(query_ptr, ", ", 2);
      query_ptr+= 2;
      memcpy(query_ptr, param_str, param_str_length);
      query_ptr+= param_str_length;
    }
    *query_ptr= '\0';

    rc= mysql_stmt_prepare(stmt, query, (ulong)(query_ptr - query));

    if (rc && nrows * COLUMN_COUNT > uint16_max) /* expected error */
      break;

    check_stmt_rc(rc, stmt);

    /* bind the parameter array and execute the query */
    rc= mysql_stmt_bind_param(stmt, my_bind);
    check_stmt_rc(rc, stmt);
    rc= mysql_stmt_execute(stmt);
    check_stmt_rc(rc, stmt);
    rc= mysql_stmt_reset(stmt);
  }

  free(param_str);
  free(query);
  rc= mysql_stmt_close(stmt);
  check_stmt_rc(rc, stmt);
  free(my_bind);
  stmt_text= "drop table t1";
  rc= mysql_real_query(mysql, SL(stmt_text));
  check_mysql_rc(rc, mysql);
  return OK;
}

static int test_bug5315(MYSQL *mysql)
{
  MYSQL_STMT *stmt;
  const char *stmt_text;
  int rc;
  SKIP_MAXSCALE;

  if (!is_mariadb)
    return SKIP;

  stmt_text= "SELECT 1";
  stmt= mysql_stmt_init(mysql);
  rc= mysql_stmt_prepare(stmt, SL(stmt_text));
  check_stmt_rc(rc, stmt);
  rc= mysql_change_user(mysql, username, password, schema);
  check_mysql_rc(rc, mysql);

  rc= mysql_stmt_execute(stmt);
  FAIL_UNLESS(rc != 0, "Error expected");

  rc= mysql_stmt_close(stmt);
  check_stmt_rc(rc, stmt);

  stmt= mysql_stmt_init(mysql);
  rc= mysql_stmt_prepare(stmt, SL(stmt_text));
  check_stmt_rc(rc, stmt);
  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);
  mysql_stmt_close(stmt);
  return OK;
}

static int test_bug5399(MYSQL *mysql)
{
  /*
    Ascii 97 is 'a', which gets mapped to Ascii 65 'A' unless internal
    statement id hash in the server uses binary collation.
  */
#define NUM_OF_USED_STMT 97
  MYSQL_STMT *stmt_list[NUM_OF_USED_STMT];
  MYSQL_STMT **stmt;
  MYSQL_BIND my_bind[1];
  char buff[600];
  int rc;
  int32 no;


  memset(my_bind, '\0', sizeof(my_bind));  my_bind[0].buffer_type= MYSQL_TYPE_LONG;
  my_bind[0].buffer= &no;

  for (stmt= stmt_list; stmt != stmt_list + NUM_OF_USED_STMT; ++stmt)
  {
    sprintf(buff, "select %d", (int) (stmt - stmt_list));
    *stmt= mysql_stmt_init(mysql);
    rc= mysql_stmt_prepare(*stmt, SL(buff));
    check_stmt_rc(rc, *stmt);    mysql_stmt_bind_result(*stmt, my_bind);
  }

  for (stmt= stmt_list; stmt != stmt_list + NUM_OF_USED_STMT; ++stmt)
  {
    rc= mysql_stmt_execute(*stmt);
    check_stmt_rc(rc, *stmt);
    rc= mysql_stmt_store_result(*stmt);
    check_stmt_rc(rc, *stmt);
    rc= mysql_stmt_fetch(*stmt);
    FAIL_UNLESS((int32) (stmt - stmt_list) == no, "");
  }

  for (stmt= stmt_list; stmt != stmt_list + NUM_OF_USED_STMT; ++stmt)
    mysql_stmt_close(*stmt);
#undef NUM_OF_USED_STMT
  return OK;
}

static int test_bug6046(MYSQL *mysql)
{
  MYSQL_STMT *stmt;
  const char *stmt_text;
  int rc;
  short b= 1;
  MYSQL_BIND my_bind[1];


  stmt_text= "DROP TABLE IF EXISTS t1";
  rc= mysql_real_query(mysql, SL(stmt_text));
  check_mysql_rc(rc, mysql);
  stmt_text= "CREATE TABLE t1 (a int, b int)";
  rc= mysql_real_query(mysql, SL(stmt_text));
  check_mysql_rc(rc, mysql);
  stmt_text= "INSERT INTO t1 VALUES (1,1),(2,2),(3,1),(4,2)";
  rc= mysql_real_query(mysql, SL(stmt_text));
  check_mysql_rc(rc, mysql);

  stmt= mysql_stmt_init(mysql);

  stmt_text= "SELECT t1.a FROM t1 NATURAL JOIN t1 as X1 "
             "WHERE t1.b > ? ORDER BY t1.a";

  rc= mysql_stmt_prepare(stmt, SL(stmt_text));
  check_stmt_rc(rc, stmt);
  b= 1;
  memset(my_bind, '\0', sizeof(my_bind));  my_bind[0].buffer= &b;
  my_bind[0].buffer_type= MYSQL_TYPE_SHORT;

  mysql_stmt_bind_param(stmt, my_bind);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);
  mysql_stmt_store_result(stmt);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);
  mysql_stmt_close(stmt);
  return OK;
}

static int test_bug6049(MYSQL *mysql)
{
  MYSQL_STMT *stmt;
  MYSQL_BIND my_bind[1];
  MYSQL_RES *res;
  MYSQL_ROW row;
  const char *stmt_text;
  char buffer[30];
  ulong length;
  int rc;


  stmt_text= "SELECT MAKETIME(-25, 12, 12)";

  rc= mysql_real_query(mysql, SL(stmt_text));
  check_mysql_rc(rc, mysql);
  res= mysql_store_result(mysql);
  row= mysql_fetch_row(res);

  stmt= mysql_stmt_init(mysql);
  rc= mysql_stmt_prepare(stmt, SL(stmt_text));
  check_stmt_rc(rc, stmt);
  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);
  memset(my_bind, '\0', sizeof(my_bind));
  my_bind[0].buffer_type    = MYSQL_TYPE_STRING;
  my_bind[0].buffer         = &buffer;
  my_bind[0].buffer_length  = sizeof(buffer);
  my_bind[0].length         = &length;

  mysql_stmt_bind_result(stmt, my_bind);
  rc= mysql_stmt_fetch(stmt);
  check_stmt_rc(rc, stmt);

  FAIL_UNLESS(strcmp(row[0], (char*) buffer) == 0, "row[0] != buffer");

  mysql_free_result(res);
  mysql_stmt_close(stmt);
  return OK;
}

static int test_bug6058(MYSQL *mysql)
{
  MYSQL_STMT *stmt;
  MYSQL_BIND my_bind[1];
  MYSQL_RES *res;
  MYSQL_ROW row;
  const char *stmt_text;
  char buffer[30];
  ulong length;
  int rc;


  stmt_text= "SELECT CAST('0000-00-00' AS DATE)";

  rc= mysql_real_query(mysql, SL(stmt_text));
  check_mysql_rc(rc, mysql);
  res= mysql_store_result(mysql);
  row= mysql_fetch_row(res);

  stmt= mysql_stmt_init(mysql);
  rc= mysql_stmt_prepare(stmt, SL(stmt_text));
  check_stmt_rc(rc, stmt);
  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);
  memset(my_bind, '\0', sizeof(my_bind));
  my_bind[0].buffer_type    = MYSQL_TYPE_STRING;
  my_bind[0].buffer         = &buffer;
  my_bind[0].buffer_length  = sizeof(buffer);
  my_bind[0].length         = &length;

  mysql_stmt_bind_result(stmt, my_bind);
  rc= mysql_stmt_fetch(stmt);
  check_stmt_rc(rc, stmt);

  FAIL_UNLESS(strcmp(row[0], buffer) == 0, "row[0] != buffer");

  mysql_free_result(res);
  mysql_stmt_close(stmt);
  return OK;
}


static int test_bug6059(MYSQL *mysql)
{
  MYSQL_STMT *stmt;
  const char *stmt_text;
  int rc;

  SKIP_SKYSQL;

  stmt_text= "SELECT 'foo' INTO OUTFILE 'x.3'";

  stmt= mysql_stmt_init(mysql);
  rc= mysql_stmt_prepare(stmt, SL(stmt_text));
  check_stmt_rc(rc, stmt);
  FAIL_UNLESS(mysql_stmt_field_count(stmt) == 0, "");
  mysql_stmt_close(stmt);
  return OK;
}

static int test_bug6096(MYSQL *mysql)
{
  MYSQL_STMT *stmt;
  MYSQL_RES *query_result, *stmt_metadata;
  const char *stmt_text;
  MYSQL_BIND my_bind[12];
  MYSQL_FIELD *query_field_list, *stmt_field_list;
  ulong query_field_count, stmt_field_count;
  int rc;
  my_bool update_max_length= TRUE;
  uint i;


  stmt_text= "drop table if exists t1";
  rc= mysql_real_query(mysql, SL(stmt_text));
  check_mysql_rc(rc, mysql);

  mysql_query(mysql, "set sql_mode=''");
  stmt_text= "create table t1 (c_tinyint tinyint, c_smallint smallint, "
                             " c_mediumint mediumint, c_int int, "
                             " c_bigint bigint, c_float float, "
                             " c_double double, c_varchar varchar(20), "
                             " c_char char(20), c_time time, c_date date, "
                             " c_datetime datetime)";
  rc= mysql_real_query(mysql, SL(stmt_text));
  check_mysql_rc(rc, mysql);
  stmt_text= "insert into t1  values (-100, -20000, 30000000, 4, 8, 1.0, "
                                     "2.0, 'abc', 'def', now(), now(), now())";
  rc= mysql_real_query(mysql, SL(stmt_text));
  check_mysql_rc(rc, mysql);

  stmt_text= "select * from t1";

  /* Run select in prepared and non-prepared mode and compare metadata */
  rc= mysql_real_query(mysql, SL(stmt_text));
  check_mysql_rc(rc, mysql);
  query_result= mysql_store_result(mysql);
  query_field_list= mysql_fetch_fields(query_result);
  FAIL_IF(!query_field_list, "fetch_fields failed");
  query_field_count= mysql_num_fields(query_result);

  stmt= mysql_stmt_init(mysql);
  rc= mysql_stmt_prepare(stmt, SL(stmt_text));
  check_stmt_rc(rc, stmt);  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);  mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH,
                      (void*) &update_max_length);
  mysql_stmt_store_result(stmt);
  stmt_metadata= mysql_stmt_result_metadata(stmt);
  stmt_field_list= mysql_fetch_fields(stmt_metadata);
  stmt_field_count= mysql_num_fields(stmt_metadata);
  FAIL_UNLESS(stmt_field_count == query_field_count, "");


  /* Bind and fetch the data */

  memset(my_bind, '\0', sizeof(my_bind));
  for (i= 0; i < stmt_field_count; ++i)
  {
    my_bind[i].buffer_type= MYSQL_TYPE_STRING;
    my_bind[i].buffer_length= stmt_field_list[i].max_length + 1;
    my_bind[i].buffer= malloc(my_bind[i].buffer_length);
  }
  mysql_stmt_bind_result(stmt, my_bind);
  rc= mysql_stmt_fetch(stmt);
  diag("rc=%d", rc);
  check_stmt_rc(rc, stmt);
  rc= mysql_stmt_fetch(stmt);
  FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");

  /* Clean up */

  for (i= 0; i < stmt_field_count; ++i)
    free(my_bind[i].buffer);
  mysql_stmt_close(stmt);
  mysql_free_result(query_result);
  mysql_free_result(stmt_metadata);
  stmt_text= "drop table t1";
  rc= mysql_real_query(mysql, SL(stmt_text));
  check_mysql_rc(rc, mysql);
  return OK;
}

/* Bug#7990 - mysql_stmt_close doesn't reset mysql->net.last_error */

static int test_bug7990(MYSQL *mysql)
{
  MYSQL_STMT *stmt;
  int rc;

  stmt= mysql_stmt_init(mysql);
  rc= mysql_stmt_prepare(stmt, "foo", 3);
  /*
    XXX: the fact that we store errno both in STMT and in
    MYSQL is not documented and is subject to change in 5.0
  */
  FAIL_UNLESS(rc && mysql_stmt_errno(stmt) && mysql_errno(mysql), "Error expected");
  mysql_stmt_close(stmt);
  return OK;
}

/* Bug#8330 - mysql_stmt_execute crashes (libmysql) */

static int test_bug8330(MYSQL *mysql)
{
  const char *stmt_text;
  MYSQL_STMT *stmt[2];
  int i, rc;
  const char *query= "select a,b from t1 where a=?";
  MYSQL_BIND my_bind[2];
  long lval[2]= {1,2};

  stmt_text= "drop table if exists t1";
  /* in case some previous test failed */
  rc= mysql_real_query(mysql, SL(stmt_text));
  check_mysql_rc(rc, mysql);
  stmt_text= "create table t1 (a int, b int)";
  rc= mysql_real_query(mysql, SL(stmt_text));
  check_mysql_rc(rc, mysql);

  memset(my_bind, '\0', sizeof(my_bind));
  for (i=0; i < 2; i++)
  {
    stmt[i]= mysql_stmt_init(mysql);
    rc= mysql_stmt_prepare(stmt[i], SL(query));
    check_stmt_rc(rc, stmt[i]);
    my_bind[i].buffer_type= MYSQL_TYPE_LONG;
    my_bind[i].buffer= (void*) &lval[i];
    my_bind[i].is_null= 0;
    mysql_stmt_bind_param(stmt[i], &my_bind[i]);
  }

  rc= mysql_stmt_execute(stmt[0]);
  check_stmt_rc(rc, stmt[0]);
  rc= mysql_stmt_execute(stmt[1]);
  FAIL_UNLESS(rc && mysql_stmt_errno(stmt[1]) == CR_COMMANDS_OUT_OF_SYNC, "Error expected");
  rc= mysql_stmt_execute(stmt[0]);
  check_stmt_rc(rc, stmt[0]);
  mysql_stmt_close(stmt[0]);
  mysql_stmt_close(stmt[1]);

  stmt_text= "drop table t1";
  rc= mysql_real_query(mysql, SL(stmt_text));
  check_mysql_rc(rc, mysql);
  return OK;
}

/* Test misc field information, bug: #74 */

static int test_field_misc(MYSQL *mysql)
{
  MYSQL_STMT  *stmt;
  MYSQL_RES   *result;
  int         rc;


  rc= mysql_query(mysql, "SELECT @@autocommit");
  check_mysql_rc(rc, mysql);

  result= mysql_store_result(mysql);
  FAIL_IF(!result, "Invalid result set");

  rc= 0;
  while (mysql_fetch_row(result))
    rc++;
  FAIL_UNLESS(rc == 1, "rowcount != 1");

  verify_prepare_field(result, 0,
                       "@@autocommit", "",  /* field and its org name */
                       MYSQL_TYPE_LONGLONG, /* field type */
                       "", "",              /* table and its org name */
                       "", 1, 0);           /* db name, length(its bool flag)*/

  mysql_free_result(result);

  stmt= mysql_stmt_init(mysql);
  FAIL_IF(!stmt, mysql_error(mysql));
  rc= mysql_stmt_prepare(stmt, SL("SELECT @@autocommit"));
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  result= mysql_stmt_result_metadata(stmt);
  FAIL_IF(!result, "Invalid result set");

  rc= 0;
  while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
    rc++;
  FAIL_UNLESS(rc == 1, "rowcount != 1");

  verify_prepare_field(result, 0,
                       "@@autocommit", "",  /* field and its org name */
                       MYSQL_TYPE_LONGLONG, /* field type */
                       "", "",              /* table and its org name */
                       "", 1, 0);           /* db name, length(its bool flag)*/

  mysql_free_result(result);
  mysql_stmt_close(stmt);

  // XPAND doesn't support @@max_error_count
  SKIP_XPAND

  stmt= mysql_stmt_init(mysql);
  FAIL_IF(!stmt, mysql_error(mysql));
  rc= mysql_stmt_prepare(stmt, SL("SELECT @@max_error_count"));
  check_stmt_rc(rc, stmt);

  result= mysql_stmt_result_metadata(stmt);
  FAIL_IF(!result, "Invalid result set");

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  rc= 0;
  while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
    rc++;
  FAIL_UNLESS(rc == 1, "rowcount != 1");

  if (verify_prepare_field(result, 0,
                       "@@max_error_count", "",   /* field and its org name */
                       MYSQL_TYPE_LONGLONG, /* field type */
                       "", "",              /* table and its org name */
                       /* db name, length */
                       "", MY_INT64_NUM_DECIMAL_DIGITS , 0))
    goto error;

  mysql_free_result(result);
  mysql_stmt_close(stmt);

  stmt= mysql_stmt_init(mysql);
  FAIL_IF(!stmt, mysql_error(mysql));
  rc= mysql_stmt_prepare(stmt, SL("SELECT @@max_allowed_packet"));
  check_stmt_rc(rc, stmt);

  result= mysql_stmt_result_metadata(stmt);
  FAIL_IF(!result, "Invalid result set");

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  rc= 0;
  while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
    rc++;
  FAIL_UNLESS(rc == 1, "rowcount != 1");

  if (verify_prepare_field(result, 0,
                       "@@max_allowed_packet", "", /* field and its org name */
                       MYSQL_TYPE_LONGLONG, /* field type */
                       "", "",              /* table and its org name */
                       /* db name, length */
                       "", MY_INT64_NUM_DECIMAL_DIGITS, 0))
    goto error;

  mysql_free_result(result);
  mysql_stmt_close(stmt);

  stmt= mysql_stmt_init(mysql);
  FAIL_IF(!stmt, mysql_error(mysql));
  rc= mysql_stmt_prepare(stmt, SL("SELECT @@sql_warnings"));
  check_stmt_rc(rc, stmt);

  result= mysql_stmt_result_metadata(stmt);
  FAIL_IF(!result, "Invalid result set");

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  rc= 0;
  while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
    rc++;
  FAIL_UNLESS(rc == 1, "rowcount != 1");

  if (verify_prepare_field(result, 0,
                       "@@sql_warnings", "",  /* field and its org name */
                       MYSQL_TYPE_LONGLONG,   /* field type */
                       "", "",                /* table and its org name */
                       "", 1, 0))             /* db name, length */
    goto error;

  mysql_free_result(result);
  mysql_stmt_close(stmt);
  return OK;

error:
  mysql_free_result(result);
  mysql_stmt_close(stmt);
  return FAIL;
}

/* Test a memory overrun bug */

static int test_mem_overun(MYSQL *mysql)
{
  char       buffer[10000], field[20];
  MYSQL_STMT *stmt;
  MYSQL_RES  *field_res, *res;
  int        rc, i, length;

  /*
    Test a memory overrun bug when a table had 1000 fields with
    a row of data
  */
  rc= mysql_query(mysql, "drop table if exists t_mem_overun");
  check_mysql_rc(rc, mysql);

  strcpy(buffer, "create table t_mem_overun(");
  for (i= 0; i < 1000; i++)
  {
    snprintf(field, sizeof(field), "c%d int, ", i);
    strcat(buffer, field);
  }
  length= (int)strlen(buffer);
  buffer[length-2]= ')';
  buffer[--length]= '\0';

  rc= mysql_real_query(mysql, buffer, length);
  check_mysql_rc(rc, mysql);

  strcpy(buffer, "insert into t_mem_overun values(");
  for (i= 0; i < 1000; i++)
  {
    strcat(buffer, "1, ");
  }
  length= (int)strlen(buffer);
  buffer[length-2]= ')';
  buffer[--length]= '\0';

  rc= mysql_real_query(mysql, buffer, length);
  check_mysql_rc(rc, mysql);

  rc= mysql_query(mysql, "select * from t_mem_overun");
  check_mysql_rc(rc, mysql);

  res= mysql_store_result(mysql);
  rc= 0;
  while (mysql_fetch_row(res))
    rc++;
  FAIL_UNLESS(rc == 1, "rowcount != 1");
  mysql_free_result(res);

  stmt= mysql_stmt_init(mysql);
  FAIL_IF(!stmt, mysql_error(mysql));
  rc= mysql_stmt_prepare(stmt, SL("select * from t_mem_overun"));
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  field_res= mysql_stmt_result_metadata(stmt);
  FAIL_IF(!field_res, "Invalid result set");

  FAIL_UNLESS( 1000 == mysql_num_fields(field_res), "fields != 1000");

  rc= mysql_stmt_store_result(stmt);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_fetch(stmt);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_fetch(stmt);
  FAIL_UNLESS(rc == MYSQL_NO_DATA, "");

  mysql_free_result(field_res);

  mysql_stmt_close(stmt);
  rc= mysql_query(mysql, "drop table if exists t_mem_overun");
  check_mysql_rc(rc, mysql);
  return OK;
}

static int test_bug8722(MYSQL *mysql)
{
  MYSQL_STMT *stmt;
  int rc;
  const char *stmt_text;

  /* Prepare test data */
  stmt_text= "drop table if exists t1";
  rc= mysql_real_query(mysql, SL(stmt_text));
  check_mysql_rc(rc, mysql);
  stmt_text= "drop view if exists v1";
  rc= mysql_real_query(mysql, SL(stmt_text));
  check_mysql_rc(rc, mysql);
  stmt_text= "CREATE TABLE t1 (c1 varchar(10), c2 varchar(10), c3 varchar(10),"
                             " c4 varchar(10), c5 varchar(10), c6 varchar(10),"
                             " c7 varchar(10), c8 varchar(10), c9 varchar(10),"
                             "c10 varchar(10))";
  rc= mysql_real_query(mysql, SL(stmt_text));
  check_mysql_rc(rc, mysql);
  stmt_text= "INSERT INTO t1 VALUES (1,2,3,4,5,6,7,8,9,10)";
  rc= mysql_real_query(mysql, SL(stmt_text));
  check_mysql_rc(rc, mysql);
  stmt_text= "CREATE VIEW v1 AS SELECT * FROM t1";
  rc= mysql_real_query(mysql, SL(stmt_text));
  check_mysql_rc(rc, mysql);

  stmt= mysql_stmt_init(mysql);
  stmt_text= "select * from v1";
  rc= mysql_stmt_prepare(stmt, SL(stmt_text));
  check_stmt_rc(rc, stmt);
  mysql_stmt_close(stmt);
  stmt_text= "drop table if exists t1, v1";
  rc= mysql_query(mysql, "DROP TABLE t1");
  check_mysql_rc(rc, mysql);
  rc= mysql_query(mysql, "DROP VIEW v1");
  check_mysql_rc(rc, mysql);
  return OK;
}

/* Test DECIMAL conversion */

static int test_decimal_bug(MYSQL *mysql)
{
  MYSQL_STMT *stmt;
  MYSQL_BIND my_bind[1];
  char       data[30];
  int        rc;
  my_bool    is_null;

  mysql_autocommit(mysql, TRUE);

  rc= mysql_query(mysql, "drop table if exists test_decimal_bug");
  check_mysql_rc(rc, mysql);

  rc= mysql_query(mysql, "create table test_decimal_bug(c1 decimal(10, 2))");
  check_mysql_rc(rc, mysql);

  rc= mysql_query(mysql, "insert into test_decimal_bug value(8), (10.22), (5.61)");
  check_mysql_rc(rc, mysql);

  stmt= mysql_stmt_init(mysql);
  FAIL_IF(!stmt, mysql_error(mysql));
  rc= mysql_stmt_prepare(stmt, SL("select c1 from test_decimal_bug where c1=?"));
  check_stmt_rc(rc, stmt);

  /*
    We need to bzero bind structure because mysql_stmt_bind_param checks all
    its members.
  */
  memset(my_bind, '\0', sizeof(my_bind));

  memset(data, 0, sizeof(data));
  my_bind[0].buffer_type= MYSQL_TYPE_NEWDECIMAL;
  my_bind[0].buffer= (void *)data;
  my_bind[0].buffer_length= 25;
  my_bind[0].is_null= &is_null;

  is_null= 0;
  rc= mysql_stmt_bind_param(stmt, my_bind);
  check_stmt_rc(rc, stmt);

  strcpy(data, "8.0");
  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  data[0]= 0;
  rc= mysql_stmt_bind_result(stmt, my_bind);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_fetch(stmt);
  check_stmt_rc(rc, stmt);

  FAIL_UNLESS(strcmp(data, "8.00") == 0, "data != '8.00'");

  rc= mysql_stmt_fetch(stmt);
  FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");

  strcpy(data, "5.61");
  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  data[0]= 0;
  rc= mysql_stmt_bind_result(stmt, my_bind);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_fetch(stmt);
  check_stmt_rc(rc, stmt);

  FAIL_UNLESS(strcmp(data, "5.61") == 0, "data != '5.61'");

  rc= mysql_stmt_fetch(stmt);
  FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");

  is_null= 1;
  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_fetch(stmt);
  FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");

  strcpy(data, "10.22"); is_null= 0;
  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  data[0]= 0;
  rc= mysql_stmt_bind_result(stmt, my_bind);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_fetch(stmt);
  check_stmt_rc(rc, stmt);

  FAIL_UNLESS(strcmp(data, "10.22") == 0, "data != '10.22'");

  rc= mysql_stmt_fetch(stmt);
  FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");

  mysql_stmt_close(stmt);
  rc= mysql_query(mysql, "drop table if exists test_decimal_bug");
  check_mysql_rc(rc, mysql);
  return OK;
}

/* Test EXPLAIN bug (#115, reported by mark@mysql.com & georg@php.net). */

static int test_explain_bug(MYSQL *mysql)
{
  MYSQL_STMT *stmt;
  MYSQL_RES  *result;
  int        rc;

  if (!is_mariadb)
    return SKIP;

  mysql_autocommit(mysql, TRUE);

  rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_explain");
  check_mysql_rc(rc, mysql);

  rc= mysql_query(mysql, "CREATE TABLE test_explain(id int, name char(2))");
  check_mysql_rc(rc, mysql);

  stmt= mysql_stmt_init(mysql);
  FAIL_IF(!stmt, mysql_error(mysql));
  rc= mysql_stmt_prepare(stmt, SL("explain test_explain"));
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  rc= 0;
  while (!mysql_stmt_fetch(stmt))
    rc++;
  FAIL_UNLESS(rc == 2, "rowcount != 2");

  result= mysql_stmt_result_metadata(stmt);
  FAIL_IF(!result, "Invalid result set");

  FAIL_UNLESS(6 == mysql_num_fields(result), "fields != 6");

  if (verify_prepare_field(result, 0, "Field", "COLUMN_NAME",
                       mysql_get_server_version(mysql) <= 50000 ?
                       MYSQL_TYPE_STRING : MYSQL_TYPE_VAR_STRING,
                       0, 0,
                       mysql_get_server_version(mysql) <= 50400 ? "" : "information_schema",
                       64, 0))
    goto error;

  if (verify_prepare_field(result, 1, "Type", "COLUMN_TYPE", MYSQL_TYPE_BLOB,
                       0, 0,
                       mysql_get_server_version(mysql) <= 50400 ? "" : "information_schema",
                       0, 0))
    goto error;

  if (verify_prepare_field(result, 2, "Null", "IS_NULLABLE",
                       mysql_get_server_version(mysql) <= 50000 ?
                       MYSQL_TYPE_STRING : MYSQL_TYPE_VAR_STRING,
                       0, 0,
                       mysql_get_server_version(mysql) <= 50400 ? "" : "information_schema",
                       3, 0))
    goto error;

  if (verify_prepare_field(result, 3, "Key", "COLUMN_KEY",
                       mysql_get_server_version(mysql) <= 50000 ?
                       MYSQL_TYPE_STRING : MYSQL_TYPE_VAR_STRING,
                       0, 0,
                       mysql_get_server_version(mysql) <= 50400 ? "" : "information_schema",
                       3, 0))
    goto error;

  if ( mysql_get_server_version(mysql) >= 50027 )
  {
    /*  The patch for bug#23037 changes column type of DEAULT to blob */
    if (verify_prepare_field(result, 4, "Default", "COLUMN_DEFAULT",
                         MYSQL_TYPE_BLOB, 0, 0,
                         mysql_get_server_version(mysql) <= 50400 ? "" : "information_schema",
                         0, 0))
      goto error;
  }
  else
  {
    if (verify_prepare_field(result, 4, "Default", "COLUMN_DEFAULT",
                         mysql_get_server_version(mysql) >= 50027 ?
                         MYSQL_TYPE_BLOB :
                         mysql_get_server_version(mysql) <= 50000 ?
                         MYSQL_TYPE_STRING : MYSQL_TYPE_VAR_STRING,
                         0, 0,
                         mysql_get_server_version(mysql) <= 50400 ? "" : "information_schema",
                         mysql_get_server_version(mysql) >= 50027 ? 0 :64, 0))
      goto error;
  }

  if (verify_prepare_field(result, 5, "Extra", "EXTRA",
                       mysql_get_server_version(mysql) <= 50000 ?
                       MYSQL_TYPE_STRING : MYSQL_TYPE_VAR_STRING,
                       0, 0,
                       mysql_get_server_version(mysql) <= 50400 ? "" : "information_schema",
                       27, 0))
    goto error;

  mysql_free_result(result);
  mysql_stmt_close(stmt);

  stmt= mysql_stmt_init(mysql);
  FAIL_IF(!stmt, mysql_error(mysql));
  rc= mysql_stmt_prepare(stmt, SL("explain select id, name FROM test_explain"));
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  rc= 0;
  while (!mysql_stmt_fetch(stmt))
    rc++;
  FAIL_UNLESS(rc == 1, "rowcount != 1");

  result= mysql_stmt_result_metadata(stmt);
  FAIL_IF(!result, "Invalid result set");

  FAIL_UNLESS(10 == mysql_num_fields(result), "fields != 10");

  if (verify_prepare_field(result, 0, "id", "", MYSQL_TYPE_LONGLONG, "", "", "", 3, 0))
    goto error;

  if (verify_prepare_field(result, 1, "select_type", "", MYSQL_TYPE_VAR_STRING, "", "", "", 19, 0))
    goto error;

  if (verify_prepare_field(result, 2, "table", "", MYSQL_TYPE_VAR_STRING, "", "", "", NAME_CHAR_LEN, 0))
    goto error;

  if (verify_prepare_field(result, 3, "type", "", MYSQL_TYPE_VAR_STRING, "", "", "", 10, 0))
    goto error;

  if (verify_prepare_field(result, 4, "possible_keys", "", MYSQL_TYPE_VAR_STRING, "", "", "", NAME_CHAR_LEN*MAX_KEY, 0))
    goto error;

  if ( verify_prepare_field(result, 5, "key", "", MYSQL_TYPE_VAR_STRING, "", "", "", NAME_CHAR_LEN, 0))
    goto error;

  if (mysql_get_server_version(mysql) <= 50000)
  {
    if (verify_prepare_field(result, 6, "key_len", "", MYSQL_TYPE_LONGLONG, "", "", "", 3, 0))
      goto error;
  }
  else if (mysql_get_server_version(mysql) <= 60000)
  {
    if (verify_prepare_field(result, 6, "key_len", "", MYSQL_TYPE_VAR_STRING, "", "", "", NAME_CHAR_LEN*MAX_KEY, 0))
      goto error;
  }
  else
  {
    if (verify_prepare_field(result, 6, "key_len", "", MYSQL_TYPE_VAR_STRING, "", "", "", (MAX_KEY_LENGTH_DECIMAL_WIDTH + 1) * MAX_KEY, 0))
    goto error;
  }

  if (verify_prepare_field(result, 7, "ref", "", MYSQL_TYPE_VAR_STRING, "", "", "",
                           NAME_CHAR_LEN*16, 0))
    goto error;

  if (verify_prepare_field(result, 8, "rows", "", MYSQL_TYPE_LONGLONG, "", "", "", 10, 0))
    goto error;

  if (verify_prepare_field(result, 9, "Extra", "", MYSQL_TYPE_VAR_STRING, "", "", "", 255, 0))
    goto error;

  mysql_free_result(result);
  mysql_stmt_close(stmt);
  rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_explain");
  check_mysql_rc(rc, mysql);
  return OK;
error:
  mysql_free_result(result);
  mysql_stmt_close(stmt);
  return FAIL;
}

static int test_sshort_bug(MYSQL *mysql)
{
  MYSQL_STMT *stmt;
  MYSQL_BIND my_bind[4];
  short      short_value;
  int32      long_value;
  ulong      s_length, l_length, ll_length, t_length;
  ulonglong  longlong_value;
  int        rc;
  uchar      tiny_value;

  rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_sshort");
  check_mysql_rc(rc, mysql);

  rc= mysql_query(mysql, "CREATE TABLE test_sshort(a smallint signed, \
                                                  b smallint signed, \
                                                  c smallint unsigned, \
                                                  d smallint unsigned)");
  check_mysql_rc(rc, mysql);

  rc= mysql_query(mysql, "INSERT INTO test_sshort VALUES(-5999, -5999, 35999, 200)");
  check_mysql_rc(rc, mysql);


  stmt= mysql_stmt_init(mysql);
  FAIL_IF(!stmt, mysql_error(mysql));
  rc= mysql_stmt_prepare(stmt, SL("SELECT * FROM test_sshort"));
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  memset(my_bind, '\0', sizeof(my_bind));
  my_bind[0].buffer_type= MYSQL_TYPE_SHORT;
  my_bind[0].buffer= (void *)&short_value;
  my_bind[0].length= &s_length;

  my_bind[1].buffer_type= MYSQL_TYPE_LONG;
  my_bind[1].buffer= (void *)&long_value;
  my_bind[1].length= &l_length;

  my_bind[2].buffer_type= MYSQL_TYPE_LONGLONG;
  my_bind[2].buffer= (void *)&longlong_value;
  my_bind[2].length= &ll_length;

  my_bind[3].buffer_type= MYSQL_TYPE_TINY;
  my_bind[3].buffer= (void *)&tiny_value;
  my_bind[3].is_unsigned= TRUE;
  my_bind[3].length= &t_length;

  rc= mysql_stmt_bind_result(stmt, my_bind);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_fetch(stmt);
  check_stmt_rc(rc, stmt);

  FAIL_UNLESS(short_value == -5999, "sv != -5999");
  FAIL_UNLESS(s_length == 2, "s_length != 2");

  FAIL_UNLESS(long_value == -5999, "l_v != -5999");
  FAIL_UNLESS(l_length == 4, "l_length != 4");

  FAIL_UNLESS(longlong_value == 35999, "llv != 35999");
  FAIL_UNLESS(ll_length == 8, "ll_length != 8");

  FAIL_UNLESS(tiny_value == 200, "t_v != 200");
  FAIL_UNLESS(t_length == 1, "t_length != 1");

  rc= mysql_stmt_fetch(stmt);
  FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");

  mysql_stmt_close(stmt);
  rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_sshort");
  check_mysql_rc(rc, mysql);
  return OK;
}


/* Test a misc tinyint-signed conversion bug */

static int test_stiny_bug(MYSQL *mysql)
{
  MYSQL_STMT *stmt;
  MYSQL_BIND my_bind[4];
  short      short_value;
  int32      long_value;
  ulong      s_length, l_length, ll_length, t_length;
  ulonglong  longlong_value;
  int        rc;
  uchar      tiny_value;

  rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_stiny");
  check_mysql_rc(rc, mysql);

  rc= mysql_query(mysql, "CREATE TABLE test_stiny(a tinyint signed, \
                                                  b tinyint signed, \
                                                  c tinyint unsigned, \
                                                  d tinyint unsigned)");
  check_mysql_rc(rc, mysql);

  rc= mysql_query(mysql, "INSERT INTO test_stiny VALUES(-128, -127, 255, 0)");
  check_mysql_rc(rc, mysql);


  stmt= mysql_stmt_init(mysql);
  FAIL_IF(!stmt, mysql_error(mysql));
  rc= mysql_stmt_prepare(stmt, SL("SELECT * FROM test_stiny"));
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  memset(my_bind, '\0', sizeof(my_bind));
  my_bind[0].buffer_type= MYSQL_TYPE_SHORT;
  my_bind[0].buffer= (void *)&short_value;
  my_bind[0].length= &s_length;

  my_bind[1].buffer_type= MYSQL_TYPE_LONG;
  my_bind[1].buffer= (void *)&long_value;
  my_bind[1].length= &l_length;

  my_bind[2].buffer_type= MYSQL_TYPE_LONGLONG;
  my_bind[2].buffer= (void *)&longlong_value;
  my_bind[2].length= &ll_length;

  my_bind[3].buffer_type= MYSQL_TYPE_TINY;
  my_bind[3].buffer= (void *)&tiny_value;
  my_bind[3].length= &t_length;

  rc= mysql_stmt_bind_result(stmt, my_bind);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_fetch(stmt);
  check_stmt_rc(rc, stmt);

  FAIL_UNLESS(short_value == -128, "s_v != -128");
  FAIL_UNLESS(s_length == 2, "s_length != 2");

  FAIL_UNLESS(long_value == -127, "l_v != -127");
  FAIL_UNLESS(l_length == 4, "l_length != 4");

  FAIL_UNLESS(longlong_value == 255, "llv != 255");
  FAIL_UNLESS(ll_length == 8, "ll_length != 8");

  FAIL_UNLESS(tiny_value == 0, "t_v != 0");
  FAIL_UNLESS(t_length == 1, "t_length != 1");

  rc= mysql_stmt_fetch(stmt);
  FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");

  mysql_stmt_close(stmt);
  rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_stiny");
  check_mysql_rc(rc, mysql);
  return OK;
}

static int test_bug53311(MYSQL *mysql)
{
  int rc;
  MYSQL_STMT *stmt;
  int i;
  const char *query= "INSERT INTO bug53311 VALUES (1)";
  SKIP_MAXSCALE;
  SKIP_XPAND;

  rc= mysql_options(mysql, MYSQL_OPT_RECONNECT, "1");
  check_mysql_rc(rc, mysql);

  rc= mysql_query(mysql, "DROP TABLE IF EXISTS bug53311");
  check_mysql_rc(rc, mysql);

  rc= mysql_query(mysql, "CREATE TABLE bug53311 (a int)");
  check_mysql_rc(rc, mysql);

  stmt= mysql_stmt_init(mysql);
  rc= mysql_stmt_prepare(stmt, SL(query));
  check_stmt_rc(rc, stmt);

  for (i=0; i < 2; i++)
  {
    rc= mysql_stmt_execute(stmt);
    check_stmt_rc(rc, stmt);
  }

  /* kill connection */
  rc= mysql_kill(mysql, mysql_thread_id(mysql));

  rc= mysql_stmt_execute(stmt);
  FAIL_IF(rc == 0, "Error expected");
  FAIL_IF(mysql_stmt_errno(stmt) == 0, "Errno != 0 expected");
  rc= mysql_stmt_close(stmt);
  check_mysql_rc(rc, mysql);
  rc= mysql_query(mysql, "DROP TABLE IF EXISTS bug53311");
  check_mysql_rc(rc, mysql);

  return OK;
}
#define PREPARE_SQL "EXPLAIN SELECT t1.*, t2.* FROM test AS t1, test AS t2"

#ifdef NOT_IN_USE
static int test_metadata(MYSQL *mysql)
{
  int rc;

	rc= mysql_query(mysql, "DROP TABLE IF EXISTS test");
  check_mysql_rc(rc, mysql);
	rc= mysql_query(mysql, "CREATE TABLE test(id INT, label CHAR(1), PRIMARY KEY(id)) ENGINE=MYISAM");
  check_mysql_rc(rc, mysql);

	rc= mysql_query(mysql, "INSERT INTO test(id, label) VALUES (1, 'a'), (2, 'b'), (3, 'c'), (4, 'd'), (5, 'e'), (6, 'f')");
  check_mysql_rc(rc, mysql);
	printf("Client=%s\n", mysql_get_client_info());
	printf("Server=%s\n", mysql_get_server_info(mysql));

	{
		MYSQL_STMT * stmt = mysql_stmt_init(mysql);
		if (!stmt) {
			fprintf(stderr, "Failed to init stmt: Error: %s\n", mysql_error(mysql));
			goto end;
		}
		if (mysql_stmt_prepare(stmt, PREPARE_SQL, sizeof(PREPARE_SQL) - 1)) {
			fprintf(stderr, "Failed to prepare stmt: Error: %s\n", mysql_stmt_error(stmt));
			goto end2;
		}
		if (mysql_stmt_execute(stmt)) {
			fprintf(stderr, "Failed to execute stmt: Error: %s\n", mysql_stmt_error(stmt));
			goto end2;
		}
		{
			MYSQL_FIELD * field = NULL;
			MYSQL_RES * res = mysql_stmt_result_metadata(stmt);
			if (!res) {
				fprintf(stderr, "Failed to get metadata: Error: %s\n", mysql_stmt_error(stmt));
				goto end2;
			}
			while ((field = mysql_fetch_field(res))) {
				printf("name=%s\n", field->name);
				printf("catalog=%s\n", field->catalog);
			}
			mysql_free_result(res);

		}
end2:
		mysql_stmt_close(stmt);
	}
end:
	return 0;
}
#endif

static int test_conc_5(MYSQL *mysql)
{
  const char *query= "SELECT a FROM t1";
  MYSQL_RES *res;
  MYSQL_STMT *stmt;
  MYSQL_FIELD *fields;
  int rc;

  rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
  check_mysql_rc(rc, mysql);
  rc= mysql_query(mysql, "CREATE TABLE t1 (a int)");
  check_mysql_rc(rc, mysql);
  rc= mysql_query(mysql, "INSERT INTO t1 VALUES (1)");
  check_mysql_rc(rc, mysql);

  stmt= mysql_stmt_init(mysql);
  FAIL_IF(!stmt, "couldn't allocate memory");

  rc= mysql_stmt_prepare(stmt, SL(query));
  check_stmt_rc(rc, stmt);
  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  res= mysql_stmt_result_metadata(stmt);
  FAIL_IF(!res, "Can't obtain resultset");

  fields= mysql_fetch_fields(res);
  FAIL_IF(!fields, "Can't obtain fields");

  FAIL_IF(strcmp("def", fields[0].catalog), "unexpected value for field->catalog");

  mysql_free_result(res);
  mysql_stmt_close(stmt);
  return OK;
}

static int test_conc141(MYSQL *mysql)
{
  int rc;
  const char *query= "CALL p_conc141";
  MYSQL_STMT *stmt= mysql_stmt_init(mysql);

  rc= mysql_query(mysql, "DROP TABLE IF EXISTS conc141");
  check_mysql_rc(rc, mysql);
  rc= mysql_query(mysql, "CREATE TABLE conc141 (KeyVal int not null primary key)");
  check_mysql_rc(rc, mysql);
  rc= mysql_query(mysql, "INSERT INTO conc141 VALUES(1)");
  check_mysql_rc(rc, mysql);
  rc= mysql_query(mysql, "DROP PROCEDURE IF EXISTS p_conc141");
  check_mysql_rc(rc, mysql);
  rc= mysql_query(mysql, "CREATE PROCEDURE p_conc141()\n"
                   "BEGIN\n"
                     "select * from conc141;\n"
                     "insert into conc141(KeyVal) VALUES(1);\n"
                   "END");
  check_mysql_rc(rc, mysql);

  rc= mysql_stmt_prepare(stmt, SL(query));
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);
  /* skip first result */
  rc= mysql_stmt_next_result(stmt);
  FAIL_IF(rc==-1, "No more results and error expected");
  mysql_stmt_free_result(stmt);
  FAIL_IF(mysql_stmt_errno(stmt), "No Error expected");
  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);
  mysql_stmt_close(stmt);
  rc= mysql_query(mysql, "DROP TABLE IF EXISTS conc141");
  check_mysql_rc(rc, mysql);
  rc= mysql_query(mysql, "DROP PROCEDURE IF EXISTS p_conc141");
  check_mysql_rc(rc, mysql);
  return OK;
}

static int test_conc154(MYSQL *mysql)
{
  MYSQL_STMT *stmt;
  const char *stmtstr= "SELECT * FROM t1";
  int rc;

  /* 1st: empty result set without free_result */
  rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
  check_mysql_rc(rc, mysql);
  rc= mysql_query(mysql, "CREATE TABLE t1 (a varchar(20))");
  check_mysql_rc(rc, mysql);

  stmt= mysql_stmt_init(mysql);
  rc= mysql_stmt_prepare(stmt, SL(stmtstr));
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_store_result(stmt);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_store_result(stmt);
  check_stmt_rc(rc, stmt);

  mysql_stmt_close(stmt);

  /* 2nd: empty result set with free_result */
  stmt= mysql_stmt_init(mysql);
  rc= mysql_stmt_prepare(stmt, SL(stmtstr));
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_store_result(stmt);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_free_result(stmt);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_store_result(stmt);
  check_stmt_rc(rc, stmt);
  rc= mysql_stmt_free_result(stmt);
  check_stmt_rc(rc, stmt);

  mysql_stmt_close(stmt);

  /* 3rd: non-empty result without free_result */
  rc= mysql_query(mysql, "INSERT INTO t1 VALUES ('test_conc154')");
  check_mysql_rc(rc, mysql);

  stmt= mysql_stmt_init(mysql);
  rc= mysql_stmt_prepare(stmt, SL(stmtstr));
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_store_result(stmt);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_store_result(stmt);
  check_stmt_rc(rc, stmt);

  mysql_stmt_close(stmt);

  /* 4th non-empty result set with free_result */
  stmt= mysql_stmt_init(mysql);
  rc= mysql_stmt_prepare(stmt, SL(stmtstr));
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_store_result(stmt);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_free_result(stmt);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_store_result(stmt);
  check_stmt_rc(rc, stmt);
  rc= mysql_stmt_free_result(stmt);
  check_stmt_rc(rc, stmt);

  mysql_stmt_close(stmt);
  rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
  check_mysql_rc(rc, mysql);

  return OK;
}

static int test_conc155(MYSQL *mysql)
{
  MYSQL_STMT *stmt;
  MYSQL_BIND bind;
  char buffer[50];
  int rc;

  rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
  check_mysql_rc(rc, mysql);
  rc= mysql_query(mysql, "CREATE TABLE t1 (a TEXT)");
  check_mysql_rc(rc, mysql);
  rc= mysql_query(mysql, "INSERT INTO t1 VALUES ('zero terminated string')");
  check_mysql_rc(rc, mysql);

  stmt= mysql_stmt_init(mysql);
  rc= mysql_stmt_prepare(stmt, SL("SELECT a FROM t1"));
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  memset(buffer, 'X', 50);
  memset(&bind, 0, sizeof(MYSQL_BIND));

  bind.buffer= buffer;
  bind.buffer_length= 50;
  bind.buffer_type= MYSQL_TYPE_STRING;

  rc= mysql_stmt_bind_result(stmt, &bind);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_fetch(stmt);
  check_stmt_rc(rc, stmt);

  if (strlen(buffer) != strlen("zero terminated string"))
  {
    diag("Wrong buffer length");
    return FAIL;
  }

  mysql_stmt_close(stmt);
  rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
  check_mysql_rc(rc, mysql);
  return OK;
}

static int test_conc168(MYSQL *mysql)
{
  MYSQL_STMT *stmt= mysql_stmt_init(mysql);

  MYSQL_BIND bind;
  char buffer[100];
  int rc;

  //https://jira.mariadb.org/browse/XPT-273
  SKIP_XPAND;

  rc= mysql_query(mysql, "DROP TABLE IF EXISTS conc168");
  check_mysql_rc(rc, mysql);
  rc= mysql_query(mysql, "CREATE TABLE conc168(a datetime(3))");
  check_mysql_rc(rc, mysql);
  rc= mysql_query(mysql, "INSERT INTO conc168 VALUES ('2016-03-09 07:51:49.000'),('2016-03-09 07:51:49.001'),('2016-03-09 07:51:49.010')");
  check_mysql_rc(rc, mysql);

  memset(&bind, 0, sizeof(MYSQL_BIND));
  bind.buffer= buffer;
  bind.buffer_type= MYSQL_TYPE_STRING;
  bind.buffer_length= 100;

  rc= mysql_stmt_prepare(stmt, SL("SELECT a FROM conc168"));
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_bind_result(stmt, &bind);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_fetch(stmt);
  check_stmt_rc(rc, stmt);
  FAIL_IF(strcmp(buffer, "2016-03-09 07:51:49.000"), "expected: 2016-03-09 07:51:49.000");

  rc= mysql_stmt_fetch(stmt);
  check_stmt_rc(rc, stmt);
  FAIL_IF(strcmp(buffer, "2016-03-09 07:51:49.001"), "expected: 2016-03-09 07:51:49.001");

  rc= mysql_stmt_fetch(stmt);
  check_stmt_rc(rc, stmt);
  FAIL_IF(strcmp(buffer, "2016-03-09 07:51:49.010"), "expected: 2016-03-09 07:51:49.010");

  mysql_stmt_close(stmt);
  rc= mysql_query(mysql, "DROP TABLE IF EXISTS conc168");
  check_mysql_rc(rc, mysql);
  return OK;
}

static int test_conc167(MYSQL *mysql)
{
  MYSQL_STMT *stmt= mysql_stmt_init(mysql);

  MYSQL_BIND bind[3];
  char buffer[100];
  int bit1=0, bit2=0;
  int rc;
  const char *stmt_str= "SELECT a,b,c FROM conc168";

  rc= mysql_query(mysql, "DROP TABLE IF EXISTS conc168");
  check_mysql_rc(rc, mysql);
  rc= mysql_query(mysql, "CREATE TABLE conc168(a bit, b bit, c varchar(10))");
  check_mysql_rc(rc, mysql);
  rc= mysql_query(mysql, "INSERT INTO conc168 VALUES (1,0, 'test12345')");
  check_mysql_rc(rc, mysql);

  memset(bind, 0, 3 * sizeof(MYSQL_BIND));
  bind[0].buffer= &bit1;
  bind[0].buffer_type= MYSQL_TYPE_BIT;
  bind[0].buffer_length= sizeof(int);
  bind[1].buffer= &bit2;
  bind[1].buffer_type= MYSQL_TYPE_BIT;
  bind[1].buffer_length= sizeof(int);
  bind[2].buffer= buffer;
  bind[2].buffer_type= MYSQL_TYPE_STRING;
  bind[2].buffer_length= 100;

  rc= mysql_stmt_prepare(stmt, SL(stmt_str));
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_bind_result(stmt, bind);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_store_result(stmt);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_fetch(stmt);
  check_stmt_rc(rc, stmt);

  diag("bit=%d %d char=%s", bit1, bit2, buffer);

  mysql_stmt_close(stmt);
  return OK;
}

static int test_conc177(MYSQL *mysql)
{
  MYSQL_STMT *stmt;
  int rc;
  MYSQL_BIND bind[2];
  const char *stmt_str= "SELECT a,b FROM t1";
  char buf1[128], buf2[128];

  // https://jira.mariadb.org/browse/XPT-286
  SKIP_XPAND

  rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
  check_mysql_rc(rc, mysql);

  rc= mysql_query(mysql, "CREATE TABLE t1 (a double zerofill default 8.8,b float zerofill default 8.8)");
  check_mysql_rc(rc, mysql);
  rc= mysql_query(mysql, "INSERT INTO t1 VALUES (DEFAULT, DEFAULT)");
  check_mysql_rc(rc, mysql);

  stmt= mysql_stmt_init(mysql);
  rc= mysql_stmt_prepare(stmt, SL(stmt_str));
  check_stmt_rc(rc, stmt);
  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  memset(bind, 0, 2 * sizeof(MYSQL_BIND));
  bind[0].buffer= &buf1;
  bind[0].buffer_type= MYSQL_TYPE_STRING;
  bind[0].buffer_length= 128;
  bind[1].buffer= &buf2;
  bind[1].buffer_type= MYSQL_TYPE_STRING;
  bind[1].buffer_length= 128;

  rc= mysql_stmt_bind_result(stmt, bind);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_fetch(stmt);
  mysql_stmt_close(stmt);

  diag("buf1 %s\nbuf2 %s", buf1, buf2);

  FAIL_IF(strcmp(buf1, "00000000000000000008.8"), "Expected 00000000000000000008.8");
  FAIL_IF(strcmp(buf2, "0000000008.8"), "Expected 0000000008.8");

  rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
  check_mysql_rc(rc, mysql);

  rc= mysql_query(mysql, "CREATE TABLE t1 (a int(8) zerofill default 1, b int(4) zerofill default 1)");
  check_mysql_rc(rc, mysql);
  rc= mysql_query(mysql, "INSERT INTO t1 VALUES (DEFAULT, DEFAULT)");
  check_mysql_rc(rc, mysql);

  stmt= mysql_stmt_init(mysql);
  rc= mysql_stmt_prepare(stmt, SL(stmt_str));
  check_stmt_rc(rc, stmt);
  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  memset(bind, 0, 2 * sizeof(MYSQL_BIND));
  bind[0].buffer= &buf1;
  bind[0].buffer_type= MYSQL_TYPE_STRING;
  bind[0].buffer_length= 128;
  bind[1].buffer= &buf2;
  bind[1].buffer_type= MYSQL_TYPE_STRING;
  bind[1].buffer_length= 128;

  rc= mysql_stmt_bind_result(stmt, bind);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_fetch(stmt);
  mysql_stmt_close(stmt);

  diag("buf1 %s\nbuf2 %s", buf1, buf2);

  FAIL_IF(strcmp(buf1, "00000001"), "Expected 00000001");
  FAIL_IF(strcmp(buf2, "0001"), "Expected 0001");
  rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
  check_mysql_rc(rc, mysql);
  return OK;
}

static int test_conc179(MYSQL *mysql)
{
  MYSQL_STMT *stmt;
  int rc;
  const char *stmtstr= "select 1 as ' '";

  stmt= mysql_stmt_init(mysql);
  rc= mysql_stmt_prepare(stmt, SL(stmtstr));
  check_stmt_rc(rc, stmt);

  if (mysql_get_server_version(mysql) >= 100100)
  {
    FAIL_IF(mysql_warning_count(mysql) < 1, "expected 1 or more warnings");
    FAIL_IF(mysql_stmt_warning_count(stmt) < 1, "expected 1 or more warnings");
  }

  mysql_stmt_close(stmt);
  rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
  check_mysql_rc(rc, mysql);

  return OK;
}

static int test_conc182(MYSQL *mysql)
{
  MYSQL_STMT *stmt;
  int rc;
  MYSQL_BIND bind[2];
  char buf1[22];
  MYSQL_RES *result;
  MYSQL_ROW row;

  stmt= mysql_stmt_init(mysql);
  rc= mariadb_stmt_execute_direct(stmt, "DROP TABLE IF EXISTS t1", -1);
  check_stmt_rc(rc, stmt);
  rc= mariadb_stmt_execute_direct(stmt, "DROP TABLE IF EXISTS t1", -1);
  check_stmt_rc(rc, stmt);
  rc= mariadb_stmt_execute_direct(stmt, "SELECT 1", -1);
  check_stmt_rc(rc, stmt);
  rc= mariadb_stmt_execute_direct(stmt, "SELECT 1", -1);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_close(stmt);
  check_stmt_rc(rc, stmt);

  rc= mysql_query(mysql, "SELECT row_count()");
  result= mysql_store_result(mysql);
  row= mysql_fetch_row(result);
  diag("buf: %s", row[0]);
  mysql_free_result(result);


  stmt= mysql_stmt_init(mysql);
  rc= mysql_stmt_prepare(stmt, "SELECT row_count()", -1);
  check_stmt_rc(rc, stmt);
  rc= mysql_stmt_execute(stmt);

  memset(bind, 0, 2 * sizeof(MYSQL_BIND));
  bind[0].buffer= &buf1;
  bind[0].buffer_length= bind[1].buffer_length= 20;
  bind[0].buffer_type= bind[1].buffer_type= MYSQL_TYPE_STRING;

  rc= mysql_stmt_bind_result(stmt, bind);

  while(!mysql_stmt_fetch(stmt))
  diag("b1: %s", buf1);
  rc= mysql_stmt_close(stmt);
  rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
  check_mysql_rc(rc, mysql);
  return OK;
}

static int test_conc181(MYSQL *mysql)
{
  MYSQL_STMT *stmt;
  int rc;
  MYSQL_BIND bind;
  const char *stmt_str= "SELECT a FROM t1";
  float f=1;
  my_bool err= 0;

  rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
  check_mysql_rc(rc, mysql);
  rc= mysql_query(mysql, "CREATE TABLE t1 (a int)");
  check_mysql_rc(rc, mysql);
  rc= mysql_query(mysql, "INSERT INTO t1 VALUES(1073741825)");
  check_mysql_rc(rc, mysql);

  stmt= mysql_stmt_init(mysql);
  rc= mysql_stmt_prepare(stmt, SL(stmt_str));
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  memset(&bind, 0, sizeof(MYSQL_BIND));
  bind.buffer= &f;
  bind.error= &err;
  bind.buffer_type= MYSQL_TYPE_FLOAT;
  rc= mysql_stmt_bind_result(stmt, &bind);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_fetch(stmt);
  diag("rc=%d err=%d float=%f, %d", rc, err, f, MYSQL_DATA_TRUNCATED);

  rc= mysql_stmt_close(stmt);
  rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
  check_mysql_rc(rc, mysql);
  return OK;
}

static int test_conc198(MYSQL *mysql)
{
  MYSQL_STMT *stmt1, *stmt2;
  MYSQL_BIND my_bind[1];
  int32 a;
  int rc;
  int num_rows= 0;
  ulong type;
  ulong prefetch_rows= 3;


  mysql_query(mysql, "drop table if exists t1");
  mysql_query(mysql, "create table t1 (id integer not null primary key)");
  rc= mysql_query(mysql, "insert into t1 (id) values "
                         " (1), (2), (3), (4), (5), (6), (7), (8), (9)");
  check_mysql_rc(rc, mysql);

  stmt1= mysql_stmt_init(mysql);
  stmt2= mysql_stmt_init(mysql);
  /* Not implemented in 5.0 */
  type= (ulong) CURSOR_TYPE_SCROLLABLE;
  rc= mysql_stmt_attr_set(stmt1, STMT_ATTR_CURSOR_TYPE, (void*) &type);
  FAIL_UNLESS(rc, "Error expected");
  rc= mysql_stmt_attr_set(stmt2, STMT_ATTR_CURSOR_TYPE, (void*) &type);
  FAIL_UNLESS(rc, "Error expected");

  type= (ulong) CURSOR_TYPE_READ_ONLY;
  rc= mysql_stmt_attr_set(stmt1, STMT_ATTR_CURSOR_TYPE, (void*) &type);
  check_stmt_rc(rc, stmt1);
  rc= mysql_stmt_attr_set(stmt2, STMT_ATTR_CURSOR_TYPE, (void*) &type);
  check_stmt_rc(rc, stmt2);
  rc= mysql_stmt_attr_set(stmt1, STMT_ATTR_PREFETCH_ROWS,
                          (void*) &prefetch_rows);
  check_stmt_rc(rc, stmt1);
  rc= mysql_stmt_attr_set(stmt2, STMT_ATTR_PREFETCH_ROWS,
                          (void*) &prefetch_rows);
  check_stmt_rc(rc, stmt2);
  rc= mysql_stmt_prepare(stmt1, "SELECT * FROM t1 ORDER by id ASC" , -1);
  check_stmt_rc(rc, stmt1);
  rc= mysql_stmt_prepare(stmt2, "SELECT * FROM t1 ORDER by id DESC", -1);
  check_stmt_rc(rc, stmt2);

  rc= mysql_stmt_execute(stmt1);
  check_stmt_rc(rc, stmt1);
  rc= mysql_stmt_execute(stmt2);
  check_stmt_rc(rc, stmt2);

  memset(my_bind, '\0', sizeof(my_bind));
  my_bind[0].buffer_type= MYSQL_TYPE_LONG;
  my_bind[0].buffer= (void*) &a;
  my_bind[0].buffer_length= sizeof(a);
  mysql_stmt_bind_result(stmt1, my_bind);
  mysql_stmt_bind_result(stmt2, my_bind);

  while ((rc= mysql_stmt_fetch(stmt1)) == 0)
    ++num_rows;
  FAIL_UNLESS(num_rows == 9, "num_rows != 9");

  num_rows= 0;
  while ((rc= mysql_stmt_fetch(stmt2)) == 0)
    ++num_rows;
  FAIL_UNLESS(num_rows == 9, "num_rows != 9");

  rc= mysql_stmt_close(stmt1);
  rc= mysql_stmt_close(stmt2);
  FAIL_UNLESS(rc == 0, "");

  rc= mysql_query(mysql, "drop table t1");
  check_mysql_rc(rc, mysql);
  return OK;
}

static int test_conc205(MYSQL *mysql)
{
  MYSQL_STMT *stmt;
  MYSQL_BIND my_bind[3];
  char       data[8];
  ulong      length[3];
  int        rc, int_col;
  short      smint_col;
  my_bool    is_null[3];
  const char *query = "SELECT text_col, smint_col, int_col FROM test_conc205";

  rc= mysql_query(mysql, "drop table if exists test_conc205");
  check_mysql_rc(rc, mysql);
  rc= mysql_query(mysql, "CREATE TABLE test_conc205 (text_col TEXT, smint_col SMALLINT, int_col INT)");
  check_mysql_rc(rc, mysql);
  rc= mysql_query(mysql, "INSERT INTO test_conc205 VALUES('data01', 21893, 1718038908), ('data2', -25734, -1857802040)");
  check_mysql_rc(rc, mysql);

  stmt= mysql_stmt_init(mysql);
  FAIL_IF(!stmt, mysql_error(mysql));

  rc= mysql_stmt_prepare(stmt, SL(query));
  check_stmt_rc(rc, stmt);

  memset(my_bind, '\0', sizeof(my_bind));
  my_bind[0].buffer_type= MYSQL_TYPE_STRING;
  my_bind[0].buffer= (void *)data;
  my_bind[0].buffer_length= sizeof(data);
  my_bind[0].is_null= &is_null[0];
  my_bind[0].length= &length[0];

  my_bind[1].buffer_type= MYSQL_TYPE_SHORT;
  my_bind[1].buffer= &smint_col;
  my_bind[1].buffer_length= 2;
  my_bind[1].is_null= &is_null[1];
  my_bind[1].length= &length[1];

  my_bind[2].buffer_type= MYSQL_TYPE_LONG;
  my_bind[2].buffer= &int_col;
  my_bind[2].buffer_length= 4;
  my_bind[2].is_null= &is_null[2];
  my_bind[2].length= &length[2];

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_bind_result(stmt, my_bind);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_fetch(stmt);
  check_stmt_rc(rc, stmt);

  FAIL_IF(length[0] != 6, "Wrong fetched string length");
  FAIL_IF(length[1] != 2, "Wrong fetched short length");
  FAIL_IF(length[2] != 4, "Wrong fetched int length");

  FAIL_IF(strncmp(data, "data01", length[0] + 1) != 0, "Wrong string value");
  FAIL_IF(smint_col != 21893, "Expected 21893");
  FAIL_IF(int_col != 1718038908, "Expected 1718038908");

  rc= mysql_stmt_fetch(stmt);
  check_stmt_rc(rc, stmt);

  FAIL_IF(length[0] != 5, "Wrong fetched string length");
  FAIL_IF(length[1] != 2, "Wrong fetched short length");
  FAIL_IF(length[2] != 4, "Wrong fetched int length");

  FAIL_IF(strncmp(data, "data2", length[0] + 1) != 0, "Wrong string value");
  FAIL_IF(smint_col != -25734, "Expected -25734");
  FAIL_IF(int_col != -1857802040, "Expected -1857802040");

  rc= mysql_stmt_fetch(stmt);
  FAIL_IF(rc != MYSQL_NO_DATA, "Expected MYSQL_NO_DATA");

  mysql_stmt_close(stmt);

  rc= mysql_query(mysql, "drop table test_conc205");
  check_mysql_rc(rc, mysql);

  return OK;
}

static int test_conc217(MYSQL *mysql)
{
  MYSQL_STMT *stmt= mysql_stmt_init(mysql);
  int rc;

  SKIP_MAXSCALE;
  rc= mariadb_stmt_execute_direct(stmt, "SELECT 1 FROM nonexisting_table", -1);
  FAIL_IF(rc==0, "Expected error\n");
  rc= mysql_query(mysql, "drop table if exists t_count");
  check_mysql_rc(rc, mysql);
  mysql_stmt_close(stmt);
  check_mysql_rc(rc, mysql);
  return OK;
}

static int test_conc208(MYSQL *mysql)
{
  MYSQL_STMT *stmt= mysql_stmt_init(mysql);
  int rc;
  int data;
  MYSQL_BIND bind;

  rc= mysql_stmt_prepare(stmt, "SELECT \"100\" UNION SELECT \"88\" UNION SELECT \"389789\"", -1);
  check_stmt_rc(rc, stmt);

  memset(&bind, 0, sizeof(MYSQL_BIND));
  bind.buffer_type= MYSQL_TYPE_LONG;
  bind.buffer= (void *)&data;

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_bind_result(stmt, &bind);

  while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
  {
    diag("data=%d", data);
    FAIL_IF(data != 100 && data != 88 && data != 389789, "Wrong value");
  }
  mysql_stmt_close(stmt);
  return OK;
}

static int test_mdev14165(MYSQL *mysql)
{
  int rc;
  MYSQL_STMT *stmt= mysql_stmt_init(mysql);
  MYSQL_FIELD *fields;
  MYSQL_RES *result;
  my_bool val= 1;
  MYSQL_BIND bind[1];
  char buf1[52];

  rc= mysql_options(mysql, MYSQL_REPORT_DATA_TRUNCATION, &val);

  rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
  rc= mysql_query(mysql, "CREATE TABLE t1 (i INT(20) ZEROFILL)");
  check_mysql_rc(rc, mysql);
  rc= mysql_query(mysql, "INSERT INTO t1 VALUES (2),(1)");
  check_mysql_rc(rc, mysql);
  rc= mysql_stmt_prepare(stmt, "SELECT i FROM t1", -1);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  memset(bind, 0, sizeof(MYSQL_BIND));
  bind[0].buffer_type= MYSQL_TYPE_STRING;
  bind[0].buffer_length= 51;
  bind[0].buffer= buf1;

  mysql_stmt_bind_result(stmt, bind);

  rc= mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, &val);
  check_stmt_rc(rc, stmt);
  rc= mysql_stmt_store_result(stmt);
  check_stmt_rc(rc, stmt);

  result= mysql_stmt_result_metadata(stmt);

  fields= mysql_fetch_fields(result);

  FAIL_IF(fields[0].length < 20, "Expected length=20");
  FAIL_IF(fields[0].max_length < 20, "Expected max_length=20");

  mysql_stmt_fetch(stmt);

  FAIL_UNLESS(strcmp(buf1, "00000000000000000002") == 0, "Wrong result");
  mysql_free_result(result);

  mysql_stmt_close(stmt);

  rc= mysql_query(mysql, "DROP TABLE t1");
  check_mysql_rc(rc, mysql);
  return OK;
}

static int test_compress(MYSQL *mysql)
{
  MYSQL_STMT *stmt= mysql_stmt_init(mysql);
  int rc;

  rc= mariadb_stmt_execute_direct(stmt, SL("SELECT 1 FROM DUAL"));
  check_stmt_rc(rc, stmt);

  mysql_stmt_close(stmt);

  return OK;
}

static int equal_MYSQL_TIME(MYSQL_TIME *tm1, MYSQL_TIME *tm2)
{
  return tm1->day==tm2->day && tm1->hour==tm2->hour && tm1->minute==tm2->minute &&
    tm1->month==tm2->month && tm1->neg==tm2->neg && tm1->second==tm2->second &&
    tm1->second_part==tm2->second_part && tm1->time_type==tm2->time_type && tm1->year==tm2->year;
}

static int test_str_to_int(MYSQL *mysql)
{
 int i;
 struct st_atoi_test{
    const char *str_value;
    int int_value;
    int rc;
  } atoi_tests[]=
  {
    {"0", 0, 0},
    {" 1",1, 0},
    {"123 ",123, 0},
    {"10.2",10, MYSQL_DATA_TRUNCATED},
    {"a", 0, MYSQL_DATA_TRUNCATED},
    {"1 2 3", 1, MYSQL_DATA_TRUNCATED},
    {NULL, 0, 0}
  };

  for(i=0; atoi_tests[i].str_value; i++)
  {
    int rc;
    MYSQL_STMT *stmt;
    MYSQL_BIND bind[1];
    struct st_atoi_test *test= &atoi_tests[i];
    char sql[256];
    int int_value;

    snprintf(sql, sizeof(sql), "SELECT '%s'",test->str_value);

    stmt= mysql_stmt_init(mysql);

    rc= mysql_stmt_prepare(stmt, sql, (ulong)strlen(sql));
    check_stmt_rc(rc, stmt);
    rc= mysql_stmt_execute(stmt);
    check_stmt_rc(rc, stmt);
    rc= mysql_stmt_store_result(stmt);

    memset(bind, 0, sizeof(MYSQL_BIND));
    bind[0].buffer_type= MYSQL_TYPE_LONG;
    bind[0].buffer= &int_value;
    bind[0].buffer_length= sizeof(int_value);

    rc= mysql_stmt_bind_result(stmt, bind);
    check_stmt_rc(rc, stmt);
    rc= mysql_stmt_fetch(stmt);

    diag("test: str='%s', expected/returned value =%d/%d, expected/returned rc=%d/%d",
      test->str_value, test->int_value, int_value, test->rc, rc);
    FAIL_UNLESS(rc == test->rc, "unexpected return code");
    FAIL_UNLESS(int_value == test->int_value, "unexpected int value");
    mysql_stmt_close(stmt);
  }
  return OK;
}


static int test_codbc138(MYSQL *mysql)
{
  int rc;
  MYSQL_STMT *stmt;
  MYSQL_BIND bind[1];
  MYSQL_TIME tm;
  int i= 0;

  struct st_time_test {
    const char *statement;
    MYSQL_TIME tm;
  } time_test[]={
    { "SELECT DATE_ADD('2018-02-01', INTERVAL -188 DAY)",
  { 2017,7,28,0,0,0,0L,0, MYSQL_TIMESTAMP_DATE }
    },
  { "SELECT '2001-02-03 11:12:13.123456'",
  { 2001,2,3,11,12,13,123456L,0, MYSQL_TIMESTAMP_DATETIME }
  },
  { "SELECT '2001-02-03 11:12:13.123'",
  { 2001,2,3,11,12,13,123000L,0, MYSQL_TIMESTAMP_DATETIME }
  },
  { "SELECT '-11:12:13'",
  { 0,0,0,11,12,13,0,1, MYSQL_TIMESTAMP_TIME }
  },
  { "SELECT ' '",
  { 0,0,0,0,0,0,0,0, MYSQL_TIMESTAMP_ERROR }
  },
  { "SELECT '1--'",
  { 0,0,0,0,0,0,0,0, MYSQL_TIMESTAMP_ERROR }
  },
  { "SELECT '-2001-01-01'",
  { 0,0,0,0,0,0,0,0, MYSQL_TIMESTAMP_ERROR }
  },
  { "SELECT '-11:00'",
  { 0,0,0,0,0,0,0,0, MYSQL_TIMESTAMP_ERROR }
  },
  {"SELECT '1972-04-22'",
  {1972,4,22, 0,0,0, 0,0,MYSQL_TIMESTAMP_DATE}
  },
  {"SELECT ' 1972-04-22 '",
  {1972,4,22, 0,0,0, 0,0,MYSQL_TIMESTAMP_DATE}
  },
  {"SELECT '1972-04-22a'",
  {1972,4,22, 0,0,0, 0,0,MYSQL_TIMESTAMP_DATE}
  },
  {"SELECT '0000-00-00'",
  {0,0,0, 0,0,0 ,0,0,MYSQL_TIMESTAMP_DATE}
  },
  {"SELECT '1970-01-00'",
  {1970,1,0, 0,0,0, 0,0, MYSQL_TIMESTAMP_DATE}
  },
  {"SELECT '0069-12-31'",
  {69,12,31, 0,0,0, 0,0, MYSQL_TIMESTAMP_DATE}
  },
  {"SELECT '69-12-31'",
  {2069,12,31, 0,0,0, 0,0, MYSQL_TIMESTAMP_DATE}
  },
  {"SELECT '68-12-31'",
  {2068,12,31, 0,0,0, 0,0, MYSQL_TIMESTAMP_DATE}
  },
  {"SELECT '70-01-01'",
  {1970,1,1, 0,0,0, 0,0, MYSQL_TIMESTAMP_DATE}
  },
  {"SELECT '2010-1-1'",
  {2010,1,1, 0,0,0, 0,0, MYSQL_TIMESTAMP_DATE}
  },

  {"SELECT '10000-01-01'",
  {0,0,0, 0,0,0, 0,0, MYSQL_TIMESTAMP_ERROR}
  },
  {"SELECT '1979-a-01'",
  {0,0,0, 0,0,0, 0,0, MYSQL_TIMESTAMP_ERROR}
  },
  {"SELECT '1979-01-32'",
  {0,0,0, 0,0,0, 0,0, MYSQL_TIMESTAMP_ERROR}
  },
  {"SELECT '1979-13-01'",
  {0,0,0, 0,0,0, 0,0, MYSQL_TIMESTAMP_ERROR}
  },
  {"SELECT '1YYY-01-01'",
  {0,0,0, 0,0,0, 0,0, MYSQL_TIMESTAMP_ERROR}
  },
  {"SELECT '1979-0M-01'",
  {0,0,0, 0,0,0, 0,0, MYSQL_TIMESTAMP_ERROR}
  },
  {"SELECT '1979-00-'",
  {0,0,0, 0,0,0, 0,0, MYSQL_TIMESTAMP_ERROR}
  },
  {"SELECT '1979-00'",
  {0,0,0, 0,0,0, 0,0,MYSQL_TIMESTAMP_ERROR}
  },
  {"SELECT '1979'",
  {0,0,0, 0,0,0, 0,0, MYSQL_TIMESTAMP_ERROR}
  },
  {"SELECT '79'",
  {0,0,0, 0,0,0, 0,0, MYSQL_TIMESTAMP_ERROR}
  },

  {"SELECT '10:15:00'",
  {0,0,0, 10,15,0, 0,0, MYSQL_TIMESTAMP_TIME}
  },
  {"SELECT '10:15:01'",
  {0,0,0, 10,15,1, 0,0, MYSQL_TIMESTAMP_TIME}
  },
  {"SELECT '00:00:00'",
  {0,0,0, 0,0,0, 0,0, MYSQL_TIMESTAMP_TIME}
  },
  {"SELECT '0:0:0'",
  {0,0,0, 0,0,0, 0,0, MYSQL_TIMESTAMP_TIME}
  },
  {"SELECT '10:15:01.'",
  {0,0,0, 10,15,1, 0,0, MYSQL_TIMESTAMP_TIME},
  },
  {"SELECT '25:59:59'",
  {0,0,0, 25,59,59, 0,0, MYSQL_TIMESTAMP_TIME},
  },
  {"SELECT '838:59:59'",
  {0,0,0, 838,59,59, 0,0, MYSQL_TIMESTAMP_TIME},
  },
  {"SELECT '-838:59:59'",
  {0,0,0, 838,59,59, 0, 1, MYSQL_TIMESTAMP_TIME},
  },

  {"SELECT '00:60:00'",
  {0,0,0, 0,0,0, 0,0, MYSQL_TIMESTAMP_ERROR},
  },
  {"SELECT '839:00:00'",
  {0,0,0, 0,0,0, 0,0, MYSQL_TIMESTAMP_ERROR},
  },
  {"SELECT '-839:00:00'",
  {0,0,0, 0,0,0, 0,0, MYSQL_TIMESTAMP_ERROR},
  },
  {"SELECT '-10:15:a'",
  { 0,0,0, 0,0,0, 0,0, MYSQL_TIMESTAMP_ERROR },
  },
  {"SELECT '1999-12-31 23:59:59.9999999'",
  {1999,12,31, 23,59,59, 999999, 0, MYSQL_TIMESTAMP_DATETIME},
  },
  {"SELECT '00-08-11 8:46:40'",
  {2000,8,11, 8,46,40, 0,0, MYSQL_TIMESTAMP_DATETIME},
  },
  {"SELECT '1999-12-31 25:59:59.999999'",
  {0,0,0, 0,0,0, 0,0, MYSQL_TIMESTAMP_ERROR },
  },
  { NULL,{ 0 } }
  };

  while (time_test[i].statement)
  {
    stmt= mysql_stmt_init(mysql);
    rc= mysql_stmt_prepare(stmt, SL(time_test[i].statement));
    check_stmt_rc(rc, stmt);
    rc= mysql_stmt_execute(stmt);
    check_stmt_rc(rc, stmt);
    rc= mysql_stmt_store_result(stmt);

    memset(bind, 0, sizeof(MYSQL_BIND));
    bind[0].buffer_type= MYSQL_TYPE_DATETIME;
    bind[0].buffer= &tm;
    bind[0].buffer_length= sizeof(MYSQL_TIME);

    rc= mysql_stmt_bind_result(stmt, bind);
    check_stmt_rc(rc, stmt);
    rc= mysql_stmt_fetch(stmt);
    check_stmt_rc(rc, stmt);
    diag("test: %s %d %d", time_test[i].statement, tm.time_type, time_test[i].tm.time_type);
    if (time_test[i].tm.time_type == MYSQL_TIMESTAMP_ERROR)
    {
      FAIL_UNLESS(tm.time_type == MYSQL_TIMESTAMP_ERROR, "MYSQL_TIMESTAMP_ERROR expected");
    }
    else
      FAIL_UNLESS(equal_MYSQL_TIME(&tm, &time_test[i].tm), "time_in != time_out");
    mysql_stmt_close(stmt);
    i++;
  }

  return OK;
}

static int test_conc334(MYSQL *mysql)
{
  MYSQL_STMT *stmt= mysql_stmt_init(mysql);
  MYSQL_RES *result;
  MYSQL_FIELD *field;
  int rc;

  rc= mysql_stmt_prepare(stmt, SL("SHOW ENGINES"));
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  result= mysql_stmt_result_metadata(stmt);
  if (!result)
  {
    diag("Couldn't retrieve result set");
    mysql_stmt_close(stmt);
    return FAIL;
  }

  mysql_field_seek(result, 0);

  while ((field= mysql_fetch_field(result)))
  {
    FAIL_IF(field->name_length == 0, "Invalid name length (0)");
    FAIL_IF(field->table_length == 0, "Invalid name length (0)");
  }
  mysql_free_result(result);
  mysql_stmt_close(stmt);

  return OK;
}
static int test_conc344(MYSQL *mysql)
{
  MYSQL_STMT *stmt= mysql_stmt_init(mysql);
  int rc;

  rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
  check_mysql_rc(rc, mysql);

  rc= mysql_query(mysql, "CREATE TABLE t1 (a int, b int)");
  check_mysql_rc(rc, mysql);
  rc= mysql_query(mysql, "INSERT INTO t1 VALUES (1,1), (2,2),(3,3),(4,4),(5,5)");
  check_mysql_rc(rc, mysql);

  rc= mysql_stmt_prepare(stmt, SL("SELECT * FROM t1 ORDER BY a"));
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  while (!mysql_stmt_fetch(stmt));
  FAIL_IF(mysql_stmt_num_rows(stmt) != 5, "expected 5 rows");
  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);
  rc= mysql_stmt_fetch(stmt);
  diag("num_rows: %lld", mysql_stmt_num_rows(stmt));
  FAIL_IF(mysql_stmt_num_rows(stmt) != 1, "expected 1 row");

  mysql_stmt_close(stmt);
  return OK;
}


static int test_conc_fraction(MYSQL *mysql)
{
  MYSQL_TIME tm;
  MYSQL_BIND bind[1];
  char query[1024];
  int i;
  MYSQL_STMT *stmt= mysql_stmt_init(mysql);
  int rc;
  unsigned long frac= 0;

  for (i=0; i < 10; i++, frac=frac*10+i)
  {
    unsigned int expected= frac;
    sprintf(query, "SELECT '2018-11-05 22:25:59.%ld'", frac);

    diag("%d: %s", i, query);

    rc= mysql_stmt_prepare(stmt, SL(query));
    check_stmt_rc(rc, stmt);

    rc= mysql_stmt_execute(stmt);
    check_stmt_rc(rc, stmt);

    rc = mysql_stmt_store_result(stmt);
    check_stmt_rc(rc, stmt);

    memset(bind, 0, sizeof(MYSQL_BIND));
    bind[0].buffer_type= MYSQL_TYPE_DATETIME;
    bind[0].buffer= &tm;
    bind[0].buffer_length= sizeof(MYSQL_TIME);

    rc= mysql_stmt_bind_result(stmt, bind);
    check_stmt_rc(rc, stmt);
    rc= mysql_stmt_fetch(stmt);
    check_stmt_rc(rc, stmt);

    diag("second_part: %ld", tm.second_part);

    while (expected && expected < 100000)
      expected *= 10;
    while (expected >= 1000000)
      expected /= 10;

    if (tm.second_part != expected)
    {
      diag("Error: tm.second_part=%ld expected=%d", tm.second_part, expected);
      mysql_stmt_close(stmt);
      return FAIL;
    }
  }
  mysql_stmt_close(stmt);
  return OK;
}

static int test_zerofill_1byte(MYSQL *mysql)
{
  MYSQL_STMT *stmt= mysql_stmt_init(mysql);
  int rc;
  MYSQL_BIND bind;
  char buffer[3];

  rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
  check_mysql_rc(rc, mysql);

  rc= mysql_query(mysql, "CREATE TABLE t1 (a int zerofill)");
  check_mysql_rc(rc, mysql);

  rc= mysql_query(mysql, "INSERT INTO t1 VALUES(1)");
  check_mysql_rc(rc, mysql);

  rc= mysql_stmt_prepare(stmt, SL("SELECT a FROM t1"));
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  memset(&bind, 0, sizeof(MYSQL_BIND));
  bind.buffer_type= MYSQL_TYPE_STRING;
  bind.buffer= buffer;
  bind.buffer_length= 1;

  rc= mysql_stmt_bind_result(stmt, &bind);

  rc= mysql_stmt_fetch(stmt);
  FAIL_IF(rc != 101, "expected truncation warning");

  mysql_stmt_close(stmt);
  rc= mysql_query(mysql, "DROP TABLE t1");
  check_mysql_rc(rc, mysql);

  return OK;
}

static int test_conc424(MYSQL *mysql)
{
  int rc;
  MYSQL_STMT *stmt;
  my_bool max_len= 1;

  rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_table1");
  check_mysql_rc(rc, mysql);
  rc= mysql_query(mysql, "CREATE TABLE test_table1 (test_int INT, b int)");
  check_mysql_rc(rc, mysql);
  rc= mysql_query(mysql, "INSERT INTO test_table1 values(10,11),(11,12)");
  check_mysql_rc(rc, mysql);

  rc= mysql_query(mysql, "DROP PROCEDURE IF EXISTS testCursor");
  check_mysql_rc(rc, mysql);

  rc= mysql_query(mysql, "CREATE PROCEDURE testCursor()\n"
                  "BEGIN\n"
                  "DECLARE test_int INT;\n"
                  "DECLARE b INT;\n"
                  "DECLARE done INT DEFAULT FALSE;\n"
                  "DECLARE testCursor CURSOR\n"
                  "FOR\n"
                  "SELECT test_int,b FROM test_table1;\n"
                  "DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;\n"
                  "OPEN testCursor;\n"

                  " read_loop: LOOP\n"
                  "   FETCH testCursor INTO test_int, b;\n"
                  "   IF done THEN\n"
                  "     LEAVE read_loop;\n"
                  "   END IF;\n"
                  "   SELECT test_int,b;"
                  " END LOOP;\n"
                  "CLOSE testCursor;\n"
                  "END");
  check_mysql_rc(rc, mysql);

  stmt= mysql_stmt_init(mysql);
  rc= mysql_stmt_prepare(stmt, SL("CALL testCursor()"));
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, &max_len);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  do {
    if (mysql_stmt_field_count(stmt))
    {
      MYSQL_RES *res= mysql_stmt_result_metadata(stmt);
      rc= mysql_stmt_fetch(stmt);
      FAIL_IF(rc, "Wrong return code");
      mysql_free_result(res);
    }
    rc= mysql_stmt_next_result(stmt);

  } while (!rc);

  mysql_stmt_close(stmt);
  rc= mysql_query(mysql, "DROP PROCEDURE testCursor");
  check_mysql_rc(rc, mysql);

  rc= mysql_query(mysql, "DROP TABLE test_table1");
  check_mysql_rc(rc, mysql);

  return OK;
}

static int test_maxparam(MYSQL *mysql)
{
  const char *query= "INSERT INTO t1 VALUES (?)";
  int rc;
  char *buffer;
  int i;
  int val= 1;
  size_t mem= strlen(query) + 1 + 4 * 65535 + 1;
  MYSQL_STMT *stmt= mysql_stmt_init(mysql);
  MYSQL_BIND* bind;

  bind = calloc(65535, sizeof *bind);
  FAIL_UNLESS(bind, "Not enough memory");

  rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
  if (rc)
    free(bind);
  check_mysql_rc(rc, mysql);

  rc= mysql_query(mysql, "CREATE TABLE t1 (a int)");
  if (rc)
    free(bind);
  check_mysql_rc(rc, mysql);

  buffer= calloc(1, mem);
  if(!buffer)
    free(bind);
  FAIL_UNLESS(bind, "Not enough memory");
  strcpy(buffer, query);
  for (i=0; i < 65534.; i++)
    strcat(buffer, ",(?)");
  rc= mysql_stmt_prepare(stmt, SL(buffer));
  if (rc)
    free(bind);
  check_stmt_rc(rc, stmt);

  for (i=0; i < 65534; i++)
  {
    bind[i].buffer_type= MYSQL_TYPE_LONG;
    bind[i].buffer= &val;
  }

  rc= mysql_stmt_bind_param(stmt, bind);
  if (rc)
    free(bind);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_execute(stmt);
  if (rc)
    free(bind);
  check_stmt_rc(rc, stmt);

  FAIL_IF(mysql_stmt_affected_rows(stmt) != 65535, "Expected affected_rows=65535");

  strcat(buffer, ",(?)");
  rc= mysql_stmt_prepare(stmt, SL(buffer));
  free(buffer);
  FAIL_IF(!rc, "Error expected");
  FAIL_IF(mysql_stmt_errno(stmt) != ER_PS_MANY_PARAM, "Expected ER_PS_MANY_PARAM error");

  mysql_stmt_close(stmt);
  free(bind);
  return OK;
}

static int test_mdev_21920(MYSQL *mysql)
{
  MYSQL_STMT *stmt= mysql_stmt_init(mysql);
  MYSQL_BIND bind[1];
  int rc;
  char buffer[128];

  rc= mysql_stmt_prepare(stmt, SL("SELECT ''"));
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  buffer[0]= 1;

  memset(bind, 0, sizeof(MYSQL_BIND));
  bind[0].buffer_type= MYSQL_TYPE_STRING;
  bind[0].buffer= buffer;
  bind[0].buffer_length= 127;

  rc= mysql_stmt_bind_result(stmt, bind);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_fetch(stmt);
  check_stmt_rc(rc, stmt);

  FAIL_IF(buffer[0] != 0, "Expected empty string");


  mysql_stmt_close(stmt);

  return OK;
}

static int test_returning(MYSQL *mysql)
{
  MYSQL_STMT *stmt= mysql_stmt_init(mysql);
  MYSQL_RES *result;
  int rc;

  diag("MDEV-23768 not fixed yet");
  mysql_stmt_close(stmt);
  return SKIP;

  rc= mysql_query(mysql, "CREATE TEMPORARY TABLE t1 (a int not null auto_increment primary key, b json)");
  check_mysql_rc(rc, mysql);

  rc= mysql_query(mysql, "INSERT INTO t1 (a,b) VALUES (NULL, '[incorrect json]') RETURNING a");
  check_mysql_rc(rc, mysql);

  if (!rc) diag("should have fail");

  result= mysql_store_result(mysql);
  mysql_free_result(result);

  diag("Error: %s", mysql_error(mysql));

  rc= mysql_stmt_prepare(stmt, SL("INSERT INTO t1 (a,b) VALUES (NULL, '[incorrect json]') RETURNING a"));
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_close(stmt);

  return OK;
}

static int test_conc504(MYSQL *mysql)
{
  int rc;
  MYSQL_STMT *stmt= mysql_stmt_init(mysql);
  const char *sp= "CREATE PROCEDURE p1()\n" \
                  "BEGIN\n"\
                  "  SELECT 1;\n"\
                  "  SELECT 2;\n"\
                  "  SELECT 3;\n"\
                  "END";

  rc= mysql_query(mysql, "DROP PROCEDURE IF EXISTS p1");
  check_mysql_rc(rc, mysql);

  rc= mysql_query(mysql, sp);
  check_mysql_rc(rc, mysql);

  rc= mysql_stmt_prepare(stmt, SL("CALL p1()"));
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  mysql_stmt_store_result(stmt);
  FAIL_IF(mysql_stmt_num_rows(stmt) != 1, "Expected 1 row");

  mysql_stmt_next_result(stmt);
  mysql_stmt_store_result(stmt);
  FAIL_IF(mysql_stmt_num_rows(stmt) != 1, "Expected 1 row");

  mysql_stmt_next_result(stmt);
  mysql_stmt_store_result(stmt);
  FAIL_IF(mysql_stmt_num_rows(stmt) != 1, "Expected 1 row");

  mysql_stmt_close(stmt);

  rc= mysql_query(mysql, "DROP PROCEDURE p1");
  check_mysql_rc(rc, mysql);

  return OK;
}

static int test_conc512(MYSQL *mysql)
{
  int rc;
  MYSQL_STMT *stmt;
  MYSQL_BIND bind;
  float f;

  rc= mysql_query(mysql, "drop table if exists t1");

  rc= mysql_real_query(mysql, SL("CREATE TABLE t1 (a int)"));

  rc= mysql_real_query(mysql, SL("INSERT INTO t1 VALUES (1073741825)"));

  stmt=  mysql_stmt_init(mysql);
  rc= mysql_stmt_prepare(stmt, SL("SELECT a FROM t1"));
  check_stmt_rc(rc, stmt);

  memset(&bind, 0, sizeof(MYSQL_BIND));
  bind.buffer= &f;
  bind.buffer_type= MYSQL_TYPE_FLOAT;

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_bind_result(stmt, &bind);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_fetch(stmt);
  FAIL_IF(rc != 101, "Truncation expected");

  mysql_stmt_close(stmt);

  rc= mysql_query(mysql, "DROP TABLE t1");
  check_mysql_rc(rc, mysql);
  return OK;
}

static int test_conc525(MYSQL *mysql)
{
  FILE *fp;
  MYSQL_STMT *stmt;
  int rc;

  rc= mysql_query(mysql, "create temporary table t1 (a blob)");
  check_mysql_rc(rc, mysql);

  /* create a dummy import file */
  if (!(fp= fopen("./test.csv", "w")))
  {
    diag("couldn't create file './test.csv'");
    return FAIL;
  }
  fprintf(fp, "1\n2\n");
  fclose(fp);

  /* Test: prepare and execute
     should fail due to non-existing file */
  stmt= mysql_stmt_init(mysql);

  rc= mysql_stmt_prepare(stmt, SL("LOAD DATA LOCAL INFILE './test.notexist' INTO table t1"));

  if (rc && mysql_stmt_errno(stmt) == ER_UNSUPPORTED_PS)
  {
    diag("Server doesn't support LOAD LOCAL INFILE in binary protocol.");
    mysql_stmt_close(stmt);
    return SKIP;
  }

  rc= mysql_stmt_execute(stmt);
  FAIL_IF(!rc, "Error expected (file does not exist)");

  mysql_stmt_close(stmt);

  /* Test: prepare and execute
     2 rows should be inserted */
  stmt= mysql_stmt_init(mysql);

  rc= mysql_stmt_prepare(stmt, SL("LOAD DATA LOCAL INFILE './test.csv' INTO table t1"));
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  FAIL_IF(mysql_stmt_affected_rows(stmt) != 2, "Expected 2 inserted rows");

  mysql_stmt_close(stmt);
  stmt= mysql_stmt_init(mysql);

  /* Test: execute_direct
     2 rows should be inserted */
  rc= mariadb_stmt_execute_direct(stmt,  SL("LOAD DATA LOCAL INFILE './test.csv' INTO table t1"));
  check_stmt_rc(rc, stmt);

  FAIL_IF(mysql_stmt_affected_rows(stmt) != 2, "Expected 2 inserted rows");

  /* Cleanup */
  mysql_stmt_close(stmt);
  unlink("./test.csv");

  return OK;
}

static int test_conc566(MYSQL *mysql)
{
  int rc;
  MYSQL_STMT *stmt = mysql_stmt_init(mysql);
  unsigned long cursor = CURSOR_TYPE_READ_ONLY;
  const char* query= "call sp()";

  SKIP_SKYSQL;

  rc= mysql_query(mysql,"drop procedure if exists sp");
  check_mysql_rc(rc, mysql);

  rc= mysql_query(mysql,"create procedure sp() select 1");
  check_mysql_rc(rc, mysql);

  rc= mysql_stmt_prepare(stmt,query,-1);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, &cursor);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  mysql_stmt_close(stmt);

  rc= mysql_query(mysql,"drop procedure sp");
  check_mysql_rc(rc, mysql);
  return OK;
}

#define MDEV19838_MAX_PARAM_COUNT 32
#define MDEV19838_FIELDS_COUNT 17

static int test_mdev19838(MYSQL *mysql)
{
  int rc;
  MYSQL_BIND bind[MDEV19838_MAX_PARAM_COUNT];
  unsigned int i, paramCount = 1;
  char charvalue[] = "012345678901234567890123456789012345";
  MYSQL_STMT *stmt;

  SKIP_MAXSCALE;
  // https://jira.mariadb.org/browse/XPT-266
  if (IS_XPAND()) {
    rc= mysql_query(mysql, "SET NAMES UTF8");
    check_mysql_rc(rc, mysql);
  }


  rc = mysql_query(mysql, "CREATE temporary TABLE mdev19838("
          "f1  char(36),"
          "f2  char(36),"
          "f3  char(36),"
          "f4  char(36),"
          "f5  char(36),"
          "f6  char(36),"
          "f7  char(36),"
          "f8  char(36),"
          "f9  char(36),"
          "f10 char(36),"
          "f11 char(36),"
          "f12 char(36),"
          "f13 char(36),"
          "f14 char(36),"
          "f15 char(36),"
          "f16 char(36),"
          "f17 char(36)"
    ")");
  check_mysql_rc(rc, mysql);

  stmt = mysql_stmt_init(mysql);

  memset(bind, 0, sizeof(bind));

  for (i = 0; i < MDEV19838_MAX_PARAM_COUNT; ++i)
  {
    bind[i].buffer = charvalue;
    bind[i].buffer_type = MYSQL_TYPE_STRING;
    bind[i].buffer_length = sizeof charvalue;
    bind[i].length = &bind[i].length_value;
    bind[i].length_value = bind[i].buffer_length - 1;
  }

  for (paramCount = 1; paramCount < MDEV19838_FIELDS_COUNT; ++paramCount)
  {
    mysql_stmt_attr_set(stmt, STMT_ATTR_PREBIND_PARAMS, &paramCount);

    rc = mysql_stmt_bind_param(stmt, bind);
    check_stmt_rc(rc, stmt);

    rc = mariadb_stmt_execute_direct(stmt, "INSERT INTO mdev19838"
      "(f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17)"
      " VALUES "
      "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", -1);

    /* Expecting an error */
    FAIL_UNLESS(rc != 0, "rc!=0");

    mysql_stmt_close(stmt);
    stmt = mysql_stmt_init(mysql);
  }

  paramCount = 0;
  mysql_stmt_attr_set(stmt, STMT_ATTR_PREBIND_PARAMS, &paramCount);
  rc = mariadb_stmt_execute_direct(stmt, "INSERT INTO mdev19838(f1)"
    " VALUES (?)", -1);
  /* Expecting an error */
  FAIL_UNLESS(rc != 0, "rc!=0");
  mysql_stmt_close(stmt);

  stmt = mysql_stmt_init(mysql);
  /* Correct number of parameters */
  paramCount = MDEV19838_FIELDS_COUNT;
  mysql_stmt_attr_set(stmt, STMT_ATTR_PREBIND_PARAMS, &paramCount);
  mysql_stmt_bind_param(stmt, bind);

  rc = mariadb_stmt_execute_direct(stmt, "INSERT INTO mdev19838"
    "(f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17)"
    " VALUES "
    "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", -1);
  check_stmt_rc(rc, stmt);

  /* MYSQL_TYPE_TINY = 1. This parameter byte can be read as "parameters send" flag byte.
     Checking that wrong packet is still detected */
  bind[0].buffer_type = MYSQL_TYPE_TINY;
  bind[0].length_value = 1;
  bind[0].buffer_length = 1;

  for (paramCount = 8; paramCount > 0; --paramCount)
  {
    mysql_stmt_close(stmt);
    stmt = mysql_stmt_init(mysql);

    mysql_stmt_attr_set(stmt, STMT_ATTR_PREBIND_PARAMS, &paramCount);

    rc = mysql_stmt_bind_param(stmt, bind);

    rc = mariadb_stmt_execute_direct(stmt, "INSERT INTO mdev19838"
      "(f1, f2, f3, f4, f5, f6, f7, f8, f9)"
      " VALUES "
      "(?, ?, ?, ?, ?, ?, ?, ?, ?)", -1);

    /* Expecting an error */
    FAIL_UNLESS(rc != 0, "rc");
  }

  /* Test of query w/out parameters, with parameter sent and not sent */
  for (paramCount = MDEV19838_MAX_PARAM_COUNT; paramCount != (unsigned int)-1; --paramCount)
  {
    mysql_stmt_close(stmt);
    stmt = mysql_stmt_init(mysql);

    mysql_stmt_attr_set(stmt, STMT_ATTR_PREBIND_PARAMS, &paramCount);

    if (paramCount > 0)
    {
      rc = mysql_stmt_bind_param(stmt, bind);
      check_stmt_rc(rc, stmt);
    }

    rc = mariadb_stmt_execute_direct(stmt, "INSERT INTO mdev19838"
      "(f1)"
      " VALUES "
      "(0x1111111111111111)", -1);

    /*
      We allow junk at the end of the packet in case of
      no parameters. So it will succeed.
    */
    FAIL_UNLESS(rc == 0, "");
  }

  mysql_stmt_close(stmt);
  return OK;
}

my_bool conc623_param_callback(void *data __attribute((unused)),
                               MYSQL_BIND *bind __attribute((unused)),
                               unsigned int row_nr __attribute((unused)))
{
  return 1;
}

static int test_conc623(MYSQL *mysql)
{
  int rc;
  unsigned int paramcount= 1;
  unsigned int array_size= 2;
  MYSQL_BIND bind;

  MYSQL_STMT *stmt= mysql_stmt_init(mysql);

  rc= mysql_query(mysql, "CREATE TEMPORARY TABLE t1 (a int)");

  rc= mysql_stmt_attr_set(stmt, STMT_ATTR_CB_USER_DATA, mysql);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_attr_set(stmt, STMT_ATTR_ARRAY_SIZE, &array_size);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_attr_set(stmt, STMT_ATTR_PREBIND_PARAMS, &paramcount);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_attr_set(stmt, STMT_ATTR_CB_PARAM, conc623_param_callback);
  check_stmt_rc(rc, stmt);

  memset(&bind, 0, sizeof(MYSQL_BIND));
  bind.buffer_type= MYSQL_TYPE_LONG;
  rc= mysql_stmt_bind_param(stmt, &bind);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_prepare(stmt, SL("INSERT INTO t1 VALUES (?)"));
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_execute(stmt);
  if (!rc)
  {
    diag("Error expected from callback function");
    mysql_stmt_close(stmt);
    return FAIL;
  }

  diag("Error (expected) %s", mysql_stmt_error(stmt));
  mysql_stmt_close(stmt);
  return OK;
}

static int test_conc627(MYSQL *mysql)
{
  MYSQL_STMT *stmt;
  int rc;

  SKIP_MYSQL(mysql);

  stmt= mysql_stmt_init(mysql);

  rc= mysql_stmt_prepare(stmt, SL("show grants for mysqltest_8"));
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  mysql_stmt_store_result(stmt);
  FAIL_IF(!mysql_stmt_errno(stmt), "Expected error");
  FAIL_IF(strcmp(mysql_error(mysql), mysql_stmt_error(stmt)), "Error messages differ");

  mysql_stmt_close(stmt);

  return OK;
}

static int test_conc633(MYSQL *mysql)
{
  MYSQL_STMT *stmt;
  MYSQL *my= NULL;
  int ret= FAIL;
  int rc;

  SKIP_MYSQL(mysql);

  stmt= mysql_stmt_init(mysql);

  if (!mariadb_stmt_execute_direct(stmt, SL("SÄLECT 1")))
  {
    diag("Syntax error expected");
    goto end;
  }

  if (mysql_errno(mysql) != mysql_stmt_errno(stmt))
  {
    diag("Different error codes. mysql_errno= %d, mysql_stmt_errno=%d",
          mysql_errno(mysql), mysql_stmt_errno(stmt));
    goto end;
  }

  if ((long)stmt->stmt_id != -1)
  {
    diag("Error: expected stmt_id=-1");
    goto end;
  }

  if (!(my= test_connect(NULL)))
  {
    diag("Can establish connection (%s)", mysql_error(my));
    goto end;
  }

  rc= mysql_query(my, "CREATE OR REPLACE TABLE conc633 (a int)");
  check_mysql_rc(rc, mysql);

  rc= mysql_query(mysql, "SET @@lock_wait_timeout=3");

  rc= mysql_query(my, "LOCK TABLES conc633 WRITE");
  check_mysql_rc(rc, mysql);

  rc= mysql_query(mysql, "SET @@lock_wait_timeout=3");
  check_mysql_rc(rc, mysql);

  if (!mariadb_stmt_execute_direct(stmt, SL("INSERT INTO conc633 VALUES (1)")))
  {
    diag("lock wait timeout error expected");
    goto end;
  }

  if (stmt->state != MYSQL_STMT_PREPARED)
  {
    diag("Error: stmt hasn't prepared status");
    goto end;
  }

  if ((long)stmt->stmt_id == -1)
  {
    diag("Error: no stmt_id assigned");
    goto end;
  }

  rc= mysql_query(my, "UNLOCK TABLES");
  check_mysql_rc(rc, mysql);
  rc= mysql_query(my, "DROP TABLE conc633");
  check_mysql_rc(rc, mysql);

  ret= OK;

end:
  if (my)
    mysql_close(my);
  mysql_stmt_close(stmt);
  return ret;
}

static int test_conc667(MYSQL *mysql)
{
  MYSQL_STMT *stmt1, *stmt2;
  int rc;

  stmt1= mysql_stmt_init(mysql);
  stmt2= mysql_stmt_init(mysql);

  rc= mysql_stmt_prepare(stmt1, "SELECT 1", -1);
  check_stmt_rc(rc, stmt1);

  rc= mysql_stmt_prepare(stmt2, "SELECT 2", -1);
  check_stmt_rc(rc, stmt2);

  rc= mysql_stmt_execute(stmt1);
  check_stmt_rc(rc, stmt1);

  rc= mysql_stmt_free_result(stmt2);
  FAIL_IF(!rc || mysql_stmt_errno(stmt2) != CR_STMT_NO_RESULT,
           "Expected CR_STMT_NO_RESULT");
  diag("Error (expected) %s", mysql_stmt_error(stmt2));

  rc= mysql_stmt_reset(stmt2);
  FAIL_IF(!rc || mysql_stmt_errno(stmt2) != CR_COMMANDS_OUT_OF_SYNC,
           "Expected commands out of sync error");

  rc= mysql_stmt_fetch(stmt1);
  check_stmt_rc(rc, stmt1);

  mysql_stmt_free_result(stmt1);

  rc= mysql_stmt_close(stmt1);
  check_stmt_rc(rc, stmt1);
  rc= mysql_stmt_close(stmt2);
  check_stmt_rc(rc, stmt2);

  return OK;
}

static int test_conc683(MYSQL *mysql)
{
  MYSQL_STMT *stmt1, *stmt2;
  int rc;

  stmt1= mysql_stmt_init(mysql);
  stmt2= mysql_stmt_init(mysql);

  rc= mysql_stmt_prepare(stmt1, "SELECT 1 UNION SELECT 2", -1);
  check_stmt_rc(rc, stmt1);

  rc= mysql_stmt_prepare(stmt2, "SELECT 1", -1);
  check_stmt_rc(rc, stmt2);

  rc= mysql_stmt_execute(stmt1);
  check_stmt_rc(rc, stmt1);

  rc= mysql_stmt_close(stmt2);
  FAIL_IF(!rc || mysql_stmt_errno(stmt2) != CR_COMMANDS_OUT_OF_SYNC,
           "Expected commands out of sync error");

  rc= mysql_stmt_close(stmt1);
  check_stmt_rc(rc, stmt1);
  rc= mysql_stmt_close(stmt2);
  check_stmt_rc(rc, stmt2);

  return OK;
}

static int test_conc702(MYSQL *ma)
{
  MYSQL_STMT *stmt, *stmt2;
  int rc;

  diag("Server info %s\nClient info: %s",
      mysql_get_server_info(ma), mysql_get_client_info());

  rc= mysql_query(ma, "DROP PROCEDURE IF EXISTS p1");
  check_mysql_rc(rc, ma);

  rc= mysql_query(ma, "CREATE PROCEDURE p1() BEGIN"
                  "  SELECT 1 FROM DUAL; "
                  "END");
  check_mysql_rc(rc, ma);

  stmt= mysql_stmt_init(ma);

  FAIL_IF(!stmt, "Could not allocate stmt");

  rc= mysql_stmt_prepare(stmt, "CALL p1()", -1);
  check_stmt_rc(rc, stmt);
  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);


  mysql_stmt_store_result(stmt);
  check_stmt_rc(rc, stmt);

  // We've done everything w/ result and skip everything else

  while (mysql_stmt_more_results(stmt)) {

    mysql_stmt_next_result(stmt);
    // state at this moment is MYSQL_STMT_WAITING_USE_OR_STORE. But there is no result,
    // we can't store it. And there is no way to change it

  }
  // Now we are not closing it, for later use. For example it's been put to the cache
  // Using connection freely - we haven't done anything wrong, "nothing is out of sync"

  mysql_query(ma, "DROP PROCEDURE p1");
  mysql_query(ma, "DROP PROCEDURE IF EXISTS p2");
  mysql_query(ma, "CREATE PROCEDURE p2() "
                  "BEGIN "
                  "  SELECT 'Marten' FROM DUAL; "
                  "  SELECT 'Zack' FROM DUAL; "
                  "END");

  stmt2= mysql_stmt_init(ma);

  mysql_stmt_prepare(stmt2, "CALL p2()", -1);

  mysql_stmt_execute(stmt2);

  mysql_stmt_store_result(stmt2);

  // I was initially wrong, this goes thru
  check_stmt_rc(mysql_stmt_next_result(stmt2), stmt2);

  // But we get error"Out of sync" set, if check
  //  check_stmt_rc(mysql_stmt_next_result(stmt2), stmt2);

  check_stmt_rc(mysql_stmt_store_result(stmt2), stmt2);

  mysql_stmt_close(stmt2);

  mysql_stmt_close(stmt);

  rc= mysql_query(ma, "DROP PROCEDURE p2");
  check_mysql_rc(rc, ma);

  return OK;
}

static int test_conc739(MYSQL *mysql)
{
  MYSQL_STMT *stmt;
  int rc;
  MYSQL_BIND bind[2];
  char buffer[2][100];
  MYSQL_ROW row;
  MYSQL_RES *result;
  uint8 i;

  rc= mysql_query(mysql, "SELECT FROM_UNIXTIME('1922.1'), FROM_UNIXTIME('1922.0')");
  check_mysql_rc(rc, mysql);
  result= mysql_store_result(mysql);
  row= mysql_fetch_row(result);

  stmt= mysql_stmt_init(mysql);

  rc= mysql_stmt_prepare(stmt, SL("SELECT FROM_UNIXTIME('1922.1'), FROM_UNIXTIME('1922.0')"));
  check_stmt_rc(rc, stmt);

  memset(bind, 0, 2 * sizeof(MYSQL_BIND));
  for (i=0; i < 2; i++)
  {
    bind[i].buffer_type= MYSQL_TYPE_STRING;
    bind[i].buffer= &buffer[i];
    bind[i].buffer_length= 100;
  }

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_bind_result(stmt, bind);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_fetch(stmt);
  check_stmt_rc(rc, stmt);

  for (i=0; i < 2; i++)
  {
    diag("text: %s  binary: %s", row[i], buffer[i]);
    FAIL_IF(strcmp(buffer[i], row[i]), "Different results (text/binary protocol)");
  }

  mysql_stmt_close(stmt);
  mysql_free_result(result);
  return OK;
}

static int test_conc176(MYSQL *mysql)
{
  MYSQL_STMT *stmt;
  MYSQL_BIND bind;
  char buffer[9];

  int rc;

  rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
  check_mysql_rc(rc, mysql);

  rc= mysql_query(mysql, "CREATE TABLE t1 (a int(8) zerofill)");
  check_mysql_rc(rc, mysql);

  rc= mysql_query(mysql, "INSERT INTO t1 VALUES (1)");
  check_mysql_rc(rc, mysql);

  stmt= mysql_stmt_init(mysql);

  rc= mysql_stmt_prepare(stmt, "SELECT a FROM t1", -1);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_execute(stmt);

  memset(&bind, 0, sizeof(MYSQL_BIND));

  bind.buffer= buffer;
  bind.buffer_type= MYSQL_TYPE_STRING;
  bind.buffer_length= 9;

  rc= mysql_stmt_bind_result(stmt, &bind);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_fetch(stmt);

  diag("Buffer: %s", buffer);
  FAIL_IF(strlen(buffer) == 1, "Expected zerofilled string");

  rc= mysql_stmt_close(stmt);

  rc= mysql_query(mysql, "DROP TABLE t1");
  check_mysql_rc(rc, mysql);

  return OK;
}

static int test_conc762(MYSQL *mysql)
{
  int rc;
  MYSQL_STMT *stmt= mysql_stmt_init(mysql);
  MYSQL_BIND bind[2];
  my_bool is_null[2]= {1,1};
  unsigned long length[2]= {1,1};

  rc= mysql_stmt_prepare(stmt, SL("SELECT NULL, 'foo' union select 'bar', NULL union select NULL, 'foobar'"));
  check_stmt_rc(rc, stmt);

  memset(&bind, 0, sizeof(MYSQL_BIND) * 2);

  bind[0].buffer_type = MYSQL_TYPE_STRING;
  bind[1].buffer_type = MYSQL_TYPE_STRING;
  bind[0].is_null= &is_null[0];
  bind[1].is_null= &is_null[1];
  bind[0].buffer_length= bind[1].buffer_length= 0;
  bind[0].length= &length[0];
  bind[1].length= &length[1];

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_bind_result(stmt, bind);


  mysql_stmt_fetch(stmt);
  FAIL_IF(is_null[0]==0, "Expected NULL value");
  FAIL_IF(is_null[1]==1, "Expected non-NULL value");
  FAIL_IF(length[0]!=0, "Expected length=0");
  FAIL_IF(length[1]!=3, "Expected length=3");

  mysql_stmt_fetch(stmt);
  FAIL_IF(is_null[1]==0, "Expected NULL value");
  FAIL_IF(is_null[0]==1, "Expected non-NULL value");
  FAIL_IF(length[1]!=0, "Expected length=0");
  FAIL_IF(length[0]!=3, "Expected length=3");

  mysql_stmt_fetch(stmt);
  FAIL_IF(is_null[0]==0, "Expected NULL value");
  FAIL_IF(is_null[1]==1, "Expected non-NULL value");
  FAIL_IF(length[0]!=0, "Expected length=0");
  FAIL_IF(length[1]!=6, "Expected length=3");

  /* Also check with MYSQL_TYPE_NULL */
  length[0]= 3;

  rc= mysql_stmt_prepare(stmt, SL("SELECT NULL"));
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_execute(stmt);
  check_stmt_rc(rc, stmt);

  rc= mysql_stmt_bind_result(stmt, bind);
  check_stmt_rc(rc, stmt);

  mysql_stmt_fetch(stmt);
  FAIL_IF(length[0]!=0, "Expected length=0");

  mysql_stmt_close(stmt);
  return OK;
}


struct my_tests_st my_tests[] = {
  {"test_conc683", test_conc683, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
  {"test_conc667", test_conc667, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
  {"test_conc702", test_conc702, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
  {"test_conc762", test_conc762, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
  {"test_conc176", test_conc176, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
  {"test_conc739", test_conc739, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
  {"test_conc633", test_conc633, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
  {"test_conc623", test_conc623, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
  {"test_conc627", test_conc627, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
  {"test_mdev19838", test_mdev19838, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
  {"test_conc525", test_conc525, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
  {"test_conc566", test_conc566, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
  {"test_conc512", test_conc512, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
  {"test_conc504", test_conc504, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
  {"test_returning", test_returning, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
  {"test_mdev_21920", test_mdev_21920, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
  {"test_maxparam", test_maxparam, TEST_CONNECTION_NEW, 0, NULL, NULL},
  {"test_conc424", test_conc424, TEST_CONNECTION_NEW, 0, NULL, NULL},
  {"test_conc344", test_conc344, TEST_CONNECTION_NEW, 0, NULL, NULL},
  {"test_conc334", test_conc334, TEST_CONNECTION_NEW, 0, NULL, NULL},
  {"test_compress", test_compress, TEST_CONNECTION_NEW, CLIENT_COMPRESS, NULL, NULL},
  {"test_zerofill_1byte", test_zerofill_1byte, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
  {"test_codbc138", test_codbc138, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
  {"test_conc208", test_conc208, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
  {"test_mdev14165", test_mdev14165, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
  {"test_conc208", test_conc208, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
  {"test_conc217", test_conc217, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
  {"test_conc205", test_conc205, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
  {"test_conc198", test_conc198, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
  {"test_conc182", test_conc182, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
  {"test_conc181", test_conc181, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
  {"test_conc179", test_conc179, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
  {"test_conc177", test_conc177, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
  {"test_conc167", test_conc167, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
  {"test_conc168", test_conc168, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
  {"test_conc155", test_conc155, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
  {"test_conc154", test_conc154, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_conc141", test_conc141, TEST_CONNECTION_NEW, 0, NULL , NULL},
  {"test_conc67", test_conc67, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_conc_5", test_conc_5, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_bug1115", test_bug1115, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_bug1180", test_bug1180, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_bug1644", test_bug1644, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_bug11037", test_bug11037, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_bug11183", test_bug11183, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_bug12744", test_bug12744, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_bug1500", test_bug1500, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_bug15510", test_bug15510, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_bug15518", test_bug15518, TEST_CONNECTION_NEW | TEST_CONNECTION_DONT_CLOSE, CLIENT_MULTI_STATEMENTS, NULL , NULL},
  {"test_bug15613", test_bug15613, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_bug16144", test_bug16144, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_bug1664", test_bug1664, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_bug1946", test_bug1946, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_bug2247", test_bug2247, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_bug2248", test_bug2248, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_bug20152", test_bug20152, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_bug23383", test_bug23383, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_bug27592", test_bug27592, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_bug28934", test_bug28934, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_bug36004", test_bug36004, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_bug3035", test_bug3035, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_bug3117", test_bug3117, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_bug3796", test_bug3796, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_bug4026", test_bug4026, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_bug4030", test_bug4030, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_bug4079", test_bug4079, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_bug4172", test_bug4172, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_bug4231", test_bug4231, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_bug4236", test_bug4236, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_bug5126", test_bug5126, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_bug5194", test_bug5194, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_bug5315", test_bug5315, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_bug5399", test_bug5399, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_bug6046", test_bug6046, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_bug6049", test_bug6049, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_bug6058", test_bug6058, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_bug6059", test_bug6059, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_bug6096", test_bug6096, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_bug7990", test_bug7990, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_bug8330", test_bug8330, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_bug8722", test_bug8722, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_ps_conj_select", test_ps_conj_select, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_ps_null_param", test_ps_null_param, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_ps_query_cache", test_ps_query_cache, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_ushort_bug", test_ushort_bug, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_field_misc", test_field_misc, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_mem_overun", test_mem_overun, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_decimal_bug", test_decimal_bug, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_explain_bug", test_explain_bug, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_sshort_bug", test_sshort_bug, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_stiny_bug", test_stiny_bug, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_bug53311", test_bug53311, TEST_CONNECTION_NEW, 0, NULL , NULL},
  {"test_conc_fraction", test_conc_fraction, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
  {"test_str_to_int", test_str_to_int, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
  {NULL, NULL, 0, 0, NULL, NULL}
};

int main(int argc, char **argv)
{
  if (argc > 1)
    get_options(argc, argv);

  get_envvars();

  run_tests(my_tests);

  return(exit_status());
}
