com.sap.cds.jdbc.postgresql.PostgreSqlStatementResolver Maven / Gradle / Ivy
/*******************************************************************
* © 2022 SAP SE or an SAP affiliate company. All rights reserved. *
*******************************************************************/
package com.sap.cds.jdbc.postgresql;
import static com.sap.cds.impl.sql.SQLHelper.commaSeparated;
import static java.util.stream.Collectors.joining;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.sap.cds.jdbc.spi.StatementResolver;
import com.sap.cds.ql.cqn.CqnLock;
import com.sap.cds.ql.cqn.CqnLock.Mode;
public class PostgreSqlStatementResolver implements StatementResolver {
/**
* PostgreSQL: INSERT INTO with ON CONFLICT DO UPDATE
*
* ON CONFLICT can be used to specify an alternative action to raising a unique
* constraint or exclusion constraint violation error. For each individual row
* proposed for insertion, either the insertion proceeds, or, if an arbiter
* constraint or index specified by conflict_target is violated, the alternative
* conflict_action is taken. ON CONFLICT DO UPDATE updates the existing row that
* conflicts with the row proposed for insertion as its alternative action.
*
* ON CONFLICT DO UPDATE guarantees an atomic INSERT or UPDATE outcome; provided
* there is no independent error, one of those two outcomes is guaranteed, even
* under high concurrency. This is also known as UPSERT — “UPDATE or INSERT”.
*
* https://www.postgresql.org/docs/current/sql-insert.html#SQL-ON-CONFLICT
*/
@Override
public String upsert(String table, Stream keyColumns, Stream upsertColumns,
Stream upsertValues) {
List col = upsertColumns.collect(Collectors.toList());
String columns = commaSeparated(col.stream());
String insertValues = commaSeparated(upsertValues);
String conflictTarget = commaSeparated(keyColumns);
String updateValues = commaSeparated(col.stream().map(c -> "EXCLUDED." + c));
return Stream.of("INSERT INTO", table, columns, "VALUES", insertValues, "ON CONFLICT", conflictTarget,
"DO UPDATE SET", columns, "= ROW", updateValues).collect(joining(" "));
}
// https://www.postgresql.org/docs/current/explicit-locking.html
@Override
public String lockMode(Mode mode) {
return mode == CqnLock.Mode.SHARED ? "FOR SHARE" : "FOR UPDATE";
}
@Override
public Optional timeoutClause(int timeoutSeconds) {
if (timeoutSeconds == 0) {
return Optional.of("NOWAIT");
}
return Optional.empty();
}
}