[jOOQ/jOOQ#9879] Support client side computed embeddables in UPSERT
This commit is contained in:
parent
b17ec92d98
commit
2f064052e8
@ -136,6 +136,7 @@ import org.jooq.Delete;
|
||||
import org.jooq.ExecuteContext;
|
||||
import org.jooq.ExecuteListener;
|
||||
import org.jooq.Field;
|
||||
import org.jooq.GeneratorStatementType;
|
||||
import org.jooq.Identity;
|
||||
import org.jooq.Insert;
|
||||
import org.jooq.Name;
|
||||
|
||||
@ -192,7 +192,7 @@ final class FieldMapsForInsert extends AbstractQueryPart implements UNotYetImple
|
||||
|
||||
|
||||
case FIREBIRD: {
|
||||
toSQLInsertSelect(ctx, insertSelect(ctx));
|
||||
toSQLInsertSelect(ctx, insertSelect(ctx, GeneratorStatementType.INSERT));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -313,10 +313,10 @@ final class FieldMapsForInsert extends AbstractQueryPart implements UNotYetImple
|
||||
|
||||
|
||||
|
||||
final Select<Record> insertSelect(Context<?> ctx) {
|
||||
final Select<Record> insertSelect(Context<?> ctx, GeneratorStatementType statementType) {
|
||||
Select<Record> select = null;
|
||||
|
||||
Map<Field<?>, List<Field<?>>> v = valuesFlattened(ctx);
|
||||
Map<Field<?>, List<Field<?>>> v = valuesFlattened(ctx, statementType);
|
||||
for (int i = 0; i < rows; i++) {
|
||||
int row = i;
|
||||
Select<Record> iteration = DSL.select(Tools.map(v.values(), l -> l.get(row)));
|
||||
@ -357,7 +357,7 @@ final class FieldMapsForInsert extends AbstractQueryPart implements UNotYetImple
|
||||
String separator = "";
|
||||
int i = 0;
|
||||
|
||||
for (List<Field<?>> list : valuesFlattened(ctx).values()) {
|
||||
for (List<Field<?>> list : valuesFlattened(ctx, GeneratorStatementType.INSERT).values()) {
|
||||
ctx.sql(separator);
|
||||
|
||||
if (indent)
|
||||
@ -597,7 +597,7 @@ final class FieldMapsForInsert extends AbstractQueryPart implements UNotYetImple
|
||||
}
|
||||
|
||||
// [#989] Avoid qualifying fields in INSERT field declaration
|
||||
Set<Field<?>> fields = keysFlattened(ctx);
|
||||
Set<Field<?>> fields = keysFlattened(ctx, GeneratorStatementType.INSERT);
|
||||
|
||||
|
||||
|
||||
@ -619,27 +619,36 @@ final class FieldMapsForInsert extends AbstractQueryPart implements UNotYetImple
|
||||
return it;
|
||||
}
|
||||
|
||||
final Set<Field<?>> keysFlattened(Context<?> ctx) {
|
||||
final Set<Field<?>> keysFlattened(Context<?> ctx, GeneratorStatementType statementType) {
|
||||
|
||||
// [#9864] TODO: Refactor and optimise these flattening algorithms
|
||||
return valuesFlattened(ctx).keySet();
|
||||
return valuesFlattened(ctx, statementType).keySet();
|
||||
}
|
||||
|
||||
final Map<Field<?>, List<Field<?>>> valuesFlattened(Context<?> ctx) {
|
||||
final Map<Field<?>, List<Field<?>>> valuesFlattened(Context<?> ctx, GeneratorStatementType statementType) {
|
||||
Map<Field<?>, List<Field<?>>> result = new LinkedHashMap<>();
|
||||
|
||||
// [#2530] [#6124] [#10481] TODO: Shortcut for performance, when there are no embeddables
|
||||
Set<Field<?>> overlapping = null;
|
||||
for (Entry<Field<?>, List<Field<?>>> entry : removeReadonly(ctx, values.entrySet(), Entry::getKey)) {
|
||||
Field<?> key = entry.getKey();
|
||||
DataType<?> keyType = key.getDataType();
|
||||
List<Field<?>> value = entry.getValue();
|
||||
|
||||
// [#2530] [#6124] [#10481] TODO: Refactor and optimise these flattening algorithms
|
||||
if (entry.getKey().getDataType().isEmbeddable()) {
|
||||
List<Iterator<? extends Field<?>>> value = new ArrayList<>(entry.getValue().size());
|
||||
if (keyType.isEmbeddable()) {
|
||||
List<Iterator<? extends Field<?>>> valueFlattened = new ArrayList<>(value.size());
|
||||
|
||||
for (Field<?> v : value)
|
||||
valueFlattened.add(flatten(v).iterator());
|
||||
|
||||
for (Field<?> k : flatten(key)) {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
for (Field<?> f : entry.getValue())
|
||||
value.add(flatten(f).iterator());
|
||||
|
||||
for (Field<?> key : flatten(entry.getKey())) {
|
||||
|
||||
|
||||
|
||||
@ -650,17 +659,23 @@ final class FieldMapsForInsert extends AbstractQueryPart implements UNotYetImple
|
||||
|
||||
|
||||
{
|
||||
List<Field<?>> list = new ArrayList<>(entry.getValue().size());
|
||||
List<Field<?>> list = new ArrayList<>(value.size());
|
||||
|
||||
for (Iterator<? extends Field<?>> v : value)
|
||||
for (Iterator<? extends Field<?>> v : valueFlattened)
|
||||
list.add(v.hasNext() ? v.next() : null);
|
||||
|
||||
result.put(key, list);
|
||||
result.put(k, list);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
else
|
||||
result.put(entry.getKey(), entry.getValue());
|
||||
result.put(key, value);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@ -629,11 +629,12 @@ implements
|
||||
|
||||
|
||||
if (select != null) {
|
||||
Set<Field<?>> keysFlattened = insertMaps.keysFlattened(ctx, GeneratorStatementType.INSERT);
|
||||
|
||||
// [#2995] Prevent the generation of wrapping parentheses around the
|
||||
// INSERT .. SELECT statement's SELECT because they would be
|
||||
// interpreted as the (missing) INSERT column list's parens.
|
||||
if (insertMaps.keysFlattened(ctx).size() == 0)
|
||||
if (keysFlattened.size() == 0)
|
||||
ctx.data(DATA_INSERT_SELECT_WITHOUT_INSERT_COLUMN_LIST, true);
|
||||
|
||||
|
||||
@ -662,7 +663,6 @@ implements
|
||||
|
||||
|
||||
|
||||
|
||||
// [#8353] TODO: Support overlapping embeddables
|
||||
toSQLInsertSelect(ctx, s);
|
||||
|
||||
@ -768,7 +768,7 @@ implements
|
||||
|
||||
if (!keys.isEmpty()) {
|
||||
Select<Record> rows = null;
|
||||
Set<Field<?>> fields = insertMaps.keysFlattened(ctx);
|
||||
Set<Field<?>> fields = insertMaps.keysFlattened(ctx, GeneratorStatementType.INSERT);
|
||||
|
||||
// [#10989] INSERT .. SELECT .. ON DUPLICATE KEY IGNORE
|
||||
if (select != null) {
|
||||
@ -822,7 +822,7 @@ implements
|
||||
|| !table().getKeys().isEmpty()) {
|
||||
|
||||
Table<?> t = null;
|
||||
Set<Field<?>> k = insertMaps.keysFlattened(ctx);
|
||||
Set<Field<?>> k = insertMaps.keysFlattened(ctx, null);
|
||||
Collection<Field<?>> f = null;
|
||||
|
||||
if (!NO_SUPPORT_SUBQUERY_IN_MERGE_USING.contains(ctx.dialect())) {
|
||||
@ -832,7 +832,7 @@ implements
|
||||
// [#11770] [#11880] Single row inserts also do, in some dialects
|
||||
Select<?> s = select != null
|
||||
? select
|
||||
: insertMaps.insertSelect(ctx);
|
||||
: insertMaps.insertSelect(ctx, null);
|
||||
|
||||
// [#8937] With DEFAULT VALUES, there is no SELECT. Create one from
|
||||
// known DEFAULT expressions, or use NULL.
|
||||
|
||||
@ -6069,16 +6069,17 @@ final class Tools {
|
||||
return filter(asList(array), predicate);
|
||||
}
|
||||
|
||||
static final List<Field<?>> flattenFieldOrRow(FieldOrRow fr) {
|
||||
static final Iterable<Field<?>> flattenFieldOrRow(FieldOrRow fr) {
|
||||
if (fr instanceof Field)
|
||||
return singletonList((Field<?>) fr);
|
||||
return flatten((Field<?>) fr);
|
||||
else
|
||||
return asList(((Row) fr).fields());
|
||||
}
|
||||
|
||||
static final <C extends Collection<Field<?>>> C flattenFieldOrRows(Collection<? extends FieldOrRow> frs, C c) {
|
||||
for (FieldOrRow fr : frs)
|
||||
c.addAll(flattenFieldOrRow(fr));
|
||||
for (Field<?> f : flattenFieldOrRow(fr))
|
||||
c.add(f);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user