From d967bc7392e95b4117b3895c6cd978e4844e8bda Mon Sep 17 00:00:00 2001 From: lukaseder Date: Thu, 13 Jul 2017 14:32:07 +0200 Subject: [PATCH] [#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 --- .../src/main/java/org/jooq/conf/Settings.java | 32 +++++++++++++ .../java/org/jooq/conf/ThrowExceptions.java | 47 +++++++++++++++++++ .../main/java/org/jooq/impl/ResultsImpl.java | 4 ++ jOOQ/src/main/java/org/jooq/impl/Tools.java | 37 +++++++++++---- .../resources/xsd/jooq-runtime-3.10.0.xsd | 18 +++++++ 5 files changed, 130 insertions(+), 8 deletions(-) create mode 100644 jOOQ/src/main/java/org/jooq/conf/ThrowExceptions.java diff --git a/jOOQ/src/main/java/org/jooq/conf/Settings.java b/jOOQ/src/main/java/org/jooq/conf/Settings.java index 01569e47ba..d10b5702cc 100644 --- a/jOOQ/src/main/java/org/jooq/conf/Settings.java +++ b/jOOQ/src/main/java/org/jooq/conf/Settings.java @@ -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; diff --git a/jOOQ/src/main/java/org/jooq/conf/ThrowExceptions.java b/jOOQ/src/main/java/org/jooq/conf/ThrowExceptions.java new file mode 100644 index 0000000000..401ed2d758 --- /dev/null +++ b/jOOQ/src/main/java/org/jooq/conf/ThrowExceptions.java @@ -0,0 +1,47 @@ + + + + + + + + +package org.jooq.conf; + +import javax.xml.bind.annotation.XmlEnum; +import javax.xml.bind.annotation.XmlType; + + +/** + *

Java class for ThrowExceptions. + * + *

The following schema fragment specifies the expected content contained within this class. + *

+ *

+ * <simpleType name="ThrowExceptions">
+ *   <restriction base="{http://www.w3.org/2001/XMLSchema}string">
+ *     <enumeration value="THROW_ALL"/>
+ *     <enumeration value="THROW_FIRST"/>
+ *     <enumeration value="THROW_NONE"/>
+ *   </restriction>
+ * </simpleType>
+ * 
+ * + */ +@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); + } + +} diff --git a/jOOQ/src/main/java/org/jooq/impl/ResultsImpl.java b/jOOQ/src/main/java/org/jooq/impl/ResultsImpl.java index 4fd17ecaa4..67aa396d87 100644 --- a/jOOQ/src/main/java/org/jooq/impl/ResultsImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/ResultsImpl.java @@ -202,6 +202,10 @@ final class ResultsImpl extends AbstractList> implements Results this(null, rows, null); } + ResultOrRowsImpl(DataAccessException exception) { + this(null, 0, exception); + } + private ResultOrRowsImpl(Result result, int rows, DataAccessException exception) { this.result = result; this.rows = rows; diff --git a/jOOQ/src/main/java/org/jooq/impl/Tools.java b/jOOQ/src/main/java/org/jooq/impl/Tools.java index 846ca9d391..988fa8fc00 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Tools.java +++ b/jOOQ/src/main/java/org/jooq/impl/Tools.java @@ -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 previous exception's + * [#3011] [#3054] [#6390] [#6413] Consume additional exceptions if there + * are any and append them to the previous 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 c = new CursorImpl(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; + } } } diff --git a/jOOQ/src/main/resources/xsd/jooq-runtime-3.10.0.xsd b/jOOQ/src/main/resources/xsd/jooq-runtime-3.10.0.xsd index f3fa669646..706c1ce51c 100644 --- a/jOOQ/src/main/resources/xsd/jooq-runtime-3.10.0.xsd +++ b/jOOQ/src/main/resources/xsd/jooq-runtime-3.10.0.xsd @@ -111,6 +111,10 @@ UpdatableRecord.store() and UpdatableRecord.update().]]> + + + + @@ -361,4 +365,18 @@ Either <input/> or <inputExpression/> must be provided]]> + + + + + + + + + + + + + + \ No newline at end of file