/*
Copyright (c) 2009, 2015, 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 "bugs.h"
#include <sstream>
#include <limits>
#include "driver/mysql_error.h"

//Prevent windows min() macro
#undef min

namespace testsuite
{
namespace regression
{

void bugs::net_write_timeout39878()
{
  logMsg("Test for #39878 - not fixed. And looks like there is no way to fix it at the moment.");
  logMsg("If the test doesn't fail - that rather means that you should tweak parameters for your system");
  logMsg("You can do that with command line parameters:");
  logMsg(" --nwtTimeout=<val> for the value net_write timeout to set to (default 1)");
  logMsg(" --nwtPause=<val> for the length of pause test shoud take while fetching rows (default 2)");
  logMsg(" --nwtRows=<val> for the number of rows to insert into table (default 9230)");

  int timeout = 1;
  int pause = 2;
  int rows = 9230;

  int tmp = TestsRunner::getStartOptions()->getInt("nwtTimeout");
  if (tmp > 0)
    timeout = tmp;


  tmp = TestsRunner::getStartOptions()->getInt("nwtPause");
  if (tmp > 0)
    pause = tmp;

  tmp = TestsRunner::getStartOptions()->getInt("nwtRows");
  if (tmp > 0)
    rows = tmp;


  pstmt.reset(con->prepareStatement("set net_write_timeout=?"));
  pstmt->setInt(1, timeout);
  pstmt->execute();

  res.reset(stmt->executeQuery("show variables like \"net_write_timeout\""));

  res->next();

  TestsListener::messagesLog() << "We've set net_write_timeout to " << res->getString(2) << std::endl;


  stmt->executeUpdate("drop table if exists bug39878");
  stmt->executeUpdate("create table bug39878 (id int unsigned not null)");

  stmt->execute("lock table bug39878 write");

  pstmt.reset(con->prepareStatement("insert into bug39878 ( id ) values( ? )"));

  for (int i = 1; i <= rows; ++i) {
    pstmt->setInt(1, i);
    pstmt->execute();
  }

  stmt->execute("unlock tables");


  res.reset(stmt->executeQuery("select count(*) from bug39878"));

  res->next();

  uint32_t rowsCount = res->getUInt(1);

  TestsListener::messagesLog() << "Now we have " << rowsCount << " rows in the table" << std::endl;

  // Must set ResultSet Type  to TYPE_FORWARD_ONLY
  stmt->setResultSetType(sql::ResultSet::TYPE_FORWARD_ONLY);

  res.reset(stmt->executeQuery("select * from bug39878"));

  TestsListener::messagesLog() << "ResultSetType: " << stmt->getResultSetType() << std::endl;

  uint32_t rowsRead = 0;

  try {
    while (res->next()) {
      if (rowsRead == 0) {
        TestsListener::messagesLog() << "Pause " << pause << "s." << std::endl;
        SLEEP(pause);
      }

      ++rowsRead;
    }
  } catch (sql::SQLException& /*e*/) {
    //if ( e.errNo == 2006 )

    /* let's think that exception is a god result itself.
       also not sure which errno should it be */

    return;
  }

  TestsListener::messagesLog() << "We've fetched " << rowsRead << " rows." << std::endl;

  try {
    stmt->execute("drop table if exists bug39878");
  } catch (sql::SQLException& e) {
    // Expected, that Server has gone away
    logMsg(e.what());

    // Lazy way to reconnect
    setUp();

    stmt->execute("drop table if exists bug39878");
  }

  ASSERT_EQUALS(rowsCount, rowsRead);
}


