[#7839] Emulate { UPDATE | DELETE } ORDER BY and LIMIT

This commit is contained in:
Lukas Eder 2018-09-21 14:49:12 +02:00
parent 5c14d8026d
commit 6164cedbd1
8 changed files with 138 additions and 81 deletions

View File

@ -37,10 +37,6 @@
*/
package org.jooq;
// ...
import static org.jooq.SQLDialect.MARIADB;
import static org.jooq.SQLDialect.MYSQL;
/**
* This type is used for the {@link Delete}'s DSL API.
* <p>
@ -75,14 +71,14 @@ import static org.jooq.SQLDialect.MYSQL;
public interface DeleteLimitStep<R extends Record> extends DeleteReturningStep<R> {
/**
* Add a <code>LIMIT</code> clause to the query
* Add a <code>LIMIT</code> clause to the query.
*/
@Support({ MARIADB, MYSQL })
@Support
DeleteReturningStep<R> limit(Number numberOfRows);
/**
* Add a <code>LIMIT</code> clause to the query using named parameters
* Add a <code>LIMIT</code> clause to the query using named parameters.
*/
@Support({ MARIADB, MYSQL })
@Support
DeleteReturningStep<R> limit(Param<? extends Number> numberOfRows);
}

View File

@ -37,10 +37,6 @@
*/
package org.jooq;
// ...
import static org.jooq.SQLDialect.MARIADB;
import static org.jooq.SQLDialect.MYSQL;
import java.util.Collection;
/**
@ -77,19 +73,19 @@ import java.util.Collection;
public interface DeleteOrderByStep<R extends Record> extends DeleteLimitStep<R> {
/**
* Add an <code>ORDER BY</code> clause to the query
* Add an <code>ORDER BY</code> clause to the query.
*/
@Support({ MARIADB, MYSQL })
@Support
DeleteLimitStep<R> orderBy(OrderField<?>... fields);
/**
* Add an <code>ORDER BY</code> clause to the query
* Add an <code>ORDER BY</code> clause to the query.
*/
@Support({ MARIADB, MYSQL })
@Support
DeleteLimitStep<R> orderBy(Collection<? extends OrderField<?>> fields);
/**
* Add an <code>ORDER BY</code> clause to the query
* Add an <code>ORDER BY</code> clause to the query.
* <p>
* Indexes start at <code>1</code> in SQL!
* <p>
@ -97,6 +93,6 @@ public interface DeleteOrderByStep<R extends Record> extends DeleteLimitStep<R>
* <code>orderBy(DSL.literal(1).desc())</code> to apply descending
* ordering
*/
@Support({ MARIADB, MYSQL })
@Support
DeleteLimitStep<R> orderBy(int... fieldIndexes);
}

View File

@ -38,12 +38,9 @@
package org.jooq;
// ...
// ...
// ...
import static org.jooq.SQLDialect.FIREBIRD;
import static org.jooq.SQLDialect.MARIADB;
import static org.jooq.SQLDialect.MYSQL;
// ...
import static org.jooq.SQLDialect.POSTGRES;
@ -109,7 +106,7 @@ public interface DeleteQuery<R extends Record> extends ConditionProvider, Delete
*
* @param fields The ordering fields
*/
@Support({ MARIADB, MYSQL })
@Support
void addOrderBy(OrderField<?>... fields);
/**
@ -117,7 +114,7 @@ public interface DeleteQuery<R extends Record> extends ConditionProvider, Delete
*
* @param fields The ordering fields
*/
@Support({ MARIADB, MYSQL })
@Support
void addOrderBy(Collection<? extends OrderField<?>> fields);
/**
@ -125,7 +122,7 @@ public interface DeleteQuery<R extends Record> extends ConditionProvider, Delete
*
* @param numberOfRows The number of rows to return
*/
@Support({ MARIADB, MYSQL })
@Support
void addLimit(Number numberOfRows);
/**
@ -133,7 +130,7 @@ public interface DeleteQuery<R extends Record> extends ConditionProvider, Delete
*
* @param numberOfRows The number of rows to return
*/
@Support({ MARIADB, MYSQL })
@Support
void addLimit(Param<? extends Number> numberOfRows);
// ------------------------------------------------------------------------

View File

