java.sql2 DynamicMultiOperation with interlaced exceptions

Douglas Surber douglas.surber at oracle.com
Thu Oct 5 15:40:34 UTC 2017


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 <mailto: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 <mailto: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 <mailto: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-jdbc-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