void bugs::store_result_error_51562()
{
  std::stringstream msg;

  logMsg("Regression test for #51562");
  try {
    stmt.reset(con->createStatement());
    /* Running a SELECT and storing the returned result set in this->res */
    res.reset(stmt->executeQuery("select 1, (select 'def' union all select 'abc')"));

    fail("SQL error not detected or the server has changed its behavior", __FILE__, __LINE__);
  } catch (sql::SQLException &e) {
    /* If anything goes wrong, write some info to the log... */
    logMsg("Expecting error: ERROR 1242 (21000): Subquery returns more than 1 row, got:");
    logMsg(e.what());
    logMsg("SQLState: " + std::string(e.getSQLState()));
    if (e.getErrorCode() != 1242) {
      msg.str("");
      msg << "Expecting MySQL error code 1242, got " << e.getErrorCode() << ".";
      msg << "This may be a compatible and acceptable code - check manually and update test if nedded!";
      logMsg(msg.str());
      fail("Wrong error code, check verbose output for details", __FILE__, __LINE__);
    }
  }

  logMsg("Checking prepared statements");
  try {
    pstmt.reset(con->prepareStatement("select 1, (select 'def' union all select 'abc')"));
    /* Running a SELECT and storing the returned result set in this->res */
    res.reset(pstmt->executeQuery());

    fail("SQL error not detected or the server has changed its behavior", __FILE__, __LINE__);
  } catch (sql::SQLException &e) {
    /* If anything goes wrong, write some info to the log... */
    logMsg("Expecting error: ERROR 1242 (21000): Subquery returns more than 1 row, got:");
    logMsg(e.what());
    logMsg("SQLState: " + std::string(e.getSQLState()));
    if (e.getErrorCode() != 1242) {
      msg.str("");
      msg << "Expecting MySQL error code 1242, got " << e.getErrorCode() << ".";
      msg << "This may be a compatible and acceptable code - check manually and update test if nedded!";
      logMsg(msg.str());
      fail("Wrong error code, check verbose output for details", __FILE__, __LINE__);
    }
  }
}


void bugs::getResultSet_54840()
{
  stmt->executeUpdate("DROP function if exists _getActivePost");
  stmt->executeUpdate("CREATE Function _getActivePost(_author INT) "
                                                "RETURNS INT "
                                                "DETERMINISTIC "
                                                "BEGIN "
                                                "       RETURN 55;"
                                                "END");

  ASSERT(stmt->execute("select _getActivePost()"));

  try
  {
    res.reset(stmt->getResultSet());
  }
  catch (::sql::SQLException & /*e*/)
  {
    stmt->executeUpdate("DROP function _getActivePost");
    return; /* Everything is fine */
  }

  stmt->executeUpdate("DROP function _getActivePost");
  FAIL("Exception wasn't thrown by getResultSet");
}

void bugs::supportIssue_52319()
{
  std::stringstream msg;

  unsigned int uiStartTime = 1289837776;
  unsigned int uiProductsID = 20;
  unsigned int uiParSetID = 2;

  logMsg("Test for MySQL support issue 52319");

  stmt->execute("DROP TABLE IF EXISTS products");
  createSchemaObject("TABLE",
                     "products",
                     "(uiProductsIdx int(10) unsigned NOT NULL AUTO_INCREMENT, startTime timestamp NULL DEFAULT NULL, stopTime timestamp NULL DEFAULT NULL, uiProductsID int(10) DEFAULT NULL, uiParameterSetID int(10) unsigned DEFAULT NULL, PRIMARY KEY (uiProductsIdx))");

  stmt->execute("DROP PROCEDURE IF EXISTS insertProduct");
  stmt->execute("CREATE PROCEDURE insertProduct(IN dwStartTimeIN INT UNSIGNED, IN uiProductsIDIN INT UNSIGNED, IN dwParSetIDIN INT UNSIGNED) BEGIN DECLARE stStartTime TIMESTAMP; SET stStartTime = FROM_UNIXTIME(dwStartTimeIN); INSERT INTO `products` (startTime, uiProductsID, uiParameterSetID) VALUES (stStartTime, uiProductsIDIN, dwParSetIDIN); END");

  pstmt.reset(con->prepareStatement("CALL insertProduct(?, ?, ?)"));
  pstmt->setInt(1, uiStartTime);
  pstmt->setInt(2, uiProductsID);
  pstmt->setInt(3, uiParSetID);

  pstmt->execute();
  logMsg("Procedure called, checking products table contents");

  res.reset(stmt->executeQuery("SELECT uiProductsIdx, startTime, stopTime, uiProductsID, uiParameterSetID FROM products"));
  ASSERT(res->next());


  msg.str("");
  msg << "uiProductsIdx     = " << res->getString("uiProductsIdx") << "\n";
  msg << "startTime         = " << res->getString("startTime") << "\n";
  msg << "stopTime          = " << res->getString("stopTime") << "\n";
  msg << "uiPrpductsID      = " << res->getString("uiProductsID") << "\n";
  msg << "uiParameterSetID  = " << res->getString("uiParameterSetID") << "\n";
  logMsg(msg.str());

  /* SKIP - timezone may trick us ASSERT_EQUALS("2010-11-15 17:16:16", res->getString("startTime")); */
  ASSERT_EQUALS("20", res->getString("uiProductsID"));
  ASSERT_EQUALS("2", res->getString("uiParameterSetID"));

  ASSERT(!res->next());
}


