All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.sap.cds.impl.ExceptionHandler Maven / Gradle / Ivy
/************************************************************************
* © 2019-2024 SAP SE or an SAP affiliate company. All rights reserved. *
************************************************************************/
package com.sap.cds.impl;
import static com.sap.cds.reflect.impl.CdsAnnotatableImpl.removeAt;
import static com.sap.cds.reflect.impl.reader.model.CdsConstants.ANNOTATION_VALID_FROM;
import static com.sap.cds.util.CdsModelUtils.concreteKeyNames;
import java.sql.BatchUpdateException;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.sap.cds.CdsDataStoreException;
import com.sap.cds.CdsException;
import com.sap.cds.CdsMissingValueException;
import com.sap.cds.NotNullConstraintException;
import com.sap.cds.UniqueConstraintException;
import com.sap.cds.jdbc.spi.ExceptionAnalyzer;
import com.sap.cds.reflect.CdsElement;
import com.sap.cds.reflect.CdsEntity;
import com.sap.cds.util.OccUtils;
public class ExceptionHandler {
private final CdsEntity entity;
private final ExceptionAnalyzer exceptionAnalyzer;
public ExceptionHandler(CdsEntity entity, ExceptionAnalyzer exceptionAnalyzer) {
this.entity = entity;
this.exceptionAnalyzer = exceptionAnalyzer;
}
public CdsException cdsBatchException(List> entries, int updatedCount, BatchUpdateException ex,
String sql) {
if (exceptionAnalyzer.isUniqueConstraint(ex)) {
return new BatchExceptionHandler(entity).uniqueConstraint(entries, updatedCount, ex);
}
if (exceptionAnalyzer.isNotNullConstraint(ex)) {
return new BatchExceptionHandler(entity).notNullConstraint(entries, updatedCount, ex, sql);
}
return dataStoreException(ex, sql);
}
public CdsException cdsException(Map entryValues, Exception ex, String sql) {
Throwable cause = ExceptionAnalyzer.getRootCause(ex);
if (cause instanceof SQLException sqlEx) {
if (exceptionAnalyzer.isUniqueConstraint(sqlEx)) {
return new UniqueConstraintException(entity, entryValues, concreteKeyNames(entity), ex);
}
if (exceptionAnalyzer.isNotNullConstraint(sqlEx)) {
return notNullConstraintException(entity, entryValues, ex, sql);
}
}
return dataStoreException(ex, sql);
}
public static CdsException cdsMissingValue(CdsEntity entity, CdsMissingValueException ex) {
Optional versEl = OccUtils.getVersionElement(entity);
if (versEl.isPresent()) {
String versElName = versEl.get().getName();
if ((OccUtils.versionParam(versElName)).equals(ex.getElementName())) {
throw new CdsMissingValueException("Versioned entity '%s' must contain a value for element '%s'"
.formatted(entity.getQualifiedName(), versElName), ex);
}
}
throw ex;
}
public static CdsException dataStoreException(Exception ex, String sql) {
if (ex instanceof SQLException e && isHanaHexEnforced(e)) {
throw new HanaHexException(ex.getMessage());
}
return new CdsDataStoreException("Error executing the statement", new CdsDataStoreException("SQL: " + sql, ex));
}
private static boolean isHanaHexEnforced(SQLException e) {
// HANA HEX enforced but cannot be selected
return e.getErrorCode() == 256 && e.getMessage().contains("hex enforced but cannot be selected");
}
public static class HanaHexException extends CdsDataStoreException {
private static final long serialVersionUID = 1L;
public HanaHexException(String message) {
super(message);
}
}
public static void chainNextExceptions(SQLException ex) {
SQLException next = ex.getNextException();
if (ex.getCause() == null && next != null) {
ex.initCause(next);
}
}
private static List getNullValuedNotNullableElements(CdsEntity entity, Map entry) {
Stream nullKeys = entity.keyElements().filter(e -> null == entry.get(e.getName()));
Stream notNullEls = entity.elements()
.filter(e -> (e.isNotNull() || e.findAnnotation(removeAt(ANNOTATION_VALID_FROM)).isPresent())
&& null == entry.get(e.getName()));
return Stream.concat(nullKeys, notNullEls).collect(Collectors.toList());
}
private static CdsException notNullConstraintException(CdsEntity entity, Map entryValues,
Exception ex, String sql) {
List nonNullableElements = getNullValuedNotNullableElements(entity, entryValues);
if (nonNullableElements.isEmpty()) {
return dataStoreException(ex, sql);
}
return new NotNullConstraintException(nonNullableElements, ex);
}
static class BatchExceptionHandler {
private final CdsEntity entity;
public BatchExceptionHandler(CdsEntity entity) {
this.entity = entity;
}
private int getFirstNonPositiveIndex(int[] rcs) {
for (int pos = 0; pos < rcs.length; pos++) {
if (rcs[pos] < 0) {
return pos;
}
}
return rcs.length;
}
public CdsException uniqueConstraint(List> entries, int updatedCount,
BatchUpdateException ex) {
int[] updateCounts = ex.getUpdateCounts();
int badPos = getFirstNonPositiveIndex(updateCounts);
Map entry = entries.get(badPos + updatedCount);
return new UniqueConstraintException(entity, entry, concreteKeyNames(entity), ex);
}
public CdsException notNullConstraint(List> entries, int updatedCount,
BatchUpdateException ex, String sql) {
int[] updateCounts = ex.getUpdateCounts();
int badPos = getFirstNonPositiveIndex(updateCounts);
Map entryValues = entries.get(badPos + updatedCount);
return notNullConstraintException(entity, entryValues, ex, sql);
}
}
}