Skip to content

Commit

Permalink
[Blazebit#1395] Ensure pending inserts for tables targeted by foreign…
Browse files Browse the repository at this point in the history
… keys by custom insert/update DML are flushed
  • Loading branch information
beikov committed Dec 12, 2021
1 parent abfbbc5 commit f0b5be2
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,23 @@
import com.blazebit.persistence.impl.query.QuerySpecification;
import com.blazebit.persistence.impl.util.SqlUtils;
import com.blazebit.persistence.parser.expression.ExpressionCopyContext;
import com.blazebit.persistence.spi.AttributePath;
import com.blazebit.persistence.spi.DbmsModificationState;
import com.blazebit.persistence.spi.ExtendedAttribute;
import com.blazebit.persistence.spi.ExtendedManagedType;
import com.blazebit.persistence.spi.ExtendedQuerySupport;
import com.blazebit.persistence.spi.JoinTable;
import com.blazebit.persistence.spi.JpaMetamodelAccessor;

import javax.persistence.Query;
import javax.persistence.TypedQuery;
import javax.persistence.metamodel.Attribute;
import javax.persistence.metamodel.EntityType;
import javax.persistence.metamodel.ListAttribute;
import javax.persistence.metamodel.MapAttribute;
import javax.persistence.metamodel.SingularAttribute;
import javax.persistence.metamodel.Type;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
Expand Down Expand Up @@ -265,6 +271,7 @@ private <R> QuerySpecification getQuerySpecification(Query baseQuery, Query exam
getInsertExecutorQuery(),
insertSqlSb.toString(),
cutoffColumns,
getForeignKeyParticipatingQueries(),
mainQuery.getQueryConfiguration().isQueryPlanCacheEnabled()
);
}
Expand Down Expand Up @@ -307,4 +314,28 @@ protected Query getInsertExecutorQuery() {
return em.createQuery(exampleQueryString);
}

protected Collection<Query> getForeignKeyParticipatingQueries() {
Map<String, Query> map = null;
JpaMetamodelAccessor jpaMetamodelAccessor = mainQuery.jpaProvider.getJpaMetamodelAccessor();
for (String attributeName : bindingMap.keySet()) {
AttributePath path = jpaMetamodelAccessor.getBasicAttributePath(getMetamodel(), entityType, attributeName);
for (Attribute<?, ?> attributePart : path.getAttributes()) {
if (attributePart instanceof SingularAttribute<?, ?>) {
SingularAttribute<?, ?> singularAttribute = (SingularAttribute<?, ?>) attributePart;
if (map == null) {
map = new HashMap<>();
}
if (singularAttribute.getType() instanceof EntityType<?>) {
String entityName = ((EntityType<?>) singularAttribute.getType()).getName();
if (!map.containsKey(entityName)) {
map.put(entityName, em.createQuery("select e from " + entityName + " e"));
}
break;
}
}
}
}
return map == null ? Collections.<Query>emptyList() : map.values();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@

import javax.persistence.Query;
import javax.persistence.TypedQuery;
import javax.persistence.metamodel.Attribute;
import javax.persistence.metamodel.EntityType;
import javax.persistence.metamodel.ListAttribute;
import javax.persistence.metamodel.ManagedType;
Expand All @@ -47,6 +48,7 @@
import javax.persistence.metamodel.SingularAttribute;
import javax.persistence.metamodel.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
Expand Down Expand Up @@ -476,6 +478,7 @@ private <R> QuerySpecification getQuerySpecification(Query baseQuery, Query exam
collectionAlias,
joinTableIdColumns.toArray(new String[0]),
setColumns,
getForeignKeyParticipatingQueries(),
aliasMapping,
getUpdateExampleQuery(),
columnExpressionRemappings
Expand All @@ -496,4 +499,27 @@ protected List<String> getSetColumns() {
return setColumns;
}

protected Collection<Query> getForeignKeyParticipatingQueries() {
Map<String, Query> map = null;
for (String attributeName : setAttributeBindingMap.keySet()) {
ExtendedAttribute<?, ?> attribute = collectionAttributeEntries.get(attributeName);
for (Attribute<?, ?> attributePart : attribute.getAttributePath()) {
if (attributePart instanceof SingularAttribute<?, ?>) {
SingularAttribute<?, ?> singularAttribute = (SingularAttribute<?, ?>) attributePart;
if (map == null) {
map = new HashMap<>();
}
if (singularAttribute.getType() instanceof EntityType<?>) {
String entityName = ((EntityType<?>) singularAttribute.getType()).getName();
if (!map.containsKey(entityName)) {
map.put(entityName, em.createQuery("select e from " + entityName + " e"));
}
break;
}
}
}
}
return map == null ? Collections.<Query>emptyList() : map.values();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import com.blazebit.persistence.parser.expression.Expression;
import com.blazebit.persistence.parser.expression.ExpressionCopyContext;
import com.blazebit.persistence.parser.expression.SubqueryExpression;
import com.blazebit.persistence.spi.AttributePath;
import com.blazebit.persistence.spi.DbmsModificationState;
import com.blazebit.persistence.spi.DbmsStatementType;
import com.blazebit.persistence.spi.ExtendedManagedType;
Expand All @@ -46,10 +47,15 @@

import javax.persistence.Query;
import javax.persistence.TypedQuery;
import javax.persistence.metamodel.Attribute;
import javax.persistence.metamodel.EntityType;
import javax.persistence.metamodel.SingularAttribute;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
Expand Down Expand Up @@ -419,6 +425,7 @@ private <R> QuerySpecification getQuerySpecification(Query baseQuery, Query exam
tableAlias,
idColumns,
setColumns,
getForeignKeyParticipatingQueries(),
aliasMapping,
getUpdateExampleQuery()
);
Expand Down Expand Up @@ -461,6 +468,30 @@ public String extract(StringBuilder sb, int index, int currentPosition) {
}));
}

