[jOOQ/jOOQ#4245] Add support for PostgreSQL's DELETE .. USING syntax

This commit is contained in:
Lukas Eder 2020-02-07 14:20:27 +01:00
parent fb2c0cc910
commit 5bf3d9f57f
9 changed files with 118 additions and 22 deletions

View File

@ -7998,7 +7998,7 @@ public interface DSLContext extends Scope , AutoCloseable {
* Some but not all databases support aliased tables in delete statements.
*/
@Support
<R extends Record> DeleteWhereStep<R> deleteFrom(Table<R> table);
<R extends Record> DeleteUsingStep<R> deleteFrom(Table<R> table);
/**
* Create a new DSL delete statement.
@ -8006,7 +8006,7 @@ public interface DSLContext extends Scope , AutoCloseable {
* This is an alias for {@link #deleteFrom(Table)}
*/
@Support
<R extends Record> DeleteWhereStep<R> delete(Table<R> table);
<R extends Record> DeleteUsingStep<R> delete(Table<R> table);
// -------------------------------------------------------------------------
// XXX Batch query execution

View File

@ -62,6 +62,24 @@ import java.util.Collection;
@SuppressWarnings("deprecation")
public interface DeleteQuery<R extends Record> extends ConditionProvider, Delete<R> {
/**
* Add tables to the <code>USING</code> clause.
*/
@Support({ POSTGRES })
void addUsing(TableLike<?> table);
/**
* Add tables to the <code>USING</code> clause.
*/
@Support({ POSTGRES })
void addUsing(TableLike<?>... tables);
/**
* Add tables to the <code>USING</code> clause.
*/
@Support({ POSTGRES })
void addUsing(Collection<? extends TableLike<?>> tables);
// ------------------------------------------------------------------------
// Methods from ConditionProvider, OrderProvider, LockProvider
// ------------------------------------------------------------------------

View File

@ -3179,5 +3179,5 @@ public interface WithStep extends QueryPart {
* Some but not all databases support aliased tables in delete statements.
*/
@Support({ POSTGRES, SQLITE })
<R extends Record> DeleteWhereStep<R> delete(Table<R> table);
<R extends Record> DeleteUsingStep<R> delete(Table<R> table);
}

View File

@ -49,7 +49,9 @@ import org.jooq.TableRecord;
* <p>
* Client code may provide proper {@link TableRecord} implementations extending
* this useful base class. All necessary parts of the {@link TableRecord}
* interface are already implemented. No methods need further implementation.
* interface are already implemented. No methods need further implementation,
* but implementations have to provide a no-arg constructor that can be called
* reflectively.
* <p>
* Use this base class when providing custom tables to any of the following
* methods:

View File

@ -188,7 +188,7 @@ import org.jooq.DataType;
import org.jooq.DatePart;
// ...
import org.jooq.Delete;
import org.jooq.DeleteWhereStep;
import org.jooq.DeleteUsingStep;
import org.jooq.DerivedColumnList;
import org.jooq.DropIndexOnStep;
import org.jooq.DropSchemaStep;
@ -5775,7 +5775,7 @@ public class DSL {
* @see DSLContext#deleteFrom(Table)
*/
@Support
public static <R extends Record> DeleteWhereStep<R> deleteFrom(Table<R> table) {
public static <R extends Record> DeleteUsingStep<R> deleteFrom(Table<R> table) {
return dsl().deleteFrom(table);
}
@ -5785,7 +5785,7 @@ public class DSL {
* This is an alias for {@link #deleteFrom(Table)}
*/
@Support
public static <R extends Record> DeleteWhereStep<R> delete(Table<R> table) {
public static <R extends Record> DeleteUsingStep<R> delete(Table<R> table) {
return dsl().deleteFrom(table);
}

View File

@ -127,7 +127,7 @@ import org.jooq.DDLFlag;
import org.jooq.DSLContext;
import org.jooq.DataType;
import org.jooq.DeleteQuery;
import org.jooq.DeleteWhereStep;
import org.jooq.DeleteUsingStep;
import org.jooq.DropIndexOnStep;
import org.jooq.DropSchemaStep;
import org.jooq.DropSequenceFinalStep;
@ -2686,12 +2686,12 @@ public class DefaultDSLContext extends AbstractScope implements DSLContext, Seri
}
@Override
public <R extends Record> DeleteWhereStep<R> delete(Table<R> table) {
public <R extends Record> DeleteUsingStep<R> delete(Table<R> table) {
return deleteFrom(table);
}
@Override
public <R extends Record> DeleteWhereStep<R> deleteFrom(Table<R> table) {
public <R extends Record> DeleteUsingStep<R> deleteFrom(Table<R> table) {
return new DeleteImpl<>(configuration(), null, table);
}

View File

@ -40,6 +40,7 @@ package org.jooq.impl;
import static org.jooq.impl.DSL.condition;
import static org.jooq.impl.DSL.exists;
import static org.jooq.impl.DSL.notExists;
import static org.jooq.impl.DSL.table;
import static org.jooq.impl.Tools.filterOne;
import java.util.Collection;
@ -49,8 +50,9 @@ import org.jooq.Condition;
import org.jooq.Configuration;
import org.jooq.DeleteConditionStep;
import org.jooq.DeleteResultStep;
import org.jooq.DeleteWhereStep;
import org.jooq.DeleteUsingStep;
import org.jooq.Field;
import org.jooq.Name;
import org.jooq.Operator;
import org.jooq.OrderField;
import org.jooq.Param;
@ -84,6 +86,7 @@ import org.jooq.Select;
import org.jooq.SelectField;
import org.jooq.SelectFieldOrAsterisk;
import org.jooq.Table;
import org.jooq.TableLike;
/**
* @author Lukas Eder
@ -94,7 +97,7 @@ final class DeleteImpl<R extends Record>
implements
// Cascading interface implementations for Delete behaviour
DeleteWhereStep<R>,
DeleteUsingStep<R>,
DeleteConditionStep<R>,
DeleteResultStep<R> {
@ -108,6 +111,49 @@ final class DeleteImpl<R extends Record>
super(new DeleteQueryImpl<>(configuration, with, table));
}
@Override
public final DeleteImpl<R> using(TableLike<?> table) {
getDelegate().addUsing(table);
return this;
}
@Override
public final DeleteImpl<R> using(TableLike<?>... tables) {
getDelegate().addUsing(tables);
return this;
}
@Override
public final DeleteImpl<R> using(Collection<? extends TableLike<?>> tables) {
getDelegate().addUsing(tables);
return this;
}
@Override
public final DeleteImpl<R> using(SQL sql) {
return using(table(sql));
}
@Override
public final DeleteImpl<R> using(String sql) {
return using(table(sql));
}
@Override
public final DeleteImpl<R> using(String sql, Object... bindings) {
return using(table(sql, bindings));
}
@Override
public final DeleteImpl<R> using(String sql, QueryPart... parts) {
return using(table(sql, parts));
}
@Override
public final DeleteImpl<R> using(Name name) {
return using(table(name));
}
@Override
public final DeleteImpl<R> where(Condition conditions) {
getDelegate().addConditions(conditions);

View File

@ -75,6 +75,7 @@ import static org.jooq.impl.Keywords.K_DELETE;
import static org.jooq.impl.Keywords.K_FROM;
import static org.jooq.impl.Keywords.K_LIMIT;
import static org.jooq.impl.Keywords.K_ORDER_BY;
import static org.jooq.impl.Keywords.K_USING;
import static org.jooq.impl.Keywords.K_WHERE;
import java.util.Arrays;
@ -94,6 +95,7 @@ import org.jooq.Param;
import org.jooq.Record;
import org.jooq.SQLDialect;
import org.jooq.Table;
import org.jooq.TableLike;
/**
* @author Lukas Eder
@ -105,6 +107,7 @@ final class DeleteQueryImpl<R extends Record> extends AbstractDMLQuery<R> implem
private static final Set<SQLDialect> SPECIAL_DELETE_AS_SYNTAX = SQLDialect.supportedBy(MARIADB, MYSQL);
private static final Set<SQLDialect> NO_SUPPORT_LIMIT = SQLDialect.supportedBy(CUBRID, DERBY, FIREBIRD, H2, HSQLDB, POSTGRES, SQLITE);
private final TableList using;
private final ConditionProviderImpl condition;
private final SortFieldList orderBy;
private Param<? extends Number> limit;
@ -112,6 +115,7 @@ final class DeleteQueryImpl<R extends Record> extends AbstractDMLQuery<R> implem
DeleteQueryImpl(Configuration configuration, WithImpl with, Table<R> table) {
super(configuration, with, table);
this.using = new TableList();
this.condition = new ConditionProviderImpl();
this.orderBy = new SortFieldList();
}
@ -124,6 +128,23 @@ final class DeleteQueryImpl<R extends Record> extends AbstractDMLQuery<R> implem
return condition.hasWhere();
}
@Override
public final void addUsing(Collection<? extends TableLike<?>> f) {
for (TableLike<?> provider : f)
using.add(provider.asTable());
}
@Override
public final void addUsing(TableLike<?> f) {
using.add(f.asTable());
}
@Override
public final void addUsing(TableLike<?>... f) {
for (TableLike<?> provider : f)
using.add(provider.asTable());
}
@Override
public final void addConditions(Collection<? extends Condition> conditions) {
condition.addConditions(conditions);
@ -194,8 +215,15 @@ final class DeleteQueryImpl<R extends Record> extends AbstractDMLQuery<R> implem
ctx.visit(K_FROM).sql(' ')
.declareTables(true)
.visit(table(ctx))
.declareTables(declare)
.visit(table(ctx));
if (!using.isEmpty())
ctx.formatSeparator()
.visit(K_USING)
.sql(' ')
.visit(using);
ctx.declareTables(declare)
.end(DELETE_DELETE);

View File

@ -384,6 +384,7 @@ import org.jooq.Delete;
import org.jooq.DeleteLimitStep;
import org.jooq.DeleteOrderByStep;
import org.jooq.DeleteReturningStep;
import org.jooq.DeleteUsingStep;
import org.jooq.DeleteWhereStep;
import org.jooq.DerivedColumnList;
import org.jooq.DropIndexCascadeStep;
@ -1696,15 +1697,16 @@ final class ParserImpl implements Parser {
table = table.as(parseIdentifierIf(ctx));
}
DeleteWhereStep<?> s1 = with == null ? ctx.dsl.delete(table) : with.delete(table);
DeleteOrderByStep<?> s2 = parseKeywordIf(ctx, "WHERE") ? s1.where(parseCondition(ctx)) : s1;
DeleteLimitStep<?> s3 = parseKeywordIf(ctx, "ORDER BY") ? s2.orderBy(parseSortSpecification(ctx)) : s2;
DeleteReturningStep<?> s4 = (limit != null || parseKeywordIf(ctx, "LIMIT"))
? s3.limit(limit != null ? limit : parseParenthesisedUnsignedIntegerOrBindVariable(ctx))
: s3;
Delete<?> s5 = parseKeywordIf(ctx, "RETURNING") ? s4.returning(parseSelectList(ctx)) : s4;
DeleteUsingStep<?> s1 = with == null ? ctx.dsl.delete(table) : with.delete(table);
DeleteWhereStep<?> s2 = parseKeywordIf(ctx, "USING") ? s1.using(parseTables(ctx)) : s1;
DeleteOrderByStep<?> s3 = parseKeywordIf(ctx, "WHERE") ? s2.where(parseCondition(ctx)) : s2;
DeleteLimitStep<?> s4 = parseKeywordIf(ctx, "ORDER BY") ? s3.orderBy(parseSortSpecification(ctx)) : s3;
DeleteReturningStep<?> s5 = (limit != null || parseKeywordIf(ctx, "LIMIT"))
? s4.limit(limit != null ? limit : parseParenthesisedUnsignedIntegerOrBindVariable(ctx))
: s4;
Delete<?> s6 = parseKeywordIf(ctx, "RETURNING") ? s5.returning(parseSelectList(ctx)) : s5;
return s5;
return s6;
}
private static final Insert<?> parseInsert(ParserContext ctx, WithImpl with) {