/* Bug#15936764/67325 */
void bugs::expired_pwd()
{
  logMsg("bugs::expired_pwd");
  if (getMySQLVersion(con) < 56006)
  {
    SKIP("The server does not support tested functionality(expired password)");
  }

  stmt->executeUpdate("DROP TABLE IF EXISTS test.ccpp_expired_pwd");

  try
  {
    stmt->executeUpdate("DROP USER ccpp_expired_pwd");
  }
  catch (sql::SQLException &)
  {
    // Catching exception if user did not exist
  }

  stmt->executeUpdate("CREATE USER ccpp_expired_pwd IDENTIFIED BY 'foo'");
  stmt->executeUpdate("GRANT ALL ON test to ccpp_expired_pwd");
  stmt->executeUpdate("ALTER USER ccpp_expired_pwd PASSWORD EXPIRE");

  sql::ConnectOptionsMap opts;

  opts["userName"]=     sql::SQLString("ccpp_expired_pwd");
  opts["password"]=     sql::SQLString("");

  try
  {
    if (getConnection(&opts))
    {
      SKIP("The expired password does not work with anonymous-user accounts.");
    }
  }
  catch (sql::SQLException &e)
  {
    /* If no anonymous user present then continue */
  }

  opts["password"]=     sql::SQLString("foo");

  testsuite::Connection c2;

  /* Seeing error first without OPT_CAN_HANDLE_EXPIRED_PASSWORDS ... */
  try
  {
    c2.reset(getConnection(&opts));
  }
  catch (sql::SQLException &e)
  {
    ASSERT_EQUALS(1862, e.getErrorCode()/*ER_MUST_CHANGE_PASSWORD_LOGIN*/);
  }

  /* ... Now with it */
  opts["OPT_CAN_HANDLE_EXPIRED_PASSWORDS"]= true;

  try
  {
    c2.reset(getConnection(&opts));
  }
  catch (sql::SQLException &e)
  {
    /*
      In case of sql::mysql::mydeCL_CANT_HANDLE_EXP_PWD tests fail - means that in
      the setup where test is run the driver does not support expired password
    */
    ASSERT_EQUALS(1820, e.getErrorCode()/*ER_MUST_CHANGE_PASSWORD*/);
  }

  // Now setting new password and getting fully functional connection
  opts["preInit"]= sql::SQLString("set password= password('bar')");

  // Connect should go thru fine
  try
  {
    c2.reset(getConnection(&opts));
  }
  catch(sql::SQLException &e)
  {
    // We can get here in case of old libmysql library
    ASSERT_EQUALS(sql::mysql::deCL_CANT_HANDLE_EXP_PWD, e.getErrorCode());
    // Wrong libmysql - we can't test anything else as we can't get connection
    return;
  }

  // Trying to connect with new pwd
  opts.erase("preInit");
  opts.erase("OPT_CAN_HANDLE_EXPIRED_PASSWORDS");
  opts["password"]= sql::SQLString("bar");
  opts["CLIENT_MULTI_STATEMENTS"]= true;
  opts["postInit"]= sql::SQLString("create table test.ccpp_expired_pwd(i int);"
                                   "insert into test.ccpp_expired_pwd(i) values(2)");

  c2.reset(getConnection(&opts));

  // postInit is introduced anong with preInit - testing it too
  Statement s2(c2->createStatement());

  /* Checking 2 things - that executeUpdate detects a resultset returning stmt, and that
     connection is usable after that */
  try
  {
    s2->executeUpdate("insert into test.ccpp_expired_pwd(i) values(7);select i from test.ccpp_expired_pwd");
    FAIL("Driver had to throw \"Query returning resultset\" exception!");
  }
  catch (sql::SQLException &)
  {
  }

  res.reset(s2->executeQuery("select i from test.ccpp_expired_pwd"));

  ASSERT(res->next());

  ASSERT_EQUALS(2, res->getInt(1));

  c2->close();
  stmt->executeUpdate("DROP TABLE test.ccpp_expired_pwd");
  stmt->executeUpdate("DROP USER ccpp_expired_pwd");
}


