diff --git a/server/re/CMakeLists.txt b/server/re/CMakeLists.txt index d4415d7dd3..b3ddb405b3 100644 --- a/server/re/CMakeLists.txt +++ b/server/re/CMakeLists.txt @@ -2,7 +2,7 @@ add_library( irods_server_re OBJECT "${CMAKE_CURRENT_SOURCE_DIR}/src/extractAvuMS.cpp" - "${CMAKE_CURRENT_SOURCE_DIR}/src/genquery2.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/src/msi_genquery2.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/src/genQueryMS.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/src/icatAdminMS.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/src/icatGeneralMS.cpp" diff --git a/server/re/include/irods/msi_genquery2.hpp b/server/re/include/irods/msi_genquery2.hpp index 0256caa352..40bf46c808 100644 --- a/server/re/include/irods/msi_genquery2.hpp +++ b/server/re/include/irods/msi_genquery2.hpp @@ -1,6 +1,29 @@ #ifndef IRODS_MSI_GENQUERY2_HPP #define IRODS_MSI_GENQUERY2_HPP +/// \file +struct MsParam; +struct RuleExecInfo; + +/// TODO +/// +/// \since 4.3.2 +auto msi_genquery2_execute(MsParam* _handle, MsParam* _query_string, RuleExecInfo* _rei) -> int; + +/// TODO +/// +/// \since 4.3.2 +auto msi_genquery2_next_row(MsParam* _handle, RuleExecInfo* _rei) -> int; + +/// TODO +/// +/// \since 4.3.2 +auto msi_genquery2_column(MsParam* _handle, MsParam* _column_index, MsParam* _column_value, RuleExecInfo* _rei) -> int; + +/// TODO +/// +/// \since 4.3.2 +auto msi_genquery2_free(MsParam* _handle, RuleExecInfo* _rei) -> int; #endif // IRODS_MSI_GENQUERY2_HPP diff --git a/server/re/include/irods/reAction.hpp b/server/re/include/irods/reAction.hpp index 93649c73cb..05e389efa6 100644 --- a/server/re/include/irods/reAction.hpp +++ b/server/re/include/irods/reAction.hpp @@ -252,6 +252,10 @@ namespace irods table_[ "msiCutBufferInHalf" ] = new irods::ms_table_entry( "msiCutBufferInHalf", 1, std::function( msiCutBufferInHalf ) ); table_[ "msiDoSomething" ] = new irods::ms_table_entry( "msiDoSomething", 2, std::function( msiDoSomething ) ); table_[ "msiTakeThreeArgumentsAndDoNothing" ] = new irods::ms_table_entry( "msiTakeThreeArgumentsAndDoNothing", 3, std::function( msiTakeThreeArgumentsAndDoNothing ) ); + table_["msi_genquery2_execute"] = new irods::ms_table_entry("msi_genquery2_execute", 2, std::function(msi_genquery2_execute)); + table_["msi_genquery2_next_row"] = new irods::ms_table_entry("msi_genquery2_next_row", 1, std::function(msi_genquery2_next_row)); + table_["msi_genquery2_column"] = new irods::ms_table_entry("msi_genquery2_column", 3, std::function(msi_genquery2_column)); + table_["msi_genquery2_free"] = new irods::ms_table_entry("msi_genquery2_free", 1, std::function(msi_genquery2_free)); }; // ms_table::ms_table // clang-format on diff --git a/server/re/src/msi_genquery2.cpp b/server/re/src/msi_genquery2.cpp index 7ab2b02859..e4af40a314 100644 --- a/server/re/src/msi_genquery2.cpp +++ b/server/re/src/msi_genquery2.cpp @@ -11,6 +11,7 @@ #include "irods/rodsError.h" #include "irods/rodsErrorTable.h" #include "irods/msi_preconditions.hpp" +#include "irods/irods_exception.hpp" #include #include @@ -42,6 +43,8 @@ namespace auto msi_genquery2_execute(MsParam* _handle, MsParam* _query_string, RuleExecInfo* _rei) -> int { + log_msi::trace(__func__); + IRODS_MSI_REQUIRE_VALID_POINTER(_handle); IRODS_MSI_REQUIRE_VALID_POINTER(_query_string); IRODS_MSI_REQUIRE_VALID_POINTER(_rei); @@ -59,7 +62,7 @@ auto msi_genquery2_execute(MsParam* _handle, MsParam* _query_string, RuleExecInf char* results{}; if (const auto ec = rs_genquery2(_rei->rsComm, &input, &results); ec < 0) { - log_msi::error("Error while executing GenQuery2 query [error_code=[{}]].", ec); + log_msi::error("{}: Error while executing GenQuery2 query [error_code=[{}]].", __func__, ec); return ec; } @@ -72,17 +75,139 @@ auto msi_genquery2_execute(MsParam* _handle, MsParam* _query_string, RuleExecInf return 0; } // msi_genquery2_execute -auto msi_genquery2_next_row() -> int +auto msi_genquery2_next_row(MsParam* _handle, RuleExecInfo* _rei) -> int { + log_msi::trace(__func__); + + IRODS_MSI_REQUIRE_VALID_POINTER(_handle); + IRODS_MSI_REQUIRE_VALID_POINTER(_rei); + + IRODS_MSI_REQUIRE_VALID_POINTER(_handle->type); + + IRODS_MSI_REQUIRE_TYPE(_handle->type, STR_MS_T); + + IRODS_MSI_REQUIRE_VALID_POINTER(_handle->inOutStruct); + + try { + const auto ctx_handle_index = std::stoll(static_cast(_handle->inOutStruct)); + + if (ctx_handle_index < 0 || static_cast(ctx_handle_index) >= gq2_context.size()) { + log_msi::error("{}: Unknown context handle.", __func__); + return SYS_INVALID_INPUT_PARAM; + } + + auto& ctx = gq2_context.at(static_cast(ctx_handle_index)); + + if (ctx.current_row < static_cast(ctx.rows.size()) - 1) { + ++ctx.current_row; + log_msi::trace("{}: Incremented row position [{} => {}]. Returning 0.", __func__, ctx.current_row - 1, ctx.current_row); + return 0; + } + + log_msi::trace("{}: Skipping increment of row position [current_row=[{}]]. Returning 1.", __func__, ctx.current_row); + + // TODO Update this. + // We must return ERROR(stop_code, "") to trigger correct usage of msi_genquery2_next_row(). + // Otherwise, the NREP can loop forever. Ultimately, this means we aren't allowed to return + // CODE(stop_code) to signal there is no new row available. + return 1; + } + catch (const irods::exception& e) { + log_msi::error("{}: {}", __func__, e.client_display_what()); + return static_cast(e.code()); + } + catch (const std::exception& e) { + log_msi::error("{}: {}", __func__, e.what()); + return SYS_LIBRARY_ERROR; + } + return 0; } // msi_genquery2_next_row -auto msi_genquery2_column() -> int +auto msi_genquery2_column(MsParam* _handle, MsParam* _column_index, MsParam* _column_value, RuleExecInfo* _rei) -> int { + log_msi::trace(__func__); + + IRODS_MSI_REQUIRE_VALID_POINTER(_handle); + IRODS_MSI_REQUIRE_VALID_POINTER(_column_index); + IRODS_MSI_REQUIRE_VALID_POINTER(_column_value); + IRODS_MSI_REQUIRE_VALID_POINTER(_rei); + + IRODS_MSI_REQUIRE_VALID_POINTER(_handle->type); + IRODS_MSI_REQUIRE_VALID_POINTER(_column_index->type); + + IRODS_MSI_REQUIRE_TYPE(_handle->type, STR_MS_T); + IRODS_MSI_REQUIRE_TYPE(_column_index->type, STR_MS_T); + + IRODS_MSI_REQUIRE_VALID_POINTER(_handle->inOutStruct); + IRODS_MSI_REQUIRE_VALID_POINTER(_column_index->inOutStruct); + + try { + const auto ctx_handle_index = std::stoll(static_cast(_handle->inOutStruct)); + + if (ctx_handle_index < 0 || + static_cast(ctx_handle_index) >= gq2_context.size()) { + log_msi::error("{}: Unknown context handle.", __func__); + return SYS_INVALID_INPUT_PARAM; + } + + auto& ctx = gq2_context.at(static_cast(ctx_handle_index)); + const auto column_index = std::stoll(static_cast(_column_index->inOutStruct)); + + const auto& value = ctx.rows.at(ctx.current_row).at(column_index).get_ref(); + log_msi::debug("{}: Column value = [{}]", __func__, value); + fillStrInMsParam(_column_value, value.c_str()); + + return 0; + } + catch (const irods::exception& e) { + log_msi::error("{}: {}", __func__, e.client_display_what()); + return static_cast(e.code()); + } + catch (const std::exception& e) { + log_msi::error("{}: {}", __func__, e.what()); + return SYS_LIBRARY_ERROR; + } + return 0; } // msi_genquery2_column -auto msi_genquery2_destroy() -> int +auto msi_genquery2_free(MsParam* _handle, RuleExecInfo* _rei) -> int { + log_msi::trace(__func__); + + IRODS_MSI_REQUIRE_VALID_POINTER(_handle); + IRODS_MSI_REQUIRE_VALID_POINTER(_rei); + + IRODS_MSI_REQUIRE_VALID_POINTER(_handle->type); + + IRODS_MSI_REQUIRE_TYPE(_handle->type, STR_MS_T); + + IRODS_MSI_REQUIRE_VALID_POINTER(_handle->inOutStruct); + + try { + const auto ctx_handle_index = std::stoll(static_cast(_handle->inOutStruct)); + + if (ctx_handle_index < 0 || + static_cast(ctx_handle_index) >= gq2_context.size()) { + log_msi::error("{}: Unknown context handle.", __func__); + return SYS_INVALID_INPUT_PARAM; + } + + auto ctx_iter = std::begin(gq2_context); + std::advance(ctx_iter, ctx_handle_index); + gq2_context.erase(ctx_iter); + + return 0; + } + catch (const irods::exception& e) { + log_msi::error("{}: {}", __func__, e.client_display_what()); + return static_cast(e.code()); + } + catch (const std::exception& e) { + log_msi::error("{}: {}", __func__, e.what()); + return SYS_LIBRARY_ERROR; + } + return 0; -} // msi_genquery2_destroy +} // msi_genquery2_free