| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #ifdef _WIN32 |
| # include <windows.h> |
| #endif |
| |
| #include <sql.h> |
| #include <sqlext.h> |
| |
| #include <boost/test/unit_test.hpp> |
| |
| #include "ignite/ignition.h" |
| |
| #include "test_utils.h" |
| #include "odbc_test_suite.h" |
| |
| using namespace ignite_test; |
| using namespace boost::unit_test; |
| |
| namespace ignite |
| { |
| namespace odbc |
| { |
| void OdbcTestSuite::Prepare() |
| { |
| // Allocate an environment handle |
| SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env); |
| |
| BOOST_REQUIRE(env != NULL); |
| |
| // We want ODBC 3 support |
| SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, reinterpret_cast<void*>(SQL_OV_ODBC3), 0); |
| |
| // Allocate a connection handle |
| SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc); |
| |
| BOOST_REQUIRE(dbc != NULL); |
| } |
| |
| void OdbcTestSuite::Connect(SQLHDBC& conn, SQLHSTMT& statement, const std::string& connectStr) |
| { |
| // Allocate a connection handle |
| SQLAllocHandle(SQL_HANDLE_DBC, env, &conn); |
| |
| BOOST_REQUIRE(conn != NULL); |
| |
| // Connect string |
| std::vector<SQLCHAR> connectStr0(connectStr.begin(), connectStr.end()); |
| |
| SQLCHAR outstr[ODBC_BUFFER_SIZE]; |
| SQLSMALLINT outstrlen; |
| |
| // Connecting to ODBC server. |
| SQLRETURN ret = SQLDriverConnect(conn, 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, conn)); |
| } |
| |
| // Allocate a statement handle |
| SQLAllocHandle(SQL_HANDLE_STMT, conn, &statement); |
| |
| BOOST_REQUIRE(statement != NULL); |
| } |
| |
| void OdbcTestSuite::Connect(const std::string& connectStr) |
| { |
| Prepare(); |
| |
| // Connect string |
| std::vector<SQLCHAR> connectStr0(connectStr.begin(), connectStr.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)); |
| |
| // Allocate a statement handle |
| SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt); |
| |
| BOOST_REQUIRE(stmt != NULL); |
| } |
| |
| std::string OdbcTestSuite::ExpectConnectionReject(const std::string& connectStr) |
| { |
| Prepare(); |
| |
| // Connect string |
| std::vector<SQLCHAR> connectStr0(connectStr.begin(), connectStr.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); |
| |
| BOOST_REQUIRE_EQUAL(ret, SQL_ERROR); |
| |
| return GetOdbcErrorState(SQL_HANDLE_DBC, dbc); |
| } |
| |
| void OdbcTestSuite::Disconnect() |
| { |
| if (stmt) |
| { |
| // Releasing statement handle. |
| SQLFreeHandle(SQL_HANDLE_STMT, stmt); |
| stmt = NULL; |
| } |
| |
| if (dbc) |
| { |
| // Disconneting from the server. |
| SQLDisconnect(dbc); |
| |
| // Releasing allocated handles. |
| SQLFreeHandle(SQL_HANDLE_DBC, dbc); |
| dbc = NULL; |
| } |
| } |
| |
| void OdbcTestSuite::CleanUp() |
| { |
| Disconnect(); |
| |
| if (env) |
| { |
| // Releasing allocated handles. |
| SQLFreeHandle(SQL_HANDLE_ENV, env); |
| env = NULL; |
| } |
| } |
| |
| Ignite OdbcTestSuite::StartTestNode(const char* cfg, const char* name) |
| { |
| std::string config(cfg); |
| |
| #ifdef IGNITE_TESTS_32 |
| // Cutting off the ".xml" part. |
| config.resize(config.size() - 4); |
| config += "-32.xml"; |
| #endif //IGNITE_TESTS_32 |
| |
| return StartNode(config.c_str(), name); |
| } |
| |
| OdbcTestSuite::OdbcTestSuite(): |
| env(NULL), |
| dbc(NULL), |
| stmt(NULL) |
| { |
| // No-op. |
| } |
| |
| OdbcTestSuite::~OdbcTestSuite() |
| { |
| CleanUp(); |
| |
| Ignition::StopAll(true); |
| } |
| |
| int8_t OdbcTestSuite::GetTestI8Field(int64_t idx) |
| { |
| return static_cast<int8_t>(idx * 8); |
| } |
| |
| void OdbcTestSuite::CheckTestI8Value(int idx, int8_t value) |
| { |
| BOOST_TEST_INFO("Test index: " << idx); |
| BOOST_CHECK_EQUAL(value, GetTestI8Field(idx)); |
| } |
| |
| int16_t OdbcTestSuite::GetTestI16Field(int64_t idx) |
| { |
| return static_cast<int16_t>(idx * 16); |
| } |
| |
| void OdbcTestSuite::CheckTestI16Value(int idx, int16_t value) |
| { |
| BOOST_TEST_INFO("Test index: " << idx); |
| BOOST_CHECK_EQUAL(value, GetTestI16Field(idx)); |
| } |
| |
| int32_t OdbcTestSuite::GetTestI32Field(int64_t idx) |
| { |
| return static_cast<int32_t>(idx * 32); |
| } |
| |
| void OdbcTestSuite::CheckTestI32Value(int idx, int32_t value) |
| { |
| BOOST_TEST_INFO("Test index: " << idx); |
| BOOST_CHECK_EQUAL(value, GetTestI32Field(idx)); |
| } |
| |
| std::string OdbcTestSuite::GetTestString(int64_t idx) |
| { |
| std::stringstream builder; |
| |
| builder << "String#" << idx; |
| |
| return builder.str(); |
| } |
| |
| void OdbcTestSuite::CheckTestStringValue(int idx, const std::string &value) |
| { |
| BOOST_TEST_INFO("Test index: " << idx); |
| BOOST_CHECK_EQUAL(value, GetTestString(idx)); |
| } |
| |
| float OdbcTestSuite::GetTestFloatField(int64_t idx) |
| { |
| return static_cast<float>(idx * 0.5f); |
| } |
| |
| void OdbcTestSuite::CheckTestFloatValue(int idx, float value) |
| { |
| BOOST_TEST_INFO("Test index: " << idx); |
| BOOST_CHECK_EQUAL(value, GetTestFloatField(idx)); |
| } |
| |
| double OdbcTestSuite::GetTestDoubleField(int64_t idx) |
| { |
| return static_cast<double>(idx * 0.25f); |
| } |
| |
| void OdbcTestSuite::CheckTestDoubleValue(int idx, double value) |
| { |
| BOOST_TEST_INFO("Test index: " << idx); |
| BOOST_CHECK_EQUAL(value, GetTestDoubleField(idx)); |
| } |
| |
| bool OdbcTestSuite::GetTestBoolField(int64_t idx) |
| { |
| return static_cast<bool>(idx % 2 == 0); |
| } |
| |
| void OdbcTestSuite::CheckTestBoolValue(int idx, bool value) |
| { |
| BOOST_TEST_INFO("Test index: " << idx); |
| BOOST_CHECK_EQUAL(value, GetTestBoolField(idx)); |
| } |
| |
| void OdbcTestSuite::GetTestDateField(int64_t idx, SQL_DATE_STRUCT& val) |
| { |
| val.year = static_cast<SQLSMALLINT>(2017 + idx / 365); |
| val.month = static_cast<SQLUSMALLINT>(((idx / 28) % 12) + 1); |
| val.day = static_cast<SQLUSMALLINT>((idx % 28) + 1); |
| } |
| |
| void OdbcTestSuite::CheckTestDateValue(int idx, const SQL_DATE_STRUCT& val) |
| { |
| BOOST_TEST_CONTEXT("Test index: " << idx) |
| { |
| SQL_DATE_STRUCT expected; |
| GetTestDateField(idx, expected); |
| |
| BOOST_CHECK_EQUAL(val.year, expected.year); |
| BOOST_CHECK_EQUAL(val.month, expected.month); |
| BOOST_CHECK_EQUAL(val.day, expected.day); |
| } |
| } |
| |
| void OdbcTestSuite::GetTestTimeField(int64_t idx, SQL_TIME_STRUCT& val) |
| { |
| val.hour = (idx / 3600) % 24; |
| val.minute = (idx / 60) % 60; |
| val.second = idx % 60; |
| } |
| |
| void OdbcTestSuite::CheckTestTimeValue(int idx, const SQL_TIME_STRUCT& val) |
| { |
| BOOST_TEST_CONTEXT("Test index: " << idx) |
| { |
| SQL_TIME_STRUCT expected; |
| GetTestTimeField(idx, expected); |
| |
| BOOST_CHECK_EQUAL(val.hour, expected.hour); |
| BOOST_CHECK_EQUAL(val.minute, expected.minute); |
| BOOST_CHECK_EQUAL(val.second, expected.second); |
| } |
| } |
| |
| void OdbcTestSuite::GetTestTimestampField(int64_t idx, SQL_TIMESTAMP_STRUCT& val) |
| { |
| SQL_DATE_STRUCT date; |
| GetTestDateField(idx, date); |
| |
| SQL_TIME_STRUCT time; |
| GetTestTimeField(idx, time); |
| |
| val.year = date.year; |
| val.month = date.month; |
| val.day = date.day; |
| val.hour = time.hour; |
| val.minute = time.minute; |
| val.second = time.second; |
| val.fraction = static_cast<uint64_t>(std::abs(idx * 914873)) % 1000000000; |
| } |
| |
| void OdbcTestSuite::CheckTestTimestampValue(int idx, const SQL_TIMESTAMP_STRUCT& val) |
| { |
| BOOST_TEST_CONTEXT("Test index: " << idx) |
| { |
| SQL_TIMESTAMP_STRUCT expected; |
| GetTestTimestampField(idx, expected); |
| |
| BOOST_CHECK_EQUAL(val.year, expected.year); |
| BOOST_CHECK_EQUAL(val.month, expected.month); |
| BOOST_CHECK_EQUAL(val.day, expected.day); |
| BOOST_CHECK_EQUAL(val.hour, expected.hour); |
| BOOST_CHECK_EQUAL(val.minute, expected.minute); |
| BOOST_CHECK_EQUAL(val.second, expected.second); |
| BOOST_CHECK_EQUAL(val.fraction, expected.fraction); |
| } |
| } |
| |
| void OdbcTestSuite::GetTestI8ArrayField(int64_t idx, int8_t* val, size_t valLen) |
| { |
| for (size_t j = 0; j < valLen; ++j) |
| val[j] = static_cast<int8_t>(idx * valLen + j); |
| } |
| |
| void OdbcTestSuite::CheckTestI8ArrayValue(int idx, const int8_t* val, size_t valLen) |
| { |
| BOOST_TEST_CONTEXT("Test index: " << idx) |
| { |
| common::FixedSizeArray<int8_t> expected(static_cast<int32_t>(valLen)); |
| GetTestI8ArrayField(idx, expected.GetData(), expected.GetSize()); |
| |
| for (size_t j = 0; j < valLen; ++j) |
| { |
| BOOST_TEST_INFO("Byte index: " << j); |
| BOOST_CHECK_EQUAL(val[j], expected[(int32_t)j]); |
| } |
| } |
| } |
| |
| void OdbcTestSuite::CheckSQLDiagnosticError(int16_t handleType, SQLHANDLE handle, const std::string& expectSqlState) |
| { |
| SQLCHAR state[ODBC_BUFFER_SIZE]; |
| SQLINTEGER nativeError = 0; |
| SQLCHAR message[ODBC_BUFFER_SIZE]; |
| SQLSMALLINT messageLen = 0; |
| |
| SQLRETURN ret = SQLGetDiagRec(handleType, handle, 1, state, &nativeError, message, sizeof(message), &messageLen); |
| |
| const std::string sqlState = reinterpret_cast<char*>(state); |
| BOOST_REQUIRE_EQUAL(ret, SQL_SUCCESS); |
| BOOST_REQUIRE_EQUAL(sqlState, expectSqlState); |
| BOOST_REQUIRE(messageLen > 0); |
| } |
| |
| void OdbcTestSuite::CheckSQLStatementDiagnosticError(const std::string& expectSqlState) |
| { |
| CheckSQLDiagnosticError(SQL_HANDLE_STMT, stmt, expectSqlState); |
| } |
| |
| void OdbcTestSuite::CheckSQLConnectionDiagnosticError(const std::string& expectSqlState) |
| { |
| CheckSQLDiagnosticError(SQL_HANDLE_DBC, dbc, expectSqlState); |
| } |
| |
| std::vector<SQLCHAR> OdbcTestSuite::MakeQuery(const std::string& qry) |
| { |
| return std::vector<SQLCHAR>(qry.begin(), qry.end()); |
| } |
| |
| SQLRETURN OdbcTestSuite::ExecQuery(const std::string& qry) |
| { |
| std::vector<SQLCHAR> sql = MakeQuery(qry); |
| |
| return SQLExecDirect(stmt, sql.data(), static_cast<SQLINTEGER>(sql.size())); |
| } |
| |
| SQLRETURN OdbcTestSuite::PrepareQuery(const std::string& qry) |
| { |
| std::vector<SQLCHAR> sql = MakeQuery(qry); |
| |
| return SQLPrepare(stmt, sql.data(), static_cast<SQLINTEGER>(sql.size())); |
| } |
| |
| void OdbcTestSuite::InsertTestStrings(int recordsNum, bool merge) |
| { |
| SQLCHAR insertReq[] = "INSERT INTO TestType(_key, strField) VALUES(?, ?)"; |
| SQLCHAR mergeReq[] = "MERGE INTO TestType(_key, strField) VALUES(?, ?)"; |
| |
| SQLRETURN ret = SQLPrepare(stmt, merge ? mergeReq : insertReq, SQL_NTS); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); |
| |
| int64_t key = 0; |
| char strField[1024] = {0}; |
| SQLLEN strFieldLen = 0; |
| |
| // Binding parameters. |
| ret = SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_BIGINT, 0, 0, &key, 0, 0); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); |
| |
| ret = SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, sizeof(strField), |
| sizeof(strField), &strField, sizeof(strField), &strFieldLen); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); |
| |
| // Inserting values. |
| for (SQLSMALLINT i = 0; i < recordsNum; ++i) |
| { |
| key = i + 1; |
| std::string val = GetTestString(i); |
| |
| CopyStringToBuffer(strField, val, sizeof(strField)); |
| strFieldLen = SQL_NTS; |
| |
| ret = SQLExecute(stmt); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); |
| |
| SQLLEN affected = 0; |
| ret = SQLRowCount(stmt, &affected); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); |
| |
| BOOST_CHECK_EQUAL(affected, 1); |
| |
| ret = SQLMoreResults(stmt); |
| |
| if (ret != SQL_NO_DATA) |
| BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); |
| } |
| |
| // Resetting parameters. |
| ret = SQLFreeStmt(stmt, SQL_RESET_PARAMS); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); |
| } |
| |
| SQLRETURN OdbcTestSuite::InsertTestBatchNoCheck(int from, int to, bool merge) |
| { |
| using common::FixedSizeArray; |
| |
| SQLCHAR insertReq[] = "INSERT " |
| "INTO TestType(_key, i8Field, i16Field, i32Field, strField, floatField, doubleField, boolField, dateField, " |
| "timeField, timestampField, i8ArrayField) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; |
| |
| SQLCHAR mergeReq[] = "MERGE " |
| "INTO TestType(_key, i8Field, i16Field, i32Field, strField, floatField, doubleField, boolField, dateField, " |
| "timeField, timestampField, i8ArrayField) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; |
| |
| SQLRETURN ret; |
| |
| int32_t recordsNum = to - from; |
| |
| ret = SQLPrepare(stmt, merge ? mergeReq : insertReq, SQL_NTS); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); |
| |
| FixedSizeArray<int64_t> keys(recordsNum); |
| FixedSizeArray<int8_t> i8Fields(recordsNum); |
| FixedSizeArray<int16_t> i16Fields(recordsNum); |
| FixedSizeArray<int32_t> i32Fields(recordsNum); |
| FixedSizeArray<char> strFields(recordsNum * 1024); |
| FixedSizeArray<float> floatFields(recordsNum); |
| FixedSizeArray<double> doubleFields(recordsNum); |
| FixedSizeArray<bool> boolFields(recordsNum); |
| FixedSizeArray<SQL_DATE_STRUCT> dateFields(recordsNum); |
| FixedSizeArray<SQL_TIME_STRUCT> timeFields(recordsNum); |
| FixedSizeArray<SQL_TIMESTAMP_STRUCT> timestampFields(recordsNum); |
| FixedSizeArray<int8_t> i8ArrayFields(recordsNum * 42); |
| |
| FixedSizeArray<SQLLEN> strFieldsLen(recordsNum); |
| FixedSizeArray<SQLLEN> i8ArrayFieldsLen(recordsNum); |
| |
| BOOST_TEST_CHECKPOINT("Filling param data"); |
| |
| for (int i = 0; i < recordsNum; ++i) |
| { |
| int seed = from + i; |
| |
| keys[i] = seed; |
| i8Fields[i] = GetTestI8Field(seed); |
| i16Fields[i] = GetTestI16Field(seed); |
| i32Fields[i] = GetTestI32Field(seed); |
| |
| std::string val = GetTestString(seed); |
| CopyStringToBuffer(strFields.GetData() + 1024 * i, val, 1023); |
| strFieldsLen[i] = val.size(); |
| |
| floatFields[i] = GetTestFloatField(seed); |
| doubleFields[i] = GetTestDoubleField(seed); |
| boolFields[i] = GetTestBoolField(seed); |
| |
| GetTestDateField(seed, dateFields[i]); |
| GetTestTimeField(seed, timeFields[i]); |
| GetTestTimestampField(seed, timestampFields[i]); |
| |
| GetTestI8ArrayField(seed, &i8ArrayFields[i*42], 42); |
| i8ArrayFieldsLen[i] = 42; |
| } |
| |
| BOOST_TEST_CHECKPOINT("Binding keys"); |
| ret = SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_SBIGINT, SQL_BIGINT, 0, 0, keys.GetData(), 0, 0); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); |
| |
| BOOST_TEST_CHECKPOINT("Binding i8Fields"); |
| ret = SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_STINYINT, SQL_TINYINT, 0, 0, i8Fields.GetData(), 0, 0); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); |
| |
| BOOST_TEST_CHECKPOINT("Binding i16Fields"); |
| ret = SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_SSHORT, SQL_SMALLINT, 0, 0, i16Fields.GetData(), 0, 0); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); |
| |
| BOOST_TEST_CHECKPOINT("Binding i32Fields"); |
| ret = SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, i32Fields.GetData(), 0, 0); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); |
| |
| BOOST_TEST_CHECKPOINT("Binding strFields"); |
| ret = SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, 1024, 0, strFields.GetData(), 1024, strFieldsLen.GetData()); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); |
| |
| BOOST_TEST_CHECKPOINT("Binding floatFields"); |
| ret = SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_FLOAT, SQL_FLOAT, 0, 0, floatFields.GetData(), 0, 0); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); |
| |
| BOOST_TEST_CHECKPOINT("Binding doubleFields"); |
| ret = SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_DOUBLE, SQL_DOUBLE, 0, 0, doubleFields.GetData(), 0, 0); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); |
| |
| BOOST_TEST_CHECKPOINT("Binding boolFields"); |
| ret = SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_BIT, SQL_BIT, 0, 0, boolFields.GetData(), 0, 0); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); |
| |
| BOOST_TEST_CHECKPOINT("Binding dateFields"); |
| ret = SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_TYPE_DATE, SQL_TYPE_DATE, 0, 0, dateFields.GetData(), 0, 0); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); |
| |
| BOOST_TEST_CHECKPOINT("Binding timeFields"); |
| ret = SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_TYPE_TIME, SQL_TYPE_TIME, 0, 0, timeFields.GetData(), 0, 0); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); |
| |
| BOOST_TEST_CHECKPOINT("Binding timestampFields"); |
| ret = SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_TYPE_TIMESTAMP, SQL_TYPE_TIMESTAMP, 0, 0, timestampFields.GetData(), 0, 0); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); |
| |
| BOOST_TEST_CHECKPOINT("Binding i8ArrayFields"); |
| ret = SQLBindParameter(stmt, 12, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_BINARY, 42, 0, i8ArrayFields.GetData(), 42, i8ArrayFieldsLen.GetData()); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); |
| |
| BOOST_TEST_CHECKPOINT("Setting paramset size"); |
| ret = SQLSetStmtAttr(stmt, SQL_ATTR_PARAMSET_SIZE, |
| reinterpret_cast<SQLPOINTER>(static_cast<ptrdiff_t>(recordsNum)), 0); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); |
| |
| BOOST_TEST_CHECKPOINT("Executing query"); |
| |
| return SQLExecute(stmt); |
| } |
| |
| int OdbcTestSuite::InsertTestBatch(int from, int to, int expectedToAffect, bool merge) |
| { |
| SQLULEN setsProcessed = 0; |
| |
| BOOST_TEST_CHECKPOINT("Setting processed pointer"); |
| SQLRETURN ret = SQLSetStmtAttr(stmt, SQL_ATTR_PARAMS_PROCESSED_PTR, &setsProcessed, SQL_IS_POINTER); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); |
| |
| ret = InsertTestBatchNoCheck(from, to, merge); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); |
| |
| SQLLEN totallyAffected = 0; |
| |
| do |
| { |
| SQLLEN affected = 0; |
| ret = SQLRowCount(stmt, &affected); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); |
| |
| totallyAffected += affected; |
| |
| BOOST_TEST_CHECKPOINT("Getting next result set"); |
| |
| ret = SQLMoreResults(stmt); |
| |
| if (ret != SQL_SUCCESS && ret != SQL_NO_DATA) |
| BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); |
| } |
| while (ret != SQL_NO_DATA); |
| |
| BOOST_CHECK_EQUAL(totallyAffected, expectedToAffect); |
| |
| BOOST_TEST_CHECKPOINT("Resetting parameters."); |
| ret = SQLFreeStmt(stmt, SQL_RESET_PARAMS); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); |
| |
| BOOST_TEST_CHECKPOINT("Setting paramset size"); |
| ret = SQLSetStmtAttr(stmt, SQL_ATTR_PARAMSET_SIZE, reinterpret_cast<SQLPOINTER>(1), 0); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); |
| |
| return static_cast<int>(setsProcessed); |
| } |
| |
| void OdbcTestSuite::InsertBatchSelect(int recordsNum) |
| { |
| Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11110;SCHEMA=cache"); |
| |
| // Inserting values. |
| int inserted = InsertTestBatch(0, recordsNum, recordsNum); |
| |
| BOOST_REQUIRE_EQUAL(inserted, recordsNum); |
| |
| int64_t key = 0; |
| char strField[1024] = {0}; |
| SQLLEN strFieldLen = 0; |
| |
| // Binding columns. |
| SQLRETURN ret = SQLBindCol(stmt, 1, SQL_C_SLONG, &key, 0, 0); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); |
| |
| // Binding columns. |
| ret = SQLBindCol(stmt, 2, SQL_C_CHAR, &strField, sizeof(strField), &strFieldLen); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); |
| |
| // Just selecting everything to make sure everything is OK |
| SQLCHAR selectReq[] = "SELECT _key, strField FROM TestType ORDER BY _key"; |
| |
| ret = SQLExecDirect(stmt, selectReq, sizeof(selectReq)); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); |
| |
| int selectedRecordsNum = 0; |
| |
| ret = SQL_SUCCESS; |
| |
| while (ret == SQL_SUCCESS) |
| { |
| ret = SQLFetch(stmt); |
| |
| if (ret == SQL_NO_DATA) |
| break; |
| |
| if (!SQL_SUCCEEDED(ret)) |
| BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); |
| |
| std::string expectedStr = GetTestString(selectedRecordsNum); |
| int64_t expectedKey = selectedRecordsNum; |
| |
| BOOST_CHECK_EQUAL(key, expectedKey); |
| |
| BOOST_CHECK_EQUAL(std::string(strField, strFieldLen), expectedStr); |
| |
| ++selectedRecordsNum; |
| } |
| |
| BOOST_CHECK_EQUAL(recordsNum, selectedRecordsNum); |
| } |
| |
| void OdbcTestSuite::InsertNonFullBatchSelect(int recordsNum, int splitAt) |
| { |
| Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11110;SCHEMA=cache"); |
| |
| std::vector<SQLUSMALLINT> statuses(recordsNum, 42); |
| |
| // Binding statuses array. |
| SQLRETURN ret = SQLSetStmtAttr(stmt, SQL_ATTR_PARAM_STATUS_PTR, &statuses[0], 0); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); |
| |
| // Inserting values. |
| int setsProcessed = InsertTestBatch(splitAt, recordsNum, recordsNum - splitAt); |
| |
| BOOST_REQUIRE_EQUAL(setsProcessed, recordsNum - splitAt); |
| |
| for (int i = 0; i < recordsNum - splitAt; ++i) |
| BOOST_REQUIRE_EQUAL(statuses[i], SQL_PARAM_SUCCESS); |
| |
| setsProcessed = InsertTestBatch(0, recordsNum, splitAt); |
| |
| BOOST_REQUIRE_EQUAL(setsProcessed, recordsNum); |
| |
| for (int i = 0; i < splitAt; ++i) |
| BOOST_REQUIRE_EQUAL(statuses[i], SQL_PARAM_SUCCESS); |
| |
| for (int i = splitAt; i < recordsNum; ++i) |
| BOOST_REQUIRE_EQUAL(statuses[i], SQL_PARAM_ERROR); |
| |
| int64_t key = 0; |
| char strField[1024] = {0}; |
| SQLLEN strFieldLen = 0; |
| |
| // Binding columns. |
| ret = SQLBindCol(stmt, 1, SQL_C_SLONG, &key, 0, 0); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); |
| |
| // Binding columns. |
| ret = SQLBindCol(stmt, 2, SQL_C_CHAR, &strField, sizeof(strField), &strFieldLen); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); |
| |
| // Just selecting everything to make sure everything is OK |
| SQLCHAR selectReq[] = "SELECT _key, strField FROM TestType ORDER BY _key"; |
| |
| ret = SQLExecDirect(stmt, selectReq, sizeof(selectReq)); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); |
| |
| int selectedRecordsNum = 0; |
| |
| ret = SQL_SUCCESS; |
| |
| while (ret == SQL_SUCCESS) |
| { |
| ret = SQLFetch(stmt); |
| |
| if (ret == SQL_NO_DATA) |
| break; |
| |
| if (!SQL_SUCCEEDED(ret)) |
| BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); |
| |
| std::string expectedStr = GetTestString(selectedRecordsNum); |
| int64_t expectedKey = selectedRecordsNum; |
| |
| BOOST_CHECK_EQUAL(key, expectedKey); |
| |
| BOOST_CHECK_EQUAL(std::string(strField, strFieldLen), expectedStr); |
| |
| ++selectedRecordsNum; |
| } |
| |
| BOOST_CHECK_EQUAL(recordsNum, selectedRecordsNum); |
| } |
| } |
| } |