IGNITE-4493: ODBC: Added missing diagnostic records for error cases This closes #1396
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/9e8e9798 Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/9e8e9798 Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/9e8e9798 Branch: refs/heads/ignite-gg-11810-1 Commit: 9e8e9798dae8b92cfbf4d940856dec35d3e30f54 Parents: bf118aa Author: Sergey Kalashnikov <skalashni...@gridgain.com> Authored: Tue Jan 10 11:10:56 2017 +0300 Committer: Pavel Tupitsyn <ptupit...@apache.org> Committed: Tue Jan 10 11:10:56 2017 +0300 ---------------------------------------------------------------------- .../cpp/odbc-test/src/api_robustness_test.cpp | 113 +++++++++++- .../cpp/odbc/include/ignite/odbc/common_types.h | 29 ++- .../cpp/odbc/include/ignite/odbc/statement.h | 143 +++++++++++---- modules/platforms/cpp/odbc/src/connection.cpp | 2 +- .../odbc/src/diagnostic/diagnostic_record.cpp | 38 ++++ modules/platforms/cpp/odbc/src/odbc.cpp | 118 ++++--------- modules/platforms/cpp/odbc/src/statement.cpp | 176 ++++++++++++++++--- 7 files changed, 484 insertions(+), 135 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/9e8e9798/modules/platforms/cpp/odbc-test/src/api_robustness_test.cpp ---------------------------------------------------------------------- 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 13a5ea6..0b6df93 100644 --- a/modules/platforms/cpp/odbc-test/src/api_robustness_test.cpp +++ b/modules/platforms/cpp/odbc-test/src/api_robustness_test.cpp @@ -50,7 +50,7 @@ using ignite::impl::binary::BinaryUtils; /** * Test setup fixture. */ -struct ApiRobustnessTestSuiteFixture +struct ApiRobustnessTestSuiteFixture { void Prepare() { @@ -206,6 +206,33 @@ struct ApiRobustnessTestSuiteFixture // Operation is not supported. However, there should be no crash. BOOST_CHECK(ret == SQL_ERROR); + + CheckSQLStatementDiagnosticError("HY106"); + } + + void 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 CheckSQLStatementDiagnosticError(const std::string& expectSqlState) + { + CheckSQLDiagnosticError(SQL_HANDLE_STMT, stmt, expectSqlState); + } + + void CheckSQLConnectionDiagnosticError(const std::string& expectSqlState) + { + CheckSQLDiagnosticError(SQL_HANDLE_DBC, dbc, expectSqlState); } /** @@ -234,6 +261,43 @@ struct ApiRobustnessTestSuiteFixture SQLHSTMT stmt; }; +SQLSMALLINT unsupportedC[] = { + SQL_C_INTERVAL_YEAR, + SQL_C_INTERVAL_MONTH, + SQL_C_INTERVAL_DAY, + SQL_C_INTERVAL_HOUR, + SQL_C_INTERVAL_MINUTE, + SQL_C_INTERVAL_SECOND, + SQL_C_INTERVAL_YEAR_TO_MONTH, + SQL_C_INTERVAL_DAY_TO_HOUR, + SQL_C_INTERVAL_DAY_TO_MINUTE, + SQL_C_INTERVAL_DAY_TO_SECOND, + SQL_C_INTERVAL_HOUR_TO_MINUTE, + SQL_C_INTERVAL_HOUR_TO_SECOND, + SQL_C_INTERVAL_MINUTE_TO_SECOND + }; + +SQLSMALLINT unsupportedSql[] = { + SQL_WVARCHAR, + SQL_WLONGVARCHAR, + SQL_REAL, + SQL_NUMERIC, + SQL_TYPE_TIME, + SQL_INTERVAL_MONTH, + SQL_INTERVAL_YEAR, + SQL_INTERVAL_YEAR_TO_MONTH, + SQL_INTERVAL_DAY, + SQL_INTERVAL_HOUR, + SQL_INTERVAL_MINUTE, + SQL_INTERVAL_SECOND, + SQL_INTERVAL_DAY_TO_HOUR, + SQL_INTERVAL_DAY_TO_MINUTE, + SQL_INTERVAL_DAY_TO_SECOND, + SQL_INTERVAL_HOUR_TO_MINUTE, + SQL_INTERVAL_HOUR_TO_SECOND, + SQL_INTERVAL_MINUTE_TO_SECOND + }; + BOOST_FIXTURE_TEST_SUITE(ApiRobustnessTestSuite, ApiRobustnessTestSuiteFixture) BOOST_AUTO_TEST_CASE(TestSQLDriverConnect) @@ -516,6 +580,19 @@ BOOST_AUTO_TEST_CASE(TestSQLBindCol) ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, stmt); + //Unsupported data types + for(int i = 0; i < sizeof(unsupportedC)/sizeof(unsupportedC[0]); ++i) + { + ret = SQLBindCol(stmt, 1, unsupportedC[i], &ind1, sizeof(ind1), &len1); + BOOST_REQUIRE_EQUAL(ret, SQL_ERROR); + CheckSQLStatementDiagnosticError("HY003"); + } + + // Size is negative. + ret = SQLBindCol(stmt, 1, SQL_C_SLONG, &ind1, -1, &len1); + BOOST_REQUIRE_EQUAL(ret, SQL_ERROR); + CheckSQLStatementDiagnosticError("HY090"); + // Size is null. SQLBindCol(stmt, 1, SQL_C_SLONG, &ind1, 0, &len1); @@ -545,6 +622,24 @@ BOOST_AUTO_TEST_CASE(TestSQLBindParameter) ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, stmt); + //Unsupported parameter type : output + SQLBindParameter(stmt, 2, SQL_PARAM_OUTPUT, SQL_C_SLONG, SQL_INTEGER, 100, 100, &ind1, sizeof(ind1), &len1); + CheckSQLStatementDiagnosticError("HY105"); + + //Unsupported parameter type : input/output + SQLBindParameter(stmt, 2, SQL_PARAM_INPUT_OUTPUT, SQL_C_SLONG, SQL_INTEGER, 100, 100, &ind1, sizeof(ind1), &len1); + CheckSQLStatementDiagnosticError("HY105"); + + + //Unsupported data types + for(int i = 0; i < sizeof(unsupportedSql)/sizeof(unsupportedSql[0]); ++i) + { + ret = SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_SLONG, unsupportedSql[i], 100, 100, &ind1, sizeof(ind1), &len1); + BOOST_REQUIRE_EQUAL(ret, SQL_ERROR); + CheckSQLStatementDiagnosticError("HYC00"); + } + + // Size is null. SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 100, 100, &ind1, 0, &len1); @@ -1111,4 +1206,20 @@ BOOST_AUTO_TEST_CASE(TestSQLError) SQLError(0, 0, 0, 0, 0, 0, 0, 0); } +BOOST_AUTO_TEST_CASE(TestSQLDiagnosticRecords) +{ + Connect("DRIVER={Apache Ignite};address=127.0.0.1:11110;cache=cache"); + + SQLHANDLE hnd; + SQLRETURN ret; + + ret = SQLAllocHandle(SQL_HANDLE_DESC, dbc, &hnd); + BOOST_REQUIRE_EQUAL(ret, SQL_ERROR); + CheckSQLConnectionDiagnosticError("IM001"); + + ret = SQLFreeStmt(stmt, 4); + BOOST_REQUIRE_EQUAL(ret, SQL_ERROR); + CheckSQLStatementDiagnosticError("HY092"); +} + BOOST_AUTO_TEST_SUITE_END() http://git-wip-us.apache.org/repos/asf/ignite/blob/9e8e9798/modules/platforms/cpp/odbc/include/ignite/odbc/common_types.h ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc/common_types.h b/modules/platforms/cpp/odbc/include/ignite/odbc/common_types.h index 517fe4e..5d8901d 100644 --- a/modules/platforms/cpp/odbc/include/ignite/odbc/common_types.h +++ b/modules/platforms/cpp/odbc/include/ignite/odbc/common_types.h @@ -113,15 +113,37 @@ namespace ignite */ SQL_STATE_HY001_MEMORY_ALLOCATION, + /** + * The argument TargetType was neither a valid data type + * nor SQL_C_DEFAULT + */ + SQL_STATE_HY003_INVALID_APPLICATION_BUFFER_TYPE, + /** Invalid use of null pointer. */ SQL_STATE_HY009_INVALID_USE_OF_NULL_POINTER, /** Function sequence error. */ SQL_STATE_HY010_SEQUENCE_ERROR, + /** + * Invalid string or buffer length + */ + SQL_STATE_HY090_INVALID_STRING_OR_BUFFER_LENGTH, + + /** + * Option type was out of range. + */ + SQL_STATE_HY092_OPTION_TYPE_OUT_OF_RANGE, + /** Column type out of range. */ SQL_STATE_HY097_COLUMN_TYPE_OUT_OF_RANGE, + /** The value specified for the argument InputOutputType was invalid. */ + SQL_STATE_HY105_INVALID_PARAMETER_TYPE, + + /** The value specified for the argument FetchOrientation was invalid. */ + SQL_STATE_HY106_FETCH_TYPE_OUT_OF_RANGE, + /** * The driver does not support the feature of ODBC behavior that * the application requested. @@ -132,7 +154,12 @@ namespace ignite * The connection timeout period expired before the data source * responded to the request. */ - SQL_STATE_HYT01_CONNECTIOIN_TIMEOUT + SQL_STATE_HYT01_CONNECTIOIN_TIMEOUT, + + /** + * Driver does not support this function. + */ + SQL_STATE_IM001_FUNCTION_NOT_SUPPORTED }; /** http://git-wip-us.apache.org/repos/asf/ignite/blob/9e8e9798/modules/platforms/cpp/odbc/include/ignite/odbc/statement.h ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc/statement.h b/modules/platforms/cpp/odbc/include/ignite/odbc/statement.h index db56660..596fc66 100644 --- a/modules/platforms/cpp/odbc/include/ignite/odbc/statement.h +++ b/modules/platforms/cpp/odbc/include/ignite/odbc/statement.h @@ -57,24 +57,15 @@ namespace ignite ~Statement(); /** - * Bind result column to specified data buffer. + * Bind result column to data buffer provided by application * * @param columnIdx Column index. - * @param buffer Buffer to put column data to. + * @param targetType Type of target buffer. + * @param targetValue Pointer to target buffer. + * @param bufferLength Length of target buffer. + * @param strLengthOrIndicator Pointer to the length/indicator buffer. */ - void BindColumn(uint16_t columnIdx, const app::ApplicationDataBuffer& buffer); - - /** - * Unbind specified column buffer. - * - * @param columnIdx Column index. - */ - void UnbindColumn(uint16_t columnIdx); - - /** - * Unbind all column buffers. - */ - void UnbindAllColumns(); + void BindColumn(uint16_t columnIdx, int16_t targetType, void* targetValue, SqlLen bufferLength, SqlLen* strLengthOrIndicator); /** * Set column binding offset pointer. @@ -101,21 +92,17 @@ namespace ignite * Bind parameter. * * @param paramIdx Parameter index. - * @param param Parameter. - */ - void BindParameter(uint16_t paramIdx, const app::Parameter& param); - - /** - * Unbind specified parameter. - * - * @param paramIdx Parameter index. + * @param ioType Type of the parameter (input/output). + * @param bufferType The data type of the parameter. + * @param paramSqlType The SQL data type of the parameter. + * @param columnSize The size of the column or expression of the corresponding parameter marker. + * @param decDigits The decimal digits of the column or expression of the corresponding parameter marker. + * @param buffer A pointer to a buffer for the parameter's data. + * @param bufferLen Length of the ParameterValuePtr buffer in bytes. + * @param resLen A pointer to a buffer for the parameter's length. */ - void UnbindParameter(uint16_t paramIdx); - - /** - * Unbind all parameters. - */ - void UnbindAllParameters(); + void BindParameter(uint16_t paramIdx, int16_t ioType, int16_t bufferType, int16_t paramSqlType, + SqlUlen columnSize, int16_t decDigits, void* buffer, SqlLen bufferLen, SqlLen* resLen); /** * Set statement attribute. @@ -171,7 +158,7 @@ namespace ignite * @param query SQL query. */ void PrepareSqlQuery(const std::string& query); - + /** * Execute SQL query. * @@ -254,11 +241,24 @@ namespace ignite void ExecuteGetTypeInfoQuery(int16_t sqlType); /** + * Free resources + * @param option indicates what needs to be freed + */ + void FreeResources(int16_t option); + + /** * Close statement. */ void Close(); /** + * Fetch query result row with offset + * @param orientation Fetch type + * @param offset Fetch offset + */ + void FetchScroll(int16_t orientation, int64_t offset); + + /** * Fetch query result row. */ void FetchRow(); @@ -362,14 +362,75 @@ namespace ignite private: IGNITE_NO_COPY_ASSIGNMENT(Statement); + + /** + * Bind result column to specified data buffer. + * + * @param columnIdx Column index. + * @param buffer Buffer to put column data to. + */ + void SafeBindColumn(uint16_t columnIdx, const app::ApplicationDataBuffer& buffer); + + /** + * Unbind specified column buffer. + * + * @param columnIdx Column index. + */ + void SafeUnbindColumn(uint16_t columnIdx); + + /** + * Unbind all column buffers. + */ + void SafeUnbindAllColumns(); + + /** + * Bind result column to data buffer provided by application + * + * @param columnIdx Column index. + * @param targetType Type of target buffer. + * @param targetValue Pointer to target buffer. + * @param bufferLength Length of target buffer. + * @param strLengthOrIndicator Pointer to the length/indicator buffer. + * @return Operation result. + */ + SqlResult InternalBindColumn(uint16_t columnIdx, int16_t targetType, void* targetValue, SqlLen bufferLength, SqlLen* strLengthOrIndicator); + /** * Bind parameter. * * @param paramIdx Parameter index. * @param param Parameter. + */ + void SafeBindParameter(uint16_t paramIdx, const app::Parameter& param); + + /** + * Unbind specified parameter. + * + * @param paramIdx Parameter index. + */ + void SafeUnbindParameter(uint16_t paramIdx); + + /** + * Unbind all parameters. + */ + void SafeUnbindAllParameters(); + + /** + * Bind parameter. + * + * @param paramIdx Parameter index. + * @param ioType Type of the parameter (input/output). + * @param bufferType The data type of the parameter. + * @param paramSqlType The SQL data type of the parameter. + * @param columnSize The size of the column or expression of the corresponding parameter marker. + * @param decDigits The decimal digits of the column or expression of the corresponding parameter marker. + * @param buffer A pointer to a buffer for the parameter's data. + * @param bufferLen Length of the ParameterValuePtr buffer in bytes. + * @param resLen A pointer to a buffer for the parameter's length. * @return Operation result. */ - SqlResult InternalBindParameter(uint16_t paramIdx, const app::Parameter& param); + SqlResult InternalBindParameter(uint16_t paramIdx, int16_t ioType, int16_t bufferType, int16_t paramSqlType, + SqlUlen columnSize, int16_t decDigits, void* buffer, SqlLen bufferLen, SqlLen* resLen); /** * Set statement attribute. @@ -403,6 +464,14 @@ namespace ignite */ SqlResult InternalGetColumnData(uint16_t columnIdx, app::ApplicationDataBuffer& buffer); + + /** + * Free resources + * @param option indicates what needs to be freed + * @return Operation result. + */ + SqlResult InternalFreeResources(int16_t option); + /** * Close statement. * Internal call. @@ -418,7 +487,7 @@ namespace ignite * @return Operation result. */ SqlResult InternalPrepareSqlQuery(const std::string& query); - + /** * Execute SQL query. * @@ -435,6 +504,14 @@ namespace ignite SqlResult InternalExecuteSqlQuery(); /** + * Fetch query result row with offset + * @param orientation Fetch type + * @param offset Fetch offset + * @return Operation result. + */ + SqlResult InternalFetchScroll(int16_t orientation, int64_t offset); + + /** * Fetch query result row. * * @return Operation result. @@ -621,7 +698,7 @@ namespace ignite /** Offset added to pointers to change binding of parameters. */ int* paramBindOffset; - + /** Offset added to pointers to change binding of column data. */ int* columnBindOffset; http://git-wip-us.apache.org/repos/asf/ignite/blob/9e8e9798/modules/platforms/cpp/odbc/src/connection.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/src/connection.cpp b/modules/platforms/cpp/odbc/src/connection.cpp index 2afa42d..4a6de5e 100644 --- a/modules/platforms/cpp/odbc/src/connection.cpp +++ b/modules/platforms/cpp/odbc/src/connection.cpp @@ -226,7 +226,7 @@ namespace ignite OdbcProtocolHeader hdr; - int64_t received = ReceiveAll(reinterpret_cast<int8_t*>(&hdr), sizeof(hdr)); + size_t received = ReceiveAll(reinterpret_cast<int8_t*>(&hdr), sizeof(hdr)); if (received != sizeof(hdr)) IGNITE_ERROR_1(IgniteError::IGNITE_ERR_GENERIC, "Can not receive message header"); http://git-wip-us.apache.org/repos/asf/ignite/blob/9e8e9798/modules/platforms/cpp/odbc/src/diagnostic/diagnostic_record.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/src/diagnostic/diagnostic_record.cpp b/modules/platforms/cpp/odbc/src/diagnostic/diagnostic_record.cpp index 215d77f..3c411d2 100644 --- a/modules/platforms/cpp/odbc/src/diagnostic/diagnostic_record.cpp +++ b/modules/platforms/cpp/odbc/src/diagnostic/diagnostic_record.cpp @@ -64,17 +64,35 @@ namespace /** SQL state HY001 constant. */ const std::string STATE_HY001 = "HY001"; + /** SQL state HY003 constant. */ + const std::string STATE_HY003 = "HY003"; + /** SQL state HY009 constant. */ const std::string STATE_HY009 = "HY009"; /** SQL state HY010 constant. */ const std::string STATE_HY010 = "HY010"; + /** SQL state HY092 constant. */ + const std::string STATE_HY092 = "HY092"; + + /** SQL state HY105 constant. */ + const std::string STATE_HY105 = "HY105"; + + /** SQL state HY106 constant. */ + const std::string STATE_HY106 = "HY106"; + /** SQL state HYC00 constant. */ const std::string STATE_HYC00 = "HYC00"; /** SQL state HYT01 constant. */ const std::string STATE_HYT01 = "HYT01"; + + /** SQL state HY090 constant. */ + const std::string STATE_HY090 = "HY090"; + + /** SQL state IM001 constant. */ + const std::string STATE_IM001 = "IM001"; } namespace ignite @@ -130,6 +148,8 @@ namespace ignite if (odbcSubclasses.empty()) { + // This is a fixed list taken from ODBC doc. + // Please do not add/remove values here. odbcSubclasses.insert("01S00"); odbcSubclasses.insert("01S01"); odbcSubclasses.insert("01S02"); @@ -234,18 +254,36 @@ namespace ignite case SQL_STATE_HY001_MEMORY_ALLOCATION: return STATE_HY001; + case SQL_STATE_HY003_INVALID_APPLICATION_BUFFER_TYPE: + return STATE_HY003; + case SQL_STATE_HY009_INVALID_USE_OF_NULL_POINTER: return STATE_HY009; case SQL_STATE_HY010_SEQUENCE_ERROR: return STATE_HY010; + case SQL_STATE_HY090_INVALID_STRING_OR_BUFFER_LENGTH: + return STATE_HY090; + + case SQL_STATE_HY092_OPTION_TYPE_OUT_OF_RANGE: + return STATE_HY092; + + case SQL_STATE_HY105_INVALID_PARAMETER_TYPE: + return STATE_HY105; + + case SQL_STATE_HY106_FETCH_TYPE_OUT_OF_RANGE: + return STATE_HY106; + case SQL_STATE_HYC00_OPTIONAL_FEATURE_NOT_IMPLEMENTED: return STATE_HYC00; case SQL_STATE_HYT01_CONNECTIOIN_TIMEOUT: return STATE_HYT01; + case SQL_STATE_IM001_FUNCTION_NOT_SUPPORTED: + return STATE_IM001; + default: break; } http://git-wip-us.apache.org/repos/asf/ignite/blob/9e8e9798/modules/platforms/cpp/odbc/src/odbc.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/src/odbc.cpp b/modules/platforms/cpp/odbc/src/odbc.cpp index dbec55f..fd69c0d 100644 --- a/modules/platforms/cpp/odbc/src/odbc.cpp +++ b/modules/platforms/cpp/odbc/src/odbc.cpp @@ -31,6 +31,7 @@ #include "ignite/odbc/dsn_config.h" #include "ignite/odbc.h" + namespace ignite { SQLRETURN SQLGetInfo(SQLHDBC conn, @@ -71,6 +72,23 @@ namespace ignite return SQLAllocStmt(parent, result); case SQL_HANDLE_DESC: + { + using odbc::Connection; + Connection *connection = reinterpret_cast<Connection*>(parent); + + if (!connection) + return SQL_INVALID_HANDLE; + + if (result) + *result = 0; + + connection->GetDiagnosticRecords().Reset(); + connection->AddStatusRecord(odbc::SQL_STATE_IM001_FUNCTION_NOT_SUPPORTED, + "The HandleType argument was SQL_HANDLE_DESC, and " + "the driver does not support allocating a descriptor handle"); + + return SQL_ERROR; + } default: break; } @@ -199,39 +217,15 @@ namespace ignite if (!statement) return SQL_INVALID_HANDLE; - switch (option) + if (option == SQL_DROP) { - case SQL_DROP: - { - delete statement; - - break; - } - - case SQL_CLOSE: - { - return SQLCloseCursor(stmt); - } - - case SQL_UNBIND: - { - statement->UnbindAllColumns(); - - break; - } - - case SQL_RESET_PARAMS: - { - statement->UnbindAllParameters(); - - break; - } - - default: - return SQL_ERROR; + delete statement; + return SQL_SUCCESS; } - return SQL_SUCCESS; + statement->FreeResources(option); + + return statement->GetDiagnosticRecords().GetReturnCode(); } SQLRETURN SQLCloseCursor(SQLHSTMT stmt) @@ -419,29 +413,14 @@ namespace ignite using odbc::Statement; using odbc::app::ApplicationDataBuffer; - LOG_MSG("SQLBindCol called: index=%d, type=%d\n", colNum, targetType); + LOG_MSG("SQLBindCol called: index=%d, type=%d targetValue=%p bufferLength=%d\n", colNum, targetType, targetValue, bufferLength); Statement *statement = reinterpret_cast<Statement*>(stmt); if (!statement) return SQL_INVALID_HANDLE; - IgniteSqlType driverType = ToDriverType(targetType); - - if (driverType == IGNITE_ODBC_C_TYPE_UNSUPPORTED) - return SQL_ERROR; - - if (bufferLength < 0) - return SQL_ERROR; - - if (targetValue || strLengthOrIndicator) - { - ApplicationDataBuffer dataBuffer(driverType, targetValue, bufferLength, strLengthOrIndicator); - - statement->BindColumn(colNum, dataBuffer); - } - else - statement->UnbindColumn(colNum); + statement->BindColumn(colNum, targetType, targetValue, bufferLength, strLengthOrIndicator); return statement->GetDiagnosticRecords().GetReturnCode(); } @@ -464,13 +443,19 @@ namespace ignite SQLRETURN SQLFetchScroll(SQLHSTMT stmt, SQLSMALLINT orientation, SQLLEN offset) { + using odbc::Statement; + LOG_MSG("SQLFetchScroll called\n"); LOG_MSG("Orientation: %d, Offset: %d\n", orientation, offset); - if (orientation != SQL_FETCH_NEXT) - return SQL_ERROR; + Statement *statement = reinterpret_cast<Statement*>(stmt); + + if (!statement) + return SQL_INVALID_HANDLE; + + statement->FetchScroll(orientation, offset); - return SQLFetch(stmt); + return statement->GetDiagnosticRecords().GetReturnCode(); } SQLRETURN SQLExtendedFetch(SQLHSTMT stmt, @@ -617,12 +602,7 @@ namespace ignite SQLLEN bufferLen, SQLLEN* resLen) { - using namespace odbc::type_traits; - using odbc::Statement; - using odbc::app::ApplicationDataBuffer; - using odbc::app::Parameter; - using odbc::type_traits::IsSqlTypeSupported; LOG_MSG("SQLBindParameter called: %d, %d, %d\n", paramIdx, bufferType, paramSqlType); @@ -631,27 +611,7 @@ namespace ignite if (!statement) return SQL_INVALID_HANDLE; - if (ioType != SQL_PARAM_INPUT) - return SQL_ERROR; - - if (!IsSqlTypeSupported(paramSqlType)) - return SQL_ERROR; - - IgniteSqlType driverType = ToDriverType(bufferType); - - if (driverType == IGNITE_ODBC_C_TYPE_UNSUPPORTED) - return SQL_ERROR; - - if (buffer) - { - ApplicationDataBuffer dataBuffer(driverType, buffer, bufferLen, resLen); - - Parameter param(dataBuffer, paramSqlType, columnSize, decDigits); - - statement->BindParameter(paramIdx, param); - } - else - statement->UnbindParameter(paramIdx); + statement->BindParameter(paramIdx, ioType, bufferType, paramSqlType, columnSize, decDigits, buffer, bufferLen, resLen); return statement->GetDiagnosticRecords().GetReturnCode(); } @@ -717,13 +677,13 @@ namespace ignite } SQLRETURN SQLDescribeCol(SQLHSTMT stmt, - SQLUSMALLINT columnNum, + SQLUSMALLINT columnNum, SQLCHAR* columnNameBuf, SQLSMALLINT columnNameBufLen, SQLSMALLINT* columnNameLen, - SQLSMALLINT* dataType, + SQLSMALLINT* dataType, SQLULEN* columnSize, - SQLSMALLINT* decimalDigits, + SQLSMALLINT* decimalDigits, SQLSMALLINT* nullable) { using odbc::Statement; http://git-wip-us.apache.org/repos/asf/ignite/blob/9e8e9798/modules/platforms/cpp/odbc/src/statement.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/src/statement.cpp b/modules/platforms/cpp/odbc/src/statement.cpp index 02c6dd9..09ad81c 100644 --- a/modules/platforms/cpp/odbc/src/statement.cpp +++ b/modules/platforms/cpp/odbc/src/statement.cpp @@ -50,26 +50,57 @@ namespace ignite // No-op. } - void Statement::BindColumn(uint16_t columnIdx, const app::ApplicationDataBuffer& buffer) + void Statement::BindColumn(uint16_t columnIdx, int16_t targetType, void* targetValue, SqlLen bufferLength, SqlLen* strLengthOrIndicator) { - IGNITE_ODBC_API_CALL_ALWAYS_SUCCESS; + IGNITE_ODBC_API_CALL(InternalBindColumn(columnIdx, targetType, targetValue, bufferLength, strLengthOrIndicator)); + } + + SqlResult Statement::InternalBindColumn(uint16_t columnIdx, int16_t targetType, void* targetValue, SqlLen bufferLength, SqlLen* strLengthOrIndicator) + { + using namespace odbc::type_traits; + IgniteSqlType driverType = ToDriverType(targetType); + + if (driverType == IGNITE_ODBC_C_TYPE_UNSUPPORTED) + { + AddStatusRecord(odbc::SQL_STATE_HY003_INVALID_APPLICATION_BUFFER_TYPE, "The argument TargetType was not a valid data type."); + + return SQL_RESULT_ERROR; + } + + if (bufferLength < 0) + { + AddStatusRecord(odbc::SQL_STATE_HY090_INVALID_STRING_OR_BUFFER_LENGTH, + "The value specified for the argument BufferLength was less than 0."); + + return SQL_RESULT_ERROR; + } + + if (targetValue || strLengthOrIndicator) + { + app::ApplicationDataBuffer dataBuffer(driverType, targetValue, bufferLength, strLengthOrIndicator); + SafeBindColumn(columnIdx, dataBuffer); + } + else + SafeUnbindColumn(columnIdx); + + return SQL_RESULT_SUCCESS; + } + + void Statement::SafeBindColumn(uint16_t columnIdx, const app::ApplicationDataBuffer& buffer) + { columnBindings[columnIdx] = buffer; columnBindings[columnIdx].SetPtrToOffsetPtr(&columnBindOffset); } - void Statement::UnbindColumn(uint16_t columnIdx) + void Statement::SafeUnbindColumn(uint16_t columnIdx) { - IGNITE_ODBC_API_CALL_ALWAYS_SUCCESS; - columnBindings.erase(columnIdx); } - void Statement::UnbindAllColumns() + void Statement::SafeUnbindAllColumns() { - IGNITE_ODBC_API_CALL_ALWAYS_SUCCESS; - columnBindings.clear(); } @@ -108,14 +139,21 @@ namespace ignite return SQL_RESULT_SUCCESS; } - void Statement::BindParameter(uint16_t paramIdx, const app::Parameter& param) + void Statement::BindParameter(uint16_t paramIdx, int16_t ioType, int16_t bufferType, int16_t paramSqlType, + SqlUlen columnSize, int16_t decDigits, void* buffer, SqlLen bufferLen, SqlLen* resLen) { - IGNITE_ODBC_API_CALL(InternalBindParameter(paramIdx, param)); + IGNITE_ODBC_API_CALL(InternalBindParameter(paramIdx, ioType, bufferType, paramSqlType, columnSize, decDigits, buffer, bufferLen, resLen)); } - - SqlResult Statement::InternalBindParameter(uint16_t paramIdx, const app::Parameter& param) + SqlResult Statement::InternalBindParameter(uint16_t paramIdx, int16_t ioType, int16_t bufferType, int16_t paramSqlType, + SqlUlen columnSize, int16_t decDigits, void* buffer, SqlLen bufferLen, SqlLen* resLen) { + using namespace odbc::type_traits; + using odbc::Statement; + using odbc::app::ApplicationDataBuffer; + using odbc::app::Parameter; + using odbc::type_traits::IsSqlTypeSupported; + if (paramIdx == 0) { AddStatusRecord(SQL_STATE_24000_INVALID_CURSOR_STATE, @@ -124,24 +162,60 @@ namespace ignite return SQL_RESULT_ERROR; } - paramBindings[paramIdx] = param; + if (ioType != SQL_PARAM_INPUT) + { + AddStatusRecord(SQL_STATE_HY105_INVALID_PARAMETER_TYPE, + "The value specified for the argument InputOutputType was not SQL_PARAM_INPUT."); - paramBindings[paramIdx].GetBuffer().SetPtrToOffsetPtr(¶mBindOffset); + return SQL_RESULT_ERROR; + } + + if (!IsSqlTypeSupported(paramSqlType)) + { + AddStatusRecord(SQL_STATE_HYC00_OPTIONAL_FEATURE_NOT_IMPLEMENTED, + "Data type is not supported."); + + return SQL_RESULT_ERROR; + } + + IgniteSqlType driverType = ToDriverType(bufferType); + + if (driverType == IGNITE_ODBC_C_TYPE_UNSUPPORTED) + { + AddStatusRecord(odbc::SQL_STATE_HY003_INVALID_APPLICATION_BUFFER_TYPE, + "The argument TargetType was not a valid data type."); + + return SQL_RESULT_ERROR; + } + + if (buffer) + { + ApplicationDataBuffer dataBuffer(driverType, buffer, bufferLen, resLen); + + Parameter param(dataBuffer, paramSqlType, columnSize, decDigits); + + SafeBindParameter(paramIdx, param); + } + else + SafeUnbindParameter(paramIdx); return SQL_RESULT_SUCCESS; } - void Statement::UnbindParameter(uint16_t paramIdx) + void Statement::SafeBindParameter(uint16_t paramIdx, const app::Parameter& param) { - IGNITE_ODBC_API_CALL_ALWAYS_SUCCESS; + paramBindings[paramIdx] = param; - paramBindings.erase(paramIdx); + paramBindings[paramIdx].GetBuffer().SetPtrToOffsetPtr(¶mBindOffset); } - void Statement::UnbindAllParameters() + void Statement::SafeUnbindParameter(uint16_t paramIdx) { - IGNITE_ODBC_API_CALL_ALWAYS_SUCCESS; + paramBindings.erase(paramIdx); + } + void Statement::SafeUnbindAllParameters() + { paramBindings.clear(); } @@ -536,6 +610,50 @@ namespace ignite return currentQuery->Execute(); } + void Statement::FreeResources(int16_t option) + { + IGNITE_ODBC_API_CALL(InternalFreeResources(option)); + } + + SqlResult Statement::InternalFreeResources(int16_t option) + { + switch (option) + { + case SQL_DROP: + { + AddStatusRecord(SQL_STATE_HY000_GENERAL_ERROR, "Deprecated, call SQLFreeHandle instead"); + + return SQL_RESULT_ERROR; + } + + case SQL_CLOSE: + { + return InternalClose(); + } + + case SQL_UNBIND: + { + SafeUnbindAllColumns(); + + break; + } + + case SQL_RESET_PARAMS: + { + SafeUnbindAllParameters(); + + break; + } + + default: + { + AddStatusRecord(SQL_STATE_HY092_OPTION_TYPE_OUT_OF_RANGE, "The value specified for the argument Option was invalid"); + return SQL_RESULT_ERROR; + } + } + return SQL_RESULT_SUCCESS; + } + void Statement::Close() { IGNITE_ODBC_API_CALL(InternalClose()); @@ -545,7 +663,7 @@ namespace ignite { if (!currentQuery.get()) return SQL_RESULT_SUCCESS; - + SqlResult result = currentQuery->Close(); if (result == SQL_RESULT_SUCCESS) @@ -554,6 +672,24 @@ namespace ignite return result; } + void Statement::FetchScroll(int16_t orientation, int64_t offset) + { + IGNITE_ODBC_API_CALL(InternalFetchScroll(orientation, offset)); + } + + SqlResult Statement::InternalFetchScroll(int16_t orientation, int64_t offset) + { + UNREFERENCED_PARAMETER(offset); + + if (orientation != SQL_FETCH_NEXT) + { + AddStatusRecord(SQL_STATE_HY106_FETCH_TYPE_OUT_OF_RANGE, "The value specified for the argument FetchOrientation was not SQL_FETCH_NEXT."); + return SQL_RESULT_ERROR; + } + + return InternalFetchRow(); + } + void Statement::FetchRow() { IGNITE_ODBC_API_CALL(InternalFetchRow());