Skip to content

Commit b5958e4

Browse files
authored
Change to not specify conflict_target by default for ON CONFLICT DO NOTHING (#1106)
* Change to not specify conflict_target by default for ON CONFLICT DO NOTHING * Delay the resolution of setValues * Refactor UpsertAssemblerContext and UpsertAssemblerContextBuilder * Fix JavaDoc format * Introduce QueryOperandPair to make the code easier to read * Add null checks
1 parent 3d4d918 commit b5958e4

21 files changed

+614
-590
lines changed

doma-core/src/main/java/org/seasar/doma/BatchInsert.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -107,10 +107,15 @@
107107

108108
/**
109109
* This variable represents the type of duplicate key handling strategy for an insert operation.
110-
* It can have one of three values: - UPDATE: If a duplicate key is encountered, the existing row
111-
* in the table will be updated. - IGNORE: If a duplicate key is encountered, the insert operation
112-
* will be ignored, and no changes will be made to the table. - EXCEPTION: If a duplicate key is
113-
* encountered, the operation will throw an exception, indicating that a duplicate key exists.
110+
* It can have one of three values:
111+
*
112+
* <ul>
113+
* <li>UPDATE: If a duplicate key is encountered, the existing row in the table will be updated.
114+
* <li>IGNORE: If a duplicate key is encountered, the insert operation will be ignored, and no
115+
* changes will be made to the table.
116+
* <li>EXCEPTION: If a duplicate key is encountered, the operation will throw an exception,
117+
* indicating that a duplicate key exists.
118+
* </ul>
114119
*
115120
* @return the type of duplicate key handling strategy for an insert operation.
116121
*/

doma-core/src/main/java/org/seasar/doma/Insert.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,10 +95,15 @@
9595

9696
/**
9797
* This variable represents the type of duplicate key handling strategy for an insert operation.
98-
* It can have one of three values: - UPDATE: If a duplicate key is encountered, the existing row
99-
* in the table will be updated. - IGNORE: If a duplicate key is encountered, the insert operation
100-
* will be ignored, and no changes will be made to the table. - EXCEPTION: If a duplicate key is
101-
* encountered, the operation will throw an exception, indicating that a duplicate key exists.
98+
* It can have one of three values:
99+
*
100+
* <ul>
101+
* <li>UPDATE: If a duplicate key is encountered, the existing row in the table will be updated.
102+
* <li>IGNORE: If a duplicate key is encountered, the insert operation will be ignored, and no
103+
* changes will be made to the table.
104+
* <li>EXCEPTION: If a duplicate key is encountered, the operation will throw an exception,
105+
* indicating that a duplicate key exists.
106+
* </ul>
102107
*
103108
* @return the type of duplicate key handling strategy for an insert operation.
104109
*/

doma-core/src/main/java/org/seasar/doma/jdbc/criteria/context/Operand.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
public interface Operand {
1313

14+
PropertyMetamodel<?> getPropertyMetamodel();
15+
1416
<R> R accept(Visitor<R> visitor);
1517

1618
final class Param implements Operand {
@@ -28,6 +30,11 @@ public InParameter<?> createInParameter(Config config) {
2830
return new ScalarInParameter<>(supplier.get());
2931
}
3032

33+
@Override
34+
public PropertyMetamodel<?> getPropertyMetamodel() {
35+
return propertyMetamodel;
36+
}
37+
3138
@Override
3239
public <R> R accept(Visitor<R> visitor) {
3340
return visitor.visit(this);
@@ -55,6 +62,11 @@ public Prop(PropertyMetamodel<?> value) {
5562
this.value = Objects.requireNonNull(value);
5663
}
5764

65+
@Override
66+
public PropertyMetamodel<?> getPropertyMetamodel() {
67+
return value;
68+
}
69+
5870
@Override
5971
public <R> R accept(Visitor<R> visitor) {
6072
return visitor.visit(this);

doma-core/src/main/java/org/seasar/doma/jdbc/criteria/statement/NativeSqlUpsertTerminal.java

Lines changed: 37 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,8 @@
66
import java.util.List;
77
import java.util.Map;
88
import java.util.Objects;
9-
import java.util.stream.Collectors;
109
import org.seasar.doma.internal.jdbc.sql.PreparedSqlBuilder;
1110
import org.seasar.doma.jdbc.Config;
12-
import org.seasar.doma.jdbc.InParameter;
1311
import org.seasar.doma.jdbc.PreparedSql;
1412
import org.seasar.doma.jdbc.SqlKind;
1513
import org.seasar.doma.jdbc.command.Command;
@@ -20,11 +18,12 @@
2018
import org.seasar.doma.jdbc.criteria.declaration.InsertDeclaration;
2119
import org.seasar.doma.jdbc.criteria.metamodel.PropertyMetamodel;
2220
import org.seasar.doma.jdbc.criteria.query.CriteriaQuery;
23-
import org.seasar.doma.jdbc.criteria.tuple.Tuple2;
2421
import org.seasar.doma.jdbc.entity.EntityPropertyType;
22+
import org.seasar.doma.jdbc.query.QueryOperand;
23+
import org.seasar.doma.jdbc.query.QueryOperandPair;
2524
import org.seasar.doma.jdbc.query.UpsertAssembler;
2625
import org.seasar.doma.jdbc.query.UpsertAssemblerContext;
27-
import org.seasar.doma.jdbc.query.UpsertSetValue;
26+
import org.seasar.doma.jdbc.query.UpsertAssemblerContextBuilder;
2827

2928
public class NativeSqlUpsertTerminal extends AbstractStatement<NativeSqlUpsertTerminal, Integer> {
3029

@@ -52,85 +51,65 @@ public Integer execute() {
5251
protected Command<Integer> createCommand() {
5352
InsertContext context = declaration.getContext();
5453
InsertSettings settings = context.getSettings();
55-
List<PropertyMetamodel<?>> upsertKeys = setUpsertKeysIfEmpty(context.onDuplicateContext);
56-
setUpsertSetValuesIfEmpty(context, upsertKeys);
57-
PreparedSql sql = getPreparedSql(settings, context);
54+
PreparedSql sql = createPreparedSql(settings, context);
5855
CriteriaQuery query = new CriteriaQuery(config, sql, getClass().getName(), EXECUTE_METHOD_NAME);
5956
query.setQueryTimeout(settings.getQueryTimeout());
6057
return new InsertCommand(query);
6158
}
6259

63-
private List<PropertyMetamodel<?>> setUpsertKeysIfEmpty(
64-
InsertContext.OnDuplicateContext context) {
65-
if (context.keys.isEmpty()) {
66-
context.keys =
67-
this.declaration.getContext().entityMetamodel.allPropertyMetamodels().stream()
68-
.filter(propertyMetamodel -> propertyMetamodel.asType().isId())
69-
.collect(Collectors.toList());
70-
}
71-
return context.keys;
72-
}
60+
private PreparedSql createPreparedSql(InsertSettings settings, InsertContext context) {
61+
List<EntityPropertyType<?, ?>> keys = prepareKeys(context.onDuplicateContext.keys);
62+
List<QueryOperandPair> insertValues = prepareInsertValues(context.values);
63+
List<QueryOperandPair> setValues = prepareSetValues(context.onDuplicateContext.setValues);
7364

74-
private void setUpsertSetValuesIfEmpty(
75-
InsertContext context, List<PropertyMetamodel<?>> upsertKeys) {
76-
if (context.onDuplicateContext.setValues.isEmpty()) {
77-
for (Operand.Prop prop : context.values.keySet()) {
78-
if (!upsertKeys.contains(prop.value)) {
79-
context.onDuplicateContext.setValues.put(prop, prop);
80-
}
81-
}
82-
}
65+
PreparedSqlBuilder sqlBuilder = assembleQuery(settings, context, keys, insertValues, setValues);
66+
return sqlBuilder.build(createCommenter(settings.getComment()));
8367
}
8468

85-
private PreparedSql getPreparedSql(InsertSettings settings, InsertContext context) {
86-
List<EntityPropertyType<?, ?>> keys = toEntityPropertyTypes(context.onDuplicateContext.keys);
87-
List<Tuple2<EntityPropertyType<?, ?>, InParameter<?>>> insertValues =
88-
insertValues(context.values);
89-
List<Tuple2<EntityPropertyType<?, ?>, UpsertSetValue>> setValues =
90-
setValues(context.onDuplicateContext.setValues);
91-
92-
PreparedSqlBuilder sql = assembleQuery(settings, context, keys, insertValues, setValues);
93-
return sql.build(createCommenter(settings.getComment()));
69+
private List<EntityPropertyType<?, ?>> prepareKeys(
70+
List<PropertyMetamodel<?>> propertyMetamodels) {
71+
return propertyMetamodels.stream().map(PropertyMetamodel::asType).collect(toList());
9472
}
9573

96-
private List<Tuple2<EntityPropertyType<?, ?>, InParameter<?>>> insertValues(
74+
private List<QueryOperandPair> prepareInsertValues(
9775
Map<Operand.Prop, Operand.Param> insertContextValue) {
98-
List<Tuple2<EntityPropertyType<?, ?>, InParameter<?>>> list = new ArrayList<>();
76+
List<QueryOperandPair> list = new ArrayList<>(insertContextValue.size());
9977
for (Map.Entry<Operand.Prop, Operand.Param> entry : insertContextValue.entrySet()) {
10078
Operand.Prop prop = entry.getKey();
10179
Operand.Param param = entry.getValue();
102-
list.add(new Tuple2<>(prop.value.asType(), param.createInParameter(config)));
80+
QueryOperand left = new QueryOperand.Prop(prop.getPropertyMetamodel().asType());
81+
QueryOperand right =
82+
new QueryOperand.Param(
83+
param.getPropertyMetamodel().asType(), param.createInParameter(config));
84+
QueryOperandPair pair = new QueryOperandPair(left, right);
85+
list.add(pair);
10386
}
10487
return list;
10588
}
10689

107-
private List<Tuple2<EntityPropertyType<?, ?>, UpsertSetValue>> setValues(
108-
Map<Operand.Prop, Operand> upsertSetValues) {
109-
List<Tuple2<EntityPropertyType<?, ?>, UpsertSetValue>> list = new ArrayList<>();
90+
private List<QueryOperandPair> prepareSetValues(Map<Operand.Prop, Operand> upsertSetValues) {
91+
List<QueryOperandPair> list = new ArrayList<>(upsertSetValues.size());
11092
for (Map.Entry<Operand.Prop, Operand> upsertSetValue : upsertSetValues.entrySet()) {
11193
Operand.Prop prop = upsertSetValue.getKey();
11294
Operand operand = upsertSetValue.getValue();
113-
UpsertSetValue jdbcQueryUpsertSetValue = operand.accept(new OperandVisitor());
114-
list.add(new Tuple2<>(prop.value.asType(), jdbcQueryUpsertSetValue));
95+
QueryOperand left = new QueryOperand.Prop(prop.getPropertyMetamodel().asType());
96+
QueryOperand right = operand.accept(new OperandVisitor());
97+
QueryOperandPair pair = new QueryOperandPair(left, right);
98+
list.add(pair);
11599
}
116100
return list;
117101
}
118102

119-
private static List<EntityPropertyType<?, ?>> toEntityPropertyTypes(
120-
List<PropertyMetamodel<?>> propertyMetamodels) {
121-
return propertyMetamodels.stream().map(PropertyMetamodel::asType).collect(toList());
122-
}
123-
124103
private PreparedSqlBuilder assembleQuery(
125104
InsertSettings settings,
126105
InsertContext context,
127106
List<EntityPropertyType<?, ?>> keys,
128-
List<Tuple2<EntityPropertyType<?, ?>, InParameter<?>>> insertValues,
129-
List<Tuple2<EntityPropertyType<?, ?>, UpsertSetValue>> setValues) {
107+
List<QueryOperandPair> insertValues,
108+
List<QueryOperandPair> setValues) {
130109
PreparedSqlBuilder sql =
131110
new PreparedSqlBuilder(config, SqlKind.INSERT, settings.getSqlLogType());
132111
UpsertAssemblerContext upsertAssemblerContext =
133-
new UpsertAssemblerContext(
112+
UpsertAssemblerContextBuilder.build(
134113
sql,
135114
context.entityMetamodel.asType(),
136115
context.onDuplicateContext.duplicateKeyType,
@@ -144,16 +123,17 @@ private PreparedSqlBuilder assembleQuery(
144123
return sql;
145124
}
146125

147-
/** A visitor for converting {@link Operand} to {@link UpsertSetValue}. */
148-
private class OperandVisitor implements Operand.Visitor<UpsertSetValue> {
126+
/** A visitor for converting {@link Operand} to {@link QueryOperand}. */
127+
private class OperandVisitor implements Operand.Visitor<QueryOperand> {
149128
@Override
150-
public UpsertSetValue visit(Operand.Param param) {
151-
return new UpsertSetValue.Param(param.createInParameter(config));
129+
public QueryOperand visit(Operand.Param param) {
130+
return new QueryOperand.Param(
131+
param.getPropertyMetamodel().asType(), param.createInParameter(config));
152132
}
153133

154134
@Override
155-
public UpsertSetValue visit(Operand.Prop prop) {
156-
return new UpsertSetValue.Prop(prop.value.asType());
135+
public QueryOperand visit(Operand.Prop prop) {
136+
return new QueryOperand.Prop(prop.value.asType());
157137
}
158138
}
159139
}

doma-core/src/main/java/org/seasar/doma/jdbc/dialect/H2UpsertAssembler.java

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,32 @@
22

33
import java.util.List;
44
import org.seasar.doma.internal.jdbc.sql.PreparedSqlBuilder;
5-
import org.seasar.doma.jdbc.InParameter;
6-
import org.seasar.doma.jdbc.criteria.tuple.Tuple2;
75
import org.seasar.doma.jdbc.entity.EntityPropertyType;
86
import org.seasar.doma.jdbc.entity.EntityType;
97
import org.seasar.doma.jdbc.query.DuplicateKeyType;
8+
import org.seasar.doma.jdbc.query.QueryOperand;
9+
import org.seasar.doma.jdbc.query.QueryOperandPair;
1010
import org.seasar.doma.jdbc.query.UpsertAssembler;
1111
import org.seasar.doma.jdbc.query.UpsertAssemblerContext;
1212
import org.seasar.doma.jdbc.query.UpsertAssemblerSupport;
13-
import org.seasar.doma.jdbc.query.UpsertSetValue;
1413

1514
public class H2UpsertAssembler implements UpsertAssembler {
15+
1616
private final PreparedSqlBuilder buf;
17+
1718
private final EntityType<?> entityType;
19+
1820
private final DuplicateKeyType duplicateKeyType;
21+
1922
private final UpsertAssemblerSupport upsertAssemblerSupport;
20-
private final List<EntityPropertyType<?, ?>> keys;
21-
private final List<Tuple2<EntityPropertyType<?, ?>, InParameter<?>>> insertValues;
22-
private final List<Tuple2<EntityPropertyType<?, ?>, UpsertSetValue>> setValues;
23-
private final UpsertSetValue.Visitor upsertSetValueVisitor = new UpsertSetValueVisitor();
23+
24+
private final List<? extends EntityPropertyType<?, ?>> keys;
25+
26+
private final List<QueryOperandPair> insertValues;
27+
28+
private final List<QueryOperandPair> setValues;
29+
30+
private final QueryOperand.Visitor queryOperandVisitor = new QueryOperandVisitor();
2431

2532
public H2UpsertAssembler(UpsertAssemblerContext context) {
2633
this.buf = context.buf;
@@ -49,24 +56,24 @@ public void assemble() {
4956
}
5057
buf.cutBackSql(5);
5158
buf.appendSql(" when not matched then insert (");
52-
for (Tuple2<EntityPropertyType<?, ?>, InParameter<?>> insertValue : insertValues) {
53-
column(insertValue.component1());
59+
for (QueryOperandPair pair : insertValues) {
60+
column(pair.getLeft().getEntityPropertyType());
5461
buf.appendSql(", ");
5562
}
5663
buf.cutBackSql(2);
5764
buf.appendSql(") values (");
58-
for (Tuple2<EntityPropertyType<?, ?>, InParameter<?>> insertValue : insertValues) {
59-
excludeColumn(insertValue.component1());
65+
for (QueryOperandPair pair : insertValues) {
66+
excludeColumn(pair.getLeft().getEntityPropertyType());
6067
buf.appendSql(", ");
6168
}
6269
buf.cutBackSql(2);
6370
buf.appendSql(")");
6471
if (duplicateKeyType == DuplicateKeyType.UPDATE) {
6572
buf.appendSql(" when matched then update set ");
66-
for (Tuple2<EntityPropertyType<?, ?>, UpsertSetValue> setValue : setValues) {
67-
targetColumn(setValue.component1());
73+
for (QueryOperandPair pair : setValues) {
74+
targetColumn(pair.getLeft().getEntityPropertyType());
6875
buf.appendSql(" = ");
69-
setValue.component2().accept(upsertSetValueVisitor);
76+
pair.getRight().accept(queryOperandVisitor);
7077
buf.appendSql(", ");
7178
}
7279
buf.cutBackSql(2);
@@ -75,20 +82,20 @@ public void assemble() {
7582

7683
private void excludeQuery() {
7784
buf.appendSql("select ");
78-
for (Tuple2<EntityPropertyType<?, ?>, InParameter<?>> insertValue : insertValues) {
79-
column(insertValue.component1());
85+
for (QueryOperandPair pair : insertValues) {
86+
column(pair.getLeft().getEntityPropertyType());
8087
buf.appendSql(", ");
8188
}
8289
buf.cutBackSql(2);
8390
buf.appendSql(" from values (");
84-
for (Tuple2<EntityPropertyType<?, ?>, InParameter<?>> insertValue : insertValues) {
85-
buf.appendParameter(insertValue.component2());
91+
for (QueryOperandPair pair : insertValues) {
92+
pair.getRight().accept(queryOperandVisitor);
8693
buf.appendSql(", ");
8794
}
8895
buf.cutBackSql(2);
8996
buf.appendSql(") as x (");
90-
for (Tuple2<EntityPropertyType<?, ?>, InParameter<?>> insertValue : insertValues) {
91-
column(insertValue.component1());
97+
for (QueryOperandPair pair : insertValues) {
98+
column(pair.getLeft().getEntityPropertyType());
9299
buf.appendSql(", ");
93100
}
94101
buf.cutBackSql(2);
@@ -128,14 +135,15 @@ private void column(EntityPropertyType<?, ?> propertyType) {
128135
buf.appendSql(sql);
129136
}
130137

131-
class UpsertSetValueVisitor implements UpsertSetValue.Visitor {
138+
class QueryOperandVisitor implements QueryOperand.Visitor {
139+
132140
@Override
133-
public void visit(UpsertSetValue.Param param) {
141+
public void visit(QueryOperand.Param param) {
134142
buf.appendParameter(param.inParameter);
135143
}
136144

137145
@Override
138-
public void visit(UpsertSetValue.Prop prop) {
146+
public void visit(QueryOperand.Prop prop) {
139147
String sql =
140148
upsertAssemblerSupport.excludeProp(
141149
prop.propertyType, UpsertAssemblerSupport.ColumnNameType.NAME_ALIAS);

0 commit comments

Comments
 (0)