[jOOQ/jOOQ#16409] Improve Javadoc and log DEBUG message on RETURNING clauses, stressing that they can't return any rows for tables without identity in some dialects

This commit is contained in:
Lukas Eder 2025-01-17 08:44:31 +01:00
parent 71e1a06781
commit 46c0a3760f
4 changed files with 79 additions and 28 deletions

View File

@ -56,20 +56,34 @@ import org.jetbrains.annotations.NotNull;
/**
* This type is used for the {@link Delete}'s DSL API.
* <p>
* Example: <pre><code>
* Example:
*
* <pre>
* <code>
* DSLContext create = DSL.using(configuration);
*
* create.delete(table)
* .where(field1.greaterThan(100))
* .execute();
* </code></pre>
* </code>
* </pre>
* <p>
* This implemented differently for every dialect:
* <ul>
* <li>Firebird and Postgres have native support for
* <code>UPDATE RETURNING</code> clauses</li>
* <li>DB2 allows to execute
* <li>{@link SQLDialect#COCKROACHDB} {@link SQLDialect#FIREBIRD},
* {@link SQLDialect#MARIADB}, {@link SQLDialect#POSTGRES},
* {@link SQLDialect#SQLITE}, {@link SQLDialect#YUGABYTEDB} have native support
* for <code>DELETE RETURNING</code> clauses in SQL</li>
* <li>{@link SQLDialect#ORACLE} has native support for
* <code>DELETE RETURNING</code> in PL/SQL, so jOOQ can render an anonymous
* block</li>
* <li>{@link SQLDialect#SQLSERVER} supports an <code>DELETE OUTPUT</code>
* syntax, which can capture defaults and computed column values, though not
* trigger generated values.</li>
* <li>{@link SQLDialect#DB2} and {@link SQLDialect#H2} allow to execute the
* standard SQL data change delta table syntax:
* <code>SELECT FROM FINAL TABLE (DELETE )</code></li>
* <li>Other dialects cannot emulate <code>DELETE RETURNING</code>.</li>
* </ul>
* <p>
* <h3>Referencing <code>XYZ*Step</code> types directly from client code</h3>

View File

@ -39,13 +39,16 @@ package org.jooq;
import org.jetbrains.annotations.*;
import java.sql.Statement;
import java.util.Collection;
/**
* This type is used for the {@link Insert}'s DSL API.
* <p>
* Example: <pre><code>
* Example:
*
* <pre>
* <code>
* DSLContext create = DSL.using(configuration);
*
* TableRecord&lt;?&gt; record =
@ -53,27 +56,38 @@ import java.util.Collection;
* .values(value1, value2)
* .returning(field1)
* .fetchOne();
* </code></pre>
* </code>
* </pre>
* <p>
* This implemented differently for every dialect:
* <ul>
* <li>Firebird and Postgres have native support for
* <code>INSERT RETURNING</code> clauses</li>
* <li>DB2 allows to execute
* <code>SELECT FROM FINAL TABLE (INSERT )</code></li>
* <li>HSQLDB, and Oracle JDBC drivers allow for retrieving any table column as
* "generated key" in one statement</li>
* <li>Derby, H2, Ingres, MySQL, SQL Server only allow for retrieving IDENTITY
* column values as "generated key". If other fields are requested, a second
* statement is issued. Client code must assure transactional integrity between
* the two statements.</li>
* <li>Sybase and SQLite allow for retrieving IDENTITY values as
* <code>@@identity</code> or <code>last_inserted_rowid()</code> values. Those
* values are fetched in a separate <code>SELECT</code> statement. If other
* fields are requested, a second statement is issued. Client code must assure
* transactional integrity between the two statements.</li>
* <li>{@link SQLDialect#COCKROACHDB}, {@link SQLDialect#DUCKDB},
* {@link SQLDialect#FIREBIRD}, {@link SQLDialect#MARIADB},
* {@link SQLDialect#POSTGRES}, {@link SQLDialect#SQLITE},
* {@link SQLDialect#YUGABYTEDB} have native support for
* <code>UPDATE RETURNING</code> clauses in SQL</li>
* <li>{@link SQLDialect#ORACLE} has native support for
* <code>UPDATE RETURNING</code> in PL/SQL, so jOOQ can render an anonymous
* block</li>
* <li>{@link SQLDialect#SQLSERVER} supports an <code>UPDATE OUTPUT</code>
* syntax, which can capture defaults and computed column values, though not
* trigger generated values.</li>
* <li>{@link SQLDialect#DB2} and {@link SQLDialect#H2} allow to execute the
* standard SQL data change delta table syntax:
* <code>SELECT FROM FINAL TABLE (UPDATE )</code></li>
* <li>Other dialects may be able to retrieve <code>IDENTITY</code> values using
* JDBC {@link Statement#RETURN_GENERATED_KEYS} or using native SQL means, such
* as <code>@@identity</code> or similar variables, and other fields using a
* second query, in case of which clients will need to ensure transactional
* integrity themselves.</li>
* </ul>
* <p>
* <strong>Note that if jOOQ cannot fetch any identity value in your given
* dialect because 1) there is no native SQL syntax or 2) there is no identity
* column, or 3) there is no support for fetching any identity values, then the
* <code>INSERT RETURNING</code> statement will simply not produce any
* rows!</strong>
* <p>
* <h3>Referencing <code>XYZ*Step</code> types directly from client code</h3>
* <p>
* It is usually not recommended to reference any <code>XYZ*Step</code> types

View File

@ -56,7 +56,10 @@ import org.jetbrains.annotations.NotNull;
/**
* This type is used for the {@link Update}'s DSL API.
* <p>
* Example: <pre><code>
* Example:
*
* <pre>
* <code>
* DSLContext create = DSL.using(configuration);
*
* TableRecord&lt;?&gt; record =
@ -65,14 +68,25 @@ import org.jetbrains.annotations.NotNull;
* .set(field2, value2)
* .returning(field1)
* .fetchOne();
* </code></pre>
* </code>
* </pre>
* <p>
* This implemented differently for every dialect:
* <ul>
* <li>Firebird and Postgres have native support for
* <code>UPDATE RETURNING</code> clauses</li>
* <li>DB2 allows to execute
* <li>{@link SQLDialect#COCKROACHDB}, {@link SQLDialect#FIREBIRD},
* {@link SQLDialect#MARIADB}, {@link SQLDialect#POSTGRES},
* {@link SQLDialect#SQLITE}, {@link SQLDialect#YUGABYTEDB} have native support
* for <code>UPDATE RETURNING</code> clauses in SQL</li>
* <li>{@link SQLDialect#ORACLE} has native support for
* <code>UPDATE RETURNING</code> in PL/SQL, so jOOQ can render an anonymous
* block</li>
* <li>{@link SQLDialect#SQLSERVER} supports an <code>UPDATE OUTPUT</code>
* syntax, which can capture defaults and computed column values, though not
* trigger generated values.</li>
* <li>{@link SQLDialect#DB2} and {@link SQLDialect#H2} allow to execute the
* standard SQL data change delta table syntax:
* <code>SELECT FROM FINAL TABLE (UPDATE )</code></li>
* <li>Other dialects cannot emulate <code>UPDATE RETURNING</code>.</li>
* </ul>
* <p>
* <h3>Referencing <code>XYZ*Step</code> types directly from client code</h3>

View File

@ -1113,6 +1113,7 @@ abstract class AbstractDMLQuery<R extends Record> extends AbstractRowCountQuery
}
// Column stores don't seem support fetching generated keys
else if (NO_SUPPORT_FETCHING_KEYS.contains(ctx.dialect())) {
log.debug("RETURNING was set on query, but dialect doesn't support fetching generated keys: " + ctx.dialect());
return super.execute(ctx, listener);
}
else {
@ -1135,6 +1136,7 @@ abstract class AbstractDMLQuery<R extends Record> extends AbstractRowCountQuery
.fetch();
returnedResult.attach(((DefaultExecuteContext) ctx).originalConfiguration());
logOnEmptyReturned(ctx);
return result;
}
else
@ -1344,6 +1346,11 @@ abstract class AbstractDMLQuery<R extends Record> extends AbstractRowCountQuery
}
}
private final void logOnEmptyReturned(Scope ctx) {
if (estimatedRowCount(ctx) == 1)
log.debug("RETURNING was set on query, but no rows were returned. This is likely due to a missing identity column (or an identity column unknown to jOOQ).");
}
private final int executeReturningGeneratedKeys(ExecuteContext ctx, ExecuteListener listener) throws SQLException {
listener.executeStart(ctx);
int result = executeImmediate(ctx.statement()).executeUpdate();
@ -1459,6 +1466,8 @@ abstract class AbstractDMLQuery<R extends Record> extends AbstractRowCountQuery
}
}
}
else
logOnEmptyReturned(derivedConfiguration.dsl());
}
private final Field<?> returnedIdentity() {