/* Bug#16970753/69492
 * Cannot Connect error when using legacy authentication
 */
void bugs::legacy_auth()
{
  logMsg("bugs::legacy_auth");
  try
  {
    stmt->executeUpdate("DROP USER ccpp_legacy_auth");
  }
  catch (sql::SQLException &)
  {
    // Catching exception if user did not exist
  }

  res.reset(stmt->executeQuery("SELECT @@secure_auth"));
  res->next();
  /* We need to know if we need to set it back*/
  int secure_auth= res->getInt(1);

  if (secure_auth)
  {
    try
    {
      stmt->executeUpdate("SET GLOBAL secure_auth= OFF");
    }
    catch(sql::SQLException &)
    {
      SKIP("For this test user should be able to set global variables.");
    }
  }

  try
  {
    stmt->executeUpdate("CREATE USER ccpp_legacy_auth@'%' IDENTIFIED BY 'foo'");
    stmt->executeUpdate("GRANT ALL ON test to ccpp_legacy_auth@'%'");
  }
  catch(sql::SQLException &)
  {
    SKIP("For this test user should have GRANT privelege");
  }

  /* Simplest way to create user identified with old password on all server versions */
  stmt->executeUpdate("UPDATE mysql.user SET Password=old_password('foo')\
                       WHERE User='ccpp_legacy_auth' AND Host='%'");

  try
  {
    stmt->executeUpdate("UPDATE mysql.user SET Plugin=''\
                        WHERE User='ccpp_legacy_auth' AND Host='%'");
  }
  catch(sql::SQLException &)
  {
    /* Doing nothing - catching for case of old server that does not have Plugin field */
  }

  stmt->executeUpdate("FLUSH PRIVILEGES");
  testsuite::Connection c2;

  sql::ConnectOptionsMap opts;

  opts["useLegacyAuth"]=  false;
  opts["userName"]=       sql::SQLString("ccpp_legacy_auth");
  opts["password"]=       sql::SQLString("foo");
  opts["schema"]=         sql::SQLString("test");

  /* First verifying that we can't connect without the option */
  try
  {
    c2.reset(getConnection(&opts));
  }
  catch (sql::SQLException &e)
  {
    ASSERT_EQUALS(2049, e.getErrorCode() /*CR_SECURE_AUTH*/);
  }

  opts["useLegacyAuth"]= true;
  c2.reset(getConnection(&opts));
  /* If this passed - we are fine */

  c2->close();

  /* Returning secure_auth if needed */
  if (secure_auth)
  {
    stmt->executeUpdate("SET GLOBAL secure_auth= ON");
  }

  stmt->executeUpdate("DROP USER ccpp_legacy_auth");
}


/* Bug #18193771/71605 - The driver does not recognize utf8mb4 charset */
void bugs::bug71606()
{
  logMsg("bugs::bug71606");
  if (getMySQLVersion(con) < 56000)
  {
    SKIP("The server does not support tested functionality(utf8mb4 charset)");
  }

  /* We only loop thru default collations - thus the testcase does not cover all
     possible cases */
  res.reset(stmt->executeQuery("SHOW CHARSET"));

  /* Connection is reset after the testcase finishes - thus we can safely "set names" here */
  Statement stmt2(con->createStatement());
  pstmt.reset(con->prepareStatement("SELECT 'a'"));
  ResultSet res2;
  ResultSetMetaData *rsmd2;

  while (res->next())
  {
    String csname(res->getString(1));
    String query("SET NAMES ");

    query.append(res->getString(1));

    try
    {
      stmt2->executeUpdate(query);
    }
    catch(sql::SQLException &)
    {
      /* Assuming this particular charset charset cannot be set as client charset,
         like atm we can't do that with utf16/32 */
      continue;
    }

    res2.reset(pstmt->executeQuery());
    rsmd2= res2->getMetaData();
    rsmd2->isCaseSensitive(1);
  }
}


