Skip to content

Commit

Permalink
#13309 - Changes in the Upsert Command for Postgres -9.4
Browse files Browse the repository at this point in the history
  • Loading branch information
acurionedotcms committed Jan 16, 2018
1 parent 29a6f8c commit c5b3a5d
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2331,8 +2331,7 @@ private void upsertPermission(DotConnect dc, String permissionId, Permissionable
replacements.setAttribute(QueryReplacements.ID_VALUE, "permission_reference_seq.NEXTVAL");
}

String query = upsertCommand.generateSQLQuery(replacements);
upsertCommand.execute(dc, query, permissionId, newReference.getPermissionId(), type);
upsertCommand.execute(dc, replacements, permissionId, newReference.getPermissionId(), type);
}

private List<Permission> filterOnlyNonInheritablePermissions(List<Permission> permissions, String permissionableId) {
Expand Down
13 changes: 11 additions & 2 deletions dotCMS/src/main/java/com/dotmarketing/common/util/SQLUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ public class SQLUtil {
public static final String _DESC = " " + DESC;
public static final String PARAMETER = "?";

private static final String SQL_STATE_UNIQUE_CONSTRAINT = "23000";
private static final String ORACLE_SQL_STATE_UNIQUE_CONSTRAINT = "23000";
private static final String POSTGRE_SQL_STATE_UNIQUE_CONSTRAINT = "23505";

private static final Set<String> EVIL_SQL_CONDITION_WORDS = ImmutableSet.of( "insert", "delete", "update",
"replace", "create", "drop", "alter", "truncate", "declare", "exec", "--", "procedure", "pg_", "lock",
Expand Down Expand Up @@ -315,9 +316,17 @@ private static boolean isValidSQLCharacter (final char c) {
return Character.isLetterOrDigit(c) || '-' == c || '_' == c;
} // isValidSQLCharacter.

/**
* Method to check if an exception is a Unique Constraint Exception
* It depends on the database engine. So far only Oracle and postgres has been implemented
* @param ex
* @return
*/
public static boolean isUniqueConstraintException (DotDataException ex) {
if (ex != null && ex.getCause() instanceof SQLException) {
return ((SQLException) ex.getCause()).getSQLState().equals(SQL_STATE_UNIQUE_CONSTRAINT);
final SQLException sqle = (SQLException) ex.getCause();
return (DbConnectionFactory.isOracle() && sqle.getSQLState().equals(ORACLE_SQL_STATE_UNIQUE_CONSTRAINT)) ||
(DbConnectionFactory.isPostgres() && sqle.getSQLState().equals(POSTGRE_SQL_STATE_UNIQUE_CONSTRAINT));
}
return false;
}
Expand Down
18 changes: 18 additions & 0 deletions dotCMS/src/main/java/com/dotmarketing/db/DbConnectionFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,24 @@ public static int getDbVersion() {
return version;
}

/**
* Method to get the Database Full Version
* @return Database Version (Major.Minor)
*/
public static float getDbFullVersion() {
try {
Connection con = getConnection();
DatabaseMetaData meta = con.getMetaData();
String version = "%d.%d";
version = String.format(version, meta.getDatabaseMajorVersion(), meta.getDatabaseMinorVersion());
return Float.parseFloat(version);
} catch (Exception e) {
Logger.error(DbConnectionFactory.class,
"---------- DBConnectionFactory: Error getting DB Full version " + "---------------", e);
throw new DotRuntimeException(e.toString());
}
}

/**
* Returns the correct MySQL system variable used to define the database
* Storage Engine. The old {@code storage_variable} was deprecated as of
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,5 @@ enum QueryReplacements {
* Execute the query
* @throws DotDataException
*/
void execute (DotConnect dotConnect, String query, Object... parameters) throws DotDataException;
void execute (DotConnect dotConnect, SimpleMapAppContext queryReplacements, Object... parameters) throws DotDataException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
import com.dotcms.system.SimpleMapAppContext;
import com.dotmarketing.common.db.DotConnect;
import com.dotmarketing.common.util.SQLUtil;
import com.dotmarketing.db.DbConnectionFactory;
import com.dotmarketing.exception.DotDataException;
import com.dotmarketing.util.Logger;
import com.liferay.util.StringUtil;
import java.util.ArrayList;
import java.util.Arrays;
Expand All @@ -23,8 +25,9 @@ public abstract class UpsertCommand implements DatabaseCommand {
* @param parameters or values
* @throws DotDataException
*/
public void execute(DotConnect dotConnect, String query, Object... parameters)
public void execute(DotConnect dotConnect, SimpleMapAppContext queryReplacements, Object... parameters)
throws DotDataException {
String query = generateSQLQuery(queryReplacements);
DotConnect dc = (dotConnect != null) ? dotConnect : new DotConnect();
ArrayList<Object> params = new ArrayList<>();
Collections.addAll(params, parameters); //Update parameters
Expand Down Expand Up @@ -129,7 +132,8 @@ public String generateSQLQuery(SimpleMapAppContext replacements) {
}

@Override
public void execute(DotConnect dotConnect, String query, Object... parameters) throws DotDataException {
public void execute(DotConnect dotConnect, SimpleMapAppContext queryReplacements, Object... parameters) throws DotDataException {
String query = generateSQLQuery(queryReplacements);
DotConnect dc = (dotConnect != null) ? dotConnect : new DotConnect();
dc.executeUpdate(query, parameters);
}
Expand All @@ -143,11 +147,19 @@ final class PostgreUpsertCommand extends UpsertCommand {
* ON CONFLICT (conditionalColumn) DO UPDATE SET column1=value1, column2=value2, etc...
*/

private static final float POSTGRES_UPSERT_MINIMUM_VERSION = 9.5f;

private static final String POSTGRES_UPSERT_QUERY =
"INSERT INTO %s (%s) "
+ "VALUES (%s) ON CONFLICT (%s) "
+ "DO UPDATE SET %s";

private static final String POSTGRES_INSERT_QUERY =
"INSERT INTO %s (%s) VALUES (%s)";

private static final String POSTGRES_UPDATE_QUERY =
"UPDATE %s SET %s WHERE %s='%s'";

@Override
public String generateSQLQuery(SimpleMapAppContext replacements) {
return
Expand All @@ -159,6 +171,57 @@ public String generateSQLQuery(SimpleMapAppContext replacements) {
getUpdateColumnValuePairs(replacements)
);
}

//If PostgreSQL gets upgraded to 9.5+ (to Support ON CONFLICT) , this override can be removed and let it use the super method execute()
@Override
public void execute(DotConnect dotConnect, SimpleMapAppContext queryReplacements,
Object... parameters) throws DotDataException {
DotConnect dc = (dotConnect != null) ? dotConnect : new DotConnect();

float version = DbConnectionFactory.getDbFullVersion();
if (version >= POSTGRES_UPSERT_MINIMUM_VERSION) {
this.executeUpsert(dc, queryReplacements, parameters);
} else {
this.executeUpdateInsert(dc, queryReplacements, parameters);
}
}

private void executeUpsert(DotConnect dotConnect, SimpleMapAppContext queryReplacements,
Object... parameters) throws DotDataException {
super.execute(dotConnect, queryReplacements, parameters);
}

private void executeUpdateInsert(DotConnect dotConnect, SimpleMapAppContext queryReplacements,
Object... parameters) throws DotDataException {
try {
//In Postgre 9.4- Upsert Statement is not supported. Attempt to Insert first.
String insertQuery =
String.format(
POSTGRES_INSERT_QUERY,
queryReplacements.getAttribute(QueryReplacements.TABLE),
getInsertColumnsString(queryReplacements),
getInsertValuesString(queryReplacements)
);
dotConnect.executeUpdate(insertQuery, false, parameters);

} catch (DotDataException ex) {
if (SQLUtil.isUniqueConstraintException(ex)) {
//On Unique Constraint exception, attempt to update:
DbConnectionFactory.closeAndCommit();
String updateQuery =
String.format(
POSTGRES_UPDATE_QUERY,
queryReplacements.getAttribute(QueryReplacements.TABLE),
getUpdateColumnValuePairs(queryReplacements),
queryReplacements.getAttribute(QueryReplacements.CONDITIONAL_COLUMN),
queryReplacements.getAttribute(QueryReplacements.CONDITIONAL_VALUE)
);
dotConnect.executeUpdate(updateQuery, parameters);
} else {
throw ex;
}
}
}
}

final class MySQLUpsertCommand extends UpsertCommand {
Expand Down Expand Up @@ -254,9 +317,10 @@ public String generateSQLQuery(SimpleMapAppContext replacements) {
}

@Override
public void execute(DotConnect dotConnect, String query, Object... parameters)
public void execute(DotConnect dotConnect, SimpleMapAppContext queryReplacements, Object... parameters)
throws DotDataException {

String query = generateSQLQuery(queryReplacements);
DotConnect dc = (dotConnect != null) ? dotConnect : new DotConnect();
ArrayList<Object> params = new ArrayList<>();

Expand Down

0 comments on commit c5b3a5d

Please sign in to comment.