@ -37,10 +37,6 @@
*/
package org.jooq;
// ...
import static org.jooq.SQLDialect.MARIADB;
import static org.jooq.SQLDialect.MYSQL;
/**
* This type is used for the {@link Update}'s DSL API.
* <p>
@ -77,15 +73,15 @@ import static org.jooq.SQLDialect.MYSQL;
public interface UpdateLimitStep<R extends Record> extends UpdateReturningStep<R> {
/**
* Add a <code>LIMIT</code> clause to the query
* Add a <code>LIMIT</code> clause to the query.
*/
@Support({ MARIADB, MYSQL })
@Support
UpdateReturningStep<R> limit(Number numberOfRows);
/**
* Add a <code>LIMIT</code> clause to the query using named parameters
* Add a <code>LIMIT</code> clause to the query using named parameters.
*/
@Support({ MARIADB, MYSQL })
@Support
UpdateReturningStep<R> limit(Param<? extends Number> numberOfRows);

View File

@ -37,10 +37,6 @@
*/
package org.jooq;
// ...
import static org.jooq.SQLDialect.MARIADB;
import static org.jooq.SQLDialect.MYSQL;
import java.util.Collection;
/**
@ -79,19 +75,19 @@ import java.util.Collection;
public interface UpdateOrderByStep<R extends Record> extends UpdateLimitStep<R> {
/**
* Add an <code>ORDER BY</code> clause to the query
* Add an <code>ORDER BY</code> clause to the query.
*/
@Support({ MARIADB, MYSQL })
@Support
UpdateLimitStep<R> orderBy(OrderField<?>... fields);
/**
* Add an <code>ORDER BY</code> clause to the query
* Add an <code>ORDER BY</code> clause to the query.
*/
@Support({ MARIADB, MYSQL })
@Support
UpdateLimitStep<R> orderBy(Collection<? extends OrderField<?>> fields);
/**
* Add an <code>ORDER BY</code> clause to the query
* Add an <code>ORDER BY</code> clause to the query.
* <p>
* Indexes start at <code>1</code> in SQL!
* <p>
@ -99,7 +95,7 @@ public interface UpdateOrderByStep<R extends Record> extends UpdateLimitStep<R>
* <code>orderBy(DSL.literal(1).desc())</code> to apply descending
* ordering
*/
@Support({ MARIADB, MYSQL })
@Support
UpdateLimitStep<R> orderBy(int... fieldIndexes);
}

View File

@ -38,7 +38,6 @@
package org.jooq;
// ...
// ...
// ...
import static org.jooq.SQLDialect.FIREBIRD;
@ -46,8 +45,6 @@ import static org.jooq.SQLDialect.H2;
// ...
import static org.jooq.SQLDialect.HSQLDB;
// ...
import static org.jooq.SQLDialect.MARIADB;
import static org.jooq.SQLDialect.MYSQL;
// ...
import static org.jooq.SQLDialect.POSTGRES;
// ...
@ -419,7 +416,7 @@ public interface UpdateQuery<R extends Record> extends StoreQuery<R>, ConditionP
*
* @param fields The ordering fields
*/
@Support({ MARIADB, MYSQL })
@Support
void addOrderBy(OrderField<?>... fields);
/**
@ -427,7 +424,7 @@ public interface UpdateQuery<R extends Record> extends StoreQuery<R>, ConditionP
*
* @param fields The ordering fields
*/
@Support({ MARIADB, MYSQL })
@Support
void addOrderBy(Collection<? extends OrderField<?>> fields);
/**
@ -435,7 +432,7 @@ public interface UpdateQuery<R extends Record> extends StoreQuery<R>, ConditionP
*
* @param numberOfRows The number of rows to return
*/
@Support({ MARIADB, MYSQL })
@Support
void addLimit(Number numberOfRows);
/**
@ -443,7 +440,7 @@ public interface UpdateQuery<R extends Record> extends StoreQuery<R>, ConditionP
*
* @param numberOfRows The number of rows to return
*/
@Support({ MARIADB, MYSQL })
@Support
void addLimit(Param<? extends Number> numberOfRows);
// ------------------------------------------------------------------------

View File