void bugs::bug72700()
{
  logMsg("bugs::bug72700");
  ASSERT(stmt->execute("select astext(geomfromtext('point(10 10)'))"));

  try
  {
    res.reset(stmt->getResultSet());
    checkResultSetScrolling(res);
    ResultSetMetaData * meta=res->getMetaData();
    ASSERT_EQUALS(meta->getColumnType(1), 15);
    ASSERT_EQUALS(meta->getColumnTypeName(1), "LONGTEXT");
  }
  catch (::sql::SQLException & /*e*/)
  {
    return; /* Everything is fine */
  }

  stmt->execute("DROP TABLE IF EXISTS bug72700");
  stmt->execute("CREATE TABLE bug72700(valtext longtext)");
  ASSERT(stmt->execute("SELECT valtext FROM bug72700"));
  try
  {
    res.reset(stmt->getResultSet());
    checkResultSetScrolling(res);
    ResultSetMetaData * meta=res->getMetaData();
    ASSERT_EQUALS(meta->getColumnType(1), 15);
    ASSERT_EQUALS(meta->getColumnTypeName(1), "TEXT");
  }
  catch (::sql::SQLException & /*e*/)
  {
    return; /* Everything is fine */
  }

  stmt->execute("DROP TABLE IF EXISTS bug72700");
}


void bugs::bug66871()
{
  sql::Connection *con;
  sql::Statement *stmt;
  sql::ResultSet *res;

  logMsg("bugs::bug66871");
  try
  {
    con = getConnection(NULL);
    stmt = con->createStatement();
    ASSERT(stmt->execute("select 1"));
    res= stmt->getResultSet();
    ASSERT(res->next());
    ASSERT_EQUALS(res->getInt(1), 1);

    con->close();
    delete con;

    ASSERT(stmt->execute("select 2"));
    res= stmt->getResultSet();
    ASSERT(res->next());
    ASSERT_EQUALS(res->getInt(1), 2);

  }
  catch (::sql::SQLException & /*e*/)
  {
    delete res;
    delete stmt;

    return; /* Everything is fine */
  }

  delete res;
  delete stmt;

  FAIL("Exception wasn't thrown by execute");
}

/*
  Segementation fault in row retrieval when defaultstatementresulttype=
  forward_only and row position is after last row
*/
void bugs::bug20085944()
{
  logMsg("bugs::bug20085944");
  try
  {
    sql::ConnectOptionsMap connection_properties;

    connection_properties["hostName"]=url;
    connection_properties["userName"]=user;
    connection_properties["password"]=passwd;
    connection_properties["defaultStatementResultType"]=sql::ResultSet::TYPE_FORWARD_ONLY;

    created_objects.clear();
    con.reset(driver->connect(connection_properties));
    con->setSchema(db);
    stmt.reset(con->createStatement());
    stmt->execute("DROP TABLE IF EXISTS bug20085944");
    stmt->execute("CREATE TABLE bug20085944(id INT)");
    stmt->execute("INSERT INTO bug20085944 VALUES(1),(2),(3)");
    res.reset(stmt->executeQuery("SELECT * FROM bug20085944"));

    for (int i=1; i <= 3; ++i) {
      ASSERT(res->next());
      ASSERT_EQUALS(i, res->getInt(1));
    }

    ASSERT(!res->next());
    res->getInt(1);
  }
  catch (::sql::SQLException & /*e*/)
  {
    return; /* Everything is fine */
  }

  FAIL("Exception wasn't thrown by getInt() in bug20085944()");
}


void bugs::bug19938873_pstmt()
{
  logMsg("bugs::bug19938873_pstmt");
  try
  {
    pstmt.reset(con->prepareStatement("SELECT NULL"));
    res.reset(pstmt->executeQuery());
    ASSERT(res->next());
    res->wasNull();
  }
  catch (sql::SQLException & /*e*/)
  {
    return; /* Everything is fine */
  }

  FAIL("Exception wasn't thrown by wasNull()");
}


void bugs::bug19938873_stmt()
{
  logMsg("bugs::bug19938873_stmt");
  try
  {
    stmt.reset(con->createStatement());
    res.reset(stmt->executeQuery("SELECT NULL"));
    ASSERT(res->next());
    res->wasNull();
  }
  catch (sql::SQLException & /*e*/)
  {
    return; /* Everything is fine */
  }

  FAIL("Exception wasn't thrown by wasNull()");
}


