java.sql2 DynamicMultiOperation with interlaced exceptions
Lukas Eder
lukas.eder at gmail.com
Mon Oct 9 15:33:37 UTC 2017
Yes, I had seen that inherited onError() method, which is why I raised the
concern:
> However, now I wonder how the new
> DynamicMultiOperation.onError(BiConsumer<Integer, Throwable>)
> method would communicate with the pre-existing
> Operation.onError(Consumer<Throable>) method...
Specifically, because the new one has a useful Integer argument indicating
what the result number is. If that is dropped, then the inherited onError()
method no longer has such an Integer argument, which is a bit inconsistent.
Also, this leads to another question: Will those Integer indexes be skipped
onError, or not?
2017-10-09 17:04 GMT+02:00 Douglas Surber <douglas.surber at oracle.com>:
> A DynamicMultiOperation is an Operation and so inherits onError. We can
> specify that the onError handler is called for any error and after it
> returns processing continues instead of completing the Operation
> exceptionally.
>
> Douglas
>
> On Oct 9, 2017, at 5:43 AM, Lukas Eder <lukas.eder at gmail.com> wrote:
>
> Hi Douglas,
>
> I'm not sure if this is an improvement over the previous version. Again,
> my T-SQL example:
>
> DECLARE @t TABLE(i INT);
> INSERT INTO @t VALUES (1),(2),(3);
> RAISERROR('message 1', 16, 2, 3);
> RAISERROR('message 2', 16, 2, 3);
> SELECT * FROM @t
> RAISERROR('message 3', 16, 2, 3);
>
> As you can see, in such a batch, there is no strict notion of an error
> belonging to a count operation, or to a result operation. It's just an
> error. There might as well be no result at all, yet there could still be
> errors. E.g. when you run this:
>
> RAISERROR('message 1', 16, 2, 3);
> RAISERROR('message 2', 16, 2, 3);
> RAISERROR('message 3', 16, 2, 3);
>
> In the presence of both onCount and onRows handlers, would you pass the
> errors along with a synthetic count or a synthetic result, or both? What if
> there are several errors? Neither seems very compelling to me. There are
> three distinct types of result, which are not strictly connected:
>
> - Results / rows
> - Update counts
> - Errors
>
> Oh, and there are warnings too (SQLWarning), which are a special kind of
> error, which I currently don't see in the API.
>
> Lukas
>
> 2017-10-05 17:40 GMT+02:00 Douglas Surber <douglas.surber at oracle.com>:
>
>> Lukas,
>>
>> On further thought, the onError handler is not needed. Each Operation has
>> an error handler so the onCount and onRows handlers have an opportunity to
>> configure an error handler specific to a result.
>>
>> conn.dynamicMultiOperation(sql)
>> .onCount( (n, op) -> {
>> op.onError( t -> handle(t) )
>> ….
>> .submit();
>> })
>> .submit();
>>
>> Given the design guideline that one way to do things is enough, I have
>> eliminated the onError handler. I do like having separate onCount and
>> onRows handlers so that is retained.
>>
>> Douglas
>>
>> On Oct 5, 2017, at 8:12 AM, Douglas Surber <DOUGLAS.SURBER at oracle.com>
>> wrote:
>>
>> Lukas,
>>
>> If there is no handler for a particular result, e.g. no onRows handler
>> and a rows result is returned, that result is ignored. If an error is
>> limited to a specific result it would be passed to the onError handler if
>> one exists. If there is no onError handler, such an error is ignored. If an
>> error is not limited to a specific result then the Operation is completed
>> exceptionally.
>>
>> Does that work?
>>
>> Does there need to be a way to abort processing subsequent results? What
>> happens when a handler throws an exception?
>>
>> Douglas
>>
>>
>> On Oct 5, 2017, at 2:14 AM, Lukas Eder <lukas.eder at gmail.com> wrote:
>>
>> I like your suggestion of having three separate handlers (which may point
>> to the same handler if the API user so desires). It is definitely cleaner
>> than having a three-arg handler.
>>
>> In classic JDBC, the relevant call is statement.getMoreResults() and the
>> user is free to completely ignore the result, e.g. by not calling
>> statement.getResultSet() or statement.getUpdateCount(). However, now I
>> wonder how the new DynamicMultiOperation.onError(BiConsumer<Integer,
>> Throwable>) method would communicate with the pre-existing
>> Operation.onError(Consumer<Throable>) method...
>>
>> 2017-10-04 18:21 GMT+02:00 Douglas Surber <douglas.surber at oracle.com>:
>>
>>> Interlaced errors was not considered. It would be simple to add a
>>> Throwable as a third arg to ResultHandler.handle. Having two args of which
>>> one was always null is a bit of a hack. Three is definitely a hack. So I
>>> would eliminate ResultHandler and add the following methods to
>>> DynamicMultiOperation:
>>>
>>> public DynamicMultiOperation<T> onCount(BiConsumer<Integer,
>>> CountOperation<T>> handler);
>>> public DynamicMultiOperation<T> onRows(BiConsumer<Integer,
>>> RowOperation<T>> handler);
>>> public DynamicMultiOperation<T> onError(BiConsumer<Integer, Throwable>
>>> handler);
>>>
>>> If there is no handler for a result the result is ignored or the
>>> Operation completes exceptionally. Not sure which would be better.
>>>
>>> Douglas
>>>
>>>
>>> > On Oct 4, 2017, at 2:22 AM, Lukas Eder <lukas.eder at gmail.com> wrote:
>>> >
>>> > Hello,
>>> >
>>> > The java.sql2 API contains a DynamicMultiOperation type which seems
>>> > intended for use with statement batches or procedure calls that
>>> produce an
>>> > unknown set of:
>>> >
>>> > - Update counts
>>> > - Result sets
>>> > - Exceptions
>>> >
>>> > Unfortunately, I'm missing the part where interlaced exceptions can be
>>> > received. This may be SQL Server (and perhaps MySQL) specific, as I
>>> haven't
>>> > really encountered this in any other databases. But in SQL Server, when
>>> > running the following statement batch:
>>> >
>>> > DECLARE @t TABLE(i INT);
>>> > INSERT INTO @t VALUES (1),(2),(3);
>>> > RAISERROR('message 1', 16, 2, 3);
>>> > RAISERROR('message 2', 16, 2, 3);
>>> > SELECT * FROM @t
>>> > RAISERROR('message 3', 16, 2, 3);
>>> >
>>> > We can run the following, complete program (taken from a blog post I've
>>> > written recently [1]):
>>> >
>>> > String sql = "DECLARE @t TABLE(i INT);\r\n" +
>>> > "INSERT INTO @t VALUES (1),(2),(3);\r\n" +
>>> > "RAISERROR('message 1', 16, 2, 3);\r\n" +
>>> > "RAISERROR('message 2', 16, 2, 3);\r\n" +
>>> > "SELECT * FROM @t\r\n" +
>>> > "RAISERROR('message 3', 16, 2, 3);";
>>> > try (Connection c = new
>>> > com.microsoft.sqlserver.jdbc.SQLServerDriver().connect(url,
>>> properties);
>>> > Statement s = c.createStatement()) {
>>> >
>>> > fetchLoop:
>>> > for (int i = 0, updateCount = 0; i < 256; i++) {
>>> > try {
>>> > boolean result = (i == 0)
>>> > ? s.execute(sql)
>>> > : s.getMoreResults();
>>> >
>>> > SQLWarning w = s.getWarnings();
>>> > for (int j = 0; j < 255 && w != null; j++) {
>>> > System.out.println("Warning : " +
>>> w.getMessage());
>>> > w = w.getNextWarning();
>>> > }
>>> >
>>> > s.clearWarnings();
>>> >
>>> > if (result)
>>> > try (ResultSet rs = s.getResultSet()) {
>>> > System.out.println("Result :");
>>> > ResultSetMetaData m = rs.getMetaData();
>>> >
>>> > while (rs.next())
>>> > for (int col = 1; col <= m.getColumnCount();
>>> > col++)
>>> > System.out.println(
>>> > " " + m.getColumnName(col) +
>>> > ": " + rs.getInt(col));
>>> > }
>>> > else if ((updateCount = s.getUpdateCount()) != -1)
>>> > System.out.println("Update Count: " + updateCount);
>>> > else
>>> > break fetchLoop;
>>> > }
>>> > catch (SQLException e) {
>>> > System.out.println("Exception : " + e.getMessage());
>>> > }
>>> > }
>>> > }
>>> >
>>> >
>>> > And get this result:
>>> >
>>> > Update Count: 3
>>> > Exception : message 1
>>> > Exception : message 2
>>> > Result :
>>> > i: 1
>>> > i: 2
>>> > i: 3
>>> > Exception : message 3
>>> >
>>> > I currently don't see a way how the exception messages "message 1" /
>>> > "message 2" / "message 3" can be fetched through the
>>> DynamicMultiOperation.
>>> > Could you perhaps show an example?
>>> >
>>> > Thanks,
>>> > Lukas
>>> >
>>> > [1]:
>>> > https://blog.jooq.org/2017/07/13/how-i-incorrectly-fetched-j
>>> dbc-resultsets-again/
>>> <https://urldefense.proofpoint.com/v2/url?u=https-3A__blog.jooq.org_2017_07_13_how-2Di-2Dincorrectly-2Dfetched-2Djdbc-2Dresultsets-2Dagain_&d=DwMFaQ&c=RoP1YumCXCgaWHvlZYR8PQcxBKCX5YTpkKY057SbK10&r=ChRVNBZ3Ru5F7CzL9kG_sNBRUO0uuqD6z6ltcMO-LbA&m=56RBDwLoPx1hjE7ozVe90yWivV6VyNiMfXWMyf3pnLw&s=jCcOZl10pZh4vO0d15g0aat2s7O9RrEPwMWcP8IVfl0&e=>
>>>
>>>
>>
>>
>>
>
>
More information about the jdbc-spec-discuss
mailing list