[jOOQ/jOOQ#6244] RecordMappers can return null

This commit is contained in:
Lukas Eder 2020-07-13 12:06:21 +02:00
parent 1958b1d814
commit 6191677da4
20 changed files with 148 additions and 1076 deletions

View File

@ -964,6 +964,13 @@ public class PostgresDatabase extends AbstractDatabase {

View File

@ -87,6 +87,8 @@ public class PostgresTableDefinition extends AbstractTableDefinition {
PostgresDatabase database = (PostgresDatabase) getDatabase();
Field<String> dataType = COLUMNS.DATA_TYPE;
Field<Integer> precision = nvl(COLUMNS.DATETIME_PRECISION, COLUMNS.NUMERIC_PRECISION);
@ -103,9 +105,7 @@ public class PostgresTableDefinition extends AbstractTableDefinition {
nvl(
COLUMNS.CHARACTER_MAXIMUM_LENGTH,
when(COLUMNS.UDT_NAME.eq(inline("_varchar")), PG_ATTRIBUTE.ATTTYPMOD.sub(inline(4)))).as(COLUMNS.CHARACTER_MAXIMUM_LENGTH),
nvl(
COLUMNS.DATETIME_PRECISION,
COLUMNS.NUMERIC_PRECISION).as(COLUMNS.NUMERIC_PRECISION),
precision.as(COLUMNS.NUMERIC_PRECISION),
COLUMNS.NUMERIC_SCALE,
(database.is10() ? COLUMNS.IS_IDENTITY : val(null, String.class)).as(COLUMNS.IS_IDENTITY),
// [#9200] only use IS_IDENTITY for ColumnDefinition#isIdentity() if

View File

@ -69,7 +69,7 @@ public final class Constants {
/**
* The current jooq-runtime XSD file name.
*/
public static final String XSD_RUNTIME = "jooq-runtime-3.13.0.xsd";
public static final String XSD_RUNTIME = "jooq-runtime-3.14.0.xsd";
/**
* The current jooq-runtime XML namespace.

View File

@ -996,7 +996,7 @@ public interface Record extends Attachable, Comparable<Record>, Formattable {
* @see #from(Object)
* @see DefaultRecordMapper
*/
@NotNull
@Nullable
<E> E into(Class<? extends E> type) throws MappingException;
/**

View File

@ -1234,7 +1234,7 @@ extends
*
* @param <E> The generic entity type.
* @param type The entity type.
* @return The resulting value. This is never <code>null</code>.
* @return The resulting value.
* @see Record#into(Class)
* @see Result#into(Class)
* @throws DataAccessException if something went wrong executing the query
@ -1244,7 +1244,7 @@ extends
* @throws TooManyRowsException if the query returned more than one record
* @see DefaultRecordMapper
*/
@NotNull
@Nullable
<E> E fetchSingleInto(Class<? extends E> type) throws DataAccessException, MappingException, NoDataFoundException, TooManyRowsException;
/**

View File

@ -37,9 +37,6 @@
*/
package org.jooq;
import org.jetbrains.annotations.*;
// ...
// ...
// ...
@ -58,6 +55,8 @@ import static org.jooq.SQLDialect.POSTGRES;
import java.util.Collection;
import org.jetbrains.annotations.NotNull;
/**
* This type is used for the {@link Select}'s DSL API when selecting generic
* {@link Record} types.

View File

@ -28,7 +28,7 @@ public class InterpreterSearchSchema
implements Serializable, Cloneable, XMLAppendable
{
private final static long serialVersionUID = 31200L;
private final static long serialVersionUID = 31400L;
protected String catalog;
@XmlElement(required = true)
protected String schema;

View File

@ -34,7 +34,7 @@ public class MappedCatalog
implements Serializable, Cloneable, XMLAppendable
{
private final static long serialVersionUID = 31200L;
private final static long serialVersionUID = 31400L;
protected String input;
@XmlElement(type = String.class)
@XmlJavaTypeAdapter(RegexAdapter.class)

View File

@ -34,7 +34,7 @@ public class MappedSchema
implements Serializable, Cloneable, XMLAppendable
{
private final static long serialVersionUID = 31200L;
private final static long serialVersionUID = 31400L;
protected String input;
@XmlElement(type = String.class)
@XmlJavaTypeAdapter(RegexAdapter.class)

View File

@ -30,7 +30,7 @@ public class MappedTable
implements Serializable, Cloneable, XMLAppendable
{
private final static long serialVersionUID = 31200L;
private final static long serialVersionUID = 31400L;
protected String input;
@XmlElement(type = String.class)
@XmlJavaTypeAdapter(RegexAdapter.class)

View File

@ -24,7 +24,7 @@ import javax.xml.namespace.QName;
@XmlRegistry
public class ObjectFactory {
private final static QName _Settings_QNAME = new QName("http://www.jooq.org/xsd/jooq-runtime-3.13.0.xsd", "settings");
private final static QName _Settings_QNAME = new QName("http://www.jooq.org/xsd/jooq-runtime-3.14.0.xsd", "settings");
/**
* Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: org.jooq.conf
@ -105,7 +105,7 @@ public class ObjectFactory {
* @return
* the new instance of {@link JAXBElement }{@code <}{@link Settings }{@code >}
*/
@XmlElementDecl(namespace = "http://www.jooq.org/xsd/jooq-runtime-3.13.0.xsd", name = "settings")
@XmlElementDecl(namespace = "http://www.jooq.org/xsd/jooq-runtime-3.14.0.xsd", name = "settings")
public JAXBElement<Settings> createSettings(Settings value) {
return new JAXBElement<Settings>(_Settings_QNAME, Settings.class, null, value);
}

View File

@ -28,7 +28,7 @@ public class ParseSearchSchema
implements Serializable, Cloneable, XMLAppendable
{
private final static long serialVersionUID = 31200L;
private final static long serialVersionUID = 31400L;
protected String catalog;
@XmlElement(required = true)
protected String schema;

View File

@ -28,7 +28,7 @@ public class RenderFormatting
implements Serializable, Cloneable, XMLAppendable
{
private final static long serialVersionUID = 31200L;
private final static long serialVersionUID = 31400L;
@XmlElement(defaultValue = "\n")
protected String newline = "\n";
@XmlElement(defaultValue = " ")

View File

@ -32,7 +32,7 @@ public class RenderMapping
implements Serializable, Cloneable, XMLAppendable
{
private final static long serialVersionUID = 31200L;
private final static long serialVersionUID = 31400L;
protected String defaultCatalog;
protected String defaultSchema;
@XmlElementWrapper(name = "catalogs")

View File

@ -36,7 +36,7 @@ public class Settings
implements Serializable, Cloneable, XMLAppendable
{
private final static long serialVersionUID = 31200L;
private final static long serialVersionUID = 31400L;
@XmlElement(defaultValue = "true")
protected Boolean renderCatalog = true;
@XmlElement(defaultValue = "true")
@ -147,6 +147,11 @@ public class Settings
protected Boolean executeWithOptimisticLockingExcludeUnversioned = false;
@XmlElement(defaultValue = "true")
protected Boolean attachRecords = true;
@XmlElement(defaultValue = "true")
protected Boolean insertUnchangedRecords = true;
@XmlElement(defaultValue = "NEVER")
@XmlSchemaType(name = "string")
protected UpdateUnchangedRecords updateUnchangedRecords = UpdateUnchangedRecords.NEVER;
@XmlElement(defaultValue = "false")
protected Boolean updatablePrimaryKeys = false;
@XmlElement(defaultValue = "true")
@ -1243,6 +1248,46 @@ public class Settings
this.attachRecords = value;
}
/**
* Whether {@link org.jooq.TableRecord#insert()} calls should be executed if the record is unchanged. This also affects the <code>INSERT</code> part of {@link org.jooq.UpdatableRecord#store()} and {@link org.jooq.UpdatableRecord#merge()} calls.
*
* @return
* possible object is
* {@link Boolean }
*
*/
public Boolean isInsertUnchangedRecords() {
return insertUnchangedRecords;
}
/**
* Sets the value of the insertUnchangedRecords property.
*
* @param value
* allowed object is
* {@link Boolean }
*
*/
public void setInsertUnchangedRecords(Boolean value) {
this.insertUnchangedRecords = value;
}
/**
* Whether {@link org.jooq.UpdatableRecord#update()} calls should be executed if the record is unchanged. This also affects the <code>UPDATE</code> part of {@link org.jooq.UpdatableRecord#store()} and {@link org.jooq.UpdatableRecord#merge()} calls.
*
*/
public UpdateUnchangedRecords getUpdateUnchangedRecords() {
return updateUnchangedRecords;
}
/**
* Whether {@link org.jooq.UpdatableRecord#update()} calls should be executed if the record is unchanged. This also affects the <code>UPDATE</code> part of {@link org.jooq.UpdatableRecord#store()} and {@link org.jooq.UpdatableRecord#merge()} calls.
*
*/
public void setUpdateUnchangedRecords(UpdateUnchangedRecords value) {
this.updateUnchangedRecords = value;
}
/**
* Whether primary key values are deemed to be "updatable" in jOOQ.
* <p>
@ -2489,6 +2534,20 @@ public class Settings
return this;
}
public Settings withInsertUnchangedRecords(Boolean value) {
setInsertUnchangedRecords(value);
return this;
}
/**
* Whether {@link org.jooq.UpdatableRecord#update()} calls should be executed if the record is unchanged. This also affects the <code>UPDATE</code> part of {@link org.jooq.UpdatableRecord#store()} and {@link org.jooq.UpdatableRecord#merge()} calls.
*
*/
public Settings withUpdateUnchangedRecords(UpdateUnchangedRecords value) {
setUpdateUnchangedRecords(value);
return this;
}
public Settings withUpdatablePrimaryKeys(Boolean value) {
setUpdatablePrimaryKeys(value);
return this;
@ -2879,6 +2938,8 @@ public class Settings
builder.append("executeWithOptimisticLocking", executeWithOptimisticLocking);
builder.append("executeWithOptimisticLockingExcludeUnversioned", executeWithOptimisticLockingExcludeUnversioned);
builder.append("attachRecords", attachRecords);
builder.append("insertUnchangedRecords", insertUnchangedRecords);
builder.append("updateUnchangedRecords", updateUnchangedRecords);
builder.append("updatablePrimaryKeys", updatablePrimaryKeys);
builder.append("reflectionCaching", reflectionCaching);
builder.append("cacheRecordMappers", cacheRecordMappers);
@ -3340,6 +3401,24 @@ public class Settings
return false;
}
}
if (insertUnchangedRecords == null) {
if (other.insertUnchangedRecords!= null) {
return false;
}
} else {
if (!insertUnchangedRecords.equals(other.insertUnchangedRecords)) {
return false;
}
}
if (updateUnchangedRecords == null) {
if (other.updateUnchangedRecords!= null) {
return false;
}
} else {
if (!updateUnchangedRecords.equals(other.updateUnchangedRecords)) {
return false;
}
}
if (updatablePrimaryKeys == null) {
if (other.updatablePrimaryKeys!= null) {
return false;
@ -3787,6 +3866,8 @@ public class Settings
result = ((prime*result)+((executeWithOptimisticLocking == null)? 0 :executeWithOptimisticLocking.hashCode()));
result = ((prime*result)+((executeWithOptimisticLockingExcludeUnversioned == null)? 0 :executeWithOptimisticLockingExcludeUnversioned.hashCode()));
result = ((prime*result)+((attachRecords == null)? 0 :attachRecords.hashCode()));
result = ((prime*result)+((insertUnchangedRecords == null)? 0 :insertUnchangedRecords.hashCode()));
result = ((prime*result)+((updateUnchangedRecords == null)? 0 :updateUnchangedRecords.hashCode()));
result = ((prime*result)+((updatablePrimaryKeys == null)? 0 :updatablePrimaryKeys.hashCode()));
result = ((prime*result)+((reflectionCaching == null)? 0 :reflectionCaching.hashCode()));
result = ((prime*result)+((cacheRecordMappers == null)? 0 :cacheRecordMappers.hashCode()));

View File

@ -1,2 +1,2 @@
@javax.xml.bind.annotation.XmlSchema(namespace = "http://www.jooq.org/xsd/jooq-runtime-3.13.0.xsd", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
@javax.xml.bind.annotation.XmlSchema(namespace = "http://www.jooq.org/xsd/jooq-runtime-3.14.0.xsd", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package org.jooq.conf;

View File

@ -37,6 +37,7 @@
*/
package org.jooq.impl;
// ...
// ...
// ...
import static org.jooq.SQLDialect.DERBY;

View File

@ -193,12 +193,18 @@ public class TableRecordImpl<R extends TableRecord<R>> extends AbstractRecord im
InsertQuery<R> insert = create.insertQuery(getTable());
addChangedValues(storeFields, insert, false);
// Don't store records if no value was set by client code
if (!insert.isExecutable()) {
if (log.isDebugEnabled())
log.debug("Query is not executable", insert);
return 0;
// Don't store records if no value was set by client code
if (FALSE.equals(create.settings().isInsertUnchangedRecords())) {
if (log.isDebugEnabled())
log.debug("Query is not executable", insert);
return 0;
}
else
insert.setDefaultValues();
}
// [#1596] Set timestamp and/or version columns to appropriate values

View File

@ -71,6 +71,7 @@ import org.jooq.TableField;
import org.jooq.TableRecord;
import org.jooq.UniqueKey;
import org.jooq.UpdatableRecord;
import org.jooq.conf.UpdateUnchangedRecords;
import org.jooq.exception.DataChangedException;
import org.jooq.exception.NoDataFoundException;
import org.jooq.tools.JooqLogger;
@ -284,16 +285,40 @@ public class UpdatableRecordImpl<R extends UpdatableRecord<R>> extends TableReco
|| getTable().getRecordVersion() == null && getTable().getRecordTimestamp() == null && fetched;
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private final <Q extends StoreQuery<R> & org.jooq.ConditionProvider> int storeMergeOrUpdate0(Field<?>[] storeFields, TableField<R, ?>[] keys, Q query, boolean merge) {
addChangedValues(storeFields, query, merge);
Tools.addConditions(query, this, keys);
// Don't store records if no value was set by client code
if (!query.isExecutable()) {
if (log.isDebugEnabled())
log.debug("Query is not executable", query);
switch (StringUtils.defaultIfNull(create().settings().getUpdateUnchangedRecords(), UpdateUnchangedRecords.NEVER)) {
return 0;
// Don't store records if no value was set by client code
case NEVER:
if (log.isDebugEnabled())
log.debug("Query is not executable", query);
return 0;
case SET_PRIMARY_KEY_TO_ITSELF:
for (TableField<R, ?> key : keys)
query.addValue(key, (Field) key);
break;
case SET_NON_PRIMARY_KEY_TO_THEMSELVES:
for (Field<?> field : storeFields)
query.addValue(field, (Field) field);
break;
case SET_NON_PRIMARY_KEY_TO_RECORD_VALUES:
for (Field<?> field : storeFields)
changed(field, true);
addChangedValues(storeFields, query, merge);
break;
}
}
// [#1596] Set timestamp and/or version columns to appropriate values

File diff suppressed because it is too large Load Diff