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/11/12 17:38:08 UTC
[ignite] branch master updated: IGNITE-13637: Implemented
column-wise binding for result rows
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 2d58258 IGNITE-13637: Implemented column-wise binding for result rows
2d58258 is described below
commit 2d582586e1402fb9174f2fdad8ed4d677b3856d2
Author: Igor Sapego <is...@apache.org>
AuthorDate: Thu Nov 12 20:37:23 2020 +0300
IGNITE-13637: Implemented column-wise binding for result rows
This closes #8403
---
modules/platforms/cpp/odbc-test/CMakeLists.txt | 1 +
.../cpp/odbc-test/include/odbc_test_suite.h | 179 ++++++++++++-
.../cpp/odbc-test/project/vs/odbc-test.vcxproj | 3 +-
.../odbc-test/project/vs/odbc-test.vcxproj.filters | 5 +-
.../cpp/odbc-test/src/api_robustness_test.cpp | 2 +-
.../cpp/odbc-test/src/cursor_binding_test.cpp | 288 +++++++++++++++++++++
.../cpp/odbc-test/src/odbc_test_suite.cpp | 214 ++++++++++++---
.../platforms/cpp/odbc-test/src/queries_test.cpp | 8 +-
.../platforms/cpp/odbc-test/src/streaming_test.cpp | 4 +-
.../cpp/odbc/include/ignite/odbc/statement.h | 25 +-
.../cpp/odbc/src/app/application_data_buffer.cpp | 22 +-
modules/platforms/cpp/odbc/src/statement.cpp | 111 ++++++--
12 files changed, 781 insertions(+), 81 deletions(-)
diff --git a/modules/platforms/cpp/odbc-test/CMakeLists.txt b/modules/platforms/cpp/odbc-test/CMakeLists.txt
index d9cefb6..3a08f42 100644
--- a/modules/platforms/cpp/odbc-test/CMakeLists.txt
+++ b/modules/platforms/cpp/odbc-test/CMakeLists.txt
@@ -65,6 +65,7 @@ set(SOURCES src/teamcity/teamcity_boost.cpp
src/authentication_test.cpp
src/sql_parsing_test.cpp
src/streaming_test.cpp
+ src/cursor_binding_test.cpp
src/test_server.cpp
../odbc/src/log.cpp
../odbc/src/cursor.cpp
diff --git a/modules/platforms/cpp/odbc-test/include/odbc_test_suite.h b/modules/platforms/cpp/odbc-test/include/odbc_test_suite.h
index 89133a9..1bdd3b0 100644
--- a/modules/platforms/cpp/odbc-test/include/odbc_test_suite.h
+++ b/modules/platforms/cpp/odbc-test/include/odbc_test_suite.h
@@ -25,6 +25,16 @@
#include <sql.h>
#include <sqlext.h>
+#include <boost/test/unit_test.hpp>
+
+#ifndef BOOST_TEST_CONTEXT
+# define BOOST_TEST_CONTEXT(...)
+#endif
+
+#ifndef BOOST_TEST_INFO
+# define BOOST_TEST_INFO(...)
+#endif
+
#include <string>
#include "ignite/ignite.h"
@@ -97,7 +107,7 @@ namespace ignite
/**
* Insert requested number of TestType values with all defaults except
- * for the strFields, which are generated using getTestString().
+ * for the strFields, which are generated using GetTestString().
*
* @param recordsNum Number of records to insert.
* @param merge Set to true to use merge instead.
@@ -131,12 +141,175 @@ namespace ignite
void InsertNonFullBatchSelect(int recordsNum, int splitAt);
/**
+ * Get test i8Field.
+ *
+ * @param idx Index.
+ * @return Corresponding i8Field value.
+ */
+ static int8_t GetTestI8Field(int64_t idx);
+
+ /**
+ * Check i8Field test value.
+ * @param idx Index.
+ * @param value Value to test.
+ */
+ static void CheckTestI8Value(int idx, int8_t value);
+
+ /**
+ * Get test i16Field.
+ *
+ * @param idx Index.
+ * @return Corresponding i16Field value.
+ */
+ static int16_t GetTestI16Field(int64_t idx);
+
+ /**
+ * Check i16Field test value.
+ * @param idx Index.
+ * @param value Value to test.
+ */
+ static void CheckTestI16Value(int idx, int16_t value);
+
+ /**
+ * Get test i32Field.
+ *
+ * @param idx Index.
+ * @return Corresponding i32Field value.
+ */
+ static int32_t GetTestI32Field(int64_t idx);
+
+ /**
+ * Check i32Field test value.
+ * @param idx Index.
+ * @param value Value to test.
+ */
+ static void CheckTestI32Value(int idx, int32_t value);
+
+ /**
* Get test string.
*
- * @param ind Index.
+ * @param idx Index.
* @return Corresponding test string.
*/
- static std::string getTestString(int64_t ind);
+ static std::string GetTestString(int64_t idx);
+
+ /**
+ * Check strField test value.
+ * @param idx Index.
+ * @param value Value to test.
+ */
+ static void CheckTestStringValue(int idx, const std::string& value);
+
+ /**
+ * Get test floatField.
+ *
+ * @param idx Index.
+ * @return Corresponding floatField value.
+ */
+ static float GetTestFloatField(int64_t idx);
+
+ /**
+ * Check floatField test value.
+ * @param idx Index.
+ * @param value Value to test.
+ */
+ static void CheckTestFloatValue(int idx, float value);
+
+ /**
+ * Get test doubleField.
+ *
+ * @param idx Index.
+ * @return Corresponding doubleField value.
+ */
+ static double GetTestDoubleField(int64_t idx);
+
+ /**
+ * Check doubleField test value.
+ * @param idx Index.
+ * @param value Value to test.
+ */
+ static void CheckTestDoubleValue(int idx, double value);
+
+ /**
+ * Get test boolField.
+ *
+ * @param idx Index.
+ * @return Corresponding boolField value.
+ */
+ static bool GetTestBoolField(int64_t idx);
+
+ /**
+ * Check boolField test value.
+ * @param idx Index.
+ * @param value Value to test.
+ */
+ static void CheckTestBoolValue(int idx, bool value);
+
+ /**
+ * Get test dateField.
+ *
+ * @param idx Index.
+ * @param val Output value.
+ */
+ static void GetTestDateField(int64_t idx, SQL_DATE_STRUCT& val);
+
+ /**
+ * Check dateField test value.
+ *
+ * @param idx Index.
+ * @param val Value to test.
+ */
+ static void CheckTestDateValue(int idx, const SQL_DATE_STRUCT& val);
+
+ /**
+ * Get test timeField.
+ *
+ * @param idx Index.
+ * @param val Output value.
+ */
+ static void GetTestTimeField(int64_t idx, SQL_TIME_STRUCT& val);
+
+ /**
+ * Check timeField test value.
+ *
+ * @param idx Index.
+ * @param val Value to test.
+ */
+ static void CheckTestTimeValue(int idx, const SQL_TIME_STRUCT& val);
+
+ /**
+ * Get test timestampField.
+ *
+ * @param idx Index.
+ * @param val Output value.
+ */
+ static void GetTestTimestampField(int64_t idx, SQL_TIMESTAMP_STRUCT& val);
+
+ /**
+ * Check timestampField test value.
+ *
+ * @param idx Index.
+ * @param val Value to test.
+ */
+ static void CheckTestTimestampValue(int idx, const SQL_TIMESTAMP_STRUCT& val);
+
+ /**
+ * Get test i8ArrayField.
+ *
+ * @param idx Index.
+ * @param val Output value.
+ * @param valLen Value length.
+ */
+ static void GetTestI8ArrayField(int64_t idx, int8_t* val, size_t valLen);
+
+ /**
+ * Check i8ArrayField test value.
+ *
+ * @param idx Index.
+ * @param val Value to test.
+ * @param valLen Value length.
+ */
+ static void CheckTestI8ArrayValue(int idx, const int8_t* val, size_t valLen);
/**
* Check that SQL error has expected SQL state.
diff --git a/modules/platforms/cpp/odbc-test/project/vs/odbc-test.vcxproj b/modules/platforms/cpp/odbc-test/project/vs/odbc-test.vcxproj
index 90abdc8..cfc5ac1 100644
--- a/modules/platforms/cpp/odbc-test/project/vs/odbc-test.vcxproj
+++ b/modules/platforms/cpp/odbc-test/project/vs/odbc-test.vcxproj
@@ -185,6 +185,7 @@
<ClCompile Include="..\..\src\configuration_test.cpp" />
<ClCompile Include="..\..\src\connection_info_test.cpp" />
<ClCompile Include="..\..\src\connection_test.cpp" />
+ <ClCompile Include="..\..\src\cursor_binding_test.cpp" />
<ClCompile Include="..\..\src\cursor_test.cpp" />
<ClCompile Include="..\..\src\errors_test.cpp" />
<ClCompile Include="..\..\src\meta_queries_test.cpp" />
@@ -252,4 +253,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
-</Project>
\ No newline at end of file
+</Project>
diff --git a/modules/platforms/cpp/odbc-test/project/vs/odbc-test.vcxproj.filters b/modules/platforms/cpp/odbc-test/project/vs/odbc-test.vcxproj.filters
index 68c78cd..5d6e787 100644
--- a/modules/platforms/cpp/odbc-test/project/vs/odbc-test.vcxproj.filters
+++ b/modules/platforms/cpp/odbc-test/project/vs/odbc-test.vcxproj.filters
@@ -37,6 +37,9 @@
<ClCompile Include="..\..\src\row_test.cpp">
<Filter>Code</Filter>
</ClCompile>
+ <ClCompile Include="..\..\src\cursor_binding_test.cpp">
+ <Filter>Code</Filter>
+ </ClCompile>
<ClCompile Include="..\..\src\cursor_test.cpp">
<Filter>Code</Filter>
</ClCompile>
@@ -246,4 +249,4 @@
<Filter>Configs</Filter>
</None>
</ItemGroup>
-</Project>
\ No newline at end of file
+</Project>
diff --git a/modules/platforms/cpp/odbc-test/src/api_robustness_test.cpp b/modules/platforms/cpp/odbc-test/src/api_robustness_test.cpp
index 9148ba9..8fcb965 100644
--- a/modules/platforms/cpp/odbc-test/src/api_robustness_test.cpp
+++ b/modules/platforms/cpp/odbc-test/src/api_robustness_test.cpp
@@ -113,7 +113,7 @@ struct ApiRobustnessTestSuiteFixture : public odbc::OdbcTestSuite
// Operation is not supported. However, there should be no crash.
BOOST_CHECK(ret == SQL_ERROR);
- CheckSQLStatementDiagnosticError("HY106");
+ CheckSQLStatementDiagnosticError("HYC00");
}
/**
diff --git a/modules/platforms/cpp/odbc-test/src/cursor_binding_test.cpp b/modules/platforms/cpp/odbc-test/src/cursor_binding_test.cpp
new file mode 100644
index 0000000..5d09501
--- /dev/null
+++ b/modules/platforms/cpp/odbc-test/src/cursor_binding_test.cpp
@@ -0,0 +1,288 @@
+/*
+ * 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 <cstdio>
+
+#include <vector>
+#include <string>
+
+#include <boost/test/unit_test.hpp>
+
+#include "ignite/ignite.h"
+#include "ignite/ignition.h"
+#include "ignite/impl/binary/binary_utils.h"
+
+#include "test_type.h"
+#include "test_utils.h"
+#include "odbc_test_suite.h"
+
+using namespace ignite;
+using namespace ignite::cache;
+using namespace ignite::cache::query;
+using namespace ignite::common;
+using namespace ignite_test;
+
+using namespace boost::unit_test;
+
+using ignite::impl::binary::BinaryUtils;
+
+/**
+ * Test setup fixture.
+ */
+struct CursorBindingTestSuiteFixture : public odbc::OdbcTestSuite
+{
+ static Ignite StartAdditionalNode(const char* name)
+ {
+ return StartPlatformNode("queries-test.xml", name);
+ }
+
+ /**
+ * Constructor.
+ */
+ CursorBindingTestSuiteFixture() :
+ testCache(0)
+ {
+ grid = StartAdditionalNode("NodeMain");
+
+ testCache = grid.GetCache<int64_t, TestType>("cache");
+ }
+
+ /**
+ * Destructor.
+ */
+ virtual ~CursorBindingTestSuiteFixture()
+ {
+ // No-op.
+ }
+
+ /** Node started during the test. */
+ Ignite grid;
+
+ /** Test cache instance. */
+ Cache<int64_t, TestType> testCache;
+};
+
+BOOST_FIXTURE_TEST_SUITE(CursorBindingTestSuite, CursorBindingTestSuiteFixture)
+
+
+#define CHECK_TEST_VALUES(idx, testIdx) \
+ do { \
+ BOOST_TEST_CONTEXT("Test idx: " << testIdx) \
+ { \
+ BOOST_CHECK(RowStatus[idx] == SQL_ROW_SUCCESS || RowStatus[idx] == SQL_ROW_SUCCESS_WITH_INFO); \
+ \
+ BOOST_CHECK(i8FieldsInd[idx] != SQL_NULL_DATA); \
+ BOOST_CHECK(i16FieldsInd[idx] != SQL_NULL_DATA); \
+ BOOST_CHECK(i32FieldsInd[idx] != SQL_NULL_DATA); \
+ BOOST_CHECK(strFieldsLen[idx] != SQL_NULL_DATA); \
+ BOOST_CHECK(floatFields[idx] != SQL_NULL_DATA); \
+ BOOST_CHECK(doubleFieldsInd[idx] != SQL_NULL_DATA); \
+ BOOST_CHECK(boolFieldsInd[idx] != SQL_NULL_DATA); \
+ BOOST_CHECK(dateFieldsInd[idx] != SQL_NULL_DATA); \
+ BOOST_CHECK(timeFieldsInd[idx] != SQL_NULL_DATA); \
+ BOOST_CHECK(timestampFieldsInd[idx] != SQL_NULL_DATA); \
+ BOOST_CHECK(i8ArrayFieldsLen[idx] != SQL_NULL_DATA); \
+ \
+ int8_t i8Field = static_cast<int8_t>(i8Fields[idx]); \
+ int16_t i16Field = static_cast<int16_t>(i16Fields[idx]); \
+ int32_t i32Field = static_cast<int32_t>(i32Fields[idx]); \
+ std::string strField(reinterpret_cast<char*>(&strFields[idx][0]), \
+ static_cast<size_t>(strFieldsLen[idx])); \
+ float floatField = static_cast<float>(floatFields[idx]); \
+ double doubleField = static_cast<double>(doubleFields[idx]); \
+ bool boolField = boolFields[idx] != 0; \
+ \
+ CheckTestI8Value(testIdx, i8Field); \
+ CheckTestI16Value(testIdx, i16Field); \
+ CheckTestI32Value(testIdx, i32Field); \
+ CheckTestStringValue(testIdx, strField); \
+ CheckTestFloatValue(testIdx, floatField); \
+ CheckTestDoubleValue(testIdx, doubleField); \
+ CheckTestBoolValue(testIdx, boolField); \
+ CheckTestDateValue(testIdx, dateFields[idx]); \
+ CheckTestTimeValue(testIdx, timeFields[idx]); \
+ CheckTestTimestampValue(testIdx, timestampFields[idx]); \
+ CheckTestI8ArrayValue(testIdx, reinterpret_cast<int8_t*>(i8ArrayFields[idx]), \
+ static_cast<SQLLEN>(i8ArrayFieldsLen[idx])); \
+ } \
+ } while (false)
+
+BOOST_AUTO_TEST_CASE(TestCursorBindingColumnWise)
+{
+ enum { ROWS_COUNT = 15 };
+ enum { ROW_ARRAY_SIZE = 10 };
+ enum { BUFFER_SIZE = 1024 };
+
+ StartAdditionalNode("Node2");
+
+ Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11110;SCHEMA=cache;PAGE_SIZE=8");
+
+ // Preloading data.
+
+ InsertTestBatch(0, ROWS_COUNT, ROWS_COUNT);
+
+ // Setting attributes.
+
+ SQLUSMALLINT RowStatus[ROW_ARRAY_SIZE];
+ SQLUINTEGER NumRowsFetched;
+
+ SQLRETURN ret;
+
+ ret = SQLSetStmtAttr(stmt, SQL_ATTR_ROW_BIND_TYPE, SQL_BIND_BY_COLUMN, 0);
+ ODBC_THROW_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
+
+ ret = SQLSetStmtAttr(stmt, SQL_ATTR_ROW_ARRAY_SIZE, reinterpret_cast<SQLPOINTER*>(ROW_ARRAY_SIZE), 0);
+ ODBC_THROW_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
+
+ ret = SQLSetStmtAttr(stmt, SQL_ATTR_ROW_STATUS_PTR, RowStatus, 0);
+ ODBC_THROW_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
+
+ ret = SQLSetStmtAttr(stmt, SQL_ATTR_ROWS_FETCHED_PTR, &NumRowsFetched, 0);
+ ODBC_THROW_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
+
+ // Binding collumns.
+
+ SQLSCHAR i8Fields[ROW_ARRAY_SIZE] = {0};
+ SQLLEN i8FieldsInd[ROW_ARRAY_SIZE];
+
+ SQLSMALLINT i16Fields[ROW_ARRAY_SIZE] = {0};
+ SQLLEN i16FieldsInd[ROW_ARRAY_SIZE];
+
+ SQLINTEGER i32Fields[ROW_ARRAY_SIZE] = {0};
+ SQLLEN i32FieldsInd[ROW_ARRAY_SIZE];
+
+ SQLCHAR strFields[ROW_ARRAY_SIZE][BUFFER_SIZE];
+ SQLLEN strFieldsLen[ROW_ARRAY_SIZE];
+
+ SQLREAL floatFields[ROW_ARRAY_SIZE];
+ SQLLEN floatFieldsInd[ROW_ARRAY_SIZE];
+
+ SQLDOUBLE doubleFields[ROW_ARRAY_SIZE];
+ SQLLEN doubleFieldsInd[ROW_ARRAY_SIZE];
+
+ SQLCHAR boolFields[ROW_ARRAY_SIZE];
+ SQLLEN boolFieldsInd[ROW_ARRAY_SIZE];
+
+ SQL_DATE_STRUCT dateFields[ROW_ARRAY_SIZE];
+ SQLLEN dateFieldsInd[ROW_ARRAY_SIZE];
+
+ SQL_TIME_STRUCT timeFields[ROW_ARRAY_SIZE];
+ SQLLEN timeFieldsInd[ROW_ARRAY_SIZE];
+
+ SQL_TIMESTAMP_STRUCT timestampFields[ROW_ARRAY_SIZE];
+ SQLLEN timestampFieldsInd[ROW_ARRAY_SIZE];
+
+ SQLCHAR i8ArrayFields[ROW_ARRAY_SIZE][BUFFER_SIZE];
+ SQLLEN i8ArrayFieldsLen[ROW_ARRAY_SIZE];
+
+ ret = SQLBindCol(stmt, 1, SQL_C_STINYINT, i8Fields, 0, i8FieldsInd);
+ ODBC_THROW_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
+
+ ret = SQLBindCol(stmt, 2, SQL_C_SSHORT, i16Fields, 0, i16FieldsInd);
+ ODBC_THROW_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
+
+ ret = SQLBindCol(stmt, 3, SQL_C_LONG, i32Fields, 0, i32FieldsInd);
+ ODBC_THROW_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
+
+ ret = SQLBindCol(stmt, 4, SQL_C_CHAR, strFields, BUFFER_SIZE, strFieldsLen);
+ ODBC_THROW_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
+
+ ret = SQLBindCol(stmt, 5, SQL_C_FLOAT, floatFields, 0, floatFieldsInd);
+ ODBC_THROW_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
+
+ ret = SQLBindCol(stmt, 6, SQL_C_DOUBLE, doubleFields, 0, doubleFieldsInd);
+ ODBC_THROW_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
+
+ ret = SQLBindCol(stmt, 7, SQL_C_BIT, boolFields, 0, boolFieldsInd);
+ ODBC_THROW_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
+
+ ret = SQLBindCol(stmt, 8, SQL_C_DATE, dateFields, 0, dateFieldsInd);
+ ODBC_THROW_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
+
+ ret = SQLBindCol(stmt, 9, SQL_C_TIME, timeFields, 0, timeFieldsInd);
+ ODBC_THROW_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
+
+ ret = SQLBindCol(stmt, 10, SQL_C_TIMESTAMP, timestampFields, 0, timestampFieldsInd);
+ ODBC_THROW_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
+
+ ret = SQLBindCol(stmt, 11, SQL_C_BINARY, i8ArrayFields, BUFFER_SIZE, i8ArrayFieldsLen);
+ ODBC_THROW_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
+
+ SQLCHAR sql[] = "SELECT "
+ "i8Field, i16Field, i32Field, strField, floatField, doubleField, "
+ "boolField, dateField, timeField, timestampField, i8ArrayField "
+ "FROM TestType "
+ "ORDER BY _key";
+
+ // Execute a statement to retrieve rows from the Orders table.
+ ret = SQLExecDirect(stmt, sql, SQL_NTS);
+ ODBC_THROW_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
+
+ ret = SQLFetchScroll(stmt, SQL_FETCH_NEXT, 0);
+ ODBC_THROW_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
+
+ BOOST_CHECK_EQUAL(NumRowsFetched, (SQLUINTEGER)ROW_ARRAY_SIZE);
+
+ for (int64_t i = 0; i < NumRowsFetched; i++)
+ {
+ CHECK_TEST_VALUES(i, static_cast<int>(i));
+ }
+
+ ret = SQLFetch(stmt);
+ ODBC_THROW_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
+
+ BOOST_CHECK_EQUAL(NumRowsFetched, ROWS_COUNT - ROW_ARRAY_SIZE);
+
+ for (int64_t i = 0; i < NumRowsFetched; i++)
+ {
+ int64_t testIdx = i + ROW_ARRAY_SIZE;
+ CHECK_TEST_VALUES(i, static_cast<int>(testIdx));
+ }
+
+ for (int64_t i = NumRowsFetched; i < ROW_ARRAY_SIZE; i++)
+ {
+ BOOST_TEST_INFO("Checking row status for row: " << i);
+ BOOST_CHECK(RowStatus[i] == SQL_ROW_NOROW);
+ }
+
+ ret = SQLFetchScroll(stmt, SQL_FETCH_NEXT, 0);
+ BOOST_CHECK_EQUAL(ret, SQL_NO_DATA);
+
+ // Close the cursor.
+ ret = SQLCloseCursor(stmt);
+ ODBC_THROW_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
+}
+
+BOOST_AUTO_TEST_CASE(TestCursorBindingRowWise)
+{
+ Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11110;SCHEMA=cache;PAGE_SIZE=8");
+
+ SQLRETURN ret = SQLSetStmtAttr(stmt, SQL_ATTR_ROW_BIND_TYPE, reinterpret_cast<SQLPOINTER*>(42), 0);
+
+ BOOST_CHECK_EQUAL(ret, SQL_ERROR);
+
+ CheckSQLStatementDiagnosticError("HYC00");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/modules/platforms/cpp/odbc-test/src/odbc_test_suite.cpp b/modules/platforms/cpp/odbc-test/src/odbc_test_suite.cpp
index 4ebec9f..28affb7 100644
--- a/modules/platforms/cpp/odbc-test/src/odbc_test_suite.cpp
+++ b/modules/platforms/cpp/odbc-test/src/odbc_test_suite.cpp
@@ -95,9 +95,7 @@ namespace ignite
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);
@@ -184,15 +182,182 @@ namespace ignite
Ignition::StopAll(true);
}
- std::string OdbcTestSuite::getTestString(int64_t ind)
+ 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#" << ind;
+ 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];
@@ -267,7 +432,7 @@ namespace ignite
for (SQLSMALLINT i = 0; i < recordsNum; ++i)
{
key = i + 1;
- std::string val = getTestString(i);
+ std::string val = GetTestString(i);
strncpy(strField, val.c_str(), sizeof(strField));
strFieldLen = SQL_NTS;
@@ -342,36 +507,23 @@ namespace ignite
int seed = from + i;
keys[i] = seed;
- i8Fields[i] = seed * 8;
- i16Fields[i] = seed * 16;
- i32Fields[i] = seed * 32;
+ i8Fields[i] = GetTestI8Field(seed);
+ i16Fields[i] = GetTestI16Field(seed);
+ i32Fields[i] = GetTestI32Field(seed);
- std::string val = getTestString(seed);
+ std::string val = GetTestString(seed);
strncpy(strFields.GetData() + 1024 * i, val.c_str(), 1023);
strFieldsLen[i] = val.size();
- floatFields[i] = seed * 0.5f;
- doubleFields[i] = seed * 0.25f;
- boolFields[i] = seed % 2 == 0;
-
- dateFields[i].year = 2017 + seed / 365;
- dateFields[i].month = ((seed / 28) % 12) + 1;
- dateFields[i].day = (seed % 28) + 1;
-
- timeFields[i].hour = (seed / 3600) % 24;
- timeFields[i].minute = (seed / 60) % 60;
- timeFields[i].second = seed % 60;
+ floatFields[i] = GetTestFloatField(seed);
+ doubleFields[i] = GetTestDoubleField(seed);
+ boolFields[i] = GetTestBoolField(seed);
- timestampFields[i].year = dateFields[i].year;
- timestampFields[i].month = dateFields[i].month;
- timestampFields[i].day = dateFields[i].day;
- timestampFields[i].hour = timeFields[i].hour;
- timestampFields[i].minute = timeFields[i].minute;
- timestampFields[i].second = timeFields[i].second;
- timestampFields[i].fraction = static_cast<uint64_t>(std::abs(seed * 914873)) % 1000000000;
+ GetTestDateField(seed, dateFields[i]);
+ GetTestTimeField(seed, timeFields[i]);
+ GetTestTimestampField(seed, timestampFields[i]);
- for (int j = 0; j < 42; ++j)
- i8ArrayFields[i * 42 + j] = seed * 42 + j;
+ GetTestI8ArrayField(seed, &i8ArrayFields[i*42], 42);
i8ArrayFieldsLen[i] = 42;
}
@@ -553,7 +705,7 @@ namespace ignite
if (!SQL_SUCCEEDED(ret))
BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
- std::string expectedStr = getTestString(selectedRecordsNum);
+ std::string expectedStr = GetTestString(selectedRecordsNum);
int64_t expectedKey = selectedRecordsNum;
BOOST_CHECK_EQUAL(key, expectedKey);
@@ -634,7 +786,7 @@ namespace ignite
if (!SQL_SUCCEEDED(ret))
BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
- std::string expectedStr = getTestString(selectedRecordsNum);
+ std::string expectedStr = GetTestString(selectedRecordsNum);
int64_t expectedKey = selectedRecordsNum;
BOOST_CHECK_EQUAL(key, expectedKey);
diff --git a/modules/platforms/cpp/odbc-test/src/queries_test.cpp b/modules/platforms/cpp/odbc-test/src/queries_test.cpp
index 46fed8a..a22c336 100644
--- a/modules/platforms/cpp/odbc-test/src/queries_test.cpp
+++ b/modules/platforms/cpp/odbc-test/src/queries_test.cpp
@@ -922,7 +922,7 @@ BOOST_AUTO_TEST_CASE(TestInsertSelect)
if (!SQL_SUCCEEDED(ret))
BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
- std::string expectedStr = getTestString(selectedRecordsNum);
+ std::string expectedStr = GetTestString(selectedRecordsNum);
int64_t expectedKey = selectedRecordsNum + 1;
BOOST_CHECK_EQUAL(key, expectedKey);
@@ -999,7 +999,7 @@ BOOST_AUTO_TEST_CASE(TestInsertUpdateSelect)
if (expectedKey == 42)
expectedStr = "Updated value";
else
- expectedStr = getTestString(selectedRecordsNum);
+ expectedStr = GetTestString(selectedRecordsNum);
BOOST_CHECK_EQUAL(std::string(strField, strFieldLen), expectedStr);
@@ -1066,7 +1066,7 @@ BOOST_AUTO_TEST_CASE(TestInsertDeleteSelect)
BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
int64_t expectedKey = (selectedRecordsNum + 1) * 2;
- std::string expectedStr = getTestString(expectedKey - 1);
+ std::string expectedStr = GetTestString(expectedKey - 1);
BOOST_CHECK_EQUAL(key, expectedKey);
BOOST_CHECK_EQUAL(std::string(strField, strFieldLen), expectedStr);
@@ -1127,7 +1127,7 @@ BOOST_AUTO_TEST_CASE(TestInsertMergeSelect)
if (!SQL_SUCCEEDED(ret))
BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
- std::string expectedStr = getTestString(selectedRecordsNum);
+ std::string expectedStr = GetTestString(selectedRecordsNum);
int64_t expectedKey = selectedRecordsNum + 1;
BOOST_CHECK_EQUAL(key, expectedKey);
diff --git a/modules/platforms/cpp/odbc-test/src/streaming_test.cpp b/modules/platforms/cpp/odbc-test/src/streaming_test.cpp
index 1d74338..d863e37 100644
--- a/modules/platforms/cpp/odbc-test/src/streaming_test.cpp
+++ b/modules/platforms/cpp/odbc-test/src/streaming_test.cpp
@@ -115,7 +115,7 @@ struct StreamingTestSuiteFixture : odbc::OdbcTestSuite
for (int32_t i = begin; i < end; ++i)
{
key = i;
- std::string val = getTestString(i);
+ std::string val = GetTestString(i);
strncpy(strField, val.c_str(), sizeof(strField));
strFieldLen = SQL_NTS;
@@ -240,7 +240,7 @@ struct StreamingTestSuiteFixture : odbc::OdbcTestSuite
BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
BOOST_CHECK_EQUAL(i, keyVal);
- BOOST_CHECK_EQUAL(getTestString(i), std::string(strField, static_cast<size_t>(strFieldLen)));
+ BOOST_CHECK_EQUAL(GetTestString(i), std::string(strField, static_cast<size_t>(strFieldLen)));
}
// Resetting parameters.
diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc/statement.h b/modules/platforms/cpp/odbc/include/ignite/odbc/statement.h
index 19d29a9..37c91b4 100644
--- a/modules/platforms/cpp/odbc/include/ignite/odbc/statement.h
+++ b/modules/platforms/cpp/odbc/include/ignite/odbc/statement.h
@@ -296,28 +296,28 @@ namespace ignite
*
* @param ptr Rows fetched buffer pointer.
*/
- void SetRowsFetchedPtr(size_t* ptr);
+ void SetRowsFetchedPtr(SQLINTEGER* ptr);
/**
* Get rows fetched buffer pointer.
*
* @return Rows fetched buffer pointer.
*/
- size_t* GetRowsFetchedPtr();
+ SQLINTEGER* GetRowsFetchedPtr();
/**
* Set row statuses array pointer.
*
* @param ptr Row statuses array pointer.
*/
- void SetRowStatusesPtr(uint16_t* ptr);
+ void SetRowStatusesPtr(SQLUSMALLINT* ptr);
/**
* Get row statuses array pointer.
*
* @return Row statuses array pointer.
*/
- uint16_t* GetRowStatusesPtr();
+ SQLUSMALLINT* GetRowStatusesPtr();
/**
* Select next parameter data for which is required.
@@ -671,6 +671,13 @@ namespace ignite
SqlResult::Type UpdateParamsMeta();
/**
+ * Convert SQLRESULT to SQL_ROW_RESULT.
+ *
+ * @return Operation result.
+ */
+ uint16_t SqlResultToRowResult(SqlResult::Type value);
+
+ /**
* Constructor.
* Called by friend classes.
*
@@ -687,18 +694,18 @@ namespace ignite
/** Underlying query. */
std::auto_ptr<query::Query> currentQuery;
- /** Row bind type. */
- SqlUlen rowBindType;
-
/** Buffer to store number of rows fetched by the last fetch. */
- size_t* rowsFetched;
+ SQLINTEGER* rowsFetched;
/** Array to store statuses of rows fetched by the last fetch. */
- uint16_t* rowStatuses;
+ SQLUSMALLINT* rowStatuses;
/** Offset added to pointers to change binding of column data. */
int* columnBindOffset;
+ /** Row array size. */
+ SqlUlen rowArraySize;
+
/** Parameters. */
app::ParameterSet parameters;
diff --git a/modules/platforms/cpp/odbc/src/app/application_data_buffer.cpp b/modules/platforms/cpp/odbc/src/app/application_data_buffer.cpp
index 2f1fbcb..35af8cf 100644
--- a/modules/platforms/cpp/odbc/src/app/application_data_buffer.cpp
+++ b/modules/platforms/cpp/odbc/src/app/application_data_buffer.cpp
@@ -1707,28 +1707,36 @@ namespace ignite
return buflen;
case OdbcNativeType::AI_SIGNED_SHORT:
+ return static_cast<SqlLen>(sizeof(SQLSMALLINT));
+
case OdbcNativeType::AI_UNSIGNED_SHORT:
- return static_cast<SqlLen>(sizeof(short));
+ return static_cast<SqlLen>(sizeof(SQLUSMALLINT));
case OdbcNativeType::AI_SIGNED_LONG:
+ return static_cast<SqlLen>(sizeof(SQLUINTEGER));
+
case OdbcNativeType::AI_UNSIGNED_LONG:
- return static_cast<SqlLen>(sizeof(long));
+ return static_cast<SqlLen>(sizeof(SQLINTEGER));
case OdbcNativeType::AI_FLOAT:
- return static_cast<SqlLen>(sizeof(float));
+ return static_cast<SqlLen>(sizeof(SQLREAL));
case OdbcNativeType::AI_DOUBLE:
- return static_cast<SqlLen>(sizeof(double));
+ return static_cast<SqlLen>(sizeof(SQLDOUBLE));
- case OdbcNativeType::AI_BIT:
case OdbcNativeType::AI_SIGNED_TINYINT:
+ return static_cast<SqlLen>(sizeof(SQLSCHAR));
+
+ case OdbcNativeType::AI_BIT:
case OdbcNativeType::AI_UNSIGNED_TINYINT:
- return static_cast<SqlLen>(sizeof(char));
+ return static_cast<SqlLen>(sizeof(SQLCHAR));
case OdbcNativeType::AI_SIGNED_BIGINT:
- case OdbcNativeType::AI_UNSIGNED_BIGINT:
return static_cast<SqlLen>(sizeof(SQLBIGINT));
+ case OdbcNativeType::AI_UNSIGNED_BIGINT:
+ return static_cast<SqlLen>(sizeof(SQLUBIGINT));
+
case OdbcNativeType::AI_TDATE:
return static_cast<SqlLen>(sizeof(SQL_DATE_STRUCT));
diff --git a/modules/platforms/cpp/odbc/src/statement.cpp b/modules/platforms/cpp/odbc/src/statement.cpp
index d88d449..9253030 100644
--- a/modules/platforms/cpp/odbc/src/statement.cpp
+++ b/modules/platforms/cpp/odbc/src/statement.cpp
@@ -46,10 +46,10 @@ namespace ignite
connection(parent),
columnBindings(),
currentQuery(),
- rowBindType(SQL_BIND_BY_COLUMN),
rowsFetched(0),
rowStatuses(0),
columnBindOffset(0),
+ rowArraySize(1),
parameters(),
timeout(0)
{
@@ -205,7 +205,7 @@ namespace ignite
if (!buffer && !resLen)
{
AddStatusRecord(SqlState::SHY009_INVALID_USE_OF_NULL_POINTER,
- "ParameterValuePtr and StrLen_or_IndPtr are both null pointers.");
+ "ParameterValuePtr and StrLen_or_IndPtr are both null pointers");
return SqlResult::AI_ERROR;
}
@@ -234,34 +234,59 @@ namespace ignite
LOG_MSG("SQL_ATTR_ROW_ARRAY_SIZE: " << val);
- if (val != 1)
+ if (val < 1)
{
- AddStatusRecord(SqlState::SHYC00_OPTIONAL_FEATURE_NOT_IMPLEMENTED,
- "Fetching of more than one row by call is not supported.");
+ AddStatusRecord(SqlState::SHY092_OPTION_TYPE_OUT_OF_RANGE,
+ "Array size value can not be less than 1");
return SqlResult::AI_ERROR;
}
+ rowArraySize = val;
+
break;
}
case SQL_ATTR_ROW_BIND_TYPE:
{
- rowBindType = reinterpret_cast<SqlUlen>(value);
+ SqlUlen rowBindType = reinterpret_cast<SqlUlen>(value);
+
+ if (rowBindType != SQL_BIND_BY_COLUMN)
+ {
+ AddStatusRecord(SqlState::SHYC00_OPTIONAL_FEATURE_NOT_IMPLEMENTED,
+ "Only binding by column is currently supported");
+
+ return SqlResult::AI_ERROR;
+ }
break;
}
case SQL_ATTR_ROWS_FETCHED_PTR:
{
- SetRowsFetchedPtr(reinterpret_cast<size_t*>(value));
+ SetRowsFetchedPtr(reinterpret_cast<SQLINTEGER*>(value));
break;
}
case SQL_ATTR_ROW_STATUS_PTR:
{
- SetRowStatusesPtr(reinterpret_cast<uint16_t*>(value));
+ SetRowStatusesPtr(reinterpret_cast<SQLUSMALLINT*>(value));
+
+ break;
+ }
+
+ case SQL_ATTR_PARAM_BIND_TYPE:
+ {
+ SqlUlen paramBindType = reinterpret_cast<SqlUlen>(value);
+
+ if (paramBindType != SQL_PARAM_BIND_BY_COLUMN)
+ {
+ AddStatusRecord(SqlState::SHYC00_OPTIONAL_FEATURE_NOT_IMPLEMENTED,
+ "Only binding by column is currently supported");
+
+ return SqlResult::AI_ERROR;
+ }
break;
}
@@ -380,7 +405,7 @@ namespace ignite
{
SqlUlen* val = reinterpret_cast<SqlUlen*>(buf);
- *val = rowBindType;
+ *val = SQL_BIND_BY_COLUMN;
break;
}
@@ -421,6 +446,15 @@ namespace ignite
break;
}
+ case SQL_ATTR_PARAM_BIND_TYPE:
+ {
+ SqlUlen* val = reinterpret_cast<SqlUlen*>(buf);
+
+ *val = SQL_PARAM_BIND_BY_COLUMN;
+
+ break;
+ }
+
case SQL_ATTR_PARAM_BIND_OFFSET_PTR:
{
SQLULEN** val = reinterpret_cast<SQLULEN**>(buf);
@@ -956,7 +990,9 @@ namespace ignite
if (orientation != SQL_FETCH_NEXT)
{
- AddStatusRecord(SqlState::SHY106_FETCH_TYPE_OUT_OF_RANGE, "The value specified for the argument FetchOrientation was not SQL_FETCH_NEXT.");
+ AddStatusRecord(SqlState::SHYC00_OPTIONAL_FEATURE_NOT_IMPLEMENTED,
+ "Only SQL_FETCH_NEXT FetchOrientation type is supported");
+
return SqlResult::AI_ERROR;
}
@@ -975,8 +1011,7 @@ namespace ignite
if (!currentQuery.get())
{
- AddStatusRecord(SqlState::S24000_INVALID_CURSOR_STATE,
- "Cursor is not in the open state.");
+ AddStatusRecord(SqlState::S24000_INVALID_CURSOR_STATE, "Cursor is not in the open state");
return SqlResult::AI_ERROR;
}
@@ -987,18 +1022,32 @@ namespace ignite
it->second.SetByteOffset(*columnBindOffset);
}
- SqlResult::Type res = currentQuery->FetchNextRow(columnBindings);
+ SQLINTEGER fetched = 0;
+ SQLINTEGER errors = 0;
- if (res == SqlResult::AI_SUCCESS)
+ for (SqlUlen i = 0; i < rowArraySize; ++i)
{
- if (rowsFetched)
- *rowsFetched = 1;
+ for (app::ColumnBindingMap::iterator it = columnBindings.begin(); it != columnBindings.end(); ++it)
+ it->second.SetElementOffset(i);
+
+ SqlResult::Type res = currentQuery->FetchNextRow(columnBindings);
+
+ if (res == SqlResult::AI_SUCCESS || res == SqlResult::AI_SUCCESS_WITH_INFO)
+ ++fetched;
+ else if (res != SqlResult::AI_NO_DATA)
+ ++errors;
if (rowStatuses)
- rowStatuses[0] = SQL_ROW_SUCCESS;
+ rowStatuses[i] = SqlResultToRowResult(res);
}
- return res;
+ if (rowsFetched)
+ *rowsFetched = fetched < 0 ? static_cast<SQLINTEGER>(rowArraySize) : fetched;
+
+ if (fetched > 0)
+ return errors == 0 ? SqlResult::AI_SUCCESS : SqlResult::AI_SUCCESS_WITH_INFO;
+
+ return errors == 0 ? SqlResult::AI_NO_DATA : SqlResult::AI_ERROR;
}
const meta::ColumnMetaVector* Statement::GetMeta()
@@ -1114,22 +1163,22 @@ namespace ignite
return SqlResult::AI_SUCCESS;
}
- void Statement::SetRowsFetchedPtr(size_t* ptr)
+ void Statement::SetRowsFetchedPtr(SQLINTEGER* ptr)
{
rowsFetched = ptr;
}
- size_t* Statement::GetRowsFetchedPtr()
+ SQLINTEGER* Statement::GetRowsFetchedPtr()
{
return rowsFetched;
}
- void Statement::SetRowStatusesPtr(uint16_t* ptr)
+ void Statement::SetRowStatusesPtr(SQLUSMALLINT* ptr)
{
rowStatuses = ptr;
}
- uint16_t * Statement::GetRowStatusesPtr()
+ SQLUSMALLINT * Statement::GetRowStatusesPtr()
{
return rowStatuses;
}
@@ -1327,6 +1376,24 @@ namespace ignite
return SqlResult::AI_SUCCESS;
}
+
+ uint16_t Statement::SqlResultToRowResult(SqlResult::Type value)
+ {
+ switch (value)
+ {
+ case SqlResult::AI_NO_DATA:
+ return SQL_ROW_NOROW;
+
+ case SqlResult::AI_SUCCESS:
+ return SQL_ROW_SUCCESS;
+
+ case SqlResult::AI_SUCCESS_WITH_INFO:
+ return SQL_ROW_SUCCESS_WITH_INFO;
+
+ default:
+ return SQL_ROW_ERROR;
+ }
+ }
}
}