<commit_before>////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2018 ArangoDB GmbH, Cologne, Germany
///
/// Licensed 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.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author <NAME>
////////////////////////////////////////////////////////////////////////////////

#include "ModificationExecutorTraits.h"
#include "Aql/AqlValue.h"
#include "Aql/Collection.h"
#include "Aql/OutputAqlItemRow.h"
#include "Basics/Common.h"
#include "Cluster/ServerState.h"
#include "VocBase/LogicalCollection.h"

#include <algorithm>

#include "velocypack/Collection.h"
#include "velocypack/velocypack-aliases.h"

using namespace arangodb;
using namespace arangodb::aql;

namespace {

int extractKeyAndRev(transaction::Methods* trx, AqlValue const& value,
                     std::string& key, std::string& rev, bool keyOnly = false) {
  if (value.isObject()) {
    bool mustDestroy;
    auto resolver = trx->resolver();
    TRI_ASSERT(resolver != nullptr);
    AqlValue sub = value.get(*resolver, StaticStrings::KeyString, mustDestroy, false);
    AqlValueGuard guard(sub, mustDestroy);

    if (sub.isString()) {
      key.assign(sub.slice().copyString());

      if (!keyOnly) {
        bool mustDestroyToo;
        AqlValue subTwo =
            value.get(*resolver, StaticStrings::RevString, mustDestroyToo, false);
        AqlValueGuard guard(subTwo, mustDestroyToo);
        if (subTwo.isString()) {
          rev.assign(subTwo.slice().copyString());
        }
      }

      return TRI_ERROR_NO_ERROR;
    }
  } else if (value.isString()) {
    key.assign(value.slice().copyString());
    return TRI_ERROR_NO_ERROR;
  }

  return TRI_ERROR_ARANGO_DOCUMENT_KEY_MISSING;
}

int extractKey(transaction::Methods* trx, AqlValue const& value, std::string& key) {
  std::string optimizeAway;
  return extractKeyAndRev(trx, value, key, optimizeAway, true /*key only*/);
}

/// @brief process the result of a data-modification operation
void handleStats(ModificationStats& stats, ModificationExecutorInfos& info, int code,
                 bool ignoreErrors, std::string const* errorMessage = nullptr) {
  if (code == TRI_ERROR_NO_ERROR) {
    // update the success counter
    if (info._doCount) {
      stats.incrWritesExecuted();
    }
    return;
  }

  if (ignoreErrors) {
    // update the ignored counter
    if (info._doCount) {
      stats.incrWritesExecuted();
    }
    return;
  }

  // bubble up the error
  if (errorMessage != nullptr && !errorMessage->empty()) {
    THROW_ARANGO_EXCEPTION_MESSAGE(code, *errorMessage);
  }

  THROW_ARANGO_EXCEPTION(code);
}

/// @brief process the result of a data-modification operation
void handleBabyStats(ModificationStats& stats, ModificationExecutorInfos& info,
                     OperationResult const& opRes, uint64_t numBabies,
                     bool ignoreErrors, bool ignoreDocumentNotFound = false) {
  auto const& errorCounter = opRes.countErrorCodes;

  size_t numberBabies = numBabies;  // from uint64_t to size_t
  if (errorCounter.empty()) {
    // update the success counter
    if (info._doCount) {
      stats.addWritesExecuted(numberBabies);
    }
    return;
  }

  if (ignoreErrors) {
    for (auto const& pair : errorCounter) {
      // update the ignored counter
      if (info._doCount) {
        stats.addWritesIgnored(pair.second);
      }
      numberBabies -= pair.second;
    }

    // update the success counter
    if (info._doCount) {
      stats.addWritesExecuted(numberBabies);
    }
    return;
  }
  auto first = errorCounter.begin();
  if (ignoreDocumentNotFound && first->first == TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND) {
    if (errorCounter.size() == 1) {
      // We only have Document not found. Fix statistics and ignore
      // update the ignored counter
      if (info._doCount) {
        stats.addWritesIgnored(first->second);
      }
      numberBabies -= first->second;
      // update the success counter
      if (info._doCount) {
        stats.addWritesExecuted(numberBabies);
      }
      return;
    }

    // Sorry we have other errors as well.
    // No point in fixing statistics.
    // Throw other error.
    ++first;
    TRI_ASSERT(first != errorCounter.end());
  }

  auto code = first->first;
  std::string message;
  try {
    if (opRes.slice().isArray()) {
      for (auto doc : VPackArrayIterator(opRes.slice())) {
        if (doc.hasKey("errorNum") && doc.get("errorNum").getInt() == code) {
          if (doc.hasKey("errorMessage")) {
            message = doc.get("errorMessage").copyString();
          }
        }
      }
    }
  } catch (...) {
    // Fall-through to returning the generic error message,
    // which better than forwarding an internal error here.
  }
  if (!message.empty()) {
    THROW_ARANGO_EXCEPTION_MESSAGE(code, message);
  }
  // Throw generic error, as no error message was found.
  THROW_ARANGO_EXCEPTION(code);
}
}  // namespace

