Repository: ignite Updated Branches: refs/heads/master 1288531ed -> c10be5780
http://git-wip-us.apache.org/repos/asf/ignite/blob/c10be578/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 ae19ed6..697f5b4 100644 --- a/modules/platforms/cpp/odbc/src/statement.cpp +++ b/modules/platforms/cpp/odbc/src/statement.cpp @@ -16,6 +16,7 @@ */ #include "ignite/odbc/system/odbc_constants.h" +#include "ignite/odbc/query/batch_query.h" #include "ignite/odbc/query/data_query.h" #include "ignite/odbc/query/column_metadata_query.h" #include "ignite/odbc/query/table_metadata_query.h" @@ -39,9 +40,8 @@ namespace ignite currentQuery(), rowsFetched(0), rowStatuses(0), - paramBindOffset(0), columnBindOffset(0), - currentParamIdx(0) + parameters() { // No-op. } @@ -58,19 +58,19 @@ namespace ignite SqlResult::Type Statement::InternalBindColumn(uint16_t columnIdx, int16_t targetType, void* targetValue, SqlLen bufferLength, SqlLen* strLengthOrIndicator) { - using namespace odbc::type_traits; + using namespace type_traits; OdbcNativeType::Type driverType = ToDriverType(targetType); if (driverType == OdbcNativeType::AI_UNSUPPORTED) { - AddStatusRecord(odbc::SqlState::SHY003_INVALID_APPLICATION_BUFFER_TYPE, "The argument TargetType was not a valid data type."); + AddStatusRecord(SqlState::SHY003_INVALID_APPLICATION_BUFFER_TYPE, "The argument TargetType was not a valid data type."); return SqlResult::AI_ERROR; } if (bufferLength < 0) { - AddStatusRecord(odbc::SqlState::SHY090_INVALID_STRING_OR_BUFFER_LENGTH, + AddStatusRecord(SqlState::SHY090_INVALID_STRING_OR_BUFFER_LENGTH, "The value specified for the argument BufferLength was less than 0."); return SqlResult::AI_ERROR; @@ -91,8 +91,6 @@ namespace ignite void Statement::SafeBindColumn(uint16_t columnIdx, const app::ApplicationDataBuffer& buffer) { columnBindings[columnIdx] = buffer; - - columnBindings[columnIdx].SetPtrToOffsetPtr(&columnBindOffset); } void Statement::SafeUnbindColumn(uint16_t columnIdx) @@ -149,32 +147,36 @@ namespace ignite SqlResult::Type 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; + using namespace type_traits; + using app::ApplicationDataBuffer; + using app::Parameter; if (paramIdx == 0) { - AddStatusRecord(SqlState::S24000_INVALID_CURSOR_STATE, - "The value specified for the argument ParameterNumber was less than 1."); + std::stringstream builder; + builder << "The value specified for the argument ParameterNumber was less than 1. [ParameterNumber=" << paramIdx << ']'; + + AddStatusRecord(SqlState::S24000_INVALID_CURSOR_STATE, builder.str()); return SqlResult::AI_ERROR; } if (ioType != SQL_PARAM_INPUT) { - AddStatusRecord(SqlState::SHY105_INVALID_PARAMETER_TYPE, - "The value specified for the argument InputOutputType was not SQL_PARAM_INPUT."); + std::stringstream builder; + builder << "The value specified for the argument InputOutputType was not SQL_PARAM_INPUT. [ioType=" << ioType << ']'; + + AddStatusRecord(SqlState::SHY105_INVALID_PARAMETER_TYPE, builder.str()); return SqlResult::AI_ERROR; } if (!IsSqlTypeSupported(paramSqlType)) { - AddStatusRecord(SqlState::SHYC00_OPTIONAL_FEATURE_NOT_IMPLEMENTED, - "Data type is not supported."); + std::stringstream builder; + builder << "Data type is not supported. [typeId=" << paramSqlType << ']'; + + AddStatusRecord(SqlState::SHYC00_OPTIONAL_FEATURE_NOT_IMPLEMENTED, builder.str()); return SqlResult::AI_ERROR; } @@ -183,8 +185,10 @@ namespace ignite if (driverType == OdbcNativeType::AI_UNSUPPORTED) { - AddStatusRecord(odbc::SqlState::SHY003_INVALID_APPLICATION_BUFFER_TYPE, - "The argument TargetType was not a valid data type."); + std::stringstream builder; + builder << "The argument TargetType was not a valid data type. [TargetType=" << bufferType << ']'; + + AddStatusRecord(SqlState::SHY003_INVALID_APPLICATION_BUFFER_TYPE, builder.str()); return SqlResult::AI_ERROR; } @@ -195,31 +199,14 @@ namespace ignite Parameter param(dataBuffer, paramSqlType, columnSize, decDigits); - SafeBindParameter(paramIdx, param); + parameters.BindParameter(paramIdx, param); } else - SafeUnbindParameter(paramIdx); + parameters.UnbindParameter(paramIdx); return SqlResult::AI_SUCCESS; } - void Statement::SafeBindParameter(uint16_t paramIdx, const app::Parameter& param) - { - paramBindings[paramIdx] = param; - - paramBindings[paramIdx].GetBuffer().SetPtrToOffsetPtr(¶mBindOffset); - } - - void Statement::SafeUnbindParameter(uint16_t paramIdx) - { - paramBindings.erase(paramIdx); - } - - void Statement::SafeUnbindAllParameters() - { - paramBindings.clear(); - } - void Statement::SetAttribute(int attr, void* value, SQLINTEGER valueLen) { IGNITE_ODBC_API_CALL(InternalSetAttribute(attr, value, valueLen)); @@ -231,7 +218,7 @@ namespace ignite { case SQL_ATTR_ROW_ARRAY_SIZE: { - SQLULEN val = reinterpret_cast<SQLULEN>(value); + SqlUlen val = reinterpret_cast<SqlUlen>(value); LOG_MSG("SQL_ATTR_ROW_ARRAY_SIZE: " << val); @@ -274,6 +261,20 @@ namespace ignite break; } + case SQL_ATTR_PARAMSET_SIZE: + { + parameters.SetParamSetSize(reinterpret_cast<SqlUlen>(value)); + + break; + } + + case SQL_ATTR_PARAMS_PROCESSED_PTR: + { + parameters.SetParamsProcessedPtr(reinterpret_cast<SqlUlen*>(value)); + + break; + } + default: { AddStatusRecord(SqlState::SHYC00_OPTIONAL_FEATURE_NOT_IMPLEMENTED, @@ -311,6 +312,9 @@ namespace ignite *val = static_cast<SQLPOINTER>(this); + if (valueLen) + *valueLen = SQL_IS_POINTER; + break; } @@ -320,14 +324,20 @@ namespace ignite *val = static_cast<SQLINTEGER>(1); + if (valueLen) + *valueLen = SQL_IS_INTEGER; + break; } case SQL_ATTR_ROWS_FETCHED_PTR: { - SQLULEN** val = reinterpret_cast<SQLULEN**>(buf); + SqlUlen** val = reinterpret_cast<SqlUlen**>(buf); + + *val = reinterpret_cast<SqlUlen*>(GetRowsFetchedPtr()); - *val = reinterpret_cast<SQLULEN*>(GetRowsFetchedPtr()); + if (valueLen) + *valueLen = SQL_IS_POINTER; break; } @@ -338,6 +348,9 @@ namespace ignite *val = reinterpret_cast<SQLUSMALLINT*>(GetRowStatusesPtr()); + if (valueLen) + *valueLen = SQL_IS_POINTER; + break; } @@ -345,16 +358,46 @@ namespace ignite { SQLULEN** val = reinterpret_cast<SQLULEN**>(buf); - *val = reinterpret_cast<SQLULEN*>(GetParamBindOffsetPtr()); + *val = reinterpret_cast<SQLULEN*>(parameters.GetParamBindOffsetPtr()); + + if (valueLen) + *valueLen = SQL_IS_POINTER; break; } case SQL_ATTR_ROW_BIND_OFFSET_PTR: { - SQLULEN** val = reinterpret_cast<SQLULEN**>(buf); + SqlUlen** val = reinterpret_cast<SqlUlen**>(buf); + + *val = reinterpret_cast<SqlUlen*>(GetColumnBindOffsetPtr()); + + if (valueLen) + *valueLen = SQL_IS_POINTER; + + break; + } + + case SQL_ATTR_PARAMSET_SIZE: + { + SqlUlen* val = reinterpret_cast<SqlUlen*>(buf); - *val = reinterpret_cast<SQLULEN*>(GetColumnBindOffsetPtr()); + *val = static_cast<SqlUlen>(parameters.GetParamSetSize()); + + if (valueLen) + *valueLen = SQL_IS_UINTEGER; + + break; + } + + case SQL_ATTR_PARAMS_PROCESSED_PTR: + { + SqlUlen** val = reinterpret_cast<SqlUlen**>(buf); + + *val = parameters.GetParamsProcessedPtr(); + + if (valueLen) + *valueLen = SQL_IS_POINTER; break; } @@ -392,7 +435,7 @@ namespace ignite return SqlResult::AI_SUCCESS; } - if (paramTypes.empty()) + if (!parameters.IsMetadataSet()) { SqlResult::Type res = UpdateParamsMeta(); @@ -400,7 +443,7 @@ namespace ignite return res; } - paramNum = static_cast<uint16_t>(paramTypes.size()); + paramNum = parameters.GetExpectedParamNum(); return SqlResult::AI_SUCCESS; } @@ -409,12 +452,7 @@ namespace ignite { IGNITE_ODBC_API_CALL_ALWAYS_SUCCESS; - paramBindOffset = ptr; - } - - int* Statement::GetParamBindOffsetPtr() - { - return paramBindOffset; + parameters.SetParamBindOffsetPtr(ptr); } void Statement::GetColumnData(uint16_t columnIdx, app::ApplicationDataBuffer& buffer) @@ -448,10 +486,10 @@ namespace ignite if (currentQuery.get()) currentQuery->Close(); - currentQuery.reset(new query::DataQuery(*this, connection, query, paramBindings)); - // Resetting parameters types as we are changing the query. - paramTypes.clear(); + parameters.Prepare(); + + currentQuery.reset(new query::DataQuery(*this, connection, query, parameters)); return SqlResult::AI_SUCCESS; } @@ -485,20 +523,31 @@ namespace ignite return SqlResult::AI_ERROR; } - bool paramDataReady = true; - - app::ParameterBindingMap::iterator it; - for (it = paramBindings.begin(); it != paramBindings.end(); ++it) + if (parameters.GetParamSetSize() > 1 && currentQuery->GetType() == query::QueryType::DATA) { - app::Parameter& param = it->second; + query::DataQuery& qry = static_cast<query::DataQuery&>(*currentQuery); - param.ResetStoredData(); + currentQuery.reset(new query::BatchQuery(*this, connection, qry.GetSql(), parameters)); + } + else if (parameters.GetParamSetSize() == 1 && currentQuery->GetType() == query::QueryType::BATCH) + { + query::BatchQuery& qry = static_cast<query::BatchQuery&>(*currentQuery); - paramDataReady &= param.IsDataReady(); + currentQuery.reset(new query::DataQuery(*this, connection, qry.GetSql(), parameters)); } - if (!paramDataReady) + if (parameters.IsDataAtExecNeeded()) + { + if (currentQuery->GetType() == query::QueryType::BATCH) + { + AddStatusRecord(SqlState::SHYC00_OPTIONAL_FEATURE_NOT_IMPLEMENTED, + "Data-at-execution is not supported together with batching."); + + return SqlResult::AI_ERROR; + } + return SqlResult::AI_NEED_DATA; + } return currentQuery->Execute(); } @@ -624,8 +673,10 @@ namespace ignite { if (!type_traits::IsSqlTypeSupported(sqlType)) { - AddStatusRecord(SqlState::SHYC00_OPTIONAL_FEATURE_NOT_IMPLEMENTED, - "Data type is not supported."); + std::stringstream builder; + builder << "Data type is not supported. [typeId=" << sqlType << ']'; + + AddStatusRecord(SqlState::SHYC00_OPTIONAL_FEATURE_NOT_IMPLEMENTED, builder.str()); return SqlResult::AI_ERROR; } @@ -668,7 +719,7 @@ namespace ignite case SQL_RESET_PARAMS: { - SafeUnbindAllParameters(); + parameters.UnbindAll(); break; } @@ -736,6 +787,12 @@ namespace ignite return SqlResult::AI_ERROR; } + if (columnBindOffset) + { + for (app::ColumnBindingMap::iterator it = columnBindings.begin(); it != columnBindings.end(); ++it) + it->second.SetByteOffset(*columnBindOffset); + } + SqlResult::Type res = currentQuery->FetchNextRow(columnBindings); if (res == SqlResult::AI_SUCCESS) @@ -904,35 +961,24 @@ namespace ignite return SqlResult::AI_ERROR; } - app::ParameterBindingMap::iterator it; + app::Parameter *selected = parameters.GetSelectedParameter(); - if (currentParamIdx) + if (selected && !selected->IsDataReady()) { - it = paramBindings.find(currentParamIdx); + AddStatusRecord(SqlState::S22026_DATA_LENGTH_MISMATCH, + "Less data was sent for a parameter than was specified with " + "the StrLen_or_IndPtr argument in SQLBindParameter."); - if (it != paramBindings.end() && !it->second.IsDataReady()) - { - AddStatusRecord(SqlState::S22026_DATA_LENGTH_MISMATCH, - "Less data was sent for a parameter than was specified with " - "the StrLen_or_IndPtr argument in SQLBindParameter."); - - return SqlResult::AI_ERROR; - } + return SqlResult::AI_ERROR; } - for (it = paramBindings.begin(); it != paramBindings.end(); ++it) - { - uint16_t paramIdx = it->first; - app::Parameter& param = it->second; - - if (!param.IsDataReady()) - { - *paramPtr = param.GetBuffer().GetData(); + selected = parameters.SelectNextParameter(); - currentParamIdx = paramIdx; + if (selected) + { + *paramPtr = selected->GetBuffer().GetData(); - return SqlResult::AI_NEED_DATA; - } + return SqlResult::AI_NEED_DATA; } SqlResult::Type res = currentQuery->Execute(); @@ -959,7 +1005,7 @@ namespace ignite return SqlResult::AI_ERROR; } - if (currentParamIdx == 0) + if (!parameters.IsParameterSelected()) { AddStatusRecord(SqlState::SHY010_SEQUENCE_ERROR, "Parameter is not selected with the SQLParamData."); @@ -967,9 +1013,9 @@ namespace ignite return SqlResult::AI_ERROR; } - app::ParameterBindingMap::iterator it = paramBindings.find(currentParamIdx); + app::Parameter* param = parameters.GetSelectedParameter(); - if (it == paramBindings.end()) + if (!param) { AddStatusRecord(SqlState::SHY000_GENERAL_ERROR, "Selected parameter has been unbound."); @@ -977,9 +1023,7 @@ namespace ignite return SqlResult::AI_ERROR; } - app::Parameter& param = it->second; - - param.PutData(data, len); + param->PutData(data, len); return SqlResult::AI_SUCCESS; } @@ -1009,10 +1053,7 @@ namespace ignite return SqlResult::AI_ERROR; } - int8_t type = 0; - - if (paramNum > 0 && static_cast<size_t>(paramNum) <= paramTypes.size()) - type = paramTypes[paramNum - 1]; + int8_t type = parameters.GetParamType(paramNum, 0); LOG_MSG("Type: " << type); @@ -1023,10 +1064,7 @@ namespace ignite if (res != SqlResult::AI_SUCCESS) return res; - if (paramNum < 1 || static_cast<size_t>(paramNum) > paramTypes.size()) - type = impl::binary::IGNITE_HDR_NULL; - else - type = paramTypes[paramNum - 1]; + type = parameters.GetParamType(paramNum, impl::binary::IGNITE_HDR_NULL); } if (dataType) @@ -1079,11 +1117,11 @@ namespace ignite return SqlResult::AI_ERROR; } - paramTypes = rsp.GetTypeIds(); + parameters.UpdateParamsTypes(rsp.GetTypeIds()); - for (size_t i = 0; i < paramTypes.size(); ++i) + for (size_t i = 0; i < rsp.GetTypeIds().size(); ++i) { - LOG_MSG("[" << i << "] Parameter type: " << paramTypes[i]); + LOG_MSG("[" << i << "] Parameter type: " << rsp.GetTypeIds()[i]); } return SqlResult::AI_SUCCESS;
