[jOOQ/jOOQ#11015] Syntax error when data type cannot be inferred from

SQL NULL literals in VALUES()
This commit is contained in:
Lukas Eder 2023-03-03 17:00:39 +01:00
parent 2b5cc36086
commit c13e781b8a
3 changed files with 41 additions and 10 deletions

View File

@ -103,16 +103,16 @@ import org.jooq.impl.Tools.BooleanDataKey;
* @author Lukas Eder
*/
final class FieldMapsForInsert extends AbstractQueryPart implements UNotYetImplemented {
private static final Set<SQLDialect> CASTS_NEEDED = SQLDialect.supportedBy(POSTGRES, YUGABYTEDB);
static final Set<SQLDialect> CASTS_NEEDED = SQLDialect.supportedBy(POSTGRES, YUGABYTEDB);
final Table<?> table;
final Map<Field<?>, Field<?>> empty;
final Table<?> table;
final Map<Field<?>, Field<?>> empty;
// Depending on whether embeddable types are allowed, this data structure
// needs to be flattened with duplicates removed, prior to consumption
// [#2530] [#6124] [#10481] TODO: Refactor and optimise these flattening algorithms
final Map<Field<?>, List<Field<?>>> values;
int rows;
int nextRow = -1;
final Map<Field<?>, List<Field<?>>> values;
int rows;
int nextRow = -1;
FieldMapsForInsert(Table<?> table) {
this.table = table;

View File

@ -59,6 +59,7 @@ import static org.jooq.SQLDialect.MYSQL;
// ...
import static org.jooq.SQLDialect.POSTGRES;
// ...
// ...
import static org.jooq.SQLDialect.SQLITE;
// ...
// ...

View File

@ -53,6 +53,7 @@ import static org.jooq.SQLDialect.MARIADB;
import static org.jooq.SQLDialect.MYSQL;
// ...
// ...
import static org.jooq.SQLDialect.POSTGRES;
// ...
// ...
// ...
@ -60,6 +61,7 @@ import static org.jooq.SQLDialect.MYSQL;
// ...
import static org.jooq.conf.ParamType.INLINED;
import static org.jooq.impl.DSL.name;
import static org.jooq.impl.DSL.row;
import static org.jooq.impl.Keywords.K_MULTISET;
import static org.jooq.impl.Keywords.K_ROW;
import static org.jooq.impl.Keywords.K_STRUCT;
@ -69,7 +71,9 @@ import static org.jooq.impl.Keywords.K_VALUES;
import static org.jooq.impl.QueryPartListView.wrap;
import static org.jooq.impl.SubqueryCharacteristics.DERIVED_TABLE;
import static org.jooq.impl.Tools.EMPTY_ROW;
import static org.jooq.impl.Tools.anyMatch;
import static org.jooq.impl.Tools.isEmpty;
import static org.jooq.impl.Tools.isVal;
import static org.jooq.impl.Tools.map;
import static org.jooq.impl.Tools.visitSubquery;
@ -101,9 +105,10 @@ implements
QOM.Values<R>
{
static final Set<SQLDialect> NO_SUPPORT_VALUES = SQLDialect.supportedUntil(FIREBIRD, MARIADB);
static final Set<SQLDialect> REQUIRE_ROWTYPE_CAST = SQLDialect.supportedBy(FIREBIRD);
static final Set<SQLDialect> NO_SUPPORT_PARENTHESES = SQLDialect.supportedBy();
static final Set<SQLDialect> NO_SUPPORT_VALUES = SQLDialect.supportedUntil(FIREBIRD, MARIADB);
static final Set<SQLDialect> REQUIRE_ROWTYPE_CAST = SQLDialect.supportedBy(FIREBIRD);
static final Set<SQLDialect> REQUIRE_ROWTYPE_CAST_ON_NULLS = SQLDialect.supportedBy(POSTGRES);
static final Set<SQLDialect> NO_SUPPORT_PARENTHESES = SQLDialect.supportedBy();
private final Row[] rows;
private transient DataType<?>[] types;
@ -198,6 +203,27 @@ implements
return result;
}
private final Row castNullLiteralToRowType(Context<?> ctx, Row row) {
if (anyMatch(row.fields(), f -> rendersNullLiteral(ctx, f))) {
Field<?>[] result = new Field[row.size()];
for (int i = 0; i < result.length; i++)
if (rendersNullLiteral(ctx, row.field(i)) && rowType()[i].getType() != Object.class)
result[i] = row.field(i).cast(rowType()[i]);
else
result[i] = row.field(i);
return row(result);
}
else
return row;
}
private final boolean rendersNullLiteral(Context<?> ctx, Field<?> field) {
return isVal(field) && ((Val<?>) field).getValue() == null && ((Val<?>) field).isInline(ctx)
|| field instanceof NullCondition;
}
@Override
public final void accept(Context<?> ctx) {
@ -266,7 +292,11 @@ implements
ctx.visit(rows[i]);
// [#11015] NULL literals of known type should be cast in PostgreSQL in the first row
if (i == 0 && ctx.family() == POSTGRES)
ctx.visit(castNullLiteralToRowType(ctx, rows[i]));
else
ctx.visit(rows[i]);
}
if (rows.length > 1)