Files
mariadb-connector-cpp/test/unit/classes/connectionmetadata.cpp
Lawrin Novitsky 18b2d22c51 CONCPP-110 Fixed, that could confuse the compiler.
Contains also libmariadb submodule update to the latest release and some
tests improvements/fixes.
2022-11-16 15:37:46 +01:00

2560 lines
93 KiB
C++

/*
* Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
* 2020, 2022 MariaDB Corporation AB
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2.0, as
* published by the Free Software Foundation.
*
* This program is also distributed with certain software (including
* but not limited to OpenSSL) that is licensed under separate terms,
* as designated in a particular file or component or in included license
* documentation. The authors of MySQL hereby grant you an
* additional permission to link the program and your derivative works
* with the separately licensed software that they have included with
* MySQL.
*
* Without limiting anything contained in the foregoing, this file,
* which is part of MySQL Connector/C++, is also subject to the
* Universal FOSS Exception, version 1.0, a copy of which can be found at
* http://oss.oracle.com/licenses/universal-foss-exception.
*
* 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, version 2.0, 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 "conncpp.hpp"
#include "connectionmetadata.h"
#include <sstream>
#include <stdlib.h>
namespace testsuite
{
namespace classes
{
void connectionmetadata::getSchemata()
{
logMsg("connectionmetadata::getSchemata() - MySQL_ConnectionMetaData::getSchemata");
SKIP("Not supported methods");
bool schema_found=false;
std::stringstream msg;
try
{
DatabaseMetaData dbmeta(con->getMetaData());
/*ResultSet resdbm1(dbmeta->getSchemata());
checkResultSetScrolling(resdbm1);
ResultSet resdbm2(dbmeta->getSchemaObjects(con->getCatalog(), "", "schema"));
logMsg("... checking if getSchemata() and getSchemaObjects() report the same schematas");
resdbm1->beforeFirst();
while (resdbm1->next())
{
schema_found=false;
resdbm2->beforeFirst();
while (resdbm2->next())
if (resdbm2->getString("SCHEMA") == resdbm1->getString(1))
{
schema_found=true;
break;
}
if (!schema_found)
FAIL("Schemata lists differ");
msg.str("");
msg << "... OK " << resdbm1->getString(1) << " = " << resdbm2->getString("SCHEMA");
logMsg(msg.str());
}*/
}
catch (sql::SQLException &e)
{
logErr(e.what());
logErr("SQLState: " + std::string(e.getSQLState()));
fail(e.what(), __FILE__, __LINE__);
}
}
void connectionmetadata::getSchemaObjects()
{
logMsg("connectionmetadata::getSchemaObject() - MySQL_ConnectionMetaData::getSchemaObjects");
try
{
DatabaseMetaData dbmeta(con->getMetaData());
ResultSet resdbm1(dbmeta->getSchemaObjects());
checkResultSetScrolling(resdbm1);
ResultSet resdbm2;
while (resdbm1->next())
{
resdbm2.reset(dbmeta->getSchemaObjects(con->getCatalog(), "", resdbm1->getString(1)));
checkResultSetScrolling(resdbm2);
}
}
catch (sql::MethodNotImplementedException& /*e*/)
{
SKIP("Method has not been implemented");
}
catch (sql::SQLException &e)
{
logErr(e.what());
logErr("SQLState: " + std::string(e.getSQLState()));
fail(e.what(), __FILE__, __LINE__);
}
}
void connectionmetadata::getAttributes()
{
logMsg("connectionmetadata::getAttributes() - MySQL_ConnectionMetaData::getAttributes");
unsigned int i;
std::vector<udtattribute>::iterator it;
std::stringstream msg;
try
{
DatabaseMetaData dbmeta(con->getMetaData());
res.reset(dbmeta->getAttributes(con->getCatalog(), con->getSchema(), "", ""));
checkResultSetScrolling(res);
ResultSetMetaData resmeta(res->getMetaData());
it=attributes.begin();
for (i=1; i <= resmeta->getColumnCount(); i++)
{
if (it == attributes.end())
FAIL("There are more columns than expected");
ASSERT_EQUALS(it->name, resmeta->getColumnName(i));
msg.str("");
msg << "... OK found column " << it->name;
logMsg(msg.str());
it++;
}
if (it != attributes.end())
FAIL("There are less columns than expected");
res.reset(dbmeta->getAttributes("ABC", "DEF", "GHI", "JKL"));
ASSERT(!res->next());
}
catch (sql::SQLException &e)
{
logErr(e.what());
logErr("SQLState: " + std::string(e.getSQLState()));
fail(e.what(), __FILE__, __LINE__);
}
}
void connectionmetadata::getBestRowIdentifier()
{
logMsg("connectionmetadata::getBestRowIdentifier()");
std::vector<columndefinition>::iterator it;
std::stringstream msg;
bool got_warning= false;
try
{
DatabaseMetaData dbmeta(con->getMetaData());
stmt.reset(con->createStatement());
logMsg("... looping over all kinds of column types");
for (it= columns.begin(); it != columns.end(); it++)
{
stmt->execute("DROP TABLE IF EXISTS test");
msg.str("");
msg << "CREATE TABLE test(id " << it->sqldef << ", PRIMARY KEY(id))";
try
{
stmt->execute(msg.str());
}
catch (sql::SQLException &)
{
msg.str("");
msg << "... skipping " << it->sqldef;
logMsg(msg.str());
continue;
}
res.reset(dbmeta->getBestRowIdentifier(con->getCatalog(), con->getSchema(), "test", 0, false));
checkResultSetScrolling(res);
ASSERT_EQUALS(true, res->next());
ASSERT_EQUALS(sql::DatabaseMetaData::bestRowSession, res->getInt(1));
ASSERT_EQUALS(res->getInt(1), res->getInt("SCOPE"));
ASSERT_EQUALS("id", res->getString(2));
ASSERT_EQUALS(res->getString(2), res->getString("COLUMN_NAME"));
if (it->ctype != res->getInt(3))
{
msg.str("");
msg << "... \t\tWARNING - check DATA_TYPE for " << it->sqldef;
msg << " - expecting type " << it->ctype << " got " << res->getInt(3);
logMsg(msg.str());
ResultSet cres(stmt->executeQuery("SHOW CREATE TABLE test"));
cres->next();
logMsg(cres->getString(2).c_str());
got_warning=true;
}
// TODO - ASSERT_EQUALS(it->ctype, res->getInt(3));
ASSERT_EQUALS(res->getInt(3), res->getInt("DATA_TYPE"));
if (res->getString(4).caseCompare(it->name) != 0)
{
msg.str("");
msg << "... \t\tWARNING - check DATA_TYPE for " << it->sqldef;
msg << " - expecting type name " << it->name << " got " << res->getString(4);
logMsg(msg.str());
got_warning=true;
}
ASSERT_EQUALS(res->getString(4), res->getString("TYPE_NAME"));
if (it->precision != res->getUInt64(5))
{
msg.str("");
msg << "... \t\tWARNING - check COLUMN_SIZE for " << it->sqldef;
msg << " - expecting precision " << it->precision << " got " << res->getInt(5);
logMsg(msg.str());
got_warning=true;
}
ASSERT_EQUALS(res->getInt(5), res->getInt("COLUMN_SIZE"));
ASSERT_EQUALS(0, res->getInt(6));
ASSERT_EQUALS(res->getInt(6), res->getInt("BUFFER_LENGTH"));
if (it->decimal_digits != res->getInt(7))
{
msg.str("");
msg << "... \t\tWARNING - check DECIMAL_DIGITS for " << it->sqldef;
msg << " - expecting decimal digits = " << it->decimal_digits << " got " << res->getInt(7);
logMsg(msg.str());
got_warning=true;
}
ASSERT_EQUALS(res->getInt(7), res->getInt("DECIMAL_DIGITS"));
ASSERT_EQUALS(sql::DatabaseMetaData::bestRowNotPseudo, res->getInt(8));
ASSERT_EQUALS(res->getInt(8), res->getInt("PSEUDO_COLUMN"));
stmt->execute("DROP TABLE test");
}
if (got_warning)
{
logMsg("Were was Warnings!");
}
stmt->execute("DROP TABLE IF EXISTS test");
// TODO - stmt->execute("CREATE TABLE test(col1 INT NOT NULL, col2 INT NOT NULL, PRIMARY KEY(col1, col2))");
res.reset(dbmeta->getBestRowIdentifier(con->getCatalog(), con->getSchema(), "test", 0, false));
ASSERT(!res->next());
}
catch (sql::SQLException &e)
{
logErr(e.what());
logErr("SQLState: " + std::string(e.getSQLState()));
fail(e.what(), __FILE__, __LINE__);
}
}
void connectionmetadata::getColumnPrivileges()
{
logMsg("connectionmetadata::getColumnPrivileges() - MySQL_ConnectionMetaData::getColumnPrivileges");
int rows=0;
bool got_warning=false;
std::stringstream msg;
DatabaseMetaData dbmeta;
sql::SQLString userLocation("");
try
{
dbmeta.reset(con->getMetaData());
stmt.reset(con->createStatement());
stmt->execute("DROP TABLE IF EXISTS test_getcolpriv");
stmt->execute("CREATE TABLE test_getcolpriv(col1 INT, col2 INT)");
}
catch (sql::SQLException & e)
{
logErr(e.what());
logErr("SQLState: " + std::string(e.getSQLState()));
fail(e.what(), __FILE__, __LINE__);
}
try
{
stmt->execute("GRANT SELECT (col1,col2) ON test_getcolpriv TO '" + this->user + "'" + userLocation);
stmt->execute("GRANT INSERT (col1) ON test_getcolpriv TO '" + this->user + "'" + userLocation);
}
catch (sql::SQLException & e)
{
logErr(e.what());
logErr("SQLState: " + std::string(e.getSQLState()));
try
{
userLocation= "@'localhost'";
stmt->execute("GRANT SELECT (col1,col2) ON test_getcolpriv TO '" + this->user + "'" + userLocation);
stmt->execute("GRANT INSERT (col1) ON test_getcolpriv TO '" + this->user + "'" + userLocation);
}
catch (sql::SQLException & e)
{
sql::SQLString failMsg("User: " + this->user + " [" + e.getSQLState() + "] ");
logErr(e.what());
logErr("SQLState: " + e.getSQLState());
failMsg.append(e.what());
fail(failMsg.c_str(), __FILE__, __LINE__);
}
}
try
{
res.reset(dbmeta->getColumnPrivileges(con->getCatalog(), con->getSchema(), "test_getcolpriv", "id"));
ASSERT_EQUALS(false, res->next());
}
catch (sql::SQLException & e)
{
logErr(e.what());
logErr("SQLState: " + std::string(e.getSQLState()));
fail(e.what(), __FILE__, __LINE__);
}
try
{
res.reset(dbmeta->getColumnPrivileges(con->getCatalog(), con->getSchema(), "test_getcolpriv", "col1"));
checkResultSetScrolling(res);
rows=0;
while (res->next())
{
rows++;
if (con->getCatalog() != "" && res->getString(1) != "" && con->getCatalog() != res->getString(1))
{
got_warning=true;
msg.str("");
msg << "... TABLE_CAT: expecting '" << con->getCatalog() << "' got ";
msg << "'" << res->getString(1) << "'";
logMsg(msg.str());
}
ASSERT_EQUALS(res->getString(1), res->getString("TABLE_CAT"));
ASSERT_EQUALS(con->getSchema(), res->getString(2));
ASSERT_EQUALS(res->getString(2), res->getString("TABLE_SCHEM"));
ASSERT_EQUALS("test_getcolpriv", res->getString(3));
ASSERT_EQUALS(res->getString(3), res->getString("TABLE_NAME"));
ASSERT_EQUALS(res->getString(4), res->getString("COLUMN_NAME"));
ASSERT_EQUALS("", res->getString(5));
ASSERT_EQUALS(res->getString(5), res->getString("GRANTOR"));
ASSERT_EQUALS(res->getString(6), res->getString("GRANTEE"));
ASSERT_EQUALS(res->getString(7), res->getString("PRIVILEGE"));
ASSERT_EQUALS(res->getString(8), res->getString("IS_GRANTABLE"));
if (("NO" != res->getString(8)) && ("YES" != res->getString(8)) && ("" != res->getString(8)))
{
// Let's be optimistic that the column does not hold this exact value...
ASSERT_EQUALS("Any of 'YES', 'NO' and empty string ''", res->getString(8));
}
}
ASSERT_GT(2, rows);
if (got_warning)
{
TODO("See --verbose warnings");
}
}
catch (sql::SQLException & e)
{
logErr(e.what());
logErr("SQLState: " + std::string(e.getSQLState()));
fail(e.what(), __FILE__, __LINE__);
}
try
{
res.reset(dbmeta->getColumnPrivileges(con->getCatalog(), con->getSchema(), "test_getcolpriv", "col2"));
ASSERT_EQUALS(true, res->next());
ASSERT_EQUALS("col2", res->getString("COLUMN_NAME"));
ASSERT_EQUALS(res->getString(4), res->getString("COLUMN_NAME"));
}
catch (sql::SQLException & e)
{
logErr(e.what());
logErr("SQLState: " + std::string(e.getSQLState()));
fail(e.what(), __FILE__, __LINE__);
}
try
{
stmt->execute("REVOKE SELECT (col1,col2) ON test_getcolpriv FROM '" + this->user + "'" + userLocation);
stmt->execute("REVOKE INSERT (col1) ON test_getcolpriv FROM '" + this->user + "'" + userLocation);
stmt->execute("DROP TABLE IF EXISTS test_getcolpriv");
res.reset(dbmeta->getColumnPrivileges(con->getCatalog(), con->getSchema(), "test_getcolpriv", "col2"));
ASSERT(!res->next());
}
catch (sql::SQLException &e)
{
logErr(e.what());
logErr("SQLState: " + std::string(e.getSQLState()));
fail(e.what(), __FILE__, __LINE__);
}
if (got_warning)
{
FAIL("TODO - See --verbose warnings");
}
}
void connectionmetadata::getColumns()
{
logMsg("connectionmetadata::getColumn() - MySQL_ConnectionMetaData::getColumns");
if (getServerVersion(con) < 800000)
{
SKIP("Due to changes on the VARBINARY, this test is disabled.");
return;
}
std::vector<columndefinition>::iterator it;
std::stringstream msg;
bool got_warning=false;
bool got_todo_warning=false;
try
{
DatabaseMetaData dbmeta(con->getMetaData());
stmt.reset(con->createStatement());
bool isVer6=dbmeta->getDatabaseMajorVersion() == 6;
int32_t serverVersion = getServerVersion(con);
logMsg("... looping over all kinds of column types");
for (it=columns.begin(); it != columns.end(); it++)
{
stmt->execute("DROP TABLE IF EXISTS test");
msg.str("");
msg << "CREATE TABLE test(dummy TIMESTAMP, id " << it->sqldef << ")";
try
{
stmt->execute(msg.str());
msg.str("");
msg << "... testing " << it->sqldef;
logMsg(msg.str());
}
catch (sql::SQLException &)
{
msg.str("");
msg << "... skipping " << it->sqldef;
logMsg(msg.str());
continue;
}
res.reset(dbmeta->getColumns(con->getCatalog(), con->getSchema(), "test", "id"));
checkResultSetScrolling(res);
ASSERT_EQUALS(true, res->next());
if (con->getCatalog() != "" && res->getString(1) != "" && con->getCatalog() != res->getString("TABLE_CAT"))
{
got_todo_warning=true;
msg.str("");
msg << "...\t\tWARNING - expecting TABLE_CAT = '" << con->getCatalog() << "'";
msg << " got '" << res->getString("TABLE_CAT") << "'";
logMsg(msg.str());
}
ASSERT_EQUALS(res->getString(1), res->getString("TABLE_CAT"));
ASSERT_EQUALS(con->getSchema(), res->getString("TABLE_SCHEM"));
ASSERT_EQUALS(res->getString(2), res->getString("TABLE_SCHEM"));
ASSERT_EQUALS("test", res->getString("TABLE_NAME"));
ASSERT_EQUALS(res->getString(3), res->getString("TABLE_NAME"));
ASSERT_EQUALS("id", res->getString("COLUMN_NAME"));
ASSERT_EQUALS(res->getString(4), res->getString("COLUMN_NAME"));
if (it->ctype != res->getInt("DATA_TYPE"))
{
msg.str("");
msg << "... \t\tWARNING - check DATA_TYPE for " << it->sqldef;
msg << " - expecting type " << it->ctype << " got " << res->getInt("DATA_TYPE");
logMsg(msg.str());
got_warning=true;
}
// ASSERT_EQUALS(it->ctype, res->getInt("DATA_TYPE"));
ASSERT_EQUALS(res->getInt(5), res->getInt("DATA_TYPE"));
if (it->name != res->getString("TYPE_NAME"))
{
msg.str("");
msg << "... \t\tWARNING - check TYPE_NAME for " << it->sqldef;
msg << " - expecting type " << it->name << " got " << res->getString("TYPE_NAME");
logMsg(msg.str());
got_warning=true;
}
// ASSERT_EQUALS(it->name, res->getString("TYPE_NAME"));
ASSERT_EQUALS(res->getString(6), res->getString("TYPE_NAME"));
if (it->precision != res->getUInt64(7))
{
msg.str("");
msg << "... \t\tWARNING - check COLUMN_SIZE for " << it->sqldef;
msg << " - expecting pecision " << it->precision << " got " << res->getUInt64(7);
logMsg(msg.str());
got_warning=true;
}
ASSERT_EQUALS(res->getUInt(7), res->getUInt("COLUMN_SIZE"));
ASSERT_EQUALS(65535, res->getInt(8));
ASSERT_EQUALS(res->getInt(8), res->getInt("BUFFER_LENGTH"));
ASSERT_EQUALS(it->decimal_digits, res->getInt(9));
ASSERT_EQUALS(res->getInt(9), res->getInt("DECIMAL_DIGITS"));
ASSERT_EQUALS(it->num_prec_radix, res->getInt(10));
ASSERT_EQUALS(res->getInt(10), res->getInt("NUM_PREC_RADIX"));
if (it->nullable != res->getInt(11))
{
msg.str("");
msg << "... \t\tWARNING - check NULLABLE for " << it->sqldef;
msg << " - expecting nullable = " << it->nullable << " got " << res->getInt(11);
msg << " columnNoNull = " << sql::DatabaseMetaData::columnNoNulls << ", ";
msg << " columnNullable = " << sql::DatabaseMetaData::columnNullable << ", ";
msg << " columnNullableUnknown = " << sql::DatabaseMetaData::columnNullableUnknown;
logMsg(msg.str());
got_warning=true;
}
ASSERT_EQUALS(it->nullable, res->getInt(11));
ASSERT_EQUALS(res->getInt(11), res->getInt("NULLABLE"));
ASSERT_EQUALS(it->remarks, res->getString(12));
ASSERT_EQUALS(res->getString(12), res->getString("REMARKS"));
if(it->column_def != res->getString(13))
{
msg.str("");
msg << "... \t\tWARNING - check COLUMN_def for " << it->sqldef;
msg << " - expecting COLUMN_def = " << it->column_def << " got " << res->getString(13);
logMsg(msg.str());
got_warning=true;
}
//res->isNull(13)
/* Looks like 10.1 returns '' where we expect NULL, and there are also other problems with it. Thus, skipping this check altogether on 10.1*/
if ((std::getenv("srv") != nullptr && (strcmp(std::getenv("srv"), "mysql") == 0 && serverVersion < 800000))
|| serverVersion > 1001999)
{
ASSERT_EQUALS(it->column_def, res->getString(13));
}
ASSERT_EQUALS(res->getString(13), res->getString("COLUMN_DEF"));
ASSERT_EQUALS(res->getInt(14), res->getInt("SQL_DATA_TYPE"));
ASSERT_EQUALS(res->getInt(15), res->getInt("SQL_DATETIME_SUB"));
if (it->char_octet_length != 0 && (it->ctype == sql::DataType::CHAR || it->ctype == sql::DataType::VARCHAR))
{
size_t expected_len=it->char_octet_length;
if ((it->ctype == sql::DataType::CHAR || it->ctype == sql::DataType::VARCHAR) &&
isVer6 &&
it->sqldef.find("TINYTEXT") == std::string::npos &&
(it->sqldef.find("utf8") != std::string::npos || it->sqldef.find("NATIONAL") != std::string::npos))
{
expected_len=(expected_len / 3)*4;
}
if (res->getUInt64(16) != expected_len)
{
msg.str("");
msg << "... \t\tWARNING - check CHAR_OCTET_LENGTH for " << it->sqldef;
msg << " - expecting char_octet_length " << it->char_octet_length << " got " << res->getUInt64(16);
logMsg(msg.str());
got_warning=true;
}
}
ASSERT_EQUALS(res->getUInt64(16), res->getUInt64("CHAR_OCTET_LENGTH"));
ASSERT_EQUALS(2, res->getInt(17));
ASSERT_EQUALS(res->getInt(17), res->getInt("ORDINAL_POSITION"));
if (((it->nullable == sql::DatabaseMetaData::columnNoNulls) && (res->getString(18) != "NO")) ||
((it->nullable == sql::DatabaseMetaData::columnNullable) && (res->getString(18) != "YES")) ||
((it->nullable == sql::DatabaseMetaData::columnNullableUnknown) && (res->getString(18) != "")))
{
msg.str("");
msg << "... \t\tWARNING - check IS_NULLABLE for " << it->sqldef;
msg << " - expecting nullable = " << it->nullable << " got is_nullable = '" << res->getInt(18) << "'";
logMsg(msg.str());
got_warning=true;
}
ASSERT_EQUALS(res->getString(18), res->getString("IS_NULLABLE"));
ASSERT_EQUALS("", res->getString(19));
ASSERT_EQUALS(res->getString(19), res->getString("SCOPE_CATALOG"));
ASSERT_EQUALS("", res->getString(20));
ASSERT_EQUALS(res->getString(20), res->getString("SCOPE_SCHEMA"));
ASSERT_EQUALS("", res->getString(21));
ASSERT_EQUALS(res->getString(21), res->getString("SCOPE_TABLE"));
ASSERT_EQUALS("", res->getString(22));
ASSERT_EQUALS(res->getString(22), res->getString("SOURCE_DATA_TYPE"));
ASSERT_EQUALS(it->is_autoincrement, res->getString(23));
ASSERT_EQUALS(res->getString(23), res->getString("IS_AUTOINCREMENT"));
stmt->execute("DROP TABLE IF EXISTS test");
}
if (got_warning)
logMsg("See --verbose warnings!");//FAIL
if (got_todo_warning)
{
TODO("See --verbose warnings!");
FAIL("TODO - see --verbose warnings");
}
try {
bool input_value=true;
bool output_value=false;
void * input;
void * output;
stmt->execute("CREATE TABLE test(id INT,val VARCHAR(20))");
input=(static_cast<bool *> (&input_value));
output=(static_cast<bool *> (&output_value));
con->setClientOption("metadataUseInfoSchema", input);
con->getClientOption("metadataUseInfoSchema", output);
ASSERT_EQUALS(input_value, output_value);
dbmeta.reset(con->getMetaData());
res.reset(dbmeta->getColumns(con->getCatalog(), "", "test", "%"));
ASSERT(res->rowsCount() == 2);
input_value=false;
output_value=true;
con->setClientOption("metadataUseInfoSchema", input);
con->getClientOption("metadataUseInfoSchema", output);
ASSERT_EQUALS(input_value, output_value);
dbmeta.reset(con->getMetaData());
res.reset(dbmeta->getColumns(con->getCatalog(), "", "test", "%"));
ASSERT(res->rowsCount() == 2);
}
catch (sql::SQLFeatureNotImplementedException & e)
{
logMsg(e.what());
}
catch (sql::SQLException &)
{
FAIL("getColumns() does not work properly for metadataUseInfoSchema");
}
stmt->execute("DROP TABLE IF EXISTS test");
res.reset(dbmeta->getColumns(con->getCatalog(), con->getSchema(), "test", "id"));
ASSERT(!res->next());
}
catch (sql::SQLException &e)
{
logErr(e.what());
logErr("SQLState: " + std::string(e.getSQLState()));
fail(e.what(), __FILE__, __LINE__);
}
}
void connectionmetadata::getConnection()
{
logMsg("connectionmetadata::getConnection() - MySQL_ConnectionMetaData::getConnection");
sql::Connection *same_con;
try
{
stmt.reset(con->createStatement());
stmt->execute("SET @this_is_my_connection_id=101");
DatabaseMetaData dbmeta(con->getMetaData());
same_con= dbmeta->getConnection();
stmt.reset(same_con->createStatement());
res.reset(stmt->executeQuery("SELECT @this_is_my_connection_id AS _connection_id"));
ASSERT(res->next());
ASSERT_EQUALS(101, res->getInt("_connection_id"));
ASSERT_EQUALS(res->getInt(1), res->getInt("_connection_id"));
}
catch (sql::SQLException &e)
{
logErr(e.what());
logErr("SQLState: " + std::string(e.getSQLState()));
fail(e.what(), __FILE__, __LINE__);
}
}
void connectionmetadata::getDatabaseVersions()
{
logMsg("connectionmetadata::getDatabaseVersions() - MySQL_ConnectionMetaData::getDatabase[Minor|Major|Patch]Version()");
std::stringstream prodversion;
try
{
DatabaseMetaData dbmeta(con->getMetaData());
ASSERT_GT(5, dbmeta->getDatabaseMajorVersion());
ASSERT_LT(10, dbmeta->getDatabaseMajorVersion());
ASSERT_LT(100, dbmeta->getDatabaseMinorVersion());
ASSERT_LT(100, dbmeta->getDatabasePatchVersion());
//ASSERT_EQUALS("MariaDB", dbmeta->getDatabaseProductName());
prodversion.str("");
prodversion << dbmeta->getDatabaseMajorVersion() << "." << dbmeta->getDatabaseMinorVersion();
prodversion << "." << dbmeta->getDatabasePatchVersion();
if (prodversion.str().length() < dbmeta->getDatabaseProductVersion().length())
{
// Check only left prefix, database could have "-alpha" or something in its product versin
ASSERT_EQUALS(prodversion.str(), dbmeta->getDatabaseProductVersion().substr(0, prodversion.str().length()));
}
else
{
ASSERT_EQUALS(prodversion.str(), dbmeta->getDatabaseProductVersion());
}
}
catch (sql::SQLException &e)
{
logErr(e.what());
logErr("SQLState: " + std::string(e.getSQLState()));
fail(e.what(), __FILE__, __LINE__);
}
}
void connectionmetadata::getDriverVersions()
{
logMsg("connectionmetadata::getDriverVersions() - MySQL_ConnectionMetaData::getDriver[Minor|Major|Patch]Version()");
std::stringstream prodversion;
try
{
DatabaseMetaData dbmeta(con->getMetaData());
ASSERT_GT(0, dbmeta->getDriverMajorVersion());
ASSERT_LT(2, dbmeta->getDriverMajorVersion());
ASSERT_LT(100, dbmeta->getDriverMinorVersion());
ASSERT_LT(100, dbmeta->getDriverPatchVersion());
ASSERT_EQUALS("MariaDB Connector/C++", dbmeta->getDriverName());
prodversion.str("");
prodversion << dbmeta->getDriverMajorVersion() << "." << dbmeta->getDriverMinorVersion();
prodversion << "." << dbmeta->getDriverPatchVersion();
if (prodversion.str().length() < dbmeta->getDriverVersion().length())
{
// Check only left prefix, Driver could have "-alpha" or something in its product versin
ASSERT_EQUALS(prodversion.str(), dbmeta->getDriverVersion().substr(0, prodversion.str().length()));
}
else
{
ASSERT_EQUALS(prodversion.str(), dbmeta->getDriverVersion());
}
}
catch (sql::SQLException &e)
{
logErr(e.what());
logErr("SQLState: " + std::string(e.getSQLState()));
fail(e.what(), __FILE__, __LINE__);
}
}
void connectionmetadata::getDefaultTransactionIsolation()
{
logMsg("connectionmetadata::getDefaultTransactionIsolation() - MySQL_ConnectionMetaData::getDefaultTransactionIsolation()");
int server_version;
try
{
DatabaseMetaData dbmeta(con->getMetaData());
server_version=(10000 * dbmeta->getDatabaseMajorVersion())
+ (100 * dbmeta->getDriverMinorVersion())
+ dbmeta->getDriverPatchVersion();
if (server_version < 32336)
FAIL("Sorry guys - we do not support MySQL <5.1. This test will not handle this case.");
ASSERT_EQUALS(sql::TRANSACTION_REPEATABLE_READ, dbmeta->getDefaultTransactionIsolation());
ASSERT(sql::TRANSACTION_NONE != dbmeta->getDefaultTransactionIsolation());
ASSERT(sql::TRANSACTION_READ_UNCOMMITTED != dbmeta->getDefaultTransactionIsolation());
ASSERT(sql::TRANSACTION_READ_COMMITTED != dbmeta->getDefaultTransactionIsolation());
ASSERT(sql::TRANSACTION_SERIALIZABLE != dbmeta->getDefaultTransactionIsolation());
}
catch (sql::SQLException &e)
{
logErr(e.what());
logErr("SQLState: " + std::string(e.getSQLState()));
fail(e.what(), __FILE__, __LINE__);
}
}
void connectionmetadata::getExtraNameCharacters()
{
logMsg("connectionmetadata::getExtraNameCharacters() - MySQL_ConnectionMetaData::getExtraNameCharacters()");
try
{
DatabaseMetaData dbmeta(con->getMetaData());
ASSERT_EQUALS("#@", dbmeta->getExtraNameCharacters());
}
catch (sql::SQLException &e)
{
logErr(e.what());
logErr("SQLState: " + std::string(e.getSQLState()));
fail(e.what(), __FILE__, __LINE__);
}
}
void connectionmetadata::getIdentifierQuoteString()
{
logMsg("connectionmetadata::getIdentifierQuoteString() - MySQL_ConnectionMetaData::getIdentifierQuoteString()");
try
{
DatabaseMetaData dbmeta(con->getMetaData());
stmt.reset(con->createStatement());
try
{
stmt->execute("SET @@sql_mode = ''");
res.reset(stmt->executeQuery("SELECT @@sql_mode AS _sql_mode"));
ASSERT(res->next());
ASSERT_EQUALS("", res->getString("_sql_mode"));
}
catch (sql::SQLException &)
{
SKIP("Cannot set SQL_MODE, skipping test");
}
ASSERT_EQUALS("`", dbmeta->getIdentifierQuoteString());
stmt->execute("SET @@sql_mode = 'ANSI_QUOTES,ALLOW_INVALID_DATES'");
res.reset(stmt->executeQuery("SELECT @@sql_mode AS _sql_mode"));
ASSERT(res->next());
ASSERT_EQUALS("ANSI_QUOTES,ALLOW_INVALID_DATES", res->getString("_sql_mode"));
// "`" still works foe identifier quotation with ANSI_QUOTES
ASSERT_EQUALS("`", dbmeta->getIdentifierQuoteString());
}
catch (sql::SQLException &e)
{
logErr(e.what());
logErr("SQLState: " + std::string(e.getSQLState()));
fail(e.what(), __FILE__, __LINE__);
}
}
void connectionmetadata::getImportedKeys()
{
logMsg("connectionmetadata::getImportedKeys() - MySQL_ConnectionMetaData::getImportedKeys()");
try
{
DatabaseMetaData dbmeta(con->getMetaData());
stmt.reset(con->createStatement());
stmt->execute("DROP TABLE IF EXISTS child");
stmt->execute("DROP TABLE IF EXISTS parent");
try
{
stmt->execute("CREATE TABLE parent(pid INT NOT NULL, PRIMARY KEY(pid)) ENGINE=INNODB;");
stmt->execute("CREATE TABLE child(cid INT NOT NULL, cpid INT, "
"INDEX idx_parent_id(cpid), FOREIGN KEY idx_parent_id(cpid) "
"REFERENCES parent(pid) ON DELETE CASCADE ON UPDATE CASCADE, PRIMARY KEY(cid)) ENGINE=INNODB;");
}
catch (sql::SQLException &)
{
SKIP("Cannot create necessary FK tables");
}
int num_res=0;
res.reset(dbmeta->getImportedKeys(con->getCatalog(), con->getSchema(), "parent"));
ASSERT(!res->next());
res.reset(dbmeta->getImportedKeys(con->getCatalog(), con->getSchema(), "child"));
checkResultSetScrolling(res);
ASSERT(res->next());
logMsg("... calling checkForeignKey for child");
checkForeignKey(con, res);
ASSERT(!res->next());
stmt->execute("DROP TABLE IF EXISTS child");
stmt->execute("DROP TABLE IF EXISTS parent");
stmt->execute("CREATE TABLE parent(pid1 INT NOT NULL, pid2 INT NOT NULL, PRIMARY KEY(pid1, pid2)) ENGINE=INNODB;");
stmt->execute("CREATE TABLE child(cid INT NOT NULL, cpid2 INT, cpid1 INT, "
"INDEX idx_parent_id(cpid1, cpid2), FOREIGN KEY idx_parent_id(cpid1, cpid2) "
"REFERENCES parent(pid1, pid2) ON DELETE CASCADE ON UPDATE CASCADE, PRIMARY KEY(cid)) ENGINE=INNODB;");
res.reset(dbmeta->getImportedKeys(con->getCatalog(), con->getSchema(), "child"));
num_res=0;
while (res->next())
{
++num_res;
switch (num_res) {
case 1:
ASSERT_EQUALS("cpid1", res->getString("FKCOLUMN_NAME"));
break;
case 2:
ASSERT_EQUALS("cpid2", res->getString("FKCOLUMN_NAME"));
break;
default:
FAIL("Expecting only two rows");
break;
}
}
ASSERT_EQUALS(2, num_res);
stmt->execute("DROP TABLE IF EXISTS child");
stmt->execute("DROP TABLE IF EXISTS parent");
res.reset(dbmeta->getImportedKeys(con->getCatalog(), con->getSchema(), "child"));
ASSERT(!res->next());
}
catch (sql::SQLException &e)
{
logErr(e.what());
logErr("SQLState: " + std::string(e.getSQLState()));
fail(e.what(), __FILE__, __LINE__);
}
}
void connectionmetadata::getExportedKeys()
{
logMsg("connectionmetadata::getExportedKeys() - MySQL_ConnectionMetaData::getExportedKeys()");
try
{
DatabaseMetaData dbmeta(con->getMetaData());
stmt.reset(con->createStatement());
stmt->execute("DROP TABLE IF EXISTS child");
stmt->execute("DROP TABLE IF EXISTS parent");
try
{
stmt->execute("CREATE TABLE parent(pid INT NOT NULL, PRIMARY KEY(pid)) ENGINE=INNODB;");
stmt->execute("CREATE TABLE child(cid INT NOT NULL, cpid INT, "
"INDEX idx_parent_id(cpid), FOREIGN KEY idx_parent_id(cpid) "
"REFERENCES parent(pid) ON DELETE CASCADE ON UPDATE CASCADE, PRIMARY KEY(cid)) ENGINE=INNODB;");
}
catch (sql::SQLException &)
{
SKIP("Cannot create necessary FK tables");
}
int num_res=0;
res.reset(dbmeta->getExportedKeys(con->getCatalog(), con->getSchema(), "child"));
ASSERT(!res->next());
res.reset(dbmeta->getExportedKeys(con->getCatalog(), con->getSchema(), "parent"));
ASSERT(res->next());
logMsg("... calling checkForeignKey for parent");
checkForeignKey(con, res);
ASSERT(!res->next());
stmt->execute("DROP TABLE IF EXISTS child");
stmt->execute("DROP TABLE IF EXISTS parent");
stmt->execute("CREATE TABLE parent(pid1 INT NOT NULL, pid2 INT NOT NULL, PRIMARY KEY(pid1, pid2)) ENGINE=INNODB;");
stmt->execute("CREATE TABLE child(cid INT NOT NULL, cpid2 INT, cpid1 INT, "
"INDEX idx_parent_id(cpid1, cpid2), FOREIGN KEY idx_parent_id(cpid1, cpid2) "
"REFERENCES parent(pid1, pid2) ON DELETE CASCADE ON UPDATE CASCADE, PRIMARY KEY(cid)) ENGINE=INNODB;");
res.reset(dbmeta->getExportedKeys(con->getCatalog(), con->getSchema(), "parent"));
checkResultSetScrolling(res);
num_res=0;
while (res->next())
{
num_res++;
switch (num_res) {
case 1:
ASSERT_EQUALS("cpid1", res->getString("FKCOLUMN_NAME"));
break;
case 2:
ASSERT_EQUALS("cpid2", res->getString("FKCOLUMN_NAME"));
break;
default:
FAIL("Expecting only two rows");
break;
}
}
ASSERT_EQUALS(2, num_res);
stmt->execute("DROP TABLE IF EXISTS child");
stmt->execute("DROP TABLE IF EXISTS parent");
res.reset(dbmeta->getExportedKeys(con->getCatalog(), con->getSchema(), "child"));
ASSERT(!res->next());
}
catch (sql::MethodNotImplementedException &e)
{
logMsg(e.what());
SKIP("Server version is too old, MethodNotImplementedException!");
}
catch (sql::SQLException &e)
{
logErr(e.what());
logErr("SQLState: " + std::string(e.getSQLState()));
fail(e.what(), __FILE__, __LINE__);
}
}
void connectionmetadata::checkForeignKey(Connection &mycon, ResultSet &myres)
{
bool got_warning=false;
std::stringstream msg;
if (mycon->getCatalog() != "" && mycon->getCatalog() != myres->getString(1))
{
got_warning=true;
msg.str("");
msg << "... WARNING expecting PKTABLE_CAT = '" << mycon->getCatalog() << "'";
msg << " got '" << myres->getString(1) << "'";
logMsg(msg.str());
}
ASSERT_EQUALS(myres->getString(1), myres->getString("PKTABLE_CAT"));
ASSERT_EQUALS(mycon->getSchema(), myres->getString(2));
ASSERT_EQUALS(myres->getString(2), myres->getString("PKTABLE_SCHEM"));
ASSERT_EQUALS("parent", myres->getString(3));
ASSERT_EQUALS(myres->getString(3), myres->getString("PKTABLE_NAME"));
ASSERT_EQUALS("pid", myres->getString(4));
ASSERT_EQUALS(myres->getString(4), myres->getString("PKCOLUMN_NAME"));
if (mycon->getCatalog() != "" && mycon->getCatalog() != myres->getString(5))
{
got_warning=true;
msg.str("");
msg << "... WARNING expecting FKTABLE_CAT = '" << mycon->getCatalog() << "'";
msg << " got '" << myres->getString(1) << "'";
logMsg(msg.str());
}
ASSERT_EQUALS(myres->getString(5), myres->getString("FKTABLE_CAT"));
ASSERT_EQUALS(mycon->getSchema(), myres->getString(6));
ASSERT_EQUALS(myres->getString(6), myres->getString("FKTABLE_SCHEM"));
ASSERT_EQUALS("child", myres->getString(7));
ASSERT_EQUALS(myres->getString(7), myres->getString("FKTABLE_NAME"));
ASSERT_EQUALS("cpid", myres->getString(8));
ASSERT_EQUALS(myres->getString(8), myres->getString("FKCOLUMN_NAME"));
ASSERT_EQUALS(1, myres->getInt(9));
ASSERT_EQUALS(myres->getInt(9), myres->getInt("KEY_SEQ"));
ASSERT_EQUALS((int64_t) sql::DatabaseMetaData::importedKeyCascade, myres->getInt64(10));
ASSERT_EQUALS(myres->getInt64(10), myres->getInt64("UPDATE_RULE"));
ASSERT(sql::DatabaseMetaData::importedKeyNoAction != myres->getInt64(10));
ASSERT(sql::DatabaseMetaData::importedKeySetNull != myres->getInt64(10));
ASSERT(sql::DatabaseMetaData::importedKeySetDefault != myres->getInt64(10));
ASSERT(sql::DatabaseMetaData::importedKeyRestrict != myres->getInt64(10));
ASSERT_EQUALS((int64_t) sql::DatabaseMetaData::importedKeyCascade, myres->getInt64(11));
ASSERT_EQUALS(myres->getInt64(11), myres->getInt64("DELETE_RULE"));
ASSERT(sql::DatabaseMetaData::importedKeyNoAction != myres->getInt64(11));
ASSERT(sql::DatabaseMetaData::importedKeySetNull != myres->getInt64(11));
ASSERT(sql::DatabaseMetaData::importedKeySetDefault != myres->getInt64(11));
ASSERT(sql::DatabaseMetaData::importedKeyRestrict != myres->getInt64(11));
// InnoDB should give the FK a name
ASSERT("" != myres->getString("FK_NAME"));
ASSERT_EQUALS(myres->getString(12), myres->getString("FK_NAME"));
// We would have PK_NAME only if I_S. By default "SHOW CREATE TABLE" result is parsed, and it doesn't have this info, and thus NULL is returned
if (!myres->isNull(13))
{
ASSERT_EQUALS("PRIMARY", myres->getString("PK_NAME"));
}
ASSERT_EQUALS(myres->getString(13), myres->getString("PK_NAME"));
ASSERT_EQUALS((int64_t) sql::DatabaseMetaData::importedKeyNotDeferrable, myres->getInt64(14));
ASSERT(sql::DatabaseMetaData::importedKeyInitiallyDeferred != myres->getInt64(10));
ASSERT(sql::DatabaseMetaData::importedKeyInitiallyImmediate != myres->getInt64(10));
if (got_warning)
{
TODO("See --verbose warnings!");
FAIL("TODO - See --verbose warnings!");
}
}
void connectionmetadata::getIndexInfo()
{
logMsg("connectionmetadata::getIndexInfo() - MySQL_ConnectionMetaData::getIndexInfo()");
std::stringstream msg;
bool got_warning=false;
bool got_todo_warning=false;
try
{
DatabaseMetaData dbmeta(con->getMetaData());
stmt.reset(con->createStatement());
stmt->execute("DROP TABLE IF EXISTS test");
stmt->execute("CREATE TABLE test(col1 INT NOT NULL, col2 INT NOT NULL, col3 INT NOT NULL, col4 INT, col5 INT, PRIMARY KEY(col1))");
stmt->execute("INSERT INTO test(col1, col2, col3) VALUES (1, 1, 1)");
res.reset(dbmeta->getIndexInfo(con->getCatalog(), con->getSchema(), "test", false, false));
ASSERT(res->next());
if (con->getCatalog() != "" && res->getString(1) != "" && con->getCatalog() != res->getString(1))
{
got_todo_warning=true;
msg.str("");
msg << "...\t\tWARNING expecting TABLE_CAT = '" << con->getCatalog() << "'";
msg << " got '" << res->getString(1) << "'";
logMsg(msg.str());
}
ASSERT_EQUALS(res->getString(1), res->getString("TABLE_CAT"));
ASSERT_EQUALS(con->getSchema(), res->getString(2));
ASSERT_EQUALS(res->getString(2), res->getString("TABLE_SCHEM"));
ASSERT_EQUALS("test", res->getString(3));
ASSERT_EQUALS(res->getString(3), res->getString("TABLE_NAME"));
ASSERT_EQUALS(false, res->getBoolean("NON_UNIQUE"));
ASSERT_EQUALS(res->getBoolean(4), res->getBoolean("NON_UNIQUE"));
ASSERT_EQUALS(res->getString("TABLE_SCHEM"), res->getString(5));
ASSERT_EQUALS(res->getString(5), res->getString("INDEX_QUALIFIER"));
ASSERT_EQUALS("PRIMARY", res->getString(6));
ASSERT_EQUALS(res->getString(6), res->getString("INDEX_NAME"));
ASSERT_EQUALS(sql::DatabaseMetaData::tableIndexOther, res->getInt(7));
ASSERT_EQUALS(res->getInt(7), res->getInt("TYPE"));
ASSERT(sql::DatabaseMetaData::tableIndexStatistic != res->getInt(7));
ASSERT(sql::DatabaseMetaData::tableIndexClustered != res->getInt(7));
ASSERT(sql::DatabaseMetaData::tableIndexHashed != res->getInt(7));
ASSERT_EQUALS(1, res->getInt(8));
ASSERT_EQUALS(res->getInt(8), res->getInt("ORDINAL_POSITION"));
ASSERT_EQUALS("col1", res->getString(9));
ASSERT_EQUALS(res->getString(9), res->getString("COLUMN_NAME"));
ASSERT_EQUALS("A", res->getString(10));
ASSERT_EQUALS(res->getString(10), res->getString("ASC_OR_DESC"));
if (res->getInt(11) != 1)
{
got_warning=true;
msg.str("");
msg << "... \t\tWARNING: There is one row in the table and PK should have a ";
msg << "cardinality of 1, got " << res->getInt(11);
logMsg(msg.str());
}
ASSERT_EQUALS(res->getInt(11), res->getInt("CARDINALITY"));
ASSERT_EQUALS(0, res->getInt(12));
ASSERT_EQUALS(res->getInt(12), res->getInt("PAGES"));
ASSERT_EQUALS("", res->getString(13));
ASSERT_EQUALS(res->getString(13), res->getString("FILTER_CONDITION"));
ASSERT(!res->next());
// New unique index
stmt->execute("CREATE UNIQUE INDEX an_idx_col3 ON test(col3 ASC)");
res.reset(dbmeta->getIndexInfo(con->getCatalog(), con->getSchema(), "test", false, false));
checkResultSetScrolling(res);
ASSERT(res->next());
ASSERT_EQUALS("an_idx_col3", res->getString("INDEX_NAME"));
ASSERT_EQUALS(false, res->getBoolean("NON_UNIQUE"));
ASSERT(res->next());
ASSERT_EQUALS("PRIMARY", res->getString("INDEX_NAME"));
ASSERT_EQUALS(false, res->getBoolean("NON_UNIQUE"));
ASSERT(!res->next());
// Now we have three indexes, unique PK, unique an_idx_col3 and non-unique idx_col2
stmt->execute("CREATE INDEX idx_col2 ON test(col2 ASC)");
// Show only the unique ones...
res.reset(dbmeta->getIndexInfo(con->getCatalog(), con->getSchema(), "test", true, false));
ASSERT(res->next());
ASSERT_EQUALS("an_idx_col3", res->getString("INDEX_NAME"));
ASSERT_EQUALS(false, res->getBoolean("NON_UNIQUE"));
ASSERT(res->next());
ASSERT_EQUALS("PRIMARY", res->getString("INDEX_NAME"));
ASSERT_EQUALS(false, res->getBoolean("NON_UNIQUE"));
if (res->next())
{
got_warning=true;
msg.str("");
msg << "... \t\tWARNING: requesting only unique keys but got also non-unique key ";
msg << "'" << res->getString("INDEX_NAME") << "', UNIQUE = " << std::boolalpha;
msg << !res->getBoolean("NON_UNIQUE");
logMsg(msg.str());
}
ASSERT(!res->next());
// Another index. Should appear in the sort order prior to the idx_col2 one...
// Sort order is: NON_UNIQUE, TYPE, INDEX_NAME
stmt->execute("CREATE INDEX an_a_idx_col4 ON test(col4 DESC)");
res.reset(dbmeta->getIndexInfo(con->getCatalog(), con->getSchema(), "test", false, false));
ASSERT(res->next());
ASSERT_EQUALS(sql::DatabaseMetaData::tableIndexOther, res->getInt(7));
ASSERT_EQUALS("an_idx_col3", res->getString("INDEX_NAME"));
ASSERT_EQUALS(false, res->getBoolean("NON_UNIQUE"));
ASSERT(res->next());
ASSERT_EQUALS("PRIMARY", res->getString("INDEX_NAME"));
ASSERT_EQUALS(false, res->getBoolean("NON_UNIQUE"));
ASSERT_EQUALS(sql::DatabaseMetaData::tableIndexOther, res->getInt(7));
ASSERT(res->next());
ASSERT_EQUALS("an_a_idx_col4", res->getString("INDEX_NAME"));
ASSERT_EQUALS(true, res->getBoolean("NON_UNIQUE"));
ASSERT_EQUALS(sql::DatabaseMetaData::tableIndexOther, res->getInt(7));
ASSERT(res->next());
ASSERT_EQUALS("idx_col2", res->getString("INDEX_NAME"));
ASSERT_EQUALS(true, res->getBoolean("NON_UNIQUE"));
ASSERT_EQUALS(sql::DatabaseMetaData::tableIndexOther, res->getInt(7));
ASSERT(!res->next());
//Was wrong on previous versions....
if (getServerVersion(con) >= 800000)
{
stmt->execute("DROP TABLE IF EXISTS test");
stmt->execute("CREATE TABLE test(col1 INT NOT NULL, col2 INT NOT NULL, col3 INT NOT NULL, col4 INT, col5 INT, PRIMARY KEY(col1))");
stmt->execute("CREATE INDEX idx_col4_col5 ON test(col5 DESC, col4 ASC)");
res.reset(dbmeta->getIndexInfo(con->getCatalog(), con->getSchema(), "test", false, false));
ASSERT(res->next());
ASSERT_EQUALS("PRIMARY", res->getString("INDEX_NAME"));
ASSERT_EQUALS(false, res->getBoolean("NON_UNIQUE"));
ASSERT(res->next());
ASSERT_EQUALS("idx_col4_col5", res->getString("INDEX_NAME"));
ASSERT_EQUALS((("MariaDB" != dbmeta->getDatabaseProductName() && getServerVersion(con) > 800000) || getServerVersion(con) > 1008000) ? "D" : "A", res->getString("ASC_OR_DESC"));
ASSERT_EQUALS("col5", res->getString("COLUMN_NAME"));
ASSERT_EQUALS(true, res->getBoolean("NON_UNIQUE"));
ASSERT(res->next());
ASSERT_EQUALS("idx_col4_col5", res->getString("INDEX_NAME"));
ASSERT_EQUALS("A", res->getString("ASC_OR_DESC"));
ASSERT_EQUALS("col4", res->getString("COLUMN_NAME"));
ASSERT_EQUALS(true, res->getBoolean("NON_UNIQUE"));
ASSERT(!res->next());
}
try
{
stmt->execute("DROP TABLE IF EXISTS test");
stmt->execute("CREATE TABLE test(col1 INT NOT NULL, col2 INT NOT NULL, PRIMARY KEY(col1)) ENGINE=MEMORY");
stmt->execute("CREATE INDEX idx_col2 USING HASH ON test(col2 DESC)");
res.reset(dbmeta->getIndexInfo(con->getCatalog(), con->getSchema(), "test", false, false));
ASSERT(res->next());
ASSERT_EQUALS("PRIMARY", res->getString("INDEX_NAME"));
ASSERT_EQUALS(false, res->getBoolean("NON_UNIQUE"));
ASSERT(res->next());
ASSERT_EQUALS("idx_col2", res->getString("INDEX_NAME"));
// There is no order when using HASH
ASSERT_EQUALS("", res->getString("ASC_OR_DESC"));
ASSERT_EQUALS("col2", res->getString("COLUMN_NAME"));
ASSERT_EQUALS(sql::DatabaseMetaData::tableIndexOther, res->getInt("TYPE"));
ASSERT_EQUALS(true, res->getBoolean("NON_UNIQUE"));
ASSERT(!res->next());
}
catch (sql::SQLException &)
{
}
stmt->execute("DROP TABLE IF EXISTS test");
res.reset(dbmeta->getIndexInfo(con->getCatalog(), con->getSchema(), "test", false, false));
ASSERT(!res->next());
if (got_warning)
{
FAIL("See above warnings!");
}
}
catch (sql::SQLException &e)
{
logErr(e.what());
logErr("SQLState: " + std::string(e.getSQLState()));
fail(e.what(), __FILE__, __LINE__);
}
if (got_todo_warning)
{
TODO("See --verbose warnings!");
FAIL("TODO - see --verbose warnings");
}
}
void connectionmetadata::getLimitsAndStuff()
{
logMsg("connectionmetadata::getLimitsAndStuff() - MySQL_ConnectionMetaData::getLimitsAndStuff()");
std::string funcs("ASCII,BIN,BIT_LENGTH,CAST,CHAR,CHARACTER_LENGTH,CHAR_LENGTH,CONCAT,"\
"CONCAT_WS,CONV,CONVERT,ELT,EXPORT_SET,EXTRACTVALUE,FIELD,FIND_IN_SET,FORMAT,FROM_BASE64,HEX,INSERT,"\
"INSTR,LCASE,LEFT,LENGTH,LIKE,LOAD_FILE,LOCATE,LOWER,LPAD,"\
"LTRIM,MAKE_SET,MATCH AGAINST,MID,NOT LIKE,NOT REGEXP,OCT,OCTET_LENGTH,ORD,POSITION,"\
"QUOTE,REPEAT,REPLACE,REVERSE,RIGHT,RPAD,RTRIM,SOUNDEX,SOUNDS LIKE,"\
"SPACE,STRCMP,SUBSTR,SUBSTRING,SUBSTRING_INDEX,TO_BASE64,TRIM,UCASE,UNHEX,UPDATEXML,UPPER,WEIGHT_STRING");
std::string sys_funcs("DATABASE,USER,SYSTEM_USER,SESSION_USER,PASSWORD,ENCRYPT,LAST_INSERT_ID,VERSION");
try
{
DatabaseMetaData dbmeta(con->getMetaData());
try {
ASSERT_EQUALS(3, dbmeta->getCDBCMajorVersion());
}
catch (sql::SQLFeatureNotSupportedException& e) {
logMsg(e.getMessage());
}
try {
ASSERT_EQUALS(0, dbmeta->getCDBCMinorVersion());
}
catch (sql::SQLFeatureNotSupportedException & e) {
logMsg(e.getMessage());
}
ASSERT_EQUALS(16777208, dbmeta->getMaxBinaryLiteralLength());
ASSERT_EQUALS(0, dbmeta->getMaxCatalogNameLength());
ASSERT_EQUALS(16777208, dbmeta->getMaxCharLiteralLength());
ASSERT_EQUALS(64, dbmeta->getMaxColumnNameLength());
ASSERT_EQUALS(64, dbmeta->getMaxColumnsInGroupBy());
ASSERT_EQUALS(16, dbmeta->getMaxColumnsInIndex());
ASSERT_EQUALS(64, dbmeta->getMaxColumnsInOrderBy());
ASSERT_EQUALS(256, dbmeta->getMaxColumnsInSelect());
ASSERT_EQUALS(0, dbmeta->getMaxColumnsInTable());
stmt.reset(con->createStatement());
res.reset(stmt->executeQuery("SELECT @@max_connections AS _max"));
ASSERT(res->next());
ASSERT_EQUALS(dbmeta->getMaxConnections(), res->getInt("_max"));
ASSERT_EQUALS(64, dbmeta->getMaxCursorNameLength());
ASSERT_EQUALS(256, dbmeta->getMaxIndexLength());
ASSERT_EQUALS(64, dbmeta->getMaxProcedureNameLength());
ASSERT_EQUALS(0, dbmeta->getMaxRowSize());
ASSERT_EQUALS(64, dbmeta->getMaxSchemaNameLength());
stmt.reset(con->createStatement());
res.reset(stmt->executeQuery("SHOW VARIABLES LIKE 'max_allowed_packet'"));
ASSERT(res->next());
ASSERT_EQUALS(/*res->getInt(2) - 4*/0, dbmeta->getMaxStatementLength()); //TODO
ASSERT_EQUALS(0, dbmeta->getMaxStatements());
ASSERT_EQUALS(64, dbmeta->getMaxTableNameLength());
ASSERT_EQUALS(256, dbmeta->getMaxTablesInSelect());
ASSERT_EQUALS(16, dbmeta->getMaxUserNameLength());
ASSERT_EQUALS("ABS,ACOS,ASIN,ATAN,ATAN2,BIT_COUNT,CEIL,CEILING,CONV,COS,"
"COT,CRC32,DEGREES,DIV,EXP,FLOOR,GREATEST,LEAST,LN,LOG,LOG10,LOG2,MAX,MIN,MOD,OCT,PI,POW,"
"POWER,RADIANS,RAND,ROUND,SIGN,SIN,SQRT,TAN,TRUNCATE"
, dbmeta->getNumericFunctions());
ASSERT_EQUALS(true, dbmeta->allProceduresAreCallable());
ASSERT_EQUALS(true, dbmeta->allTablesAreSelectable());
ASSERT_EQUALS(true, dbmeta->dataDefinitionCausesTransactionCommit());
ASSERT_EQUALS(false, dbmeta->dataDefinitionIgnoredInTransactions());
ASSERT_EQUALS(false, dbmeta->deletesAreDetected(-1));
ASSERT_EQUALS(false, dbmeta->deletesAreDetected(0));
ASSERT_EQUALS(false, dbmeta->deletesAreDetected(1));
ASSERT_EQUALS(true, dbmeta->dataDefinitionCausesTransactionCommit());
ASSERT_EQUALS(false, dbmeta->doesMaxRowSizeIncludeBlobs());
ASSERT_EQUALS(sql::DatabaseMetaData::sqlStateSQL99, dbmeta->getSQLStateType());
ASSERT(sql::DatabaseMetaData::sqlStateXOpen != dbmeta->getSQLStateType());
ASSERT_EQUALS(funcs, dbmeta->getStringFunctions());
ASSERT_EQUALS(sys_funcs, dbmeta->getSystemFunctions());
ASSERT_EQUALS(false, dbmeta->insertsAreDetected(-1));
ASSERT_EQUALS(false, dbmeta->insertsAreDetected(0));
ASSERT_EQUALS(false, dbmeta->insertsAreDetected(1));
ASSERT_EQUALS(true, dbmeta->isCatalogAtStart());
ASSERT_EQUALS(false, dbmeta->isReadOnly());
ASSERT_EQUALS(true, dbmeta->nullPlusNonNullIsNull());
ASSERT_EQUALS(false, dbmeta->nullsAreSortedAtEnd());
ASSERT_EQUALS(true, dbmeta->nullsAreSortedAtStart());
// KLUDGE - the code takes care of some exotic MySQL 4.x, however, we don't support 4.x
ASSERT_EQUALS(false, dbmeta->nullsAreSortedHigh());
ASSERT_EQUALS(!dbmeta->nullsAreSortedLow(), dbmeta->nullsAreSortedHigh());
ASSERT_EQUALS(false, dbmeta->othersDeletesAreVisible(-1));
ASSERT_EQUALS(false, dbmeta->othersDeletesAreVisible(0));
ASSERT_EQUALS(false, dbmeta->othersDeletesAreVisible(1));
ASSERT_EQUALS(false, dbmeta->othersInsertsAreVisible(-1));
ASSERT_EQUALS(false, dbmeta->othersInsertsAreVisible(0));
ASSERT_EQUALS(false, dbmeta->othersInsertsAreVisible(1));
ASSERT_EQUALS(false, dbmeta->othersUpdatesAreVisible(-1));
ASSERT_EQUALS(false, dbmeta->othersUpdatesAreVisible(0));
ASSERT_EQUALS(false, dbmeta->othersUpdatesAreVisible(1));
ASSERT_EQUALS(false, dbmeta->ownDeletesAreVisible(-1));
ASSERT_EQUALS(false, dbmeta->ownDeletesAreVisible(0));
ASSERT_EQUALS(false, dbmeta->ownDeletesAreVisible(1));
ASSERT_EQUALS(false, dbmeta->ownInsertsAreVisible(-1));
ASSERT_EQUALS(false, dbmeta->ownInsertsAreVisible(0));
ASSERT_EQUALS(false, dbmeta->ownInsertsAreVisible(1));
ASSERT_EQUALS(false, dbmeta->ownUpdatesAreVisible(-1));
ASSERT_EQUALS(false, dbmeta->ownUpdatesAreVisible(0));
ASSERT_EQUALS(false, dbmeta->ownUpdatesAreVisible(1));
ASSERT_EQUALS(false, dbmeta->storesUpperCaseIdentifiers());
ASSERT_EQUALS(false, dbmeta->storesUpperCaseQuotedIdentifiers());
ASSERT_EQUALS(true, dbmeta->supportsAlterTableWithAddColumn());
ASSERT_EQUALS(true, dbmeta->supportsAlterTableWithDropColumn());
ASSERT_EQUALS(true, dbmeta->supportsANSI92EntryLevelSQL());
ASSERT_EQUALS(true, dbmeta->supportsANSI92FullSQL());
ASSERT_EQUALS(true, dbmeta->supportsANSI92IntermediateSQL());
ASSERT_EQUALS(true, dbmeta->supportsBatchUpdates());
ASSERT_EQUALS(false, dbmeta->supportsCatalogsInDataManipulation());
ASSERT_EQUALS(false, dbmeta->supportsCatalogsInIndexDefinitions());
ASSERT_EQUALS(false, dbmeta->supportsCatalogsInPrivilegeDefinitions());
ASSERT_EQUALS(false, dbmeta->supportsCatalogsInProcedureCalls());
ASSERT_EQUALS(false, dbmeta->supportsCatalogsInTableDefinitions());
ASSERT_EQUALS(true, dbmeta->supportsColumnAliasing());
ASSERT_EQUALS(false, dbmeta->supportsConvert());
ASSERT_EQUALS(true, dbmeta->supportsCoreSQLGrammar());
/* We support MySQL 5.1+ . It must be true */
ASSERT_EQUALS(true, dbmeta->supportsCorrelatedSubqueries());
ASSERT_EQUALS(true, dbmeta->supportsDataDefinitionAndDataManipulationTransactions());
ASSERT_EQUALS(false, dbmeta->supportsDataManipulationTransactionsOnly());
ASSERT_EQUALS(true, dbmeta->supportsDifferentTableCorrelationNames());
ASSERT_EQUALS(true, dbmeta->supportsExpressionsInOrderBy());
ASSERT_EQUALS(false, dbmeta->supportsExtendedSQLGrammar());
ASSERT_EQUALS(false, dbmeta->supportsFullOuterJoins());
ASSERT_EQUALS(true, dbmeta->supportsGetGeneratedKeys());
ASSERT_EQUALS(true, dbmeta->supportsGroupBy());
ASSERT_EQUALS(true, dbmeta->supportsGroupByBeyondSelect());
ASSERT_EQUALS(true, dbmeta->supportsGroupByUnrelated());
ASSERT_EQUALS(true, dbmeta->supportsLikeEscapeClause());
ASSERT_EQUALS(true, dbmeta->supportsLimitedOuterJoins());
ASSERT_EQUALS(true, dbmeta->supportsMinimumSQLGrammar());
ASSERT_EQUALS(false, dbmeta->supportsMultipleOpenResults());
ASSERT_EQUALS(false, dbmeta->supportsMultipleResultSets());
ASSERT_EQUALS(true, dbmeta->supportsMultipleTransactions());
ASSERT_EQUALS(false, dbmeta->supportsNamedParameters());
ASSERT_EQUALS(true, dbmeta->supportsNonNullableColumns());
ASSERT_EQUALS(true, dbmeta->supportsOpenCursorsAcrossCommit());
ASSERT_EQUALS(true, dbmeta->supportsOpenCursorsAcrossRollback());
ASSERT_EQUALS(true, dbmeta->supportsOpenStatementsAcrossCommit());
ASSERT_EQUALS(true, dbmeta->supportsOpenStatementsAcrossRollback());
ASSERT_EQUALS(true, dbmeta->supportsOrderByUnrelated());
ASSERT_EQUALS(true, dbmeta->supportsOuterJoins());
ASSERT_EQUALS(false, dbmeta->supportsPositionedDelete());
ASSERT_EQUALS(false, dbmeta->supportsPositionedUpdate());
ASSERT_EQUALS(true, dbmeta->supportsResultSetHoldability(sql::ResultSet::HOLD_CURSORS_OVER_COMMIT));
ASSERT_EQUALS(false, dbmeta->supportsResultSetHoldability(sql::ResultSet::CLOSE_CURSORS_AT_COMMIT));
ASSERT_EQUALS(true, dbmeta->supportsResultSetType(sql::ResultSet::TYPE_SCROLL_INSENSITIVE));
ASSERT_EQUALS(false, dbmeta->supportsResultSetType(sql::ResultSet::TYPE_SCROLL_SENSITIVE));
ASSERT_EQUALS(true, dbmeta->supportsResultSetType(sql::ResultSet::TYPE_FORWARD_ONLY));
/* We support MySQL 5.1+ . It must be true */
ASSERT_EQUALS(true, dbmeta->supportsSavepoints());
ASSERT_EQUALS(true, dbmeta->supportsSchemasInDataManipulation());
ASSERT_EQUALS(true, dbmeta->supportsSchemasInDataManipulation());
ASSERT_EQUALS(true, dbmeta->supportsSchemasInIndexDefinitions());
ASSERT_EQUALS(true, dbmeta->supportsSchemasInPrivilegeDefinitions());
ASSERT_EQUALS(true, dbmeta->supportsSchemasInProcedureCalls());
ASSERT_EQUALS(true, dbmeta->supportsSchemasInTableDefinitions());
/* We support MySQL 5.1+ . It must be true */
ASSERT_EQUALS(true, dbmeta->supportsSelectForUpdate());
ASSERT_EQUALS(false, dbmeta->supportsStatementPooling());
ASSERT_EQUALS(true, dbmeta->supportsStoredProcedures());
ASSERT_EQUALS(true, dbmeta->supportsSubqueriesInComparisons());
ASSERT_EQUALS(true, dbmeta->supportsSubqueriesInExists());
ASSERT_EQUALS(true, dbmeta->supportsSubqueriesInIns());
ASSERT_EQUALS(true, dbmeta->supportsSubqueriesInQuantifieds());
ASSERT_EQUALS(true, dbmeta->supportsTableCorrelationNames());
/* We support MySQL 5.1+ . It must be true */
ASSERT_EQUALS(true, dbmeta->supportsTransactionIsolationLevel(sql::TRANSACTION_NONE));
ASSERT_EQUALS(true, dbmeta->supportsTransactionIsolationLevel(sql::TRANSACTION_READ_COMMITTED));
ASSERT_EQUALS(true, dbmeta->supportsTransactionIsolationLevel(sql::TRANSACTION_READ_UNCOMMITTED));
ASSERT_EQUALS(true, dbmeta->supportsTransactionIsolationLevel(sql::TRANSACTION_REPEATABLE_READ));
ASSERT_EQUALS(true, dbmeta->supportsTransactionIsolationLevel(sql::TRANSACTION_SERIALIZABLE));
ASSERT_EQUALS(true, dbmeta->supportsTransactions());
ASSERT_EQUALS(true, dbmeta->supportsTypeConversion());
/* We support MySQL 5.1+ . It must be true */
ASSERT_EQUALS(true, dbmeta->supportsUnion());
ASSERT_EQUALS(true, dbmeta->supportsUnionAll());
ASSERT_EQUALS(false, dbmeta->updatesAreDetected(sql::ResultSet::TYPE_FORWARD_ONLY));
ASSERT_EQUALS(false, dbmeta->updatesAreDetected(sql::ResultSet::TYPE_SCROLL_INSENSITIVE));
ASSERT_EQUALS(false, dbmeta->updatesAreDetected(sql::ResultSet::TYPE_SCROLL_SENSITIVE));
ASSERT_EQUALS(false, dbmeta->usesLocalFilePerTable());
ASSERT_EQUALS(false, dbmeta->usesLocalFiles());
}
catch (sql::SQLException &e)
{
logErr(e.what());
logErr("SQLState: " + std::string(e.getSQLState()));
fail(e.what(), __FILE__, __LINE__);
}
}
void connectionmetadata::getPrimaryKeys()
{
logMsg("connectionmetadata::getPrimaryKeys() - MySQL_ConnectionMetaData::getPrimaryKeys");
int row_num;
std::string catalog;
std::string schema("");
std::stringstream msg;
bool got_warning=false;
try
{
DatabaseMetaData dbmeta(con->getMetaData());
stmt.reset(con->createStatement());
stmt->execute("DROP TABLE IF EXISTS test");
stmt->execute("CREATE TABLE test(col2 INT NOT NULL, col1 INT NOT NULL, PRIMARY KEY(col2, col1))");
// The descriptions are ordered by the column COLUMN_NAME, will they?
res.reset(dbmeta->getPrimaryKeys(con->getCatalog(), con->getSchema(), "test"));
checkResultSetScrolling(res);
row_num=0;
while (res->next())
{
row_num++;
if (con->getCatalog() != "" && res->getString("TABLE_CAT") != "" && con->getCatalog() != res->getString("TABLE_CAT"))
{
got_warning=true;
msg.str("");
msg << "...\t\tWARNING expecting TABLE_CAT = '" << con->getCatalog() << "'";
msg << " got '" << res->getString("TABLE_CAT") << "'";
logMsg(msg.str());
}
ASSERT_EQUALS(con->getSchema(), res->getString("TABLE_SCHEM"));
ASSERT_EQUALS("test", res->getString("TABLE_NAME"));
switch (row_num) {
case 1:
// getPrimaryKeys results ordered by COLUMN_NAME only. Thus col1, and then col2
ASSERT_EQUALS("col1", res->getString("COLUMN_NAME"));
ASSERT_EQUALS(2, res->getInt("KEY_SEQ"));
break;
case 2:
ASSERT_EQUALS("col2", res->getString("COLUMN_NAME"));
ASSERT_EQUALS(1, res->getInt("KEY_SEQ"));
break;
default:
FAIL("Too many PK columns reported");
break;
}
ASSERT_EQUALS("PRIMARY", res->getString("PK_NAME"));
}
ASSERT_EQUALS(2, row_num);
// catalog - a string ... "" retrieves pk from tables wo catalog, NULL = catalog should not be used to narrow the search
res.reset(dbmeta->getPrimaryKeys(catalog, con->getSchema(), "test"));
ASSERT_EQUALS(true, res->next());
ASSERT_EQUALS("test", res->getString("TABLE_NAME"));
res.reset(dbmeta->getPrimaryKeys(catalog, schema, "test"));
ASSERT(!res->next());
stmt->execute("DROP TABLE IF EXISTS test");
res.reset(dbmeta->getPrimaryKeys(con->getCatalog(), con->getSchema(), "test"));
ASSERT_EQUALS(false, res->next());
}
catch (sql::SQLException &e)
{
logErr(e.what());
logErr("SQLState: " + std::string(e.getSQLState()));
fail(e.what(), __FILE__, __LINE__);
}
if (got_warning)
{
TODO("See --verbose warnings!");
FAIL("TODO - see --verbose warnings!");
}
}
void connectionmetadata::getProcedures()
{
logMsg("connectionmetadata::getProcedures() - MySQL_ConnectionMetaData::getProcedures");
bool got_warning=false;
std::stringstream msg;
bool autoCommit = con->getAutoCommit();
try
{
DatabaseMetaData dbmeta(con->getMetaData());
stmt.reset(con->createStatement());
try
{
stmt->execute("DROP PROCEDURE IF EXISTS p1");
stmt->execute("CREATE PROCEDURE p1(OUT param1 INT) BEGIN SELECT 1 INTO param1; END");
}
catch (sql::SQLException &)
{
SKIP("Cannot create procedure");
}
if (isSkySqlHA())
{
con->setAutoCommit(false);
}
// Verify if the procedure creally has been created...
stmt->execute("SET @myvar = -1");
stmt->execute("CALL p1(@myvar)");
res.reset(stmt->executeQuery("SELECT @myvar AS _myvar"));
ASSERT(res->next());
ASSERT_EQUALS(1, res->getInt("_myvar"));
logMsg("...who is the bad guy?");
res.reset(dbmeta->getProcedures(con->getCatalog(), con->getSchema(), "p1"));
checkResultSetScrolling(res);
logMsg("...is it you, getProcedures()?");
ASSERT(res->next());
if (con->getCatalog() != "" && res->getString("PROCEDURE_CAT") != "" && con->getCatalog() != res->getString("PROCEDURE_CAT"))
{
got_warning=true;
msg.str("");
msg << "\t\tWARNING expecting PROCEDURE_CAT = '" << con->getCatalog() << "'";
msg << " got '" << res->getString("PROCEDURE_CAT") << "'";
logMsg(msg.str());
}
ASSERT_EQUALS(res->getString(1), res->getString("PROCEDURE_CAT"));
ASSERT_EQUALS(con->getSchema(), res->getString("PROCEDURE_SCHEM"));
ASSERT_EQUALS(res->getString(2), res->getString("PROCEDURE_SCHEM"));
ASSERT_EQUALS("p1", res->getString(3));
ASSERT_EQUALS(res->getString(3), res->getString("PROCEDURE_NAME"));
ASSERT_EQUALS("", res->getString(4));
ASSERT_EQUALS("", res->getString(5));
ASSERT_EQUALS("", res->getString(6));
ASSERT_EQUALS("", res->getString(7));
ASSERT_EQUALS(res->getString("REMARKS"), res->getString(7));
ASSERT_EQUALS(sql::DatabaseMetaData::procedureNoResult, res->getInt("PROCEDURE_TYPE"));
ASSERT(sql::DatabaseMetaData::procedureReturnsResult != res->getInt(8));
ASSERT(sql::DatabaseMetaData::procedureResultUnknown != res->getInt(8));
ASSERT(!res->next());
if (isSkySqlHA())
{
con->commit();
con->setAutoCommit(autoCommit);
}
}
catch (sql::SQLException &e)
{
if (isSkySqlHA())
{
con->rollback();
con->setAutoCommit(autoCommit);
}
logErr(e.what());
logErr("SQLState: " + std::string(e.getSQLState()));
fail(e.what(), __FILE__, __LINE__);
}
if (got_warning)
{
TODO("See --verbose warnings!");
FAIL("TODO - see --verbose warnings!");
}
}
void connectionmetadata::getProcedureColumns()
{
logMsg("connectionmetadata::getProcedureColumns() - MySQL_ConnectionMetaData::getProcedureColumns()");
int server_version;
SKIP("method not implemented");
try
{
DatabaseMetaData dbmeta(con->getMetaData());
stmt.reset(con->createStatement());
try
{
stmt->execute("DROP PROCEDURE IF EXISTS p1");
stmt->execute("CREATE PROCEDURE p1(OUT param1 INT) BEGIN SELECT 1 INTO param1; END");
}
catch (sql::SQLException &)
{
SKIP("Cannot create procedure");
}
// Verify if the procedure creally has been created...
stmt->execute("SET @myvar = -1");
stmt->execute("CALL p1(@myvar)");
res.reset(stmt->executeQuery("SELECT @myvar AS _myvar"));
checkResultSetScrolling(res);
ASSERT(res->next());
ASSERT_EQUALS(1, res->getInt("_myvar"));
res.reset(dbmeta->getProcedureColumns(con->getCatalog(), con->getSchema(), "p1", "%"));
server_version=(10000 * dbmeta->getDatabaseMajorVersion())
+ (100 * dbmeta->getDriverMinorVersion())
+ dbmeta->getDriverPatchVersion();
if (server_version < 50206)
ASSERT(!res->next());
else
{
ASSERT(res->next());
FAIL("Theres a new I_S table PARAMETERS. The test should use it");
}
}
catch (sql::SQLException &e)
{
logErr(e.what());
logErr("SQLState: " + std::string(e.getSQLState()));
fail(e.what(), __FILE__, __LINE__);
}
}
void connectionmetadata::getCatalogs()
{
logMsg("connectionmetadata::getCatalogs() - MySQL_ConnectionMetaData::getCatalogs()");
try
{
DatabaseMetaData dbmeta(con->getMetaData());
res.reset(dbmeta->getCatalogs());
//ASSERT(res->next());
ASSERT(!res->next());
ResultSetMetaData resmeta(res->getMetaData());
/* http://java.sun.com/j2se/1.4.2/docs/api/java/sql/DatabaseMetaData.html#getCatalogs() */
ASSERT_EQUALS((unsigned int) 1, resmeta->getColumnCount());
ASSERT_EQUALS("TABLE_CAT", resmeta->getColumnLabel(1));
}
catch (sql::SQLException &e)
{
logErr(e.what());
logErr("SQLState: " + std::string(e.getSQLState()));
fail(e.what(), __FILE__, __LINE__);
}
}
void connectionmetadata::getCatalogSeparator()
{
logMsg("connectionmetadata::getCatalogSeparator() - MySQL_ConnectionMetaData::getCatalogSeparator()");
try
{
DatabaseMetaData dbmeta(con->getMetaData());
ASSERT_EQUALS("", dbmeta->getCatalogSeparator());
}
catch (sql::SQLException &e)
{
logErr(e.what());
logErr("SQLState: " + std::string(e.getSQLState()));
fail(e.what(), __FILE__, __LINE__);
}
}
void connectionmetadata::getCatalogTerm()
{
logMsg("connectionmetadata::getCatalogTerm() - MySQL_ConnectionMetaData::getCatalogTerm()");
try
{
DatabaseMetaData dbmeta(con->getMetaData());
ASSERT_EQUALS("", dbmeta->getCatalogTerm());
}
catch (sql::SQLException &e)
{
logErr(e.what());
logErr("SQLState: " + std::string(e.getSQLState()));
fail(e.what(), __FILE__, __LINE__);
}
}
void connectionmetadata::getCrossReference()
{
logMsg("connectionmetadata::getCrossReference() - MySQL_ConnectionMetaData::getCrossReference()");
try
{
DatabaseMetaData dbmeta(con->getMetaData());
stmt.reset(con->createStatement());
stmt->execute("DROP TABLE IF EXISTS child");
stmt->execute("DROP TABLE IF EXISTS parent");
try
{
stmt->execute("CREATE TABLE parent(pid INT NOT NULL, PRIMARY KEY(pid)) ENGINE=INNODB;");
stmt->execute("CREATE TABLE child(cid INT NOT NULL, cpid INT, "
"INDEX idx_parent_id(cpid), FOREIGN KEY idx_parent_id(cpid) "
"REFERENCES parent(pid) ON DELETE CASCADE ON UPDATE CASCADE, PRIMARY KEY(cid)) ENGINE=INNODB;");
}
catch (sql::SQLException &)
{
SKIP("Cannot create necessary FK tables");
}
logMsg("... checking parent->child");
res.reset(dbmeta->getCrossReference(con->getCatalog(), con->getSchema(), "parent", con->getCatalog(), con->getSchema(), "child"));
checkResultSetScrolling(res);
ASSERT(res->next());
checkForeignKey(con, res);
logMsg("... checking child->parent");
stmt->execute("DROP TABLE IF EXISTS child");
stmt->execute("DROP TABLE IF EXISTS parent");
res.reset(dbmeta->getCrossReference(con->getCatalog(), con->getSchema(), "child", con->getCatalog(), con->getSchema(), "parent"));
ASSERT(!res->next());
}
catch (sql::MethodNotImplementedException &e)
{
logMsg(e.what());
SKIP("Server version is too old, MethodNotImplementedException!");
}
catch (sql::SQLException &e)
{
logErr(e.what());
logErr("SQLState: " + std::string(e.getSQLState()));
fail(e.what(), __FILE__, __LINE__);
}
}
void connectionmetadata::getProcedureTerm()
{
logMsg("connectionmetadata::getProcedureTerm() - MySQL_ConnectionMetaData::getProcedureTerm");
try
{
DatabaseMetaData dbmeta(con->getMetaData());
ASSERT_EQUALS("procedure", dbmeta->getProcedureTerm());
}
catch (sql::SQLException &e)
{
logErr(e.what());
logErr("SQLState: " + std::string(e.getSQLState()));
fail(e.what(), __FILE__, __LINE__);
}
}
void connectionmetadata::getResultSetHoldability()
{
logMsg("connectionmetadata::getResultSetHoldability() - MySQL_ConnectionMetaData::getResultSetHoldability()");
try
{
DatabaseMetaData dbmeta(con->getMetaData());
ASSERT_EQUALS(sql::ResultSet::HOLD_CURSORS_OVER_COMMIT, dbmeta->getResultSetHoldability());
ASSERT(sql::ResultSet::CLOSE_CURSORS_AT_COMMIT != dbmeta->getResultSetHoldability());
}
catch (sql::SQLException &e)
{
logErr(e.what());
logErr("SQLState: " + std::string(e.getSQLState()));
fail(e.what(), __FILE__, __LINE__);
}
}
void connectionmetadata::getSchemaTerm()
{
logMsg("connectionmetadata::getSchemaTerm() - MySQL_ConnectionMetaData::getSchemaTerm()");
try
{
DatabaseMetaData dbmeta(con->getMetaData());
ASSERT_EQUALS("schema", dbmeta->getSchemaTerm());
}
catch (sql::SQLException &e)
{
logErr(e.what());
logErr("SQLState: " + std::string(e.getSQLState()));
fail(e.what(), __FILE__, __LINE__);
}
}
void connectionmetadata::getSearchStringEscape()
{
logMsg("connectionmetadata::getSearchStringEscape - MySQL_ConnectionMetaData::getSearchStringEscape()");
try
{
DatabaseMetaData dbmeta(con->getMetaData());
ASSERT_EQUALS("\\", dbmeta->getSearchStringEscape());
}
catch (sql::SQLException &e)
{
logErr(e.what());
logErr("SQLState: " + std::string(e.getSQLState()));
fail(e.what(), __FILE__, __LINE__);
}
}
void connectionmetadata::getSQLKeywords()
{
logMsg("connectionmetadata::getSQLKeywords - MySQL_ConnectionMetaData::getSQLKeywords()");
std::string keywords(
"ACCESSIBLE,ANALYZE,ASENSITIVE,BEFORE,BIGINT,BINARY,BLOB,CALL,CHANGE,CONDITION,DATABASE,DATABASES,"
"DAY_HOUR,DAY_MICROSECOND,DAY_MINUTE,DAY_SECOND,DELAYED,DETERMINISTIC,DISTINCTROW,DIV,DUAL,EACH,"
"ELSEIF,ENCLOSED,ESCAPED,EXIT,EXPLAIN,FLOAT4,FLOAT8,FORCE,FULLTEXT,GENERAL,HIGH_PRIORITY,"
"HOUR_MICROSECOND,HOUR_MINUTE,HOUR_SECOND,IF,IGNORE,IGNORE_SERVER_IDS,INDEX,INFILE,INOUT,INT1,INT2,"
"INT3,INT4,INT8,ITERATE,KEY,KEYS,KILL,LEAVE,LIMIT,LINEAR,LINES,LOAD,LOCALTIME,LOCALTIMESTAMP,LOCK,"
"LONG,LONGBLOB,LONGTEXT,LOOP,LOW_PRIORITY,MASTER_HEARTBEAT_PERIOD,MASTER_SSL_VERIFY_SERVER_CERT,"
"MAXVALUE,MEDIUMBLOB,MEDIUMINT,MEDIUMTEXT,MIDDLEINT,MINUTE_MICROSECOND,MINUTE_SECOND,MOD,MODIFIES,"
"NO_WRITE_TO_BINLOG,OPTIMIZE,OPTIONALLY,OUT,OUTFILE,PURGE,RANGE,READ_WRITE,READS,REGEXP,RELEASE,"
"RENAME,REPEAT,REPLACE,REQUIRE,RESIGNAL,RESTRICT,RETURN,RLIKE,SCHEMAS,SECOND_MICROSECOND,SENSITIVE,"
"SEPARATOR,SHOW,SIGNAL,SLOW,SPATIAL,SPECIFIC,SQL_BIG_RESULT,SQL_CALC_FOUND_ROWS,SQL_SMALL_RESULT,"
"SQLEXCEPTION,SSL,STARTING,STRAIGHT_JOIN,TERMINATED,TINYBLOB,TINYINT,TINYTEXT,TRIGGER,UNDO,UNLOCK,"
"UNSIGNED,USE,UTC_DATE,UTC_TIME,UTC_TIMESTAMP,VARBINARY,VARCHARACTER,WHILE,XOR,YEAR_MONTH,ZEROFILL");
try
{
DatabaseMetaData dbmeta(con->getMetaData());
ASSERT_EQUALS(keywords, dbmeta->getSQLKeywords());
}
catch (sql::SQLException &e)
{
logErr(e.what());
logErr("SQLState: " + std::string(e.getSQLState()));
fail(e.what(), __FILE__, __LINE__);
}
}
void connectionmetadata::getSuperTables()
{
logMsg("connectionmetadata::getSuperTables - MySQL_ConnectionMetaData::getSuperTables()");
try
{
DatabaseMetaData dbmeta(con->getMetaData());
stmt.reset(con->createStatement());
stmt->execute("DROP TABLE IF EXISTS test");
stmt->execute("CREATE TABLE test(id INT)");
res.reset(dbmeta->getSuperTables(con->getCatalog(), con->getSchema(), "test"));
checkResultSetScrolling(res);
ASSERT(!res->next());
ResultSetMetaData resmeta(res->getMetaData());
ASSERT_EQUALS((unsigned int) 4, resmeta->getColumnCount());
ASSERT_EQUALS("TABLE_CAT", resmeta->getColumnLabel(1));
ASSERT_EQUALS("TABLE_SCHEM", resmeta->getColumnLabel(2));
ASSERT_EQUALS("TABLE_NAME", resmeta->getColumnLabel(3));
ASSERT_EQUALS("SUPERTABLE_NAME", resmeta->getColumnLabel(4));
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 connectionmetadata::getSuperTypes()
{
logMsg("connectionmetadata::getSuperTypes - MySQL_ConnectionMetaData::getSuperTypes()");
try
{
DatabaseMetaData dbmeta(con->getMetaData());
stmt.reset(con->createStatement());
stmt->execute("DROP TABLE IF EXISTS test");
stmt->execute("CREATE TABLE test(id INT)");
res.reset(dbmeta->getSuperTypes(con->getCatalog(), con->getSchema(), "test"));
checkResultSetScrolling(res);
ASSERT(!res->next());
ResultSetMetaData resmeta(res->getMetaData());
ASSERT_EQUALS((unsigned int) 6, resmeta->getColumnCount());
ASSERT_EQUALS("TYPE_CAT", resmeta->getColumnLabel(1));
ASSERT_EQUALS("TYPE_SCHEM", resmeta->getColumnLabel(2));
ASSERT_EQUALS("TYPE_NAME", resmeta->getColumnLabel(3));
ASSERT_EQUALS("SUPERTYPE_CAT", resmeta->getColumnLabel(4));
ASSERT_EQUALS("SUPERTYPE_SCHEM", resmeta->getColumnLabel(5));
ASSERT_EQUALS("SUPERTYPE_NAME", resmeta->getColumnLabel(6));
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 connectionmetadata::classAttributes()
{
logMsg("connectionmetadata::classAttributes - MySQL_ConnectionMetaData class attributes");
TODO("Check if JDBC compliance requires certain values");
try
{
DatabaseMetaData dbmeta(con->getMetaData());
ASSERT_EQUALS(0, dbmeta->attributeNoNulls);
ASSERT_EQUALS(1, dbmeta->attributeNullable);
ASSERT_EQUALS(2, dbmeta->attributeNullableUnknown);
ASSERT_EQUALS(1, dbmeta->bestRowNotPseudo);
// BUG - ASSERT_EQUALS(2, dbmeta->bestRowPseudo);
ASSERT_EQUALS(2, dbmeta->bestRowSession);
ASSERT_EQUALS(0, dbmeta->bestRowTemporary);
ASSERT_EQUALS(1, dbmeta->bestRowTransaction);
ASSERT_EQUALS(0, dbmeta->bestRowUnknown);
ASSERT_EQUALS(0, dbmeta->columnNoNulls);
ASSERT_EQUALS(1, dbmeta->columnNullable);
ASSERT_EQUALS(2, dbmeta->columnNullableUnknown);
ASSERT_EQUALS(0, dbmeta->importedKeyCascade);
// BUG - got 1 - ASSERT_EQUALS(5, dbmeta->importedKeyInitiallyDeferred);
// BUG - got 2 - ASSERT_EQUALS(6, dbmeta->importedKeyInitiallyImmediate);
ASSERT_EQUALS(3, dbmeta->importedKeyNoAction);
// BUG - got 4 - ASSERT_EQUALS(7, dbmeta->importedKeyNotDeferrable);
// BUG - got 5 - ASSERT_EQUALS(1, dbmeta->importedKeyRestrict);
// BUG - got 6 - ASSERT_EQUALS(4, dbmeta->importedKeySetDefault);
// BUG - got 7 - ASSERT_EQUALS(2, dbmeta->importedKeySetNull);
// BUG - got 0 - ASSERT_EQUALS(1, dbmeta->procedureColumnIn);
// BUG - got 1 - ASSERT_EQUALS(2, dbmeta->procedureColumnInOut);
// BUG - got 2 - ASSERT_EQUALS(4, dbmeta->procedureColumnOut);
ASSERT_EQUALS(3, dbmeta->procedureColumnResult);
// BUG - got 4 - ASSERT_EQUALS(5, dbmeta->procedureColumnReturn);
// BUG - got 5 - ASSERT_EQUALS(1, dbmeta->importedKeyRestrict);
// BUG - got 6 - ASSERT_EQUALS(4, dbmeta->importedKeySetDefault);
// BUG - got 7 - ASSERT_EQUALS(2, dbmeta->importedKeySetNull);
// BUG - got 0 - ASSERT_EQUALS(1, dbmeta->procedureColumnIn);
ASSERT_EQUALS(1, dbmeta->procedureColumnInOut);
// BUG - got 2 - ASSERT_EQUALS(4, dbmeta->procedureColumnOut);
ASSERT_EQUALS(3, dbmeta->procedureColumnResult);
// BUG - got 4 - ASSERT_EQUALS(5, dbmeta->procedureColumnReturn);
// BUG - got 5 - ASSERT_EQUALS(0, dbmeta->procedureColumnUnknown);
// BUG - got 6 - ASSERT_EQUALS(0, dbmeta->procedureNoNulls);
// BUG - got 7 - ASSERT_EQUALS(1, dbmeta->procedureNoResult);
// BUG - got 8 - ASSERT_EQUALS(1, dbmeta->procedureNullable);
// BUG - got 9 - ASSERT_EQUALS(0, dbmeta->procedureNullableUnknown);
// BUG - got 10 - ASSERT_EQUALS(2, dbmeta->procedureResultUnknown);
// BUG - got 11 - ASSERT_EQUALS(2, dbmeta->procedureReturnsResult);
// BUG - got 0 - ASSERT_EQUALS(2, dbmeta->sqlStateSQL99);
ASSERT_EQUALS(1, dbmeta->sqlStateXOpen);
// BUG - got 0 - ASSERT_EQUALS(1, dbmeta->tableIndexClustered);
// BUG - got 1 - ASSERT_EQUALS(2, dbmeta->tableIndexHashed);
// BUG - got 2 - ASSERT_EQUALS(3, dbmeta->tableIndexOther);
// BUG - got 3 - ASSERT_EQUALS(0, dbmeta->tableIndexStatistic);
ASSERT_EQUALS(0, dbmeta->typeNoNulls);
ASSERT_EQUALS(1, dbmeta->typeNullable);
ASSERT_EQUALS(2, dbmeta->typeNullableUnknown);
ASSERT_EQUALS(2, dbmeta->typePredBasic);
ASSERT_EQUALS(1, dbmeta->typePredChar);
ASSERT_EQUALS(0, dbmeta->typePredNone);
ASSERT_EQUALS(3, dbmeta->typeSearchable);
ASSERT_EQUALS(1, dbmeta->versionColumnNotPseudo);
ASSERT_EQUALS(2, dbmeta->versionColumnPseudo);
ASSERT_EQUALS(0, dbmeta->versionColumnUnknown);
}
catch (sql::SQLException &e)
{
logErr(e.what());
logErr("SQLState: " + std::string(e.getSQLState()));
fail(e.what(), __FILE__, __LINE__);
}
}
void connectionmetadata::getColumnsTypeConversions()
{
logMsg("connectionmetadata::getColumnsTypeConversions() - MySQL_ConnectionMetaData::getColumns");
std::vector<columndefinition>::iterator it;
std::stringstream msg;
int i;
bool got_warning;
SKIP("It's not clear whether some conversion should really work in the way this test expects. Thus either test or connector should be fixed at some point.");
try
{
DatabaseMetaData dbmeta(con->getMetaData());
stmt.reset(con->createStatement());
got_warning=false;
logMsg("... looping over all kinds of column types");
for (it=columns.begin(), i=0; it != columns.end(); i++, it++)
{
stmt->execute("DROP TABLE IF EXISTS test");
msg.str("");
msg << "CREATE TABLE test(dummy TIMESTAMP, id " << it->sqldef << ")";
try
{
stmt->execute(msg.str());
msg.str("");
msg << "... testing " << it->sqldef;
logMsg(msg.str());
}
catch (sql::SQLException &)
{
msg.str("");
msg << "... skipping " << it->sqldef;
logMsg(msg.str());
continue;
}
res.reset(dbmeta->getColumns(con->getCatalog(), con->getSchema(), "test", "id"));
checkResultSetScrolling(res);
ASSERT_EQUALS(true, res->next());
// string -> xyz
ASSERT_EQUALS("test", res->getString("TABLE_NAME"));
ASSERT_EQUALS(false, res->wasNull());
ASSERT_EQUALS(res->getString(3), res->getString("TABLE_NAME"));
ASSERT_EQUALS(true, res->getBoolean("TABLE_NAME"));
ASSERT_EQUALS(false, res->wasNull());
ASSERT_EQUALS(res->getBoolean(3), res->getBoolean("TABLE_NAME"));
ASSERT_EQUALS((int64_t) 0, res->getInt64("TABLE_NAME"));
ASSERT_EQUALS(false, res->wasNull());
ASSERT_EQUALS(res->getInt64(3), res->getInt64("TABLE_NAME"));
ASSERT_EQUALS((uint64_t) 0, res->getUInt64("TABLE_NAME"));
ASSERT_EQUALS(false, res->wasNull());
ASSERT_EQUALS(res->getUInt64(3), res->getUInt64("TABLE_NAME"));
ASSERT_EQUALS((double) 0, res->getDouble("TABLE_NAME"));
ASSERT_EQUALS(false, res->wasNull());
ASSERT_EQUALS(res->getDouble(3), res->getDouble("TABLE_NAME"));
ASSERT_EQUALS((int) 0, res->getInt("TABLE_NAME"));
ASSERT_EQUALS(false, res->wasNull());
ASSERT_EQUALS(res->getInt(3), res->getInt("TABLE_NAME"));
ASSERT_EQUALS((unsigned int) 0, res->getUInt("TABLE_NAME"));
ASSERT_EQUALS(false, res->wasNull());
ASSERT_EQUALS(res->getUInt(3), res->getUInt("TABLE_NAME"));
ASSERT_EQUALS(false, res->isNull("TABLE_NAME"));
ASSERT_EQUALS(false, res->wasNull());
ASSERT_EQUALS(res->isNull(3), res->isNull("TABLE_NAME"));
// integer -> xyz
if (it->decimal_digits != res->getInt("DECIMAL_DIGITS"))
{
msg.str("");
msg << "...\t\tWARNING: expecting DECIMAL_DIGITS = (int)'" << it->decimal_digits << "'";
msg << " got (int)'" << res->getString("DECIMAL_DIGITS") << "'";
logMsg(msg.str());
got_warning=true;
}
ASSERT_EQUALS(false, res->wasNull());
ASSERT_EQUALS(res->getInt(9), res->getInt("DECIMAL_DIGITS"));
msg.str("");
if (0 == it->decimal_digits)
{
msg << "0";
}
else
{
msg << it->decimal_digits;
}
if (msg.str() != res->getString("DECIMAL_DIGITS"))
{
msg.str("");
msg << "...\t\tWARNING: expecting DECIMAL_DIGITS = '" << it->decimal_digits << "'";
msg << " length() is '" << msg.str().length() << "'";
msg << " got '" << res->getString("DECIMAL_DIGITS") << "'";
msg << " length() is '" << res->getString("DECIMAL_DIGITS").length() << "'";
logMsg(msg.str());
got_warning=true;
}
else
{
// If string and int are broken, the rest is broken as well - you can bet!
ASSERT_EQUALS(false, res->wasNull());
ASSERT_EQUALS(res->getString(9), res->getString("DECIMAL_DIGITS"));
ASSERT_EQUALS(it->decimal_digits != 0, res->getBoolean("DECIMAL_DIGITS"));
ASSERT_EQUALS(false, res->wasNull());
ASSERT_EQUALS(res->getBoolean(9), res->getBoolean("DECIMAL_DIGITS"));
ASSERT_EQUALS((int64_t) it->decimal_digits, res->getInt64("DECIMAL_DIGITS"));
ASSERT_EQUALS(false, res->wasNull());
ASSERT_EQUALS(res->getInt64(9), res->getInt64("DECIMAL_DIGITS"));
ASSERT_EQUALS((uint64_t) it->decimal_digits, res->getUInt64("DECIMAL_DIGITS"));
ASSERT_EQUALS(false, res->wasNull());
ASSERT_EQUALS(res->getUInt64(9), res->getUInt64("DECIMAL_DIGITS"));
ASSERT_EQUALS((double) it->decimal_digits, res->getDouble("DECIMAL_DIGITS"));
ASSERT_EQUALS(false, res->wasNull());
ASSERT_EQUALS(res->getDouble(9), res->getDouble("DECIMAL_DIGITS"));
ASSERT_EQUALS((int32_t) it->decimal_digits, res->getInt("DECIMAL_DIGITS"));
ASSERT_EQUALS(false, res->wasNull());
ASSERT_EQUALS(res->getInt(9), res->getInt("DECIMAL_DIGITS"));
ASSERT_EQUALS((uint32_t) it->decimal_digits, res->getUInt("DECIMAL_DIGITS"));
ASSERT_EQUALS(false, res->wasNull());
ASSERT_EQUALS(res->getUInt(9), res->getUInt("DECIMAL_DIGITS"));
ASSERT_EQUALS(false, res->isNull(9));
ASSERT_EQUALS(res->isNull(9), res->isNull("DECIMAL_DIGITS"));
ASSERT_EQUALS(false, res->wasNull());
}
try
{
res->isNull(0);
FAIL("Invalid column index");
}
catch (sql::SQLException &)
{
}
try
{
res->isNull("invalid column index");
FAIL("Invalid column index");
}
catch (sql::SQLException &)
{
}
stmt->execute("DROP TABLE IF EXISTS test");
}
stmt->execute("DROP TABLE IF EXISTS test");
res.reset(dbmeta->getColumns(con->getCatalog(), con->getSchema(), "test", "id"));
ASSERT(!res->next());
}
catch (sql::SQLException &e)
{
logErr(e.what());
logErr("SQLState: " + std::string(e.getSQLState()));
fail(e.what(), __FILE__, __LINE__);
}
try
{
res->isNull(1);
FAIL("Not on resultset, should fail");
}
catch (sql::SQLException &)
{
}
try
{
res->isNull("not on resultset and unknown column");
FAIL("Not on resultset, should fail");
}
catch (sql::SQLException &)
{
}
if (got_warning)
FAIL("See --verbose warnings!");
}
/* Simple testcase of getBestRowIdentifier returns columns making UNIQUE not Null filters
in case of primary key is not present
*/
void connectionmetadata::bestIdUniqueNotNull()
{
createSchemaObject("TABLE", "bestIdUniqueNotNull", "(id int not null, value varchar(25),"
"UNIQUE INDEX(id))");
createSchemaObject("TABLE", "bestIdUniqueNull", "(id int, value varchar(25),"
"UNIQUE INDEX(id))");
DatabaseMetaData dbmeta(con->getMetaData());
res.reset(dbmeta->getBestRowIdentifier(con->getCatalog(), con->getSchema(), "bestIdUniqueNotNull", 0, false));
ASSERT(res->next());
ASSERT_EQUALS("id", res->getString(2));
ASSERT(!res->next());
res.reset(dbmeta->getBestRowIdentifier(con->getCatalog(), con->getSchema(), "bestIdUniqueNull", 0, false));
ASSERT(!res->next());
}
void connectionmetadata::getSchemaCollation()
{
logMsg("connectionmetadata::getSchemaCollation - MySQL_ConnectionMetaData::getSchemaCollation()");
try
{
ResultSetMetaData resmeta;
DatabaseMetaData dbmeta(con->getMetaData());
stmt.reset(con->createStatement());
stmt->execute("DROP DATABASE IF EXISTS collationTestDatabase");
stmt->execute("CREATE DATABASE collationTestDatabase CHARACTER SET utf8 COLLATE utf8_bin");
/* SchemaCollation */
res.reset(dbmeta->getSchemaCollation(con->getCatalog(), "collationTestDatabase"));
ASSERT(res->next());
resmeta.reset(res->getMetaData());
ASSERT_EQUALS((unsigned int) 3, resmeta->getColumnCount());
ASSERT_EQUALS("SCHEMA_CAT", resmeta->getColumnLabel(1));
ASSERT_EQUALS("SCHEMA_NAME", resmeta->getColumnLabel(2));
ASSERT_EQUALS("SCHEMA_COLLATION", resmeta->getColumnLabel(3));
ASSERT(res->getString("SCHEMA_NAME").caseCompare("collationTestDatabase") == 0);
ASSERT_EQUALS("utf8_bin", res->getString("SCHEMA_COLLATION"));
stmt->execute("DROP DATABASE IF EXISTS collationTestDatabase");
}
catch (sql::SQLFeatureNotImplementedException &e)
{
SKIP(e.what());
}
catch (sql::SQLException &e)
{
logErr(e.what());
logErr("SQLState: " + std::string(e.getSQLState()));
fail(e.what(), __FILE__, __LINE__);
}
}
void connectionmetadata::getSchemaCharset()
{
logMsg("connectionmetadata::getSchemaCharset - MySQL_ConnectionMetaData::getSchemaCharset()");
try
{
ResultSetMetaData resmeta;
DatabaseMetaData dbmeta(con->getMetaData());
stmt.reset(con->createStatement());
stmt->execute("DROP DATABASE IF EXISTS charsetTestDatabase");
stmt->execute("CREATE DATABASE charsetTestDatabase CHARACTER SET utf8 COLLATE utf8_bin");
/* SchemaCharset */
res.reset(dbmeta->getSchemaCharset(con->getCatalog(), "charsetTestDatabase"));
ASSERT(res->next());
resmeta.reset(res->getMetaData());
ASSERT_EQUALS((unsigned int) 3, resmeta->getColumnCount());
ASSERT_EQUALS("SCHEMA_CAT", resmeta->getColumnLabel(1));
ASSERT_EQUALS("SCHEMA_NAME", resmeta->getColumnLabel(2));
ASSERT_EQUALS("SCHEMA_CHARSET", resmeta->getColumnLabel(3));
ASSERT(res->getString("SCHEMA_NAME").caseCompare("charsetTestDatabase") == 0);
ASSERT_EQUALS("utf8", res->getString("SCHEMA_CHARSET"));
stmt->execute("DROP DATABASE IF EXISTS charsetTestDatabase");
}
catch (sql::SQLFeatureNotImplementedException & e)
{
SKIP(e.what());
}
catch (sql::SQLException &e)
{
logErr(e.what());
logErr("SQLState: " + std::string(e.getSQLState()));
fail(e.what(), __FILE__, __LINE__);
}
}
void connectionmetadata::getTableCollation()
{
logMsg("connectionmetadata::getTableCollation - MySQL_ConnectionMetaData::getTableCollation()");
try
{
ResultSetMetaData resmeta;
DatabaseMetaData dbmeta(con->getMetaData());
stmt.reset(con->createStatement());
stmt->execute("DROP DATABASE IF EXISTS collationTestDatabase");
stmt->execute("CREATE DATABASE collationTestDatabase CHARACTER SET utf8 COLLATE utf8_bin");
stmt->execute("DROP TABLE IF EXISTS collationTestDatabase.collationTestTable");
stmt->execute("CREATE TABLE collationTestDatabase.collationTestTable(id INT) CHARACTER SET latin1 COLLATE latin1_general_ci");
stmt->execute("DROP TABLE IF EXISTS collationTestDatabase.collationTestTableAnother");
stmt->execute("CREATE TABLE collationTestDatabase.collationTestTableAnother(id INT) CHARACTER SET utf8 COLLATE utf8_bin");
/* TableCollation */
res.reset(dbmeta->getTableCollation(con->getCatalog(), "collationTestDatabase", "%collationTestTable%"));
ASSERT(res->next());
resmeta.reset(res->getMetaData());
ASSERT_EQUALS((unsigned int) 4, resmeta->getColumnCount());
ASSERT_EQUALS("TABLE_CAT", resmeta->getColumnLabel(1));
ASSERT_EQUALS("TABLE_SCHEMA", resmeta->getColumnLabel(2));
ASSERT_EQUALS("TABLE_NAME", resmeta->getColumnLabel(3));
ASSERT_EQUALS("TABLE_COLLATION", resmeta->getColumnLabel(4));
ASSERT(res->getString("TABLE_SCHEMA").caseCompare("collationTestDatabase") == 0);
ASSERT(res->getString("TABLE_NAME").caseCompare("collationTestTable") == 0);
ASSERT_EQUALS("latin1_general_ci", res->getString("TABLE_COLLATION"));
ASSERT(res->next());
ASSERT(res->getString("TABLE_SCHEMA").caseCompare("collationTestDatabase") == 0);
ASSERT(res->getString("TABLE_NAME").caseCompare("collationTestTableAnother") == 0);
ASSERT_EQUALS("utf8_bin", res->getString("TABLE_COLLATION"));
stmt->execute("DROP DATABASE IF EXISTS collationTestDatabase");
}
catch (sql::SQLFeatureNotImplementedException & e)
{
SKIP(e.what());
}
catch (sql::SQLException &e)
{
logErr(e.what());
logErr("SQLState: " + std::string(e.getSQLState()));
fail(e.what(), __FILE__, __LINE__);
}
}
void connectionmetadata::getTableCharset()
{
logMsg("connectionmetadata::getTableCharset - MySQL_ConnectionMetaData::getTableCharset()");
try
{
ResultSetMetaData resmeta;
DatabaseMetaData dbmeta(con->getMetaData());
stmt.reset(con->createStatement());
stmt->execute("DROP DATABASE IF EXISTS charsetTestDatabase");
stmt->execute("CREATE DATABASE charsetTestDatabase CHARACTER SET utf8 COLLATE utf8_bin");
stmt->execute("DROP TABLE IF EXISTS charsetTestDatabase.charsetTestTable");
stmt->execute("CREATE TABLE charsetTestDatabase.charsetTestTable(id INT) CHARACTER SET latin1 COLLATE latin1_general_ci");
stmt->execute("DROP TABLE IF EXISTS charsetTestDatabase.charsetTestTableAnother");
stmt->execute("CREATE TABLE charsetTestDatabase.charsetTestTableAnother(id INT) CHARACTER SET utf8 COLLATE utf8_bin");
/* TableCharset */
res.reset(dbmeta->getTableCharset(con->getCatalog(), "charsetTestDatabase", "%charsetTestTable%"));
ASSERT(res->next());
resmeta.reset(res->getMetaData());
ASSERT_EQUALS((unsigned int) 4, resmeta->getColumnCount());
ASSERT_EQUALS("TABLE_CAT", resmeta->getColumnLabel(1));
ASSERT_EQUALS("TABLE_SCHEMA", resmeta->getColumnLabel(2));
ASSERT_EQUALS("TABLE_NAME", resmeta->getColumnLabel(3));
ASSERT_EQUALS("TABLE_CHARSET", resmeta->getColumnLabel(4));
ASSERT(res->getString("TABLE_SCHEMA").caseCompare("charsetTestDatabase") == 0);
ASSERT(res->getString("TABLE_NAME").caseCompare("charsetTestTable") == 0);
ASSERT_EQUALS("latin1", res->getString("TABLE_CHARSET"));
ASSERT(res->next());
ASSERT(res->getString("TABLE_SCHEMA").caseCompare("charsetTestDatabase") == 0);
ASSERT(res->getString("TABLE_NAME").caseCompare("charsetTestTableAnother") == 0);
ASSERT_EQUALS("utf8", res->getString("TABLE_CHARSET"));
stmt->execute("DROP DATABASE IF EXISTS charsetTestDatabase");
}
catch (sql::SQLFeatureNotImplementedException & e)
{
SKIP(e.what());
}
catch (sql::SQLException &e)
{
logErr(e.what());
logErr("SQLState: " + std::string(e.getSQLState()));
fail(e.what(), __FILE__, __LINE__);
}
}
void connectionmetadata::getTables()
{
logMsg("connectionmetadata::getTables - MySQL_ConnectionMetaData::getTables()");
try
{
DatabaseMetaData dbmeta(con->getMetaData());
std::list< sql::SQLString > tableTypes;
stmt.reset(con->createStatement());
stmt->execute("DROP TABLE IF EXISTS testtable1");
stmt->execute("CREATE TABLE testtable1(id INT)");
stmt->execute("DROP VIEW IF EXISTS testview1");
stmt->execute("CREATE VIEW testview1 AS SELECT * FROM testtable1");
/* for tableType = TABLE */
tableTypes.clear();
tableTypes.push_back(sql::SQLString("TABLE"));
res.reset(dbmeta->getTables("", "%", "testtable%", tableTypes));
ASSERT(res->next());
ASSERT_EQUALS(res->getString(3), "testtable1");
ASSERT_EQUALS(res->getString(4), "TABLE");
/* for tableType = VIEW */
tableTypes.clear();
tableTypes.push_back(sql::SQLString("VIEW"));
res.reset(dbmeta->getTables("", "%", "testview%", tableTypes));
ASSERT(res->next());
ASSERT_EQUALS(res->getString(3), "testview1");
ASSERT_EQUALS(res->getString(4), "VIEW");
stmt->execute("DROP TABLE IF EXISTS testtable1");
stmt->execute("DROP VIEW IF EXISTS testview1");
}
catch (sql::SQLException &e)
{
logErr(e.what());
logErr("SQLState: " + std::string(e.getSQLState()));
fail(e.what(), __FILE__, __LINE__);
}
}
void connectionmetadata::bugCpp25()
{
logMsg("bugs::bugCpp25");
DatabaseMetaData dbmeta(con->getMetaData());
uint64_t major = dbmeta->getDatabaseMajorVersion(), minor = dbmeta->getDatabaseMinorVersion(), patch = dbmeta->getDatabasePatchVersion();
logMsg("Server version from metadata object: " + std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(patch));
ASSERT(major > 2 && major < 100);
res.reset(stmt->executeQuery("SELECT version()"));
res->next();
sql::SQLString verFromServer = res->getString(1);
logMsg("Server version from SQL query: " + verFromServer);
size_t dash= verFromServer.find_first_of('-');
if (dash != std::string::npos) {
verFromServer= verFromServer.substr(0, dash);
}
// More to test connector's split
#ifndef _WIN32
// In case of mixing relese/debug versions, split may crash on Windows. Thus leaving it to be tested on other platforms
// On Windows doing testing the same without split
sql::mariadb::Tokens verParts(sql::mariadb::split(verFromServer, "."));
ASSERT_EQUALS(3ULL, static_cast<uint64_t>(verParts->size()));
ASSERT_EQUALS(major, std::stoul((*verParts)[0].c_str()));
if (std::getenv("MAXSCALE_TEST_DISABLE") == nullptr) {
ASSERT_EQUALS(minor, std::stoul((*verParts)[1].c_str()));
std::size_t dashPos = (*verParts)[2].find_first_of('-');
ASSERT_EQUALS(patch, std::stoul(dashPos == std::string::npos ? (*verParts)[2].c_str() : (*verParts)[2].substr(0, dashPos).c_str()));
}
// And even some more testing of the internal split
sql::mariadb::Tokens csv(sql::mariadb::split("575,1,,22,,", ","));
ASSERT_EQUALS(6ULL, static_cast<uint64_t>(csv->size()));
ASSERT_EQUALS("575", (*csv)[0]);
ASSERT_EQUALS("1", (*csv)[1]);
ASSERT_EQUALS("", (*csv)[2]);
ASSERT_EQUALS("22", (*csv)[3]);
ASSERT_EQUALS("", (*csv)[4]);
ASSERT_EQUALS("", (*csv)[5]);
#else
TestList verParts;
StringUtils::split(verParts, verFromServer.c_str(), ".", true, true);
ASSERT_EQUALS(3ULL, static_cast<uint64_t>(verParts.size()));
ASSERT_EQUALS(major, std::stoul(verParts[0].c_str()));
ASSERT_EQUALS(minor, std::stoul(verParts[1].c_str()));
std::size_t dashPos = verParts[2].find_first_of('-');
if (std::getenv("MAXSCALE_TEST_DISABLE") == nullptr) {
ASSERT_EQUALS(patch, std::stoul(dashPos == std::string::npos ? verParts[2].c_str() : verParts[2].substr(0, dashPos).c_str()));
}
#endif // !_WIN32
}
} /* namespace connectionmetadata */
} /* namespace testsuite */