protected Collection<Query> getForeignKeyParticipatingQueries() {
Map<String, Query> map = null;
JpaMetamodelAccessor jpaMetamodelAccessor = mainQuery.jpaProvider.getJpaMetamodelAccessor();
for (String attributeName : setAttributeBindingMap.keySet()) {
AttributePath path = jpaMetamodelAccessor.getBasicAttributePath(getMetamodel(), entityType, attributeName);
for (Attribute<?, ?> attributePart : path.getAttributes()) {
if (attributePart instanceof SingularAttribute<?, ?>) {
SingularAttribute<?, ?> singularAttribute = (SingularAttribute<?, ?>) attributePart;
if (map == null) {
map = new HashMap<>();
}
if (singularAttribute.getType() instanceof EntityType<?>) {
String entityName = ((EntityType<?>) singularAttribute.getType()).getName();
if (!map.containsKey(entityName)) {
map.put(entityName, em.createQuery("select e from " + entityName + " e"));
}
break;
}
}
}
}
return map == null ? Collections.<Query>emptyList() : map.values();
}

protected void appendSetClause(StringBuilder sbSelectFrom, boolean externalRepresentation) {
sbSelectFrom.append(" SET ");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,17 @@ public class CollectionInsertModificationQuerySpecification<T> extends Modificat
private final Query insertExampleQuery;
private final String insertSql;
private final int cutoffColumns;
private final Collection<Query> foreignKeyParticipatingQueries;

public CollectionInsertModificationQuerySpecification(AbstractCommonQueryBuilder<?, ?, ?, ?, ?> commonQueryBuilder, Query baseQuery, Query exampleQuery, Collection<? extends Parameter<?>> parameters, Set<String> parameterListNames,
List<String> keyRestrictedLeftJoinAliases, List<EntityFunctionNode> entityFunctionNodes, boolean recursive, List<CTENode> ctes, boolean shouldRenderCteNodes,
boolean isEmbedded, String[] returningColumns, ReturningObjectBuilder<T> objectBuilder, Map<DbmsModificationState, String> includedModificationStates, Map<String, String> returningAttributeBindingMap, Query insertExampleQuery, String insertSql, int cutoffColumns,
boolean queryPlanCacheEnabled) {
boolean isEmbedded, String[] returningColumns, ReturningObjectBuilder<T> objectBuilder, Map<DbmsModificationState, String> includedModificationStates, Map<String, String> returningAttributeBindingMap,
Query insertExampleQuery, String insertSql, int cutoffColumns, Collection<Query> foreignKeyParticipatingQueries, boolean queryPlanCacheEnabled) {
super(commonQueryBuilder, baseQuery, exampleQuery, parameters, parameterListNames, keyRestrictedLeftJoinAliases, entityFunctionNodes, recursive, ctes, shouldRenderCteNodes, isEmbedded, returningColumns, objectBuilder, includedModificationStates, returningAttributeBindingMap, queryPlanCacheEnabled);
this.insertExampleQuery = insertExampleQuery;
this.insertSql = insertSql;
this.cutoffColumns = cutoffColumns;
this.foreignKeyParticipatingQueries = foreignKeyParticipatingQueries;
}

@Override
Expand Down Expand Up @@ -123,6 +125,7 @@ public String extract(StringBuilder sb, int index, int currentPosition) {
participatingQueries.add(baseQuery);
participatingQueries.add(exampleQuery);
participatingQueries.add(insertExampleQuery);
participatingQueries.addAll(foreignKeyParticipatingQueries);

// Some dbms like DB2 will need to wrap modification queries in select queries when using CTEs
boolean hasCtes = withClause != null && withClause.length() != 0 || addedCtes != null && !addedCtes.isEmpty();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ public class CollectionUpdateModificationQuerySpecification<T> extends UpdateMod

public CollectionUpdateModificationQuerySpecification(AbstractCommonQueryBuilder<?, ?, ?, ?, ?> commonQueryBuilder, Query baseQuery, Query exampleQuery, Collection<? extends Parameter<?>> parameters, Set<String> parameterListNames, boolean recursive, List<CTENode> ctes, boolean shouldRenderCteNodes,
boolean isEmbedded, String[] returningColumns, ReturningObjectBuilder<T> objectBuilder, Map<DbmsModificationState, String> includedModificationStates, Map<String, String> returningAttributeBindingMap, boolean queryPlanCacheEnabled,
String tableToUpdate, String tableAlias, String[] idColumns, List<String> setColumns, Map<String, String> aliasMapping, Query updateExampleQuery, Map<String, String> columnExpressionRemappings) {
super(commonQueryBuilder, baseQuery, exampleQuery, parameters, parameterListNames, recursive, ctes, shouldRenderCteNodes, isEmbedded, returningColumns, objectBuilder, includedModificationStates, returningAttributeBindingMap, queryPlanCacheEnabled, tableToUpdate, tableAlias, idColumns, setColumns, aliasMapping, updateExampleQuery);
String tableToUpdate, String tableAlias, String[] idColumns, List<String> setColumns, Collection<Query> foreignKeyParticipatingQueries, Map<String, String> aliasMapping, Query updateExampleQuery, Map<String, String> columnExpressionRemappings) {
super(commonQueryBuilder, baseQuery, exampleQuery, parameters, parameterListNames, recursive, ctes, shouldRenderCteNodes, isEmbedded, returningColumns, objectBuilder, includedModificationStates, returningAttributeBindingMap, queryPlanCacheEnabled, tableToUpdate, tableAlias, idColumns, setColumns, foreignKeyParticipatingQueries, aliasMapping, updateExampleQuery);
this.columnExpressionRemappings = columnExpressionRemappings;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,19 @@ public class UpdateModificationQuerySpecification<T> extends ModificationQuerySp
private final String tableAlias;
private final String[] idColumns;
private final List<String> setColumns;
private final Collection<Query> foreignKeyParticipatingQueries;
private final Map<String, String> aliasMapping;
private final Query updateExampleQuery;

public UpdateModificationQuerySpecification(AbstractCommonQueryBuilder<?, ?, ?, ?, ?> commonQueryBuilder, Query baseQuery, Query exampleQuery, Collection<? extends Parameter<?>> parameters, Set<String> parameterListNames, boolean recursive, List<CTENode> ctes, boolean shouldRenderCteNodes,
boolean isEmbedded, String[] returningColumns, ReturningObjectBuilder<T> objectBuilder, Map<DbmsModificationState, String> includedModificationStates, Map<String, String> returningAttributeBindingMap, boolean queryPlanCacheEnabled,
String tableToUpdate, String tableAlias, String[] idColumns, List<String> setColumns, Map<String, String> aliasMapping, Query updateExampleQuery) {
String tableToUpdate, String tableAlias, String[] idColumns, List<String> setColumns, Collection<Query> foreignKeyParticipatingQueries, Map<String, String> aliasMapping, Query updateExampleQuery) {
super(commonQueryBuilder, baseQuery, exampleQuery, parameters, parameterListNames, recursive, ctes, shouldRenderCteNodes, isEmbedded, returningColumns, objectBuilder, includedModificationStates, returningAttributeBindingMap, queryPlanCacheEnabled);
this.tableToUpdate = tableToUpdate;
this.tableAlias = tableAlias;
this.idColumns = idColumns;
this.setColumns = setColumns;
this.foreignKeyParticipatingQueries = foreignKeyParticipatingQueries;
this.aliasMapping = aliasMapping;
this.updateExampleQuery = updateExampleQuery;
}
Expand Down Expand Up @@ -151,6 +153,7 @@ protected void initialize() {
participatingQueries.add(baseQuery);
participatingQueries.add(exampleQuery);
participatingQueries.add(updateExampleQuery);
participatingQueries.addAll(foreignKeyParticipatingQueries);

boolean hasCtes = withClause != null && withClause.length() != 0 || addedCtes != null && !addedCtes.isEmpty();
if (hasCtes && returningAttributeBindingMap.isEmpty() && !dbmsDialect.usesExecuteUpdateWhenWithClauseInModificationQuery()) {
Expand Down

0 comments on commit f0b5be2

Please sign in to comment.