You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by is...@apache.org on 2020/12/09 15:13:23 UTC
[ignite] branch master updated: IGNITE-13801: Fix Ab Initio related
ODBC issues
This is an automated email from the ASF dual-hosted git repository.
isapego pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite.git
The following commit(s) were added to refs/heads/master by this push:
new 27062ee IGNITE-13801: Fix Ab Initio related ODBC issues
27062ee is described below
commit 27062ee6b1c5d934d25b27089177b920d4c70417
Author: Igor Sapego <is...@apache.org>
AuthorDate: Wed Dec 9 18:12:16 2020 +0300
IGNITE-13801: Fix Ab Initio related ODBC issues
This closes #8528
---
.../platforms/cpp/odbc-test/include/test_utils.h | 6 +-
.../cpp/odbc-test/src/attributes_test.cpp | 20 ++
.../cpp/odbc-test/src/authentication_test.cpp | 91 +++++++-
.../cpp/odbc-test/src/meta_queries_test.cpp | 260 +++++++++++++++++++++
modules/platforms/cpp/odbc-test/src/test_utils.cpp | 8 +-
.../platforms/cpp/odbc-test/src/utility_test.cpp | 64 +++++
.../ignite/odbc/config/connection_string_parser.h | 6 +
.../cpp/odbc/include/ignite/odbc/dsn_config.h | 5 +-
.../platforms/cpp/odbc/os/win/src/system_dsn.cpp | 4 +-
.../odbc/src/config/connection_string_parser.cpp | 18 +-
modules/platforms/cpp/odbc/src/connection.cpp | 2 +-
modules/platforms/cpp/odbc/src/dsn_config.cpp | 12 +-
.../platforms/cpp/odbc/src/meta/column_meta.cpp | 2 +-
modules/platforms/cpp/odbc/src/odbc.cpp | 5 +-
modules/platforms/cpp/odbc/src/statement.cpp | 2 +
modules/platforms/cpp/odbc/src/utility.cpp | 14 +-
16 files changed, 491 insertions(+), 28 deletions(-)
diff --git a/modules/platforms/cpp/odbc-test/include/test_utils.h b/modules/platforms/cpp/odbc-test/include/test_utils.h
index 1f2aeec..6cac2af 100644
--- a/modules/platforms/cpp/odbc-test/include/test_utils.h
+++ b/modules/platforms/cpp/odbc-test/include/test_utils.h
@@ -121,18 +121,20 @@ namespace ignite_test
*
* @param handleType Type of the handle.
* @param handle Handle.
+ * @param idx Error record index.
* @return Error state.
*/
- std::string GetOdbcErrorState(SQLSMALLINT handleType, SQLHANDLE handle);
+ std::string GetOdbcErrorState(SQLSMALLINT handleType, SQLHANDLE handle, int idx = 1);
/**
* Extract error message.
*
* @param handleType Type of the handle.
* @param handle Handle.
+ * @param idx Error record index.
* @return Error message.
*/
- std::string GetOdbcErrorMessage(SQLSMALLINT handleType, SQLHANDLE handle);
+ std::string GetOdbcErrorMessage(SQLSMALLINT handleType, SQLHANDLE handle, int idx = 1);
/**
* @return Test config directory path.
diff --git a/modules/platforms/cpp/odbc-test/src/attributes_test.cpp b/modules/platforms/cpp/odbc-test/src/attributes_test.cpp
index 0519f61..278a066 100644
--- a/modules/platforms/cpp/odbc-test/src/attributes_test.cpp
+++ b/modules/platforms/cpp/odbc-test/src/attributes_test.cpp
@@ -243,4 +243,24 @@ BOOST_AUTO_TEST_CASE(ConnectionAttributeLoginTimeout)
BOOST_REQUIRE_EQUAL(timeout, 42);
}
+/**
+ * Check that environment returns expected version of ODBC standard.
+ *
+ * 1. Start node.
+ * 2. Establish connection using ODBC driver.
+ * 3. Get current ODBC version from env handle.
+ * 4. Check that version is of the expected value.
+ */
+BOOST_AUTO_TEST_CASE(TestSQLGetEnvAttrDriverVersion)
+{
+ Connect("DRIVER={Apache Ignite};address=127.0.0.1:11110;schema=cache");
+
+ SQLINTEGER version;
+ SQLRETURN ret = SQLGetEnvAttr(env, SQL_ATTR_ODBC_VERSION, &version, 0, 0);
+
+ ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_ENV, env);
+
+ BOOST_CHECK_EQUAL(version, SQL_OV_ODBC3);
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/modules/platforms/cpp/odbc-test/src/authentication_test.cpp b/modules/platforms/cpp/odbc-test/src/authentication_test.cpp
index 5a77370..e082413 100644
--- a/modules/platforms/cpp/odbc-test/src/authentication_test.cpp
+++ b/modules/platforms/cpp/odbc-test/src/authentication_test.cpp
@@ -85,8 +85,6 @@ struct AuthenticationTestSuiteFixture : odbc::OdbcTestSuite
*/
static std::string MakeConnectionString(const std::string& user, const std::string& pass)
{
- std::string cfgDirPath = GetTestConfigDir();
-
std::stringstream connectString;
connectString <<
@@ -122,6 +120,95 @@ BOOST_AUTO_TEST_CASE(TestConnectionDefaultAuthSuccess)
InsertTestBatch(11, 20, 9);
}
+/**
+ * Check that connection with UID and PWD arguments established successfully.
+ *
+ * 1. Start test node with configured authentication.
+ * 2. Establish connection using UID and PWD arguments. Check that it established successfully.
+ * 3. Check that connection can be used successfully for SQL insert and select operations.
+ */
+BOOST_AUTO_TEST_CASE(TestConnectionLegacyAuthSuccess)
+{
+ std::stringstream comp;
+
+ comp <<
+ "DRIVER={Apache Ignite};"
+ "ADDRESS=127.0.0.1:11110;"
+ "SCHEMA=cache;"
+ "UID=" << defaultUser << ";"
+ "PWD=" << defaultPass << ";";
+
+ std::string connStr = comp.str();
+
+ Connect(connStr);
+
+ InsertTestStrings(10, false);
+ InsertTestBatch(11, 20, 9);
+}
+
+/**
+ * Check that connection with UID, USER, PWD and PASSWORD arguments established successfully.
+ *
+ * 1. Start test node with configured authentication.
+ * 2. Establish connection using UID, USER, PWD and PASSWORD arguments. Check that it established successfully.
+ * 3. Check that connection returns warning that password and user arguments duplicated.
+ * 4. Check that connection can be used successfully for SQL insert and select operations.
+ */
+BOOST_AUTO_TEST_CASE(TestConnectionBothAuthSuccess)
+{
+ std::stringstream comp;
+
+ comp <<
+ "DRIVER={Apache Ignite};"
+ "ADDRESS=127.0.0.1:11110;"
+ "SCHEMA=cache;"
+ "UID=" << defaultUser << ";"
+ "PWD=" << defaultPass << ";"
+ "USER=" << defaultUser << ";"
+ "PASSWORD=" << defaultPass << ";";
+
+ std::string connStr = comp.str();
+
+ Prepare();
+
+ // Connect string
+ std::vector<SQLCHAR> connectStr0(connStr.begin(), connStr.end());
+
+ SQLCHAR outstr[ODBC_BUFFER_SIZE];
+ SQLSMALLINT outstrlen;
+
+ // Connecting to ODBC server.
+ SQLRETURN ret = SQLDriverConnect(dbc, NULL, &connectStr0[0], static_cast<SQLSMALLINT>(connectStr0.size()),
+ outstr, sizeof(outstr), &outstrlen, SQL_DRIVER_COMPLETE);
+
+ if (!SQL_SUCCEEDED(ret))
+ BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_DBC, dbc));
+
+ BOOST_CHECK_EQUAL(ret, SQL_SUCCESS_WITH_INFO);
+
+ std::string message = GetOdbcErrorMessage(SQL_HANDLE_DBC, dbc);
+
+ BOOST_CHECK(!message.empty());
+
+ BOOST_CHECK(message.find("01S02") != std::string::npos);
+ BOOST_CHECK(message.find("Re-writing PASSWORD (have you specified it several times?") != std::string::npos);
+
+ message = GetOdbcErrorMessage(SQL_HANDLE_DBC, dbc, 2);
+
+ BOOST_CHECK(!message.empty());
+
+ BOOST_CHECK(message.find("01S02") != std::string::npos);
+ BOOST_CHECK(message.find("Re-writing USER (have you specified it several times?") != std::string::npos);
+
+ // Allocate a statement handle
+ SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt);
+
+ BOOST_REQUIRE(stmt != NULL);
+
+ InsertTestStrings(10, false);
+ InsertTestBatch(11, 20, 9);
+}
+
BOOST_AUTO_TEST_CASE(TestConnectionAuthReject)
{
std::string state = ExpectConnectionReject(MakeConnectionString("unknown", "unknown"));
diff --git a/modules/platforms/cpp/odbc-test/src/meta_queries_test.cpp b/modules/platforms/cpp/odbc-test/src/meta_queries_test.cpp
index 04f7692..05a0e46 100644
--- a/modules/platforms/cpp/odbc-test/src/meta_queries_test.cpp
+++ b/modules/platforms/cpp/odbc-test/src/meta_queries_test.cpp
@@ -132,6 +132,212 @@ struct MetaQueriesTestSuiteFixture : public odbc::OdbcTestSuite
}
/**
+ * Check result set column metadata using SQLDescribeCol.
+ *
+ * @param stmt Statement.
+ * @param idx Index.
+ * @param expName Expected name.
+ * @param expDataType Expected data type.
+ * @param expSize Expected column size.
+ * @param expScale Expected column scale.
+ * @param expNullability expected nullability.
+ */
+ void CheckColumnMetaWithSQLDescribeCol(SQLHSTMT stmt, SQLUSMALLINT idx, const std::string& expName,
+ SQLSMALLINT expDataType, SQLULEN expSize, SQLSMALLINT expScale, SQLSMALLINT expNullability)
+ {
+ std::vector<SQLCHAR> name(ODBC_BUFFER_SIZE);
+ SQLSMALLINT nameLen = 0;
+ SQLSMALLINT dataType = 0;
+ SQLULEN size;
+ SQLSMALLINT scale;
+ SQLSMALLINT nullability;
+
+ SQLRETURN ret = SQLDescribeCol(stmt, idx, &name[0], (SQLSMALLINT)name.size(), &nameLen, &dataType, &size, &scale, &nullability);
+ ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
+
+ BOOST_CHECK_GE(nameLen, 0);
+ BOOST_CHECK_LE(nameLen, static_cast<SQLSMALLINT>(ODBC_BUFFER_SIZE));
+
+ std::string nameStr(name.begin(), name.begin() + nameLen);
+
+ BOOST_CHECK_EQUAL(nameStr, expName);
+ BOOST_CHECK_EQUAL(dataType, expDataType);
+ BOOST_CHECK_EQUAL(size, expSize);
+ BOOST_CHECK_EQUAL(scale, expScale);
+ BOOST_CHECK_EQUAL(nullability, expNullability);
+ }
+
+ /**
+ * @param func Function to call before tests. May be PrepareQuery or ExecQuery.
+ *
+ * 1. Start node.
+ * 2. Connect to node using ODBC.
+ * 3. Create table with decimal and char columns with specified size and scale.
+ * 4. Execute or prepare statement.
+ * 5. Check presicion and scale of every column using SQLDescribeCol.
+ */
+ template<typename F>
+ void CheckSQLDescribeColPrecisionAndScale(F func)
+ {
+ Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11110;SCHEMA=PUBLIC");
+
+ SQLRETURN ret = ExecQuery(
+ "create table TestScalePrecision("
+ " id int primary key,"
+ " dec1 decimal(3,0),"
+ " dec2 decimal(42,12),"
+ " dec3 decimal,"
+ " char1 char(3),"
+ " char2 char(42),"
+ " char3 char,"
+ " vchar varchar"
+ ")");
+
+ ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
+
+ ret = SQLFreeStmt(stmt, SQL_CLOSE);
+ ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
+
+ ret = ExecQuery(
+ "insert into "
+ "TestScalePrecision(id, dec1, dec2, dec3, char1, char2, char3, vchar) "
+ "values (1, 12, 160.23, -1234.56789, 'TST', 'Lorem Ipsum', 'Some test value', 'Some test varchar')");
+
+ ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
+
+ ret = SQLFreeStmt(stmt, SQL_CLOSE);
+ ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
+
+ ret = (this->*func)("select id, dec1, dec2, dec3, char1, char2, char3, vchar from PUBLIC.TestScalePrecision");
+ ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
+
+ SQLSMALLINT columnCount = 0;
+
+ ret = SQLNumResultCols(stmt, &columnCount);
+ ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
+
+ BOOST_CHECK_EQUAL(columnCount, 8);
+
+ CheckColumnMetaWithSQLDescribeCol(stmt, 1, "ID", SQL_INTEGER, 10, 0, SQL_NULLABLE_UNKNOWN);
+ CheckColumnMetaWithSQLDescribeCol(stmt, 2, "DEC1", SQL_DECIMAL, 3, 0, SQL_NULLABLE_UNKNOWN);
+ CheckColumnMetaWithSQLDescribeCol(stmt, 3, "DEC2", SQL_DECIMAL, 42, 12, SQL_NULLABLE_UNKNOWN);
+ CheckColumnMetaWithSQLDescribeCol(stmt, 4, "DEC3", SQL_DECIMAL, 65535, 32767, SQL_NULLABLE_UNKNOWN);
+ CheckColumnMetaWithSQLDescribeCol(stmt, 5, "CHAR1", SQL_VARCHAR, 3, 0, SQL_NULLABLE_UNKNOWN);
+ CheckColumnMetaWithSQLDescribeCol(stmt, 6, "CHAR2", SQL_VARCHAR, 42, 0, SQL_NULLABLE_UNKNOWN);
+ CheckColumnMetaWithSQLDescribeCol(stmt, 7, "CHAR3", SQL_VARCHAR, 2147483647, 0, SQL_NULLABLE_UNKNOWN);
+ CheckColumnMetaWithSQLDescribeCol(stmt, 8, "VCHAR", SQL_VARCHAR, 2147483647, 0, SQL_NULLABLE_UNKNOWN);
+ }
+
+ /**
+ * Check result set column metadata using SQLColAttribute.
+ *
+ * @param stmt Statement.
+ * @param idx Index.
+ * @param expName Expected name.
+ * @param expDataType Expected data type.
+ * @param expSize Expected column size.
+ * @param expScale Expected column scale.
+ * @param expNullability expected nullability.
+ */
+ void CheckColumnMetaWithSQLColAttribute(SQLHSTMT stmt, SQLUSMALLINT idx, const std::string& expName,
+ SQLLEN expDataType, SQLULEN expSize, SQLLEN expScale, SQLLEN expNullability)
+ {
+ std::vector<SQLCHAR> name(ODBC_BUFFER_SIZE);
+ SQLSMALLINT nameLen = 0;
+ SQLLEN dataType = 0;
+ SQLLEN size;
+ SQLLEN scale;
+ SQLLEN nullability;
+
+ SQLRETURN ret = SQLColAttribute(stmt, idx, SQL_DESC_NAME, &name[0], (SQLSMALLINT)name.size(), &nameLen, 0);
+ ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
+
+ ret = SQLColAttribute(stmt, idx, SQL_DESC_TYPE, 0, 0, 0, &dataType);
+ ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
+
+ ret = SQLColAttribute(stmt, idx, SQL_DESC_PRECISION, 0, 0, 0, &size);
+ ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
+
+ ret = SQLColAttribute(stmt, idx, SQL_DESC_SCALE, 0, 0, 0, &scale);
+ ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
+
+ ret = SQLColAttribute(stmt, idx, SQL_DESC_NULLABLE, 0, 0, 0, &nullability);
+ ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
+
+ BOOST_CHECK_GE(nameLen, 0);
+ BOOST_CHECK_LE(nameLen, static_cast<SQLSMALLINT>(ODBC_BUFFER_SIZE));
+
+ std::string nameStr(name.begin(), name.begin() + nameLen);
+
+ BOOST_CHECK_EQUAL(nameStr, expName);
+ BOOST_CHECK_EQUAL(dataType, expDataType);
+ BOOST_CHECK_EQUAL(size, expSize);
+ BOOST_CHECK_EQUAL(scale, expScale);
+ BOOST_CHECK_EQUAL(nullability, expNullability);
+ }
+
+ /**
+ * @param func Function to call before tests. May be PrepareQuery or ExecQuery.
+ *
+ * 1. Start node.
+ * 2. Connect to node using ODBC.
+ * 3. Create table with decimal and char columns with specified size and scale.
+ * 4. Execute or prepare statement.
+ * 5. Check presicion and scale of every column using SQLColAttribute.
+ */
+ template<typename F>
+ void CheckSQLColAttributePrecisionAndScale(F func)
+ {
+ Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11110;SCHEMA=PUBLIC");
+
+ SQLRETURN ret = ExecQuery(
+ "create table TestScalePrecision("
+ " id int primary key,"
+ " dec1 decimal(3,0),"
+ " dec2 decimal(42,12),"
+ " dec3 decimal,"
+ " char1 char(3),"
+ " char2 char(42),"
+ " char3 char,"
+ " vchar varchar"
+ ")");
+
+ ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
+
+ ret = SQLFreeStmt(stmt, SQL_CLOSE);
+ ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
+
+ ret = ExecQuery(
+ "insert into "
+ "TestScalePrecision(id, dec1, dec2, dec3, char1, char2, char3, vchar) "
+ "values (1, 12, 160.23, -1234.56789, 'TST', 'Lorem Ipsum', 'Some test value', 'Some test varchar')");
+
+ ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
+
+ ret = SQLFreeStmt(stmt, SQL_CLOSE);
+ ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
+
+ ret = (this->*func)("select id, dec1, dec2, dec3, char1, char2, char3, vchar from PUBLIC.TestScalePrecision");
+ ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
+
+ SQLSMALLINT columnCount = 0;
+
+ ret = SQLNumResultCols(stmt, &columnCount);
+ ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
+
+ BOOST_CHECK_EQUAL(columnCount, 8);
+
+ CheckColumnMetaWithSQLColAttribute(stmt, 1, "ID", SQL_INTEGER, 10, 0, SQL_NULLABLE_UNKNOWN);
+ CheckColumnMetaWithSQLColAttribute(stmt, 2, "DEC1", SQL_DECIMAL, 3, 0, SQL_NULLABLE_UNKNOWN);
+ CheckColumnMetaWithSQLColAttribute(stmt, 3, "DEC2", SQL_DECIMAL, 42, 12, SQL_NULLABLE_UNKNOWN);
+ CheckColumnMetaWithSQLColAttribute(stmt, 4, "DEC3", SQL_DECIMAL, 65535, 32767, SQL_NULLABLE_UNKNOWN);
+ CheckColumnMetaWithSQLColAttribute(stmt, 5, "CHAR1", SQL_VARCHAR, 3, 0, SQL_NULLABLE_UNKNOWN);
+ CheckColumnMetaWithSQLColAttribute(stmt, 6, "CHAR2", SQL_VARCHAR, 42, 0, SQL_NULLABLE_UNKNOWN);
+ CheckColumnMetaWithSQLColAttribute(stmt, 7, "CHAR3", SQL_VARCHAR, 2147483647, 0, SQL_NULLABLE_UNKNOWN);
+ CheckColumnMetaWithSQLColAttribute(stmt, 8, "VCHAR", SQL_VARCHAR, 2147483647, 0, SQL_NULLABLE_UNKNOWN);
+ }
+
+ /**
* Destructor.
*/
~MetaQueriesTestSuiteFixture()
@@ -670,4 +876,58 @@ BOOST_AUTO_TEST_CASE(TestSQLNumResultColsAfterSQLPrepare)
BOOST_CHECK_EQUAL(columnCount, 4);
}
+/**
+ * Check that SQLDescribeCol return valid scale and precision for columns of different type after Prepare.
+ *
+ * 1. Start node.
+ * 2. Connect to node using ODBC.
+ * 3. Create table with decimal and char columns with specified size and scale.
+ * 4. Prepare statement.
+ * 5. Check presicion and scale of every column using SQLDescribeCol.
+ */
+BOOST_AUTO_TEST_CASE(TestSQLDescribeColPrecisionAndScaleAfterPrepare)
+{
+ CheckSQLDescribeColPrecisionAndScale(&OdbcTestSuite::PrepareQuery);
+}
+
+/**
+ * Check that SQLDescribeCol return valid scale and precision for columns of different type after Execute.
+ *
+ * 1. Start node.
+ * 2. Connect to node using ODBC.
+ * 3. Create table with decimal and char columns with specified size and scale.
+ * 4. Execute statement.
+ * 5. Check presicion and scale of every column using SQLDescribeCol. */
+BOOST_AUTO_TEST_CASE(TestSQLDescribeColPrecisionAndScaleAfterExec)
+{
+ CheckSQLDescribeColPrecisionAndScale(&OdbcTestSuite::ExecQuery);
+}
+
+/**
+ * Check that SQLColAttribute return valid scale and precision for columns of different type after Prepare.
+ *
+ * 1. Start node.
+ * 2. Connect to node using ODBC.
+ * 3. Create table with decimal and char columns with specified size and scale.
+ * 4. Prepare statement.
+ * 5. Check presicion and scale of every column using SQLColAttribute.
+ */
+BOOST_AUTO_TEST_CASE(TestSQLColAttributePrecisionAndScaleAfterPrepare)
+{
+ CheckSQLColAttributePrecisionAndScale(&OdbcTestSuite::PrepareQuery);
+}
+
+/**
+ * Check that SQLColAttribute return valid scale and precision for columns of different type after Execute.
+ *
+ * 1. Start node.
+ * 2. Connect to node using ODBC.
+ * 3. Create table with decimal and char columns with specified size and scale.
+ * 4. Execute statement.
+ * 5. Check presicion and scale of every column using SQLColAttribute. */
+BOOST_AUTO_TEST_CASE(TestSQLColAttributePrecisionAndScaleAfterExec)
+{
+ CheckSQLColAttributePrecisionAndScale(&OdbcTestSuite::ExecQuery);
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/modules/platforms/cpp/odbc-test/src/test_utils.cpp b/modules/platforms/cpp/odbc-test/src/test_utils.cpp
index 6cdaed2..1519e73 100644
--- a/modules/platforms/cpp/odbc-test/src/test_utils.cpp
+++ b/modules/platforms/cpp/odbc-test/src/test_utils.cpp
@@ -40,7 +40,7 @@ namespace ignite_test
std::string(reinterpret_cast<char*>(message), reallen));
}
- std::string GetOdbcErrorState(SQLSMALLINT handleType, SQLHANDLE handle)
+ std::string GetOdbcErrorState(SQLSMALLINT handleType, SQLHANDLE handle, int idx)
{
SQLCHAR sqlstate[7] = {};
SQLINTEGER nativeCode;
@@ -48,12 +48,12 @@ namespace ignite_test
SQLCHAR message[ODBC_BUFFER_SIZE];
SQLSMALLINT reallen = 0;
- SQLGetDiagRec(handleType, handle, 1, sqlstate, &nativeCode, message, ODBC_BUFFER_SIZE, &reallen);
+ SQLGetDiagRec(handleType, handle, idx, sqlstate, &nativeCode, message, ODBC_BUFFER_SIZE, &reallen);
return std::string(reinterpret_cast<char*>(sqlstate));
}
- std::string GetOdbcErrorMessage(SQLSMALLINT handleType, SQLHANDLE handle)
+ std::string GetOdbcErrorMessage(SQLSMALLINT handleType, SQLHANDLE handle, int idx)
{
SQLCHAR sqlstate[7] = {};
SQLINTEGER nativeCode;
@@ -61,7 +61,7 @@ namespace ignite_test
SQLCHAR message[ODBC_BUFFER_SIZE];
SQLSMALLINT reallen = 0;
- SQLGetDiagRec(handleType, handle, 1, sqlstate, &nativeCode, message, ODBC_BUFFER_SIZE, &reallen);
+ SQLGetDiagRec(handleType, handle, idx, sqlstate, &nativeCode, message, ODBC_BUFFER_SIZE, &reallen);
std::string res(reinterpret_cast<char*>(sqlstate));
diff --git a/modules/platforms/cpp/odbc-test/src/utility_test.cpp b/modules/platforms/cpp/odbc-test/src/utility_test.cpp
index 7fe602c..58469bd 100644
--- a/modules/platforms/cpp/odbc-test/src/utility_test.cpp
+++ b/modules/platforms/cpp/odbc-test/src/utility_test.cpp
@@ -90,4 +90,68 @@ BOOST_AUTO_TEST_CASE(TestUtilityWriteReadString)
BOOST_REQUIRE(outStr4.empty());
}
+void CheckDecimalWriteRead(const std::string& val)
+{
+ using namespace ignite::impl::binary;
+ using namespace ignite::impl::interop;
+ using namespace ignite::common;
+ using namespace ignite::utility;
+
+ InteropUnpooledMemory mem(1024);
+ InteropOutputStream outStream(&mem);
+ BinaryWriterImpl writer(&outStream, 0);
+
+ Decimal decimal(val);
+
+ WriteDecimal(writer, decimal);
+
+ outStream.Synchronize();
+
+ InteropInputStream inStream(&mem);
+ BinaryReaderImpl reader(&inStream);
+
+ Decimal out;
+ ReadDecimal(reader, out);
+
+ std::stringstream converter;
+ converter << out;
+
+ std::string res = converter.str();
+
+ BOOST_CHECK_EQUAL(res, val);
+}
+
+/**
+ * Check that Decimal writing and reading works as expected.
+ *
+ * 1. Create Decimal value.
+ * 2. Write using standard serialization algorithm.
+ * 3. Read using standard de-serialization algorithm.
+ * 4. Check that initial and read value are equal.
+ *
+ * Repeat with the following values: 0, 1, -1, 0.1, -0.1, 42, -42, 160, -160, 34729864879625196, -34729864879625196,
+ * 3472986487.9625196, -3472986487.9625196, 3472.9864879625196, -3472.9864879625196, 0.34729864879625196,
+ * -0.34729864879625196
+ */
+BOOST_AUTO_TEST_CASE(TestUtilityWriteReadDecimal)
+{
+ CheckDecimalWriteRead("0");
+ CheckDecimalWriteRead("1");
+ CheckDecimalWriteRead("-1");
+ CheckDecimalWriteRead("0.1");
+ CheckDecimalWriteRead("-0.1");
+ CheckDecimalWriteRead("42");
+ CheckDecimalWriteRead("-42");
+ CheckDecimalWriteRead("160");
+ CheckDecimalWriteRead("-160");
+ CheckDecimalWriteRead("34729864879625196");
+ CheckDecimalWriteRead("-34729864879625196");
+ CheckDecimalWriteRead("3472986487.9625196");
+ CheckDecimalWriteRead("-3472986487.9625196");
+ CheckDecimalWriteRead("3472.9864879625196");
+ CheckDecimalWriteRead("-3472.9864879625196");
+ CheckDecimalWriteRead("0.34729864879625196");
+ CheckDecimalWriteRead("-0.34729864879625196");
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc/config/connection_string_parser.h b/modules/platforms/cpp/odbc/include/ignite/odbc/config/connection_string_parser.h
index 1fdedf6..de02cb4 100644
--- a/modules/platforms/cpp/odbc/include/ignite/odbc/config/connection_string_parser.h
+++ b/modules/platforms/cpp/odbc/include/ignite/odbc/config/connection_string_parser.h
@@ -98,6 +98,12 @@ namespace ignite
/** Connection attribute keyword for password attribute. */
static const std::string password;
+ /** Connection attribute keyword for username attribute. */
+ static const std::string uid;
+
+ /** Connection attribute keyword for password attribute. */
+ static const std::string pwd;
+
/** Connection attribute keyword for nestedTxMode attribute. */
static const std::string nestedTxMode;
};
diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc/dsn_config.h b/modules/platforms/cpp/odbc/include/ignite/odbc/dsn_config.h
index dbad9b5..640046f 100644
--- a/modules/platforms/cpp/odbc/include/ignite/odbc/dsn_config.h
+++ b/modules/platforms/cpp/odbc/include/ignite/odbc/dsn_config.h
@@ -53,9 +53,10 @@ namespace ignite
*
* @param dsn DSN name.
* @param config Configuration.
+ * @param diag Diagnostic collector.
*/
- void ReadDsnConfiguration(const char* dsn, config::Configuration& config);
+ void ReadDsnConfiguration(const char* dsn, config::Configuration& config, diagnostic::DiagnosticRecordStorage *diag);
}
}
-#endif //_IGNITE_ODBC_DSN_CONFIG
\ No newline at end of file
+#endif //_IGNITE_ODBC_DSN_CONFIG
diff --git a/modules/platforms/cpp/odbc/os/win/src/system_dsn.cpp b/modules/platforms/cpp/odbc/os/win/src/system_dsn.cpp
index 733d0cd..0672911 100644
--- a/modules/platforms/cpp/odbc/os/win/src/system_dsn.cpp
+++ b/modules/platforms/cpp/odbc/os/win/src/system_dsn.cpp
@@ -189,7 +189,7 @@ BOOL INSTAPI ConfigDSN(HWND hwndParent, WORD req, LPCSTR driver, LPCSTR attribut
Configuration loaded(config);
- ReadDsnConfiguration(dsn.c_str(), loaded);
+ ReadDsnConfiguration(dsn.c_str(), loaded, &diag);
if (!DisplayConfigureDsnWindow(hwndParent, loaded))
return FALSE;
@@ -218,4 +218,4 @@ BOOL INSTAPI ConfigDSN(HWND hwndParent, WORD req, LPCSTR driver, LPCSTR attribut
}
return TRUE;
-}
\ No newline at end of file
+}
diff --git a/modules/platforms/cpp/odbc/src/config/connection_string_parser.cpp b/modules/platforms/cpp/odbc/src/config/connection_string_parser.cpp
index fb779f6..a93e3b5 100644
--- a/modules/platforms/cpp/odbc/src/config/connection_string_parser.cpp
+++ b/modules/platforms/cpp/odbc/src/config/connection_string_parser.cpp
@@ -51,6 +51,8 @@ namespace ignite
const std::string ConnectionStringParser::Key::sslCaFile = "ssl_ca_file";
const std::string ConnectionStringParser::Key::user = "user";
const std::string ConnectionStringParser::Key::password = "password";
+ const std::string ConnectionStringParser::Key::uid = "uid";
+ const std::string ConnectionStringParser::Key::pwd = "pwd";
const std::string ConnectionStringParser::Key::nestedTxMode = "nested_tx_mode";
ConnectionStringParser::ConnectionStringParser(Configuration& cfg):
@@ -417,12 +419,24 @@ namespace ignite
{
cfg.SetDriver(value);
}
- else if (lKey == Key::user)
+ else if (lKey == Key::user || lKey == Key::uid)
{
+ if (!cfg.GetUser().empty() && diag)
+ {
+ diag->AddStatusRecord(SqlState::S01S02_OPTION_VALUE_CHANGED,
+ "Re-writing USER (have you specified it several times?");
+ }
+
cfg.SetUser(value);
}
- else if (lKey == Key::password)
+ else if (lKey == Key::password || lKey == Key::pwd)
{
+ if (!cfg.GetPassword().empty() && diag)
+ {
+ diag->AddStatusRecord(SqlState::S01S02_OPTION_VALUE_CHANGED,
+ "Re-writing PASSWORD (have you specified it several times?");
+ }
+
cfg.SetPassword(value);
}
else if (lKey == Key::nestedTxMode)
diff --git a/modules/platforms/cpp/odbc/src/connection.cpp b/modules/platforms/cpp/odbc/src/connection.cpp
index a5beb0c..b073580 100644
--- a/modules/platforms/cpp/odbc/src/connection.cpp
+++ b/modules/platforms/cpp/odbc/src/connection.cpp
@@ -119,7 +119,7 @@ namespace ignite
{
std::string dsn = config.GetDsn();
- ReadDsnConfiguration(dsn.c_str(), config);
+ ReadDsnConfiguration(dsn.c_str(), config, &GetDiagnosticRecords());
}
return InternalEstablish(config);
diff --git a/modules/platforms/cpp/odbc/src/dsn_config.cpp b/modules/platforms/cpp/odbc/src/dsn_config.cpp
index dcdb8f4..8f1a6df 100644
--- a/modules/platforms/cpp/odbc/src/dsn_config.cpp
+++ b/modules/platforms/cpp/odbc/src/dsn_config.cpp
@@ -72,10 +72,8 @@ namespace ignite
std::string res(buf.GetData());
- if (res == unique)
- return val;
-
- val.SetValue(res);
+ if (res != unique)
+ val.SetValue(res);
return val;
}
@@ -104,7 +102,7 @@ namespace ignite
return res;
}
- void ReadDsnConfiguration(const char* dsn, Configuration& config)
+ void ReadDsnConfiguration(const char* dsn, Configuration& config, diagnostic::DiagnosticRecordStorage* diag)
{
SettableValue<std::string> address = ReadDsnString(dsn, ConnectionStringParser::Key::address);
@@ -112,7 +110,7 @@ namespace ignite
{
std::vector<EndPoint> endPoints;
- ParseAddress(address.GetValue(), endPoints, 0);
+ ParseAddress(address.GetValue(), endPoints, diag);
config.SetAddresses(endPoints);
}
@@ -219,4 +217,4 @@ namespace ignite
config.SetNestedTxMode(NestedTxMode::FromString(nestedTxModeStr.GetValue(), config.GetNestedTxMode()));
}
}
-}
\ No newline at end of file
+}
diff --git a/modules/platforms/cpp/odbc/src/meta/column_meta.cpp b/modules/platforms/cpp/odbc/src/meta/column_meta.cpp
index 476f6a6..203b4ad 100644
--- a/modules/platforms/cpp/odbc/src/meta/column_meta.cpp
+++ b/modules/platforms/cpp/odbc/src/meta/column_meta.cpp
@@ -163,7 +163,7 @@ namespace ignite
if (scale == -1)
return false;
- value = common::LexicalCast<std::string>(precision);
+ value = common::LexicalCast<std::string>(scale);
return true;
}
diff --git a/modules/platforms/cpp/odbc/src/odbc.cpp b/modules/platforms/cpp/odbc/src/odbc.cpp
index b9107fc..f297ec4 100644
--- a/modules/platforms/cpp/odbc/src/odbc.cpp
+++ b/modules/platforms/cpp/odbc/src/odbc.cpp
@@ -325,7 +325,7 @@ namespace ignite
LOG_MSG("DSN: " << dsn);
- odbc::ReadDsnConfiguration(dsn.c_str(), config);
+ odbc::ReadDsnConfiguration(dsn.c_str(), config, &connection->GetDiagnosticRecords());
connection->Establish(config);
@@ -1144,6 +1144,7 @@ namespace ignite
using odbc::Environment;
LOG_MSG("SQLSetEnvAttr called");
+ LOG_MSG("Attribute: " << attr << ", Value: " << (size_t)value);
Environment *environment = reinterpret_cast<Environment*>(env);
@@ -1174,7 +1175,7 @@ namespace ignite
return SQL_INVALID_HANDLE;
SqlLen outResLen;
- ApplicationDataBuffer outBuffer(OdbcNativeType::AI_DEFAULT, valueBuf,
+ ApplicationDataBuffer outBuffer(OdbcNativeType::AI_SIGNED_LONG, valueBuf,
static_cast<int32_t>(valueBufLen), &outResLen);
environment->GetAttribute(attr, outBuffer);
diff --git a/modules/platforms/cpp/odbc/src/statement.cpp b/modules/platforms/cpp/odbc/src/statement.cpp
index 9253030..cc508e3 100644
--- a/modules/platforms/cpp/odbc/src/statement.cpp
+++ b/modules/platforms/cpp/odbc/src/statement.cpp
@@ -1096,6 +1096,8 @@ namespace ignite
{
const meta::ColumnMetaVector *meta = GetMeta();
+ LOG_MSG("Collumn ID: " << colIdx << ", Attribute ID: " << attrId);
+
if (!meta)
return SqlResult::AI_ERROR;
diff --git a/modules/platforms/cpp/odbc/src/utility.cpp b/modules/platforms/cpp/odbc/src/utility.cpp
index 498490c..c060a0a 100644
--- a/modules/platforms/cpp/odbc/src/utility.cpp
+++ b/modules/platforms/cpp/odbc/src/utility.cpp
@@ -111,10 +111,18 @@ namespace ignite
unscaled.MagnitudeToBytes(magnitude);
- if (unscaled.GetSign() == -1)
- magnitude[0] |= -0x80;
+ int8_t addBit = unscaled.GetSign() == -1 ? -0x80 : 0;
- writer.WriteInt32(magnitude.GetSize());
+ if (magnitude[0] < 0)
+ {
+ writer.WriteInt32(magnitude.GetSize() + 1);
+ writer.WriteInt8(addBit);
+ }
+ else
+ {
+ writer.WriteInt32(magnitude.GetSize());
+ magnitude[0] |= addBit;
+ }
impl::binary::BinaryUtils::WriteInt8Array(writer.GetStream(), magnitude.GetData(), magnitude.GetSize());
}