@ -43,9 +43,32 @@ import static org.jooq.Clause.DELETE_DELETE;
import static org.jooq.Clause.DELETE_RETURNING;
import static org.jooq.Clause.DELETE_WHERE;
// ...
// ...
// ...
// ...
import static org.jooq.SQLDialect.CUBRID;
// ...
import static org.jooq.SQLDialect.DERBY;
import static org.jooq.SQLDialect.FIREBIRD;
import static org.jooq.SQLDialect.H2;
// ...
import static org.jooq.SQLDialect.HSQLDB;
// ...
// ...
import static org.jooq.SQLDialect.MARIADB;
import static org.jooq.SQLDialect.MYSQL;
// ...
import static org.jooq.SQLDialect.POSTGRES;
// ...
// ...
import static org.jooq.SQLDialect.SQLITE;
// ...
// ...
// ...
// ...
import static org.jooq.conf.SettingsTools.getExecuteDeleteWithoutWhere;
import static org.jooq.impl.DSL.row;
import static org.jooq.impl.DSL.select;
import static org.jooq.impl.Keywords.K_DELETE;
import static org.jooq.impl.Keywords.K_FROM;
import static org.jooq.impl.Keywords.K_LIMIT;
@ -67,6 +90,8 @@ import org.jooq.Param;
import org.jooq.Record;
import org.jooq.SQLDialect;
import org.jooq.Table;
import org.jooq.TableField;
import org.jooq.UniqueKey;
/**
* @author Lukas Eder
@ -76,10 +101,11 @@ final class DeleteQueryImpl<R extends Record> extends AbstractDMLQuery<R> implem
private static final long serialVersionUID = -1943687511774150929L;
private static final Clause[] CLAUSES = { DELETE };
private static final EnumSet<SQLDialect> SPECIAL_DELETE_AS_SYNTAX = EnumSet.of(MARIADB, MYSQL);
private static final EnumSet<SQLDialect> NO_SUPPORT_LIMIT = EnumSet.of(CUBRID, DERBY, FIREBIRD, H2, HSQLDB, POSTGRES, SQLITE);
private final ConditionProviderImpl condition;
private final SortFieldList orderBy;
private Param<?> limit;
private Param<? extends Number> limit;
DeleteQueryImpl(Configuration configuration, WithImpl with, Table<R> table) {
super(configuration, with, table);
@ -167,25 +193,45 @@ final class DeleteQueryImpl<R extends Record> extends AbstractDMLQuery<R> implem
.declareTables(true)
.visit(table)
.declareTables(declare)
.end(DELETE_DELETE)
.start(DELETE_WHERE);
.end(DELETE_DELETE);
if (hasWhere())
ctx.formatSeparator()
.visit(K_WHERE).sql(' ')
.visit(getWhere());
if (limit != null && NO_SUPPORT_LIMIT.contains(ctx.family()) && !table.getKeys().isEmpty()) {
UniqueKey<?> key = table.getPrimaryKey() != null ? table.getPrimaryKey() : table.getKeys().get(0);
ctx.end(DELETE_WHERE);
@SuppressWarnings("unchecked")
TableField<?, Object>[] keyFields = (TableField<?, Object>[]) key.getFieldsArray();
if (!orderBy.isEmpty())
ctx.formatSeparator()
.visit(K_ORDER_BY).sql(' ')
.visit(orderBy);
ctx.start(DELETE_WHERE)
.formatSeparator()
.visit(K_WHERE).sql(' ');
if (limit != null)
ctx.formatSeparator()
.visit(K_LIMIT).sql(' ')
.visit(limit);
if (keyFields.length == 1)
ctx.visit(keyFields[0].in(select(keyFields[0]).from(table).where(getWhere()).orderBy(orderBy).limit(limit)));
else
ctx.visit(row(keyFields).in(select(keyFields).from(table).where(getWhere()).orderBy(orderBy).limit(limit)));
ctx.end(DELETE_WHERE);
}
else {
ctx.start(DELETE_WHERE);
if (hasWhere())
ctx.formatSeparator()
.visit(K_WHERE).sql(' ')
.visit(getWhere());
ctx.end(DELETE_WHERE);
if (!orderBy.isEmpty())
ctx.formatSeparator()
.visit(K_ORDER_BY).sql(' ')
.visit(orderBy);
if (limit != null)
ctx.formatSeparator()
.visit(K_LIMIT).sql(' ')
.visit(limit);
}
ctx.start(DELETE_RETURNING);
toSQLReturning(ctx);

View File

@ -47,17 +47,28 @@ import static org.jooq.Clause.UPDATE_UPDATE;
import static org.jooq.Clause.UPDATE_WHERE;
// ...
// ...
// ...
import static org.jooq.SQLDialect.CUBRID;
// ...
import static org.jooq.SQLDialect.DERBY;
import static org.jooq.SQLDialect.FIREBIRD;
import static org.jooq.SQLDialect.H2;
// ...
import static org.jooq.SQLDialect.HSQLDB;
// ...
// ...
// ...
import static org.jooq.SQLDialect.POSTGRES;
import static org.jooq.SQLDialect.POSTGRES_10;
// ...
// ...
import static org.jooq.SQLDialect.SQLITE;
// ...
// ...
// ...
// ...
import static org.jooq.conf.SettingsTools.getExecuteUpdateWithoutWhere;
import static org.jooq.impl.DSL.row;
import static org.jooq.impl.DSL.select;
import static org.jooq.impl.Keywords.K_FROM;
import static org.jooq.impl.Keywords.K_LIMIT;
@ -130,7 +141,9 @@ import org.jooq.RowN;
import org.jooq.SQLDialect;
import org.jooq.Select;
import org.jooq.Table;
import org.jooq.TableField;
import org.jooq.TableLike;
import org.jooq.UniqueKey;
import org.jooq.UpdateQuery;
/**
@ -144,6 +157,7 @@ final class UpdateQueryImpl<R extends Record> extends AbstractStoreQuery<R> impl
private static final EnumSet<SQLDialect> SUPPORT_RVE_SET = EnumSet.of(H2, HSQLDB, POSTGRES);
private static final EnumSet<SQLDialect> NO_SUPPORT_LIMIT = EnumSet.of(CUBRID, DERBY, FIREBIRD, H2, HSQLDB, POSTGRES, SQLITE);
private final FieldMapForUpdate updateMap;
private final TableList from;
@ -152,7 +166,7 @@ final class UpdateQueryImpl<R extends Record> extends AbstractStoreQuery<R> impl
private Row multiValue;
private Select<?> multiSelect;
private final SortFieldList orderBy;
private Param<?> limit;
private Param<? extends Number> limit;
UpdateQueryImpl(Configuration configuration, WithImpl with, Table<R> table) {
super(configuration, with, table);
@ -629,24 +643,43 @@ final class UpdateQueryImpl<R extends Record> extends AbstractStoreQuery<R> impl
break;
}
ctx.start(UPDATE_WHERE);
if (limit != null && NO_SUPPORT_LIMIT.contains(ctx.family()) && !table.getKeys().isEmpty()) {
UniqueKey<?> key = table.getPrimaryKey() != null ? table.getPrimaryKey() : table.getKeys().get(0);
if (hasWhere())
ctx.formatSeparator()
.visit(K_WHERE).sql(' ')
.visit(getWhere());
@SuppressWarnings("unchecked")
TableField<?, Object>[] keyFields = (TableField<?, Object>[]) key.getFieldsArray();
ctx.end(UPDATE_WHERE);
ctx.start(UPDATE_WHERE)
.formatSeparator()
.visit(K_WHERE).sql(' ');
if (!orderBy.isEmpty())
ctx.formatSeparator()
.visit(K_ORDER_BY).sql(' ')
.visit(orderBy);
if (keyFields.length == 1)
ctx.visit(keyFields[0].in(select(keyFields[0]).from(table).where(getWhere()).orderBy(orderBy).limit(limit)));
else
ctx.visit(row(keyFields).in(select(keyFields).from(table).where(getWhere()).orderBy(orderBy).limit(limit)));
if (limit != null)
ctx.formatSeparator()
.visit(K_LIMIT).sql(' ')
.visit(limit);
ctx.end(UPDATE_WHERE);
}
else {
ctx.start(UPDATE_WHERE);
if (hasWhere())
ctx.formatSeparator()
.visit(K_WHERE).sql(' ')
.visit(getWhere());
ctx.end(UPDATE_WHERE);
if (!orderBy.isEmpty())
ctx.formatSeparator()
.visit(K_ORDER_BY).sql(' ')
.visit(orderBy);
if (limit != null)
ctx.formatSeparator()
.visit(K_LIMIT).sql(' ')
.visit(limit);
}
ctx.start(UPDATE_RETURNING);
toSQLReturning(ctx);