[#6391] [#6413] Exception propagation changes

- [#6391] Add ResultOrRows.exception() to improve support for SQL Server's RAISERROR
- [#6413] Add Setting.throwExceptions to define how SQLException should be propagated out of jOOQ
This commit is contained in:
lukaseder 2017-07-13 14:32:07 +02:00
parent d4c391209c
commit d967bc7392
5 changed files with 130 additions and 8 deletions

View File

@ -74,6 +74,9 @@ public class Settings
protected Boolean updatablePrimaryKeys = false;
@XmlElement(defaultValue = "true")
protected Boolean reflectionCaching = true;
@XmlElement(defaultValue = "THROW_ALL")
@XmlSchemaType(name = "string")
protected ThrowExceptions throwExceptions = ThrowExceptions.THROW_ALL;
@XmlElement(defaultValue = "true")
protected Boolean fetchWarnings = true;
@XmlElement(defaultValue = "false")
@ -534,6 +537,30 @@ public class Settings
this.reflectionCaching = value;
}
/**
* A strategy defining how exceptions from the database / JDBC driver should be propagated
*
* @return
* possible object is
* {@link ThrowExceptions }
*
*/
public ThrowExceptions getThrowExceptions() {
return throwExceptions;
}
/**
* Sets the value of the throwExceptions property.
*
* @param value
* allowed object is
* {@link ThrowExceptions }
*
*/
public void setThrowExceptions(ThrowExceptions value) {
this.throwExceptions = value;
}
/**
* Whether warnings should be fetched after each query execution.
*
@ -867,6 +894,11 @@ public class Settings
return this;
}
public Settings withThrowExceptions(ThrowExceptions value) {
setThrowExceptions(value);
return this;
}
public Settings withFetchWarnings(Boolean value) {
setFetchWarnings(value);
return this;

View File

@ -0,0 +1,47 @@
package org.jooq.conf;
import javax.xml.bind.annotation.XmlEnum;
import javax.xml.bind.annotation.XmlType;
/**
* <p>Java class for ThrowExceptions.
*
* <p>The following schema fragment specifies the expected content contained within this class.
* <p>
* <pre>
* &lt;simpleType name="ThrowExceptions"&gt;
* &lt;restriction base="{http://www.w3.org/2001/XMLSchema}string"&gt;
* &lt;enumeration value="THROW_ALL"/&gt;
* &lt;enumeration value="THROW_FIRST"/&gt;
* &lt;enumeration value="THROW_NONE"/&gt;
* &lt;/restriction&gt;
* &lt;/simpleType&gt;
* </pre>
*
*/
@XmlType(name = "ThrowExceptions")
@XmlEnum
public enum ThrowExceptions {
THROW_ALL,
THROW_FIRST,
THROW_NONE;
public String value() {
return name();
}
public static ThrowExceptions fromValue(String v) {
return valueOf(v);
}
}

View File

@ -202,6 +202,10 @@ final class ResultsImpl extends AbstractList<Result<Record>> implements Results
this(null, rows, null);
}
ResultOrRowsImpl(DataAccessException exception) {
this(null, 0, exception);
}
private ResultOrRowsImpl(Result<Record> result, int rows, DataAccessException exception) {
this.result = result;
this.rows = rows;

View File

@ -56,6 +56,8 @@ import static org.jooq.conf.ParamType.NAMED_OR_INLINED;
import static org.jooq.conf.SettingsTools.getBackslashEscaping;
import static org.jooq.conf.SettingsTools.reflectionCaching;
import static org.jooq.conf.SettingsTools.updatablePrimaryKeys;
import static org.jooq.conf.ThrowExceptions.THROW_FIRST;
import static org.jooq.conf.ThrowExceptions.THROW_NONE;
import static org.jooq.impl.DDLStatementType.ALTER_TABLE;
import static org.jooq.impl.DDLStatementType.ALTER_VIEW;
import static org.jooq.impl.DDLStatementType.CREATE_INDEX;
@ -211,9 +213,11 @@ import org.jooq.UDTRecord;
import org.jooq.UpdatableRecord;
import org.jooq.conf.BackslashEscaping;
import org.jooq.conf.Settings;
import org.jooq.conf.ThrowExceptions;
import org.jooq.exception.DataAccessException;
import org.jooq.exception.MappingException;
import org.jooq.exception.TooManyRowsException;
import org.jooq.impl.ResultsImpl.ResultOrRowsImpl;
import org.jooq.impl.Tools.Cache.CachedOperation;
import org.jooq.tools.JooqLogger;
import org.jooq.tools.StringUtils;
@ -3043,11 +3047,17 @@ final class Tools {
// ------------------------------------------------------------------------
/**
* [#3011] [#3054] [#6390] Consume additional exceptions if there are any
* and append them to the <code>previous</code> exception's
* [#3011] [#3054] [#6390] [#6413] Consume additional exceptions if there
* are any and append them to the <code>previous</code> exception's
* {@link SQLException#getNextException()} list.
*/
static final void consumeExceptions(Configuration configuration, PreparedStatement stmt, SQLException previous) {
// [#6413] Don't consume any additional exceptions if we're throwing only the first.
ThrowExceptions exceptions = configuration.settings().getThrowExceptions();
if (exceptions == THROW_FIRST)
return;
@ -3196,6 +3206,7 @@ final class Tools {
boolean anyResults = false;
int i = 0;
int rows = (ctx.resultSet() == null) ? ctx.rows() : 0;
SQLException x = null;
for (i = 0; i < maxConsumedResults; i++) {
try {
@ -3204,11 +3215,11 @@ final class Tools {
Field<?>[] fields = new MetaDataFieldProvider(ctx.configuration(), ctx.resultSet().getMetaData()).getFields();
Cursor<Record> c = new CursorImpl<Record>(ctx, listener, fields, intern != null ? intern.internIndexes(fields) : null, true, false);
results.resultsOrRows().add(new ResultsImpl.ResultOrRowsImpl(c.fetch()));
results.resultsOrRows().add(new ResultOrRowsImpl(c.fetch()));
}
else {
else if (x == null) {
if (rows != -1)
results.resultsOrRows().add(new ResultsImpl.ResultOrRowsImpl(rows));
results.resultsOrRows().add(new ResultOrRowsImpl(rows));
else
break;
}
@ -3225,12 +3236,22 @@ final class Tools {
else
break;
}
x = null;
}
// [#3011] [#3054] [#6390] Consume additional exceptions if there are any
// [#3011] [#3054] [#6390] [#6413] Consume additional exceptions if there are any
catch (SQLException e) {
consumeExceptions(ctx.configuration(), ctx.statement(), e);
throw e;
x = e;
if (ctx.settings().getThrowExceptions() == THROW_NONE) {
ctx.sqlException(e);
results.resultsOrRows().add(new ResultOrRowsImpl(Tools.translate(ctx.sql(), e)));
}
else {
consumeExceptions(ctx.configuration(), ctx.statement(), e);
throw e;
}
}
}

View File

@ -111,6 +111,10 @@ UpdatableRecord.store() and UpdatableRecord.update().]]></jxb:javadoc></jxb:prop
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[Whether reflection information should be cached in the configuration.]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>
<element name="throwExceptions" type="jooq-runtime:ThrowExceptions" minOccurs="0" maxOccurs="1" default="THROW_ALL">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[A strategy defining how exceptions from the database / JDBC driver should be propagated]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>
<element name="fetchWarnings" type="boolean" minOccurs="0" maxOccurs="1" default="true">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[Whether warnings should be fetched after each query execution.]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>
@ -361,4 +365,18 @@ Either &lt;input/> or &lt;inputExpression/> must be provided]]></jxb:javadoc></j
<enumeration value="OFF"/>
</restriction>
</simpleType>
<simpleType name="ThrowExceptions">
<restriction base="string">
<!-- Collect all exceptions from a batch and throw them all together -->
<enumeration value="THROW_ALL"/>
<!-- Throw only the first exception from a batch -->
<enumeration value="THROW_FIRST"/>
<!-- Throw no exceptions, but collect them in ResultOrRows -->
<enumeration value="THROW_NONE"/>
</restriction>
</simpleType>
</schema>