[jOOQ/jOOQ#18274] Query.getSQL(NAMED) produces a gap in the parameter

numbering when the query contains a null UDT value, while Query::getBindValues still produces the value
This commit is contained in:
Lukas Eder 2025-04-02 12:49:00 +02:00
parent e98d164653
commit 34147ba9f6
5 changed files with 35 additions and 8 deletions

View File

@ -151,7 +151,13 @@ public interface Param<T> extends ParamOrVariable<T> {
void setInline(boolean inline);
/**
* A flag on the bind value to force it to be inlined in rendered SQL
* A flag on the bind value to force it to be inlined in rendered SQL.
* <p>
* Please note that despite this flag returning <code>false</code>, jOOQ
* internals may decide to inline a {@link Param} at their own discretion,
* e.g. because of a limitation in the dialect's syntactic capabilities
* (e.g. some functions may require literals as arguments), or of the JDBC
* driver.
*/
boolean isInline();

View File

@ -193,7 +193,7 @@ abstract class AbstractParam<T> extends AbstractParamX<T> implements SimpleQuery
return inline;
}
final boolean isInline(Context<?> ctx) {
/* non-final */ boolean isInline(Context<?> ctx) {
return isInline()
|| (ctx.paramType() == INLINED)
|| (ctx.paramType() == NAMED_OR_INLINED && StringUtils.isBlank(paramName))

View File

@ -740,10 +740,8 @@ class DefaultRenderContext extends AbstractContext<RenderContext> implements Ren
// collected the bind variable. The same is true if custom data
// type bindings use Context.visit(Param), in case of which we
// must not collect the current Param
if (after == before && paramType != INLINED && internal instanceof Param) {
Param<?> param = (Param<?>) internal;
if (!param.isInline()) {
if (after == before && paramType != INLINED && internal instanceof AbstractParam<?> param) {
if (!param.isInline(this)) {
// [#16340] Increment index even if we don't need it internally, while rendering
nextIndex();

View File

@ -75,10 +75,10 @@ final class ParamCollector extends AbstractBindContext {
@Override
protected final void bindInternal(QueryPartInternal internal) {
if (internal instanceof Param<?> param) {
if (internal instanceof AbstractParam<?> param) {
// [#3131] Inlined parameters should not be returned in some contexts
if (includeInlinedParams || !param.isInline()) {
if (includeInlinedParams || !param.isInline(this)) {
String i = String.valueOf(nextIndex());
String paramName = param.getParamName();

View File

@ -138,9 +138,32 @@ final class QualifiedRecordConstant<R extends QualifiedRecord<R>> extends Abstra
ctx.paramType(paramType);
}
@Override
final boolean isInline(Context<?> ctx) {
switch (ctx.family()) {
// [#18274] NULL values are inlined, not bound in these dialects
case POSTGRES:
case YUGABYTEDB:
default:
return value == null
|| super.isInline(ctx);
}
}
private final void toSQLInline(RenderContext ctx) {
Cast.renderCastIf(ctx,
c -> {
// [#18274] NULL values are inlined, not bound in these dialects
if (value == null) {
c.visit(K_NULL);
}