void bugs::bug68523()
{
  try
  {
    stmt->execute("DROP TABLE IF EXISTS bug68523");
    stmt->execute("CREATE TABLE bug68523(ts TIMESTAMP(6))");
    stmt->execute("INSERT INTO bug68523(ts) values('2015-01-20 16:14:36.709649')");

    pstmt.reset(con->prepareStatement("SELECT ts, TIME(ts) from bug68523"));
    res.reset(pstmt->executeQuery());
    ASSERT(res->next());

    ASSERT_EQUALS(res->getString(1), "2015-01-20 16:14:36.709649");
    ASSERT_EQUALS(res->getString(2), "16:14:36.709649");

    stmt->execute("DROP TABLE IF EXISTS bug68523");
  }
  catch (sql::SQLException &e)
  {
    logErr(e.what());
    logErr("SQLState: " + std::string(e.getSQLState()));
    fail(e.what(), __FILE__, __LINE__);
  }

}


void bugs::bug66235()
{
  logMsg("bug::bug66235");
  try
  {
    stmt.reset(con->createStatement());
    stmt->execute("DROP TABLE IF EXISTS test");
    stmt->execute("CREATE TABLE test(id BIT(3))");
    stmt->execute("INSERT INTO test(id) VALUES(0b1), (0b10), (0b1), (0b1), (0b10), (0b111);");

    res.reset(stmt->executeQuery("SELECT MAX(id), MIN(id) FROM test"));
    while (res->next())
    {
      ASSERT_EQUALS(res->getString(1), "7");
      ASSERT_EQUALS(res->getInt(1), 7);

      ASSERT_EQUALS(res->getString(2), "1");
      ASSERT_EQUALS(res->getInt(2), 1);
    }

    res.reset(stmt->executeQuery("SELECT id FROM test limit 1"));
    while (res->next())
    {
      ASSERT_EQUALS(res->getString(1), "1");
      ASSERT_EQUALS(res->getInt(1), 1);
    }

    stmt->execute("DROP TABLE IF EXISTS test");
  }
  catch (sql::SQLException &e)
  {
    logErr(e.what());
    logErr("SQLState: " + std::string(e.getSQLState()));
    fail(e.what(), __FILE__, __LINE__);
  }
}

void bugs::bug21066575()
{
  logMsg("bug::bug21066575");
  try
  {


    stmt.reset(con->createStatement());
    stmt->execute("DROP TABLE IF EXISTS bug21066575");
    stmt->execute("CREATE TABLE bug21066575(txt text)");
    stmt->execute("INSERT INTO bug21066575(txt) VALUES('abc')");

    pstmt.reset(con->prepareStatement("select * from bug21066575"));

    res.reset();

    for (int i = 0; i < 10; ++i)
    {
      res.reset(pstmt->executeQuery());
      res->next();
      ASSERT_EQUALS("abc", res->getString(1));
    }

    stmt->execute("DROP TABLE IF EXISTS bug21066575_2");

    stmt->execute("CREATE TABLE `bug21066575_2` (\
                  `f1` longtext,\
                  `id` int(11) NOT NULL AUTO_INCREMENT,\
                  PRIMARY KEY (`id`)\
                  ) ENGINE=MyISAM AUTO_INCREMENT=3 DEFAULT CHARSET=latin1");

    stmt->execute("insert into bug21066575_2(f1) values(repeat('f',1024000)),"
                  "(repeat('f',1024000)),"
                  "(repeat('f',1024000)),"
                  "(repeat('f',1024000))");


    for(int i= 0; i < 100; i++)
    {
      pstmt.reset(con->prepareStatement("select id, f1 from bug21066575_2"));

      //pstmt->setInt(1, i);
      res.reset(pstmt->executeQuery());
      while (res->next()) {
        std::stringstream ss;
        ss << "id = " << res->getInt(1);
        ss << std::endl;
        ss << "f1 = " << res->getString(2);
        logMsg(ss.str().c_str());
      }
      //Detect if process frees ResultSet resources.
      res.reset();
    }

  }
  catch (sql::SQLException &e)
  {
    logErr(e.what());
    logErr("SQLState: " + std::string(e.getSQLState()));
    fail(e.what(), __FILE__, __LINE__);
  }
}

void bugs::bug14520822()
{

  logMsg("bug::bug14520822");
  try
  {

    stmt.reset(con->createStatement());
    stmt->execute("DROP TABLE IF EXISTS bug14520822");
    stmt->execute("CREATE TABLE bug14520822(b BIT NOT NULL DEFAULT 0)");
    stmt->execute("INSERT INTO bug14520822(b) VALUES(0b0), (0b1)");

    res.reset(stmt->executeQuery("select min(b) ,max(b) from bug14520822"));
    res->next();
    ASSERT_EQUALS("0", res->getString(1));
    ASSERT_EQUALS("1", res->getString(2));
    ASSERT_EQUALS(false, res->getBoolean(1));
    ASSERT_EQUALS(true, res->getBoolean(2));
    ASSERT_EQUALS((int64_t)0, res->getInt64(1));
    ASSERT_EQUALS((int64_t)1, res->getInt64(2));

    pstmt.reset(con->prepareStatement("select min(b) ,max(b) from bug14520822"));
    res.reset(pstmt->executeQuery());
    res->next();
    ASSERT_EQUALS("0", res->getString(1));
    ASSERT_EQUALS("1", res->getString(2));
    ASSERT_EQUALS(false, res->getBoolean(1));
    ASSERT_EQUALS(true, res->getBoolean(2));
    ASSERT_EQUALS((int64_t)0, res->getInt64(1));
    ASSERT_EQUALS((int64_t)1, res->getInt64(2));

  }
  catch (sql::SQLException &e)
  {
    logErr(e.what());
    logErr("SQLState: " + std::string(e.getSQLState()));
    fail(e.what(), __FILE__, __LINE__);
  }
}

void bugs::bug21053335()
{

  logMsg("bugs::bug21053335");
  try
  {

    stmt->execute("DROP TABLE IF EXISTS bug21053335");
    stmt->execute("CREATE TABLE bug21053335(c char(10))");
    stmt->execute("INSERT INTO bug21053335 values(NULL), (1)");
    res.reset(stmt->executeQuery("select c from bug21053335"));
    res->next();
    std::stringstream log;
    log << "Data :" <<res->getString(1);
    log<<"\nrs->wasNull(1) : "<<res->wasNull()<<std::endl;
    logMsg(log.str().c_str());

    ASSERT(res->wasNull());

    res->next();

    try{
      ASSERT(res->wasNull());
      FAIL("Exception was not thrown by wasNull()");
    }
    catch (sql::SQLException & e)
    {
      // Everything is ok
    }

    log.flush();
    log << "Data :" <<res->getString(1);
    log<<"\nrs->wasNull(1) : "<<res->wasNull()<<std::endl;
    logMsg(log.str().c_str());

    ASSERT(!res->wasNull());


  }

  catch (sql::SQLException &e)
  {
    FAIL("Exception thrown by wasNull()");
    throw;
  }

}


void bugs::bug17218692()
{
  logMsg("bugs::bug17218692");
  try
  {

    stmt->execute("DROP TABLE IF EXISTS bug17218692");
    stmt->execute("CREATE TABLE bug17218692(c1  time(6))");
    stmt->execute("INSERT INTO bug17218692 VALUES('-838:59:58.987657')");

    res.reset(stmt->executeQuery("select * from bug17218692"));
    res->next();

    std::stringstream log;
    log<<"["<<res->getString(1)<<"]";

    ASSERT_EQUALS(log.str(), "[-838:59:58.987657]");

    pstmt.reset(con->prepareStatement("select * from bug17218692 "));
    res.reset(pstmt->executeQuery());
    res->next();

    std::stringstream log2;
    log2 << "["<<res->getString(1)<<"]";
    ASSERT_EQUALS(log.str(), log2.str());

  }
  catch (sql::SQLException & e)
  {
    FAIL("Exception thrown");
    throw;
  }


}

void bugs::bug21067193()
{
  logMsg("bugs::bug21067193");
  try
  {


    stmt->execute("DROP TABLE IF EXISTS bug21067193");
    stmt->execute("create table bug21067193(id int)");
    stmt->execute("insert into bug21067193 values(1),(2),(3)");

    res.reset((stmt->setResultSetType(sql::ResultSet::TYPE_SCROLL_SENSITIVE)->executeQuery("select * from bug21067193")));

    ASSERT_EQUALS(true, res->absolute(2));
    ASSERT_EQUALS(2, res->getInt(1));

    ASSERT_EQUALS(true, res->absolute(-1));
    ASSERT_EQUALS(3, res->getInt(1));

    ASSERT_EQUALS(false, res->absolute(std::numeric_limits<int>::min())); //Invalid position, Returns FALSE

  }
  catch (sql::SQLException & e)
  {
//	Error....
      throw;
  }


}

} /* namespace regression */
} /* namespace testsuite */