///////////////////////////////////////////////////////////////////////////////
// INSERT /////////////////////////////////////////////////////////////////////
bool Insert::doModifications(ModificationExecutorInfos& info, ModificationStats& stats) {
  OperationOptions& options = info._options;

  reset();
  _tmpBuilder.openArray();

  const RegisterId& inReg = info._input1RegisterId.value();
  TRI_ASSERT(_block);
  _block->forRowInBlock([this, inReg, &info](InputAqlItemRow&& row) {<commit_msg>stop after receiving first error message (#8555)<commit_after>////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2018 ArangoDB GmbH, Cologne, Germany
///
/// Licensed 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.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author <NAME>
////////////////////////////////////////////////////////////////////////////////

#include "ModificationExecutorTraits.h"
#include "Aql/AqlValue.h"
#include "Aql/Collection.h"
#include "Aql/OutputAqlItemRow.h"
#include "Basics/Common.h"
#include "Cluster/ServerState.h"
#include "VocBase/LogicalCollection.h"

#include <algorithm>

#include "velocypack/Collection.h"
#include "velocypack/velocypack-aliases.h"

using namespace arangodb;
using namespace arangodb::aql;

namespace {

int extractKeyAndRev(transaction::Methods* trx, AqlValue const& value,
                     std::string& key, std::string& rev, bool keyOnly = false) {
  if (value.isObject()) {
    bool mustDestroy;
    auto resolver = trx->resolver();
    TRI_ASSERT(resolver != nullptr);
    AqlValue sub = value.get(*resolver, StaticStrings::KeyString, mustDestroy, false);
    AqlValueGuard guard(sub, mustDestroy);

    if (sub.isString()) {
      key.assign(sub.slice().copyString());

      if (!keyOnly) {
        bool mustDestroyToo;
        AqlValue subTwo =
            value.get(*resolver, StaticStrings::RevString, mustDestroyToo, false);
        AqlValueGuard guard(subTwo, mustDestroyToo);
        if (subTwo.isString()) {
          rev.assign(subTwo.slice().copyString());
        }
      }

      return TRI_ERROR_NO_ERROR;
    }
  } else if (value.isString()) {
    key.assign(value.slice().copyString());
    return TRI_ERROR_NO_ERROR;
  }

  return TRI_ERROR_ARANGO_DOCUMENT_KEY_MISSING;
}

int extractKey(transaction::Methods* trx, AqlValue const& value, std::string& key) {
  std::string optimizeAway;
  return extractKeyAndRev(trx, value, key, optimizeAway, true /*key only*/);
}

/// @brief process the result of a data-modification operation
void handleStats(ModificationStats& stats, ModificationExecutorInfos& info, int code,
                 bool ignoreErrors, std::string const* errorMessage = nullptr) {
  if (code == TRI_ERROR_NO_ERROR) {
    // update the success counter
    if (info._doCount) {
      stats.incrWritesExecuted();
    }
    return;
  }

  if (ignoreErrors) {
    // update the ignored counter
    if (info._doCount) {
      stats.incrWritesExecuted();
    }
    return;
  }

  // bubble up the error
  if (errorMessage != nullptr && !errorMessage->empty()) {
    THROW_ARANGO_EXCEPTION_MESSAGE(code, *errorMessage);
  }

  THROW_ARANGO_EXCEPTION(code);
}

/// @brief process the result of a data-modification operation
void handleBabyStats(ModificationStats& stats, ModificationExecutorInfos& info,
                     OperationResult const& opRes, uint64_t numBabies,
                     bool ignoreErrors, bool ignoreDocumentNotFound = false) {
  auto const& errorCounter = opRes.countErrorCodes;

  size_t numberBabies = numBabies;  // from uint64_t to size_t
  if (errorCounter.empty()) {
    // update the success counter
    if (info._doCount) {
      stats.addWritesExecuted(numberBabies);
    }
    return;
  }

  if (ignoreErrors) {
    for (auto const& pair : errorCounter) {
      // update the ignored counter
      if (info._doCount) {
        stats.addWritesIgnored(pair.second);
      }
      numberBabies -= pair.second;
    }

    // update the success counter
    if (info._doCount) {
      stats.addWritesExecuted(numberBabies);
    }
    return;
  }
  auto first = errorCounter.begin();
  if (ignoreDocumentNotFound && first->first == TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND) {
    if (errorCounter.size() == 1) {
      // We only have Document not found. Fix statistics and ignore
      // update the ignored counter
      if (info._doCount) {
        stats.addWritesIgnored(first->second);
      }
      numberBabies -= first->second;
      // update the success counter
      if (info._doCount) {
        stats.addWritesExecuted(numberBabies);
      }
      return;
    }

    // Sorry we have other errors as well.
    // No point in fixing statistics.
    // Throw other error.
    ++first;
    TRI_ASSERT(first != errorCounter.end());
  }

  auto code = first->first;
  std::string message;
  try {
    if (opRes.slice().isArray()) {
      for (auto doc : VPackArrayIterator(opRes.slice())) {
        if (doc.isObject() && doc.hasKey("errorNum") && doc.get("errorNum").getInt() == code) {
          if (doc.hasKey("errorMessage")) {
            message = doc.get("errorMessage").copyString();
            break;
          }
        }
      }
    }
  } catch (...) {
    // Fall-through to returning the generic error message,
    // which better than forwarding an internal error here.
  }
  if (!message.empty()) {
    THROW_ARANGO_EXCEPTION_MESSAGE(code, message);
  }
  // Throw generic error, as no error message was found.
  THROW_ARANGO_EXCEPTION(code);
}
}  // namespace

///////////////////////////////////////////////////////////////////////////////
// INSERT /////////////////////////////////////////////////////////////////////
bool Insert::doModifications(ModificationExecutorInfos& info, ModificationStats& stats) {
  OperationOptions& options = info._options;

  reset();
  _tmpBuilder.openArray();

  const RegisterId& inReg = info._input1RegisterId.value();
  TRI_ASSERT(_block);
  _block->forRowInBlock([this, inReg, &info](InputAqlItemRow&& row) {
{'fraction_non_alphanumeric': 0.16514749751408683, 'fraction_numerical': 0.002651640702684786, 'mean_word_length': 2.505373221028173, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3736553', 'n_tokens_mistral': 3569, 'n_tokens_neox': 3446, 'n_words': 902}