From davecramer at gmail.com Tue May 1 01:42:36 2018 From: davecramer at gmail.com (Dave Cramer) Date: Mon, 30 Apr 2018 21:42:36 -0400 Subject: Collectors versus Flow.Subscriber In-Reply-To: References: Message-ID: On 30 April 2018 at 12:06, Douglas Surber wrote: > We haven?t discussed much aside from ANSI SQL. I don?t know anything about > postgresql logical decoding. Is it a row sequence? If so then either > RowOperation or RowProcessorOperation should do fine. If it returns a > result that doesn?t map to an ANSI SQL result then it would require a > vendor specific extension. > > No it is not a row sequence perse. It is stream of changes in the database. Dave Cramer Douglas > > > On Apr 28, 2018, at 1:21 PM, Alexander Kj?ll > wrote: > > > > Hi > > > > I have been poking around writing an implementation of ADBA for > postgresql > > and have a question regarding how 'endless' datastreams should be > handled. > > > > To take a concrete case is the feature in postgresql that's called > logical > > decoding, it lets a user subscribe to the replication stream from the > > database. > > > > This isn't a stream that has an end, and by that account it doesn't > really > > in the stream model with collectors and would maybe fit better with the > > Flow.Subscriber model. > > > > Have this usecase been considered and is there a way to implement this > that > > I haven't seen? > > > > best regards > > Alexander Kj?ll > > From lukas.eder at gmail.com Tue May 1 07:41:18 2018 From: lukas.eder at gmail.com (Lukas Eder) Date: Tue, 1 May 2018 09:41:18 +0200 Subject: ADBA feedback In-Reply-To: <584803DD-CEF5-4010-8F17-809369FA36E3@oracle.com> References: <2A60BE56-E2E6-4A99-BE9E-9B90794CF82E@oracle.com> <87BE9865-29B4-4435-9665-96EC54C1B812@oracle.com> <82C0E82F-6DD0-408C-8545-975D88EE9861@oracle.com> <584803DD-CEF5-4010-8F17-809369FA36E3@oracle.com> Message-ID: Indeed, once client code works *directly* with JDBC, I agree that index-based access is a big pain. But most people have worked around these limitations by using either some third party tool (simple wrappers, like Spring's JdbcTemplate or JDBI, Apache DbUtils), or they wrote some mapper / query builder like jOOQ that abstracts over the queries themselves such that an actual object model would hide the concrete column indexes. I've always seen JDBC as a lower level API that abstracts over the network protocol, but that still needs additional abstraction on top of it from client code. From that perspective, it's OK for the lower level API to be lower level and thus make index based access first class citizens. I do appreciate your effort to include the higher level convenience in the API itself, of course, but I don't think the two API "parts" really have to compete with one another. They're for different target audiences: - Name based: For programmers writing business logic directly with JDBC / ADBA - Index based: For programmers writing generic infrastructure logic on top of JDBC / ADBA Having said so, given that JDBC already does offer name based access, why wasn't that being used in those two JDBC apps you've maintained? 2018-04-30 18:25 GMT+02:00 Douglas Surber : > I have maintained two JDBC apps. One uses column indexes and the other > column names. Maintenance on the one that uses indexes is a nightmare. > Everyone that works on it spends an inordinate amount of time counting and > recounting columns trying to get the indexes right. Every time a query or > table changes there is a lot of breakage because the column indexes shift. > Fixing that is painful. Using names these problems do not occur. > > I understand your arguments for column indexes. My experience has been > that they are problematic. I?d like to find a solution that addresses the > use cases you describe and at the same time addresses the maintenance > problems I have seen with using indexes. > > The following is not strictly a serious proposal. It is a attempt to > inspire alternate solutions. > > /** > * Return the value of the column identified by name at the specified > index. If both name and > * index are specified then the column at the specified index must be > identified by name. Either > * but not both may be null in which case only the non-null value is > used. > */ > public T get(String name, int index, Class type) throws > IllegalArgumentException; > > If there are several similar columns in sequence, then an off-by-one error > may be difficult to detect. The redundant specification of the column makes > it easier to detect such errors. While it allows runtime detection of > errors, it doesn?t eliminate column counting and index shifting. > > With respect to case, I?d say the spec should be silent. Vendors can do > whatever is appropriate for their database. For example Oracle Database > would likely ignore case but would support case-sensitive double quoted > identifiers, ?\?lower case identifier with spaces\??. > > Douglas > > > On Apr 30, 2018, at 1:59 AM, Mark Rotteveel > wrote: > > > > On 30-4-2018 10:35, Lukas Eder wrote: > >> 2018-04-30 10:28 GMT+02:00 Mark Rotteveel >: > >> Retrieval by column label in JDBC is case insensitive by > >> specification, and I think that ADBA should maintain that. That is > >> irrespective if the label was originally case sensitive or not. > >> Interesting, thanks I wasn't aware of that (you see, I've never really > used the API) :) > > > > Not sure if you're joking or not :| > > > >> So, in the event of a query like this: > >> SELECT 1 AS "A", 2 AS "a" > >> In JDBC, the index-based API is the only one that works, despite the > query being correct SQL, producing two explicitly distinct column names > (even if that's an edge case). > > > > Yes, and in JDBC that is also in the specification :): > > > > """ > > Column names used as input to getter methods are case insensitive. When > a getter method is called with a column name and several columns have the > same name, the value of the first matching column will be returned. The > column name option is designed to be used when column names are used in the > SQL query that generated the result set. For columns that are NOT > explicitly named in the query, it is best to use column numbers. If column > names are used, the programmer should take care to guarantee that they > uniquely refer to the intended columns, which can be assured with the SQL > AS clause. > > """ > > > > -- > > Mark Rotteveel > > From alexander.kjall at gmail.com Tue May 1 11:09:03 2018 From: alexander.kjall at gmail.com (=?UTF-8?Q?Alexander_Kj=C3=A4ll?=) Date: Tue, 01 May 2018 11:09:03 +0000 Subject: Collectors versus Flow.Subscriber In-Reply-To: References: Message-ID: It can maybe be thought of as an row sequence with one row per event, and it should be possible to be represented as a RowOperation. But I was more thinking about back pressure, the collector interface doesn't really allow the implementation to signal to the driver that it can't handle the rate of traffic, and a busy event generator might overwhelm the consumer. This might maybe be a problem with normal queries also? I haven't done any testing of this, and I don't have any concrete code that demonstrates the problem. I can revisit this topic later when I have something more concrete to show and talk about. best regards Alexander Kj?ll Den m?n 30 apr. 2018 kl 18:06 skrev Douglas Surber < douglas.surber at oracle.com>: > We haven?t discussed much aside from ANSI SQL. I don?t know anything about postgresql logical decoding. Is it a row sequence? If so then either RowOperation or RowProcessorOperation should do fine. If it returns a result that doesn?t map to an ANSI SQL result then it would require a vendor specific extension. > Douglas > > On Apr 28, 2018, at 1:21 PM, Alexander Kj?ll wrote: > > > > Hi > > > > I have been poking around writing an implementation of ADBA for postgresql > > and have a question regarding how 'endless' datastreams should be handled. > > > > To take a concrete case is the feature in postgresql that's called logical > > decoding, it lets a user subscribe to the replication stream from the > > database. > > > > This isn't a stream that has an end, and by that account it doesn't really > > in the stream model with collectors and would maybe fit better with the > > Flow.Subscriber model. > > > > Have this usecase been considered and is there a way to implement this that > > I haven't seen? > > > > best regards > > Alexander Kj?ll From mark at lawinegevaar.nl Tue May 1 11:37:49 2018 From: mark at lawinegevaar.nl (Mark Rotteveel) Date: Tue, 1 May 2018 13:37:49 +0200 Subject: ADBA feedback In-Reply-To: <584803DD-CEF5-4010-8F17-809369FA36E3@oracle.com> References: <2A60BE56-E2E6-4A99-BE9E-9B90794CF82E@oracle.com> <87BE9865-29B4-4435-9665-96EC54C1B812@oracle.com> <82C0E82F-6DD0-408C-8545-975D88EE9861@oracle.com> <584803DD-CEF5-4010-8F17-809369FA36E3@oracle.com> Message-ID: On 30-4-2018 18:25, Douglas Surber wrote: > If there are several similar columns in sequence, then an off-by-one error may be difficult to detect. The redundant specification of the column makes it easier to detect such errors. While it allows runtime detection of errors, it doesn?t eliminate column counting and index shifting. > > With respect to case, I?d say the spec should be silent. Vendors can do whatever is appropriate for their database. For example Oracle Database would likely ignore case but would support case-sensitive double quoted identifiers, ?\?lower case identifier with spaces\??. I would really prefer if ADBA uses the same rules as JDBC, instead of just making this a free-for-all which will only lead to confusion and mismatches in expectations between drivers. Consistency is important. Mark -- Mark Rotteveel From lance.andersen at oracle.com Tue May 1 11:47:09 2018 From: lance.andersen at oracle.com (Lance Andersen) Date: Tue, 1 May 2018 07:47:09 -0400 Subject: ADBA feedback In-Reply-To: References: <2A60BE56-E2E6-4A99-BE9E-9B90794CF82E@oracle.com> <87BE9865-29B4-4435-9665-96EC54C1B812@oracle.com> <82C0E82F-6DD0-408C-8545-975D88EE9861@oracle.com> <584803DD-CEF5-4010-8F17-809369FA36E3@oracle.com> Message-ID: > On May 1, 2018, at 7:37 AM, Mark Rotteveel wrote: > > On 30-4-2018 18:25, Douglas Surber wrote: >> If there are several similar columns in sequence, then an off-by-one error may be difficult to detect. The redundant specification of the column makes it easier to detect such errors. While it allows runtime detection of errors, it doesn?t eliminate column counting and index shifting. >> With respect to case, I?d say the spec should be silent. Vendors can do whatever is appropriate for their database. For example Oracle Database would likely ignore case but would support case-sensitive double quoted identifiers, ?\?lower case identifier with spaces\??. > > I would really prefer if ADBA uses the same rules as JDBC, instead of just making this a free-for-all which will only lead to confusion and mismatches in expectations between drivers. Consistency is important. Yes, I agree something needs specified and as I mentioned in my previous email, > > Mark > > -- > Mark Rotteveel Lance Andersen| Principal Member of Technical Staff | +1.781.442.2037 Oracle Java Engineering 1 Network Drive Burlington, MA 01803 Lance.Andersen at oracle.com From douglas.surber at oracle.com Tue May 1 14:11:49 2018 From: douglas.surber at oracle.com (Douglas Surber) Date: Tue, 1 May 2018 07:11:49 -0700 Subject: ADBA feedback In-Reply-To: References: <2A60BE56-E2E6-4A99-BE9E-9B90794CF82E@oracle.com> <87BE9865-29B4-4435-9665-96EC54C1B812@oracle.com> <82C0E82F-6DD0-408C-8545-975D88EE9861@oracle.com> <584803DD-CEF5-4010-8F17-809369FA36E3@oracle.com> Message-ID: <26CD0941-AB70-4F01-8994-D5445278FA14@oracle.com> We are trying to avoid anything that requires the implementation to scan the SQL. The goal is for an implementation to use the info provided by ADBA calls to create network packets. Since each vendor?s network protocol is different, the more ADBA specifies how the SQL and other user provided info is interpreted the more likely there will be a mismatch between ADBA and the network protocol. Another reason I am reluctant to require both indexed and named columns is that some databases may not have the info to support both. Same for parameters. Referring to Lukas?s most recent comments, most frameworks that sit on top of JDBC have a vendor plug-in that handles the differences between databases and drivers. I expect the same to be true for ADBA. We want the overall architecture of ADBA code to be the same for each database so that frameworks can keep that logic in common. The details of database specific SQL, column ids and parameter ids would be in the database plug-in. Rather than require the ADBA implementation to translate from some ?ADBA SQL? to the database SQL (and ids) we think it is better that the framework or programmer generate the database specific form in the first place. Douglas > On May 1, 2018, at 4:37 AM, Mark Rotteveel wrote: > > On 30-4-2018 18:25, Douglas Surber wrote: >> If there are several similar columns in sequence, then an off-by-one error may be difficult to detect. The redundant specification of the column makes it easier to detect such errors. While it allows runtime detection of errors, it doesn?t eliminate column counting and index shifting. >> With respect to case, I?d say the spec should be silent. Vendors can do whatever is appropriate for their database. For example Oracle Database would likely ignore case but would support case-sensitive double quoted identifiers, ?\?lower case identifier with spaces\??. > > I would really prefer if ADBA uses the same rules as JDBC, instead of just making this a free-for-all which will only lead to confusion and mismatches in expectations between drivers. Consistency is important. > > Mark > > -- > Mark Rotteveel From douglas.surber at oracle.com Tue May 1 14:57:03 2018 From: douglas.surber at oracle.com (Douglas Surber) Date: Tue, 1 May 2018 07:57:03 -0700 Subject: Collectors versus Flow.Subscriber In-Reply-To: References: Message-ID: This sounds like it does not match any ANSI SQL result which means it will not be supported by standard ADBA. There is absolutely no reason that a postgres ADBA driver could not have an extension that supports such an operation. With the current spec it is possible to gain access to implementation extensions with few or no casts. If the DataSource is typed with the implementation specific type and the implementation adds all the necessary covariant overrides, then an extension is transparently accessible. public void example(VendorDataSource vds) { try (VendorConnection vc = vds.getConnection()) { vc.vendorOperation(sql) .set(?parameter?, value, AdbaType.VARCHAR) .vendorMethod() .submit(); } } Notice that vds.getConnection can be assigned to a VendorConnection without a cast and that vendorMethod can be called on the result of the standard method set. (This assumes vendorOperation implements ParameterizedOperation.) Douglas > On Apr 30, 2018, at 6:42 PM, Dave Cramer wrote: > > > > > On 30 April 2018 at 12:06, Douglas Surber > wrote: > We haven?t discussed much aside from ANSI SQL. I don?t know anything about postgresql logical decoding. Is it a row sequence? If so then either RowOperation or RowProcessorOperation should do fine. If it returns a result that doesn?t map to an ANSI SQL result then it would require a vendor specific extension. > > > No it is not a row sequence perse. It is stream of changes in the database. > > Dave Cramer > > > Douglas > > > On Apr 28, 2018, at 1:21 PM, Alexander Kj?ll > wrote: > > > > Hi > > > > I have been poking around writing an implementation of ADBA for postgresql > > and have a question regarding how 'endless' datastreams should be handled. > > > > To take a concrete case is the feature in postgresql that's called logical > > decoding, it lets a user subscribe to the replication stream from the > > database. > > > > This isn't a stream that has an end, and by that account it doesn't really > > in the stream model with collectors and would maybe fit better with the > > Flow.Subscriber model. > > > > Have this usecase been considered and is there a way to implement this that > > I haven't seen? > > > > best regards > > Alexander Kj?ll > > From douglas.surber at oracle.com Tue May 1 14:58:44 2018 From: douglas.surber at oracle.com (Douglas Surber) Date: Tue, 1 May 2018 07:58:44 -0700 Subject: Collectors versus Flow.Subscriber In-Reply-To: References: Message-ID: <09BEC425-3A0E-49A8-AEB6-52693A5D5ECA@oracle.com> If it is a row sequence then a RowProcessorOperation should be exactly what you need. Douglas > On May 1, 2018, at 4:09 AM, Alexander Kj?ll wrote: > > It can maybe be thought of as an row sequence with one row per event, and > it should be possible to be represented as a RowOperation. > > But I was more thinking about back pressure, the collector interface > doesn't really allow the implementation to signal to the driver that it > can't handle the rate of traffic, and a busy event generator might > overwhelm the consumer. This might maybe be a problem with normal queries > also? > > I haven't done any testing of this, and I don't have any concrete code that > demonstrates the problem. I can revisit this topic later when I have > something more concrete to show and talk about. > > best regards > Alexander Kj?ll > > Den m?n 30 apr. 2018 kl 18:06 skrev Douglas Surber < > douglas.surber at oracle.com>: > >> We haven?t discussed much aside from ANSI SQL. I don?t know anything > about postgresql logical decoding. Is it a row sequence? If so then either > RowOperation or RowProcessorOperation should do fine. If it returns a > result that doesn?t map to an ANSI SQL result then it would require a > vendor specific extension. > >> Douglas > >>> On Apr 28, 2018, at 1:21 PM, Alexander Kj?ll > wrote: >>> >>> Hi >>> >>> I have been poking around writing an implementation of ADBA for > postgresql >>> and have a question regarding how 'endless' datastreams should be > handled. >>> >>> To take a concrete case is the feature in postgresql that's called > logical >>> decoding, it lets a user subscribe to the replication stream from the >>> database. >>> >>> This isn't a stream that has an end, and by that account it doesn't > really >>> in the stream model with collectors and would maybe fit better with the >>> Flow.Subscriber model. >>> >>> Have this usecase been considered and is there a way to implement this > that >>> I haven't seen? >>> >>> best regards >>> Alexander Kj?ll From mark at lawinegevaar.nl Tue May 1 15:24:36 2018 From: mark at lawinegevaar.nl (Mark Rotteveel) Date: Tue, 1 May 2018 17:24:36 +0200 Subject: ADBA feedback In-Reply-To: References: <2A60BE56-E2E6-4A99-BE9E-9B90794CF82E@oracle.com> <2F2B6089-C994-4441-9DB6-9472F20BEDDB@oracle.com> Message-ID: <2364e70f-d101-fd49-1a6b-db490bf46316@lawinegevaar.nl> Thanks, I have reached out to Dave, and we are discussing things now. On 27-4-2018 18:11, Lance Andersen wrote: > Maybe sync up with Dave Cramer. ?Please see https://github.com/pgjdbc/AoJ/ > > >> On Apr 27, 2018, at 11:53 AM, Mark Rotteveel > > wrote: >> >> On 27-4-2018 16:36, Douglas Surber wrote: >>> The world doesn?t need more than one implementation of AoJ. AoJ is >>> purely a descriptive name; there is nothing creative about it. >>> Perhaps our biggest goal in creating AoJ was to jump start a >>> community project to create an AoJ implementation. So a community AoJ >>> fork could (should) use the AoJ name though a different package. >> >> I think idea this has a bootstrapping problem. There needs to be one >> such initiative (and - hopefully - only one), and there needs to be >> sufficient traction for that to remain alive. >> >> I'm willing to create an organization on GitHub that contains such a >> fork, but - partly due to health issues - I really don't have the time >> and energy to be very actively contributing or involved in that for >> the foreseeable future. And that can easily be the downfall of such a >> fork. >> >> Would there be any objections to create a GitHub organization called >> adba-community, or maybe jdbc-community (which would allow it to be >> broader than just AoJ and ADBA)? -- Mark Rotteveel From alexander.kjall at gmail.com Tue May 1 15:28:49 2018 From: alexander.kjall at gmail.com (=?UTF-8?Q?Alexander_Kj=C3=A4ll?=) Date: Tue, 01 May 2018 15:28:49 +0000 Subject: Collectors versus Flow.Subscriber In-Reply-To: <09BEC425-3A0E-49A8-AEB6-52693A5D5ECA@oracle.com> References: <09BEC425-3A0E-49A8-AEB6-52693A5D5ECA@oracle.com> Message-ID: Thanks for the input, It was valueble. I hadn't realized that doing a vendor extension was so easy for the user, it looks like the correct approach to solve this. best regards Alexander Kj?ll Den tis 1 maj 2018 kl 16:58 skrev Douglas Surber : > If it is a row sequence then a RowProcessorOperation should be exactly what you need. > Douglas > > On May 1, 2018, at 4:09 AM, Alexander Kj?ll wrote: > > > > It can maybe be thought of as an row sequence with one row per event, and > > it should be possible to be represented as a RowOperation. > > > > But I was more thinking about back pressure, the collector interface > > doesn't really allow the implementation to signal to the driver that it > > can't handle the rate of traffic, and a busy event generator might > > overwhelm the consumer. This might maybe be a problem with normal queries > > also? > > > > I haven't done any testing of this, and I don't have any concrete code that > > demonstrates the problem. I can revisit this topic later when I have > > something more concrete to show and talk about. > > > > best regards > > Alexander Kj?ll > > > > Den m?n 30 apr. 2018 kl 18:06 skrev Douglas Surber < > > douglas.surber at oracle.com>: > > > >> We haven?t discussed much aside from ANSI SQL. I don?t know anything > > about postgresql logical decoding. Is it a row sequence? If so then either > > RowOperation or RowProcessorOperation should do fine. If it returns a > > result that doesn?t map to an ANSI SQL result then it would require a > > vendor specific extension. > > > >> Douglas > > > >>> On Apr 28, 2018, at 1:21 PM, Alexander Kj?ll < alexander.kjall at gmail.com> > > wrote: > >>> > >>> Hi > >>> > >>> I have been poking around writing an implementation of ADBA for > > postgresql > >>> and have a question regarding how 'endless' datastreams should be > > handled. > >>> > >>> To take a concrete case is the feature in postgresql that's called > > logical > >>> decoding, it lets a user subscribe to the replication stream from the > >>> database. > >>> > >>> This isn't a stream that has an end, and by that account it doesn't > > really > >>> in the stream model with collectors and would maybe fit better with the > >>> Flow.Subscriber model. > >>> > >>> Have this usecase been considered and is there a way to implement this > > that > >>> I haven't seen? > >>> > >>> best regards > >>> Alexander Kj?ll From douglas.surber at oracle.com Tue May 1 20:12:15 2018 From: douglas.surber at oracle.com (Douglas Surber) Date: Tue, 1 May 2018 13:12:15 -0700 Subject: ADBA feedback In-Reply-To: References: <2A60BE56-E2E6-4A99-BE9E-9B90794CF82E@oracle.com> <87BE9865-29B4-4435-9665-96EC54C1B812@oracle.com> <82C0E82F-6DD0-408C-8545-975D88EE9861@oracle.com> <584803DD-CEF5-4010-8F17-809369FA36E3@oracle.com> Message-ID: This is not intended as a solution to the id vs index issue, but rather as a proposal to address the question of case sensitivity etc. Douglas /** * Return the value indicated by the {@code id}. The {@code id} may be either * the id for an OUT parameter marker or for a column. See {@link OutOperation} and * {@link RowOperation}. * * The interpretation of the id is implementation dependent. An implementation * may interpret id in whatever way best supports the underlying database. For * example an implementation may ignore case, may define special characters, * or may impose specific syntax. An implementation could interpret the id * as the decimal representation of an integer, or could ignore case unless * the first and last characters of the id were double quotes. An implementation * should interpret the id in whatever way best supports the underlying * database with the least overhead to the implementation. An implementation * must specify how the id is interpreted. * * @param the type of the returned value * @param id the id of the column or OUT parameter marker * @param type the value indicated by {@code id} is converted to this type * @return a value of type {@code T} * @throws IllegalArgumentException if id is not the identifier of a value * in this {@link ResultMap} * @throws IllegalStateException if the call that was passed this {@link ResultMap} has * ended * @throws ClassCastException if the returned value cannot be converted to the * specified type -- ISSUE: Not really a class cast. Maybe a new unchecked exception. */ public T get(String id, Class type); > On May 1, 2018, at 4:47 AM, Lance Andersen wrote: > > >> On May 1, 2018, at 7:37 AM, Mark Rotteveel wrote: >> >> On 30-4-2018 18:25, Douglas Surber wrote: >>> If there are several similar columns in sequence, then an off-by-one error may be difficult to detect. The redundant specification of the column makes it easier to detect such errors. While it allows runtime detection of errors, it doesn?t eliminate column counting and index shifting. >>> With respect to case, I?d say the spec should be silent. Vendors can do whatever is appropriate for their database. For example Oracle Database would likely ignore case but would support case-sensitive double quoted identifiers, ?\?lower case identifier with spaces\??. >> >> I would really prefer if ADBA uses the same rules as JDBC, instead of just making this a free-for-all which will only lead to confusion and mismatches in expectations between drivers. Consistency is important. > > Yes, I agree something needs specified and as I mentioned in my previous email, > > >> >> Mark >> >> -- >> Mark Rotteveel > > > > Lance Andersen| Principal Member of Technical Staff | +1.781.442.2037 > Oracle Java Engineering > 1 Network Drive > Burlington, MA 01803 > Lance.Andersen at oracle.com > > > From lance.andersen at oracle.com Tue May 1 20:43:45 2018 From: lance.andersen at oracle.com (Lance Andersen) Date: Tue, 1 May 2018 16:43:45 -0400 Subject: ADBA feedback In-Reply-To: References: <2A60BE56-E2E6-4A99-BE9E-9B90794CF82E@oracle.com> <87BE9865-29B4-4435-9665-96EC54C1B812@oracle.com> <82C0E82F-6DD0-408C-8545-975D88EE9861@oracle.com> <584803DD-CEF5-4010-8F17-809369FA36E3@oracle.com> Message-ID: <10643648-9EF1-4C13-9D4D-834377872DCA@oracle.com> This is definitely heading in the right direction :-) We will want to break this into an implementation note in the javadoc. I will take a cut reworking and send it back out. > On May 1, 2018, at 4:12 PM, Douglas Surber wrote: > > This is not intended as a solution to the id vs index issue, but rather as a proposal to address the question of case sensitivity etc. > > Douglas > > > > /** > * Return the value indicated by the {@code id}. The {@code id} may be either > * the id for an OUT parameter marker or for a column. See {@link OutOperation} and > * {@link RowOperation}. > * > * The interpretation of the id is implementation dependent. An implementation > * may interpret id in whatever way best supports the underlying database. For > * example an implementation may ignore case, may define special characters, > * or may impose specific syntax. An implementation could interpret the id > * as the decimal representation of an integer, or could ignore case unless > * the first and last characters of the id were double quotes. An implementation > * should interpret the id in whatever way best supports the underlying > * database with the least overhead to the implementation. An implementation > * must specify how the id is interpreted. > * > * @param the type of the returned value > * @param id the id of the column or OUT parameter marker > * @param type the value indicated by {@code id} is converted to this type > * @return a value of type {@code T} > * @throws IllegalArgumentException if id is not the identifier of a value > * in this {@link ResultMap} > * @throws IllegalStateException if the call that was passed this {@link ResultMap} has > * ended > * @throws ClassCastException if the returned value cannot be converted to the > * specified type -- ISSUE: Not really a class cast. Maybe a new unchecked exception. > */ > public T get(String id, Class type); > > >> On May 1, 2018, at 4:47 AM, Lance Andersen wrote: >> >> >>> On May 1, 2018, at 7:37 AM, Mark Rotteveel wrote: >>> >>> On 30-4-2018 18:25, Douglas Surber wrote: >>>> If there are several similar columns in sequence, then an off-by-one error may be difficult to detect. The redundant specification of the column makes it easier to detect such errors. While it allows runtime detection of errors, it doesn?t eliminate column counting and index shifting. >>>> With respect to case, I?d say the spec should be silent. Vendors can do whatever is appropriate for their database. For example Oracle Database would likely ignore case but would support case-sensitive double quoted identifiers, ?\?lower case identifier with spaces\??. >>> >>> I would really prefer if ADBA uses the same rules as JDBC, instead of just making this a free-for-all which will only lead to confusion and mismatches in expectations between drivers. Consistency is important. >> >> Yes, I agree something needs specified and as I mentioned in my previous email, >> >> >>> >>> Mark >>> >>> -- >>> Mark Rotteveel >> >> >> >> Lance Andersen| Principal Member of Technical Staff | +1.781.442.2037 >> Oracle Java Engineering >> 1 Network Drive >> Burlington, MA 01803 >> Lance.Andersen at oracle.com >> >> >> > Lance Andersen| Principal Member of Technical Staff | +1.781.442.2037 Oracle Java Engineering 1 Network Drive Burlington, MA 01803 Lance.Andersen at oracle.com From douglas.surber at oracle.com Tue May 1 22:59:31 2018 From: douglas.surber at oracle.com (Douglas Surber) Date: Tue, 1 May 2018 15:59:31 -0700 Subject: ADBA feedback In-Reply-To: References: <2A60BE56-E2E6-4A99-BE9E-9B90794CF82E@oracle.com> <87BE9865-29B4-4435-9665-96EC54C1B812@oracle.com> <82C0E82F-6DD0-408C-8545-975D88EE9861@oracle.com> <584803DD-CEF5-4010-8F17-809369FA36E3@oracle.com> Message-ID: One was written using names, the other with indexes. I was not involved in the development of either. I?ve only done maintenance work on them. I don?t know why either followed the path it did. For what it is worth I did develop a JDBC app but it uses Hibernate and so names vs indexes is irrelevant. > On May 1, 2018, at 12:41 AM, Lukas Eder wrote: > > Having said so, given that JDBC already does offer name based access, why wasn't that being used in those two JDBC apps you've maintained? From mark at lawinegevaar.nl Wed May 2 15:44:27 2018 From: mark at lawinegevaar.nl (Mark Rotteveel) Date: Wed, 2 May 2018 17:44:27 +0200 Subject: ADBA feedback In-Reply-To: <2364e70f-d101-fd49-1a6b-db490bf46316@lawinegevaar.nl> References: <2A60BE56-E2E6-4A99-BE9E-9B90794CF82E@oracle.com> <2F2B6089-C994-4441-9DB6-9472F20BEDDB@oracle.com> <2364e70f-d101-fd49-1a6b-db490bf46316@lawinegevaar.nl> Message-ID: To give an update, Dave and I created www.asyncjdbc.org and created a project on https://gitlab.com/asyncjdbc/asyncjdbc with a fork of the ADBA-over-JDBC code from Oracle (from https://github.com/oracle/oracle-db-examples) We decided to call it asyncjdbc instead of AoJ or ADBA-over-JDBC because it is short but also clear about what it does. We're still setting things up, and when we have reorganized the code a bit and maybe given the site a bit more polish (actual content, replaced some placeholder content, etc), we'll post a real announcement (hopefully later this week). We chose GitLab instead of GitHub, as we hope some of their features will benefit the project. We may add a repository mirror on GitHub in the future if that is sensible (and not a maintenance nightmare), to that end we also reserved https://github.com/asyncjdbc. Mark On 1-5-2018 17:24, Mark Rotteveel wrote: > Thanks, I have reached out to Dave, and we are discussing things now. > > On 27-4-2018 18:11, Lance Andersen wrote: >> Maybe sync up with Dave Cramer. ?Please see >> https://github.com/pgjdbc/AoJ/ >> >> >>> On Apr 27, 2018, at 11:53 AM, Mark Rotteveel >> > wrote: >>> >>> On 27-4-2018 16:36, Douglas Surber wrote: >>>> The world doesn?t need more than one implementation of AoJ. AoJ is >>>> purely a descriptive name; there is nothing creative about it. >>>> Perhaps our biggest goal in creating AoJ was to jump start a >>>> community project to create an AoJ implementation. So a community >>>> AoJ fork could (should) use the AoJ name though a different package. >>> >>> I think idea this has a bootstrapping problem. There needs to be one >>> such initiative (and - hopefully - only one), and there needs to be >>> sufficient traction for that to remain alive. >>> >>> I'm willing to create an organization on GitHub that contains such a >>> fork, but - partly due to health issues - I really don't have the >>> time and energy to be very actively contributing or involved in that >>> for the foreseeable future. And that can easily be the downfall of >>> such a fork. >>> >>> Would there be any objections to create a GitHub organization called >>> adba-community, or maybe jdbc-community (which would allow it to be >>> broader than just AoJ and ADBA)? > > -- Mark Rotteveel From douglas.surber at oracle.com Wed May 2 17:42:19 2018 From: douglas.surber at oracle.com (Douglas Surber) Date: Wed, 2 May 2018 10:42:19 -0700 Subject: referencing columns Message-ID: <6FF4016A-015F-4F3C-BEE3-35508CE6461D@oracle.com> Here is another way to approach referencing columns. Replace ResultMap with Column as defined below. This is not a fully thought out proposal. It is instead an attempt to look at the problem from another direction and not get stuck with the same old JDBC ResultSet model. Douglas /** * A mutable handle to one value of an ordered sequence of columns or of * out parameters. Columns have a 1-based index and optionally an identifier. * Identifiers are not guaranteed to be unique. */ public interface Column extends Iterable, Iterator, Cloneable { /** * Return the value of this column as an instance of the given type. * * @param * @param type * @return */ public T get(Class type); /** * Return the identifier of this column. May be null. * * @return */ public String identifier(); /** * Return the 1-based index of this Column. * * @return */ public int index(); /** * Return the SQL type of the value of this column. * * @return */ public SqlType type(); /** * Modify this Column to point to the next value identified by id. * * @param id * @return this Column */ public Column at(String id); /** * Modify this Column to point to the value at index. The first value is at index 1. * Negative numbers count back from the last value. The last value is at * index -1. * * @param index * @return this Column */ public Column at(int index); /** * Return a new Column that is a handle to a subsequence of sequence of values * referenced by this Column. The subsequence consists of the length values in * order starting with the value this Column points to when this method is * called. This Column is not modified. * * @param length * @return a new Column. */ public Column slice(int length); /** * Return a new Column that is a duplicate of this Column. * * @return a new Column */ public Column clone(); /** * Modify this Column to point to the next value in the sequence. * * @return this Column */ @Override public Column next(); @Override public boolean hasNext(); static void sample(Column columns) { Map map = new HashMap(); for (Column m : columns) { map.put(m.identifier(), m.get(Integer.class)); } List l = new ArrayList(); for (Column m : columns.at(3).slice(5)) { l.add(m.get(String.class)); } Column addr = columns.clone().at("street_address_1"); String streetAddress1 = addr.get(String.class); String streetAddress2 = addr.next().get(String.class); String city = addr.next().get(String.class); String state = addr.next().get(String.class); String postalCode = addr.next().get(String.class); String givenName = columns.at("GIVEN_NAME").get(String.class); String familyName = columns.at("FAMILY_NAME").get(String.class); } } From douglas.surber at oracle.com Wed May 2 18:35:36 2018 From: douglas.surber at oracle.com (Douglas Surber) Date: Wed, 2 May 2018 11:35:36 -0700 Subject: ADBA feedback In-Reply-To: References: <2A60BE56-E2E6-4A99-BE9E-9B90794CF82E@oracle.com> <2F2B6089-C994-4441-9DB6-9472F20BEDDB@oracle.com> <2364e70f-d101-fd49-1a6b-db490bf46316@lawinegevaar.nl> Message-ID: <0DAF8837-2297-45C5-8886-CFEE285E38B8@oracle.com> I?m glad to hear this. While we don?t intend to continue active development of AoJ, I do intend to push changes to keep it in sync with ADBA. If there is anything I can do to make those changes more palatable to asyncjdbc, do let me know. I?m not an experienced git user so I have no idea what is possible. Douglas > On May 2, 2018, at 8:44 AM, Mark Rotteveel wrote: > > To give an update, Dave and I created www.asyncjdbc.org and created a project on https://gitlab.com/asyncjdbc/asyncjdbc with a fork of the ADBA-over-JDBC code from Oracle (from https://github.com/oracle/oracle-db-examples) > > We decided to call it asyncjdbc instead of AoJ or ADBA-over-JDBC because it is short but also clear about what it does. > > We're still setting things up, and when we have reorganized the code a bit and maybe given the site a bit more polish (actual content, replaced some placeholder content, etc), we'll post a real announcement (hopefully later this week). > > We chose GitLab instead of GitHub, as we hope some of their features will benefit the project. We may add a repository mirror on GitHub in the future if that is sensible (and not a maintenance nightmare), to that end we also reserved https://github.com/asyncjdbc. > > Mark > > On 1-5-2018 17:24, Mark Rotteveel wrote: >> Thanks, I have reached out to Dave, and we are discussing things now. >> On 27-4-2018 18:11, Lance Andersen wrote: >>> Maybe sync up with Dave Cramer. Please see https://github.com/pgjdbc/AoJ/ >>> >>> >>>> On Apr 27, 2018, at 11:53 AM, Mark Rotteveel > wrote: >>>> >>>> On 27-4-2018 16:36, Douglas Surber wrote: >>>>> The world doesn?t need more than one implementation of AoJ. AoJ is purely a descriptive name; there is nothing creative about it. Perhaps our biggest goal in creating AoJ was to jump start a community project to create an AoJ implementation. So a community AoJ fork could (should) use the AoJ name though a different package. >>>> >>>> I think idea this has a bootstrapping problem. There needs to be one such initiative (and - hopefully - only one), and there needs to be sufficient traction for that to remain alive. >>>> >>>> I'm willing to create an organization on GitHub that contains such a fork, but - partly due to health issues - I really don't have the time and energy to be very actively contributing or involved in that for the foreseeable future. And that can easily be the downfall of such a fork. >>>> >>>> Would there be any objections to create a GitHub organization called adba-community, or maybe jdbc-community (which would allow it to be broader than just AoJ and ADBA)? > > > -- > Mark Rotteveel From lance.andersen at oracle.com Wed May 2 21:22:39 2018 From: lance.andersen at oracle.com (Lance Andersen) Date: Wed, 2 May 2018 17:22:39 -0400 Subject: ADBA feedback In-Reply-To: <10643648-9EF1-4C13-9D4D-834377872DCA@oracle.com> References: <2A60BE56-E2E6-4A99-BE9E-9B90794CF82E@oracle.com> <87BE9865-29B4-4435-9665-96EC54C1B812@oracle.com> <82C0E82F-6DD0-408C-8545-975D88EE9861@oracle.com> <584803DD-CEF5-4010-8F17-809369FA36E3@oracle.com> <10643648-9EF1-4C13-9D4D-834377872DCA@oracle.com> Message-ID: <984DF927-0C34-4A67-BEBF-46FD0D6E0A60@oracle.com> Here is a slightly revised version ??????????? /** * Returns the value indicated by the {@code id} converted to the specified Java type. * The {@code id} may be either the name for an OUT parameter marker * or for a column. * * @apiNote * The value specified for {@code id} represents the name of a column or * parameter marker for the underlying datasource and is implementation * specific. This may be a simple SQL identifier, a quoted identifier, or * any other type of identifier supported by the datasource. *

* Consult your implementation's documentation for additional information. * * * @param the type of the returned value * @param id the name of the column or OUT parameter marker * @param type the value indicated by {@code id} is converted to this type * @return a value of type {@code T} * @throws IllegalArgumentException if id is not the identifier of a value * in this {@link ResultMap} * @throws IllegalStateException if the call that was passed this {@link ResultMap} has * ended * @throws ClassCastException if the returned value cannot be converted to the * specified type -- ISSUE: Not really a class cast. Maybe a new unchecked exception. * @see OutOperation * @see RowOperation */ public T get(String id, Class type); ???????????????? > On May 1, 2018, at 4:43 PM, Lance Andersen wrote: > > This is definitely heading in the right direction :-) > > We will want to break this into an implementation note in the javadoc. > > I will take a cut reworking and send it back out. > > >> On May 1, 2018, at 4:12 PM, Douglas Surber wrote: >> >> This is not intended as a solution to the id vs index issue, but rather as a proposal to address the question of case sensitivity etc. >> >> Douglas >> >> >> >> /** >> * Return the value indicated by the {@code id}. The {@code id} may be either >> * the id for an OUT parameter marker or for a column. See {@link OutOperation} and >> * {@link RowOperation}. >> * >> * The interpretation of the id is implementation dependent. An implementation >> * may interpret id in whatever way best supports the underlying database. For >> * example an implementation may ignore case, may define special characters, >> * or may impose specific syntax. An implementation could interpret the id >> * as the decimal representation of an integer, or could ignore case unless >> * the first and last characters of the id were double quotes. An implementation >> * should interpret the id in whatever way best supports the underlying >> * database with the least overhead to the implementation. An implementation >> * must specify how the id is interpreted. >> * >> * @param the type of the returned value >> * @param id the id of the column or OUT parameter marker >> * @param type the value indicated by {@code id} is converted to this type >> * @return a value of type {@code T} >> * @throws IllegalArgumentException if id is not the identifier of a value >> * in this {@link ResultMap} >> * @throws IllegalStateException if the call that was passed this {@link ResultMap} has >> * ended >> * @throws ClassCastException if the returned value cannot be converted to the >> * specified type -- ISSUE: Not really a class cast. Maybe a new unchecked exception. >> */ >> public T get(String id, Class type); >> >> >>> On May 1, 2018, at 4:47 AM, Lance Andersen wrote: >>> >>> >>>> On May 1, 2018, at 7:37 AM, Mark Rotteveel wrote: >>>> >>>> On 30-4-2018 18:25, Douglas Surber wrote: >>>>> If there are several similar columns in sequence, then an off-by-one error may be difficult to detect. The redundant specification of the column makes it easier to detect such errors. While it allows runtime detection of errors, it doesn?t eliminate column counting and index shifting. >>>>> With respect to case, I?d say the spec should be silent. Vendors can do whatever is appropriate for their database. For example Oracle Database would likely ignore case but would support case-sensitive double quoted identifiers, ?\?lower case identifier with spaces\??. >>>> >>>> I would really prefer if ADBA uses the same rules as JDBC, instead of just making this a free-for-all which will only lead to confusion and mismatches in expectations between drivers. Consistency is important. >>> >>> Yes, I agree something needs specified and as I mentioned in my previous email, >>> >>> >>>> >>>> Mark >>>> >>>> -- >>>> Mark Rotteveel >>> >>> >>> >>> Lance Andersen| Principal Member of Technical Staff | +1.781.442.2037 >>> Oracle Java Engineering >>> 1 Network Drive >>> Burlington, MA 01803 >>> Lance.Andersen at oracle.com >>> >>> >>> >> > > > > Lance Andersen| Principal Member of Technical Staff | +1.781.442.2037 > Oracle Java Engineering > 1 Network Drive > Burlington, MA 01803 > Lance.Andersen at oracle.com > > > Lance Andersen| Principal Member of Technical Staff | +1.781.442.2037 Oracle Java Engineering 1 Network Drive Burlington, MA 01803 Lance.Andersen at oracle.com From DOUGLAS.SURBER at oracle.com Wed May 2 23:07:53 2018 From: DOUGLAS.SURBER at oracle.com (Douglas Surber) Date: Wed, 2 May 2018 16:07:53 -0700 Subject: Non-Blocking JDBC API In-Reply-To: References: <6C68689C-9C2F-42C8-BCEB-9B47D10DD3CE@oracle.com> <50c3281e-b849-7417-ddec-9878a622053d@gmail.com> <226a7638-e5ab-0cf2-c1fa-9525d727501f@gmail.com> Message-ID: <0F3E4B11-3DC4-4925-9BE7-C461865C71FA@oracle.com> > On May 2, 2018, at 9:14 AM, Lance Andersen > wrote: > On May 1, 2018, at 8:02 PM, Rick Hillegas > wrote: >> Transaction management confuses me. What kinds of problems are solved by passing around a Transaction object rather than simply calling the commit()/rollback() methods on Connection? For those use-cases, why is it bad to pass around the Connection itself? Why is commitMaybeRollback() in the OperationGroup interface rather than in the Connection interface? What other OperationGroups are imagined besides Connection? > > Douglas, can you answer this for Rick. > endTransactinoOperation() is in OperationGroup as it makes sense to have an endTransactionOperation as a member Operation of an OperationGroup. This is especially obvious if the OperationGroup is conditional. commitMaybeRollback is also in OperationGroup as it?s default implementation is possible in OperationGroup. commit() and rollback() are not in OperationGroup as their default implementations call transaction() which is only declared in Connection. transaction() is only in Connection because it is global, ie not restricted to a particular OperationGroup. It would be misleading to put transaction in OperationGroup. I don?t expect the standard to define any other sub-types of OperationGroup other than Connection. OperationGroup itself will have concrete implementations in the various ADBA drivers. There are a number of use cases for OperationGroup independent of Connection. The transaction model was difficult to arrive at but this one works. The problem that it has to address is timing. Conceptually there are two execution sequences that have to be considered: the app thread execution sequence that creates and submits the Operations and the async execution sequence that runs as the Operations are executed. In the ideal case the app thread will create and submit all the Operations including Connection.closeOperation long before the Connection.connectOperation has returned. So before the first Operation is completed any transactionEndOperation must be submitted. (commit(), rollback(), and commitMaybeRollback all submit a transactionEndOperation.) Requiring the app to decide whether to commit or rollback before the first Operation completes is unreasonable. So the endTransactionOperation must be conditioned by something that the async thread can modify. (Modifying the endTransactionOperation itself doesn?t work for a variety of reasons.) That something is the Transaction. (Please suggest alternate names.) Passing around the Connection doesn?t work because the Connection.closeOperation has already been submitted. The async thread cannot submit an endTransactionOperation as it would be executed after the closeOperation. The first cut at this model made the relationship between endTransactionOperation and the decision to commit or rollback implicit. That was exceedingly hard to describe and completely impossible to understand. Making endTransactionOperation take a Transaction argument, thus making the relationship between the endTransactionOperation and the decision to commit or rollback explicit made this much easier to describe and understand. I believe that you understand how to use Transaction. The questions you and others have asked are about what motivates it, not how to use it. I don?t think commit() and rollback() are particularly useful and would be completely happy to remove them. Douglas From lukas.eder at gmail.com Thu May 3 08:23:45 2018 From: lukas.eder at gmail.com (Lukas Eder) Date: Thu, 3 May 2018 10:23:45 +0200 Subject: referencing columns In-Reply-To: <6FF4016A-015F-4F3C-BEE3-35508CE6461D@oracle.com> References: <6FF4016A-015F-4F3C-BEE3-35508CE6461D@oracle.com> Message-ID: Hi Douglas, This type would be very interesting. Akin to JDBC's ResultSetMetaData type, but more object oriented. Mixed with JDBC's ResultSet's notion of being a cursor with a current position. Of course, this cursor-ness is precisely the "old JDBC ResultSet" model, which is understandable from the perspective of a result set being a flattened stream of column/value pairs, but I think that few people think about result sets or records in this way. In JDBC, most people would like to fetch a List style type. In ADBA, being asynchronous, a Consumer style type (simplified Collector) seems appropriate. Putting the individual column and its value at the top abstraction level might be surprising. What would be the benefit of this approach? 2018-05-02 19:42 GMT+02:00 Douglas Surber : > Here is another way to approach referencing columns. Replace ResultMap > with Column as defined below. This is not a fully thought out proposal. It > is instead an attempt to look at the problem from another direction and not > get stuck with the same old JDBC ResultSet model. > > Douglas > > /** > * A mutable handle to one value of an ordered sequence of columns or of > * out parameters. Columns have a 1-based index and optionally an > identifier. > * Identifiers are not guaranteed to be unique. > */ > public interface Column extends Iterable, Iterator, > Cloneable { > > /** > * Return the value of this column as an instance of the given type. > * > * @param > * @param type > * @return > */ > public T get(Class type); > > /** > * Return the identifier of this column. May be null. > * > * @return > */ > public String identifier(); > > /** > * Return the 1-based index of this Column. > * > * @return > */ > public int index(); > > /** > * Return the SQL type of the value of this column. > * > * @return > */ > public SqlType type(); > > /** > * Modify this Column to point to the next value identified by id. > * > * @param id > * @return this Column > */ > public Column at(String id); > > /** > * Modify this Column to point to the value at index. The first value is > at index 1. > * Negative numbers count back from the last value. The last value is at > * index -1. > * > * @param index > * @return this Column > */ > public Column at(int index); > > /** > * Return a new Column that is a handle to a subsequence of sequence of > values > * referenced by this Column. The subsequence consists of the length > values in > * order starting with the value this Column points to when this method > is > * called. This Column is not modified. > * > * @param length > * @return a new Column. > */ > public Column slice(int length); > > /** > * Return a new Column that is a duplicate of this Column. > * > * @return a new Column > */ > public Column clone(); > > /** > * Modify this Column to point to the next value in the sequence. > * > * @return this Column > */ > @Override > public Column next(); > > @Override > public boolean hasNext(); > > > static void sample(Column columns) { > > Map map = new HashMap(); > for (Column m : columns) { > map.put(m.identifier(), m.get(Integer.class)); > } > > List l = new ArrayList(); > for (Column m : columns.at(3).slice(5)) { > l.add(m.get(String.class)); > } > > Column addr = columns.clone().at("street_address_1"); > String streetAddress1 = addr.get(String.class); > String streetAddress2 = addr.next().get(String.class); > String city = addr.next().get(String.class); > String state = addr.next().get(String.class); > String postalCode = addr.next().get(String.class); > > String givenName = columns.at("GIVEN_NAME").get(String.class); > String familyName = columns.at("FAMILY_NAME").get(String.class); > > } > } > > From mark at lawinegevaar.nl Thu May 3 08:30:33 2018 From: mark at lawinegevaar.nl (Mark Rotteveel) Date: Thu, 3 May 2018 10:30:33 +0200 Subject: ADBA feedback In-Reply-To: <0DAF8837-2297-45C5-8886-CFEE285E38B8@oracle.com> References: <2A60BE56-E2E6-4A99-BE9E-9B90794CF82E@oracle.com> <2F2B6089-C994-4441-9DB6-9472F20BEDDB@oracle.com> <2364e70f-d101-fd49-1a6b-db490bf46316@lawinegevaar.nl> <0DAF8837-2297-45C5-8886-CFEE285E38B8@oracle.com> Message-ID: On 2-5-2018 20:35, Douglas Surber wrote: > I?m glad to hear this. > > While we don?t intend to continue active development of AoJ, I do intend to push changes to keep it in sync with ADBA. If there is anything I can do to make those changes more palatable to asyncjdbc, do let me know. I?m not an experienced git user so I have no idea what is possible. My git skills are 'adequate'. I have seen posts by people doing absolutely amazing magical things with git, but I wouldn't be able to replicate that :) We keep a separate branch with the content as it was when we copied it out the oracle-db-examples repository. Just gives a heads up when AoJ gets updated there, and we'll use that to 'track the changes', and apply them manually where necessary. I don't think efforts to be able to do this automatically will work well (or at least, the effort needed is probably too high compared to just doing it manually). Mark -- Mark Rotteveel From douglas.surber at oracle.com Thu May 3 15:33:48 2018 From: douglas.surber at oracle.com (Douglas Surber) Date: Thu, 3 May 2018 08:33:48 -0700 Subject: referencing columns In-Reply-To: References: <6FF4016A-015F-4F3C-BEE3-35508CE6461D@oracle.com> Message-ID: Lukas, This is orthogonal to the Flow.Processor vs Collector discussion. And please note that ADBA has both. Using a column cursor to access the columns is an attempt to break out of the get(int) vs get(String) way of thinking. I came up with this by thinking about all the different patterns of column access I?ve seen over the years and trying to wrap them up in a reasonably simple API. It quickly became clear that I needed to separate column selection from value access. Once I did that this class was an obvious consequence. It provides baked-in support for many different access patterns rather than requiring the programmer to roll his own. What I especially like is the way it supports mixing access patterns, for example locating a column by name, then iterating over a subsequence of successive columns. The advantage is that it should make it easy to avoid counting columns to come up with the desired index and at the same time handle missing and duplicate identifiers. From a framework perspective simple iteration over columns should be incredibly useful. Douglas > On May 3, 2018, at 1:23 AM, Lukas Eder wrote: > > Hi Douglas, > > This type would be very interesting. Akin to JDBC's ResultSetMetaData type, but more object oriented. Mixed with JDBC's ResultSet's notion of being a cursor with a current position. > > Of course, this cursor-ness is precisely the "old JDBC ResultSet" model, which is understandable from the perspective of a result set being a flattened stream of column/value pairs, but I think that few people think about result sets or records in this way. In JDBC, most people would like to fetch a List style type. In ADBA, being asynchronous, a Consumer style type (simplified Collector) seems appropriate. Putting the individual column and its value at the top abstraction level might be surprising. > > What would be the benefit of this approach? > > > 2018-05-02 19:42 GMT+02:00 Douglas Surber >: > Here is another way to approach referencing columns. Replace ResultMap with Column as defined below. This is not a fully thought out proposal. It is instead an attempt to look at the problem from another direction and not get stuck with the same old JDBC ResultSet model. > > Douglas > > /** > * A mutable handle to one value of an ordered sequence of columns or of > * out parameters. Columns have a 1-based index and optionally an identifier. > * Identifiers are not guaranteed to be unique. > */ > public interface Column extends Iterable, Iterator, Cloneable { > > /** > * Return the value of this column as an instance of the given type. > * > * @param > * @param type > * @return > */ > public T get(Class type); > > /** > * Return the identifier of this column. May be null. > * > * @return > */ > public String identifier(); > > /** > * Return the 1-based index of this Column. > * > * @return > */ > public int index(); > > /** > * Return the SQL type of the value of this column. > * > * @return > */ > public SqlType type(); > > /** > * Modify this Column to point to the next value identified by id. > * > * @param id > * @return this Column > */ > public Column at(String id); > > /** > * Modify this Column to point to the value at index. The first value is at index 1. > * Negative numbers count back from the last value. The last value is at > * index -1. > * > * @param index > * @return this Column > */ > public Column at(int index); > > /** > * Return a new Column that is a handle to a subsequence of sequence of values > * referenced by this Column. The subsequence consists of the length values in > * order starting with the value this Column points to when this method is > * called. This Column is not modified. > * > * @param length > * @return a new Column. > */ > public Column slice(int length); > > /** > * Return a new Column that is a duplicate of this Column. > * > * @return a new Column > */ > public Column clone(); > > /** > * Modify this Column to point to the next value in the sequence. > * > * @return this Column > */ > @Override > public Column next(); > > @Override > public boolean hasNext(); > > > static void sample(Column columns) { > > Map map = new HashMap(); > for (Column m : columns) { > map.put(m.identifier(), m.get(Integer.class)); > } > > List l = new ArrayList(); > for (Column m : columns.at (3).slice(5)) { > l.add(m.get(String.class)); > } > > Column addr = columns.clone().at("street_address_1"); > String streetAddress1 = addr.get(String.class); > String streetAddress2 = addr.next().get(String.class); > String city = addr.next().get(String.class); > String state = addr.next().get(String.class); > String postalCode = addr.next().get(String.class); > > String givenName = columns.at ("GIVEN_NAME").get(String.class); > String familyName = columns.at ("FAMILY_NAME").get(String.class); > > } > } > > From lukas.eder at gmail.com Fri May 4 07:56:31 2018 From: lukas.eder at gmail.com (Lukas Eder) Date: Fri, 4 May 2018 09:56:31 +0200 Subject: referencing columns In-Reply-To: References: <6FF4016A-015F-4F3C-BEE3-35508CE6461D@oracle.com> Message-ID: I agree that iterating over columns is very useful and I've noticed that you've mixed the two paradigms, which is also useful. If you pursue the thought of this API, will you consider separating the functionality into two types? - Columns extends Iterable (which is essentially ResultMap) - Column If not, what would be the motivation to make Column iterate on itself as a type? Lukas 2018-05-03 17:33 GMT+02:00 Douglas Surber : > Lukas, > > This is orthogonal to the Flow.Processor vs Collector discussion. And > please note that ADBA has both. > > Using a column cursor to access the columns is an attempt to break out of > the get(int) vs get(String) way of thinking. I came up with this by > thinking about all the different patterns of column access I?ve seen over > the years and trying to wrap them up in a reasonably simple API. It quickly > became clear that I needed to separate column selection from value access. > Once I did that this class was an obvious consequence. > > It provides baked-in support for many different access patterns rather > than requiring the programmer to roll his own. What I especially like is > the way it supports mixing access patterns, for example locating a column > by name, then iterating over a subsequence of successive columns. > > The advantage is that it should make it easy to avoid counting columns to > come up with the desired index and at the same time handle missing and > duplicate identifiers. From a framework perspective simple iteration over > columns should be incredibly useful. > > Douglas > > > On May 3, 2018, at 1:23 AM, Lukas Eder wrote: > > Hi Douglas, > > This type would be very interesting. Akin to JDBC's ResultSetMetaData > type, but more object oriented. Mixed with JDBC's ResultSet's notion of > being a cursor with a current position. > > Of course, this cursor-ness is precisely the "old JDBC ResultSet" model, > which is understandable from the perspective of a result set being a > flattened stream of column/value pairs, but I think that few people think > about result sets or records in this way. In JDBC, most people would like > to fetch a List style type. In ADBA, being asynchronous, a Consumer< > Row> style type (simplified Collector) seems appropriate. Putting the > individual column and its value at the top abstraction level might be > surprising. > > What would be the benefit of this approach? > > > 2018-05-02 19:42 GMT+02:00 Douglas Surber : > >> Here is another way to approach referencing columns. Replace ResultMap >> with Column as defined below. This is not a fully thought out proposal. It >> is instead an attempt to look at the problem from another direction and not >> get stuck with the same old JDBC ResultSet model. >> >> Douglas >> >> /** >> * A mutable handle to one value of an ordered sequence of columns or of >> * out parameters. Columns have a 1-based index and optionally an >> identifier. >> * Identifiers are not guaranteed to be unique. >> */ >> public interface Column extends Iterable, Iterator, >> Cloneable { >> >> /** >> * Return the value of this column as an instance of the given type. >> * >> * @param >> * @param type >> * @return >> */ >> public T get(Class type); >> >> /** >> * Return the identifier of this column. May be null. >> * >> * @return >> */ >> public String identifier(); >> >> /** >> * Return the 1-based index of this Column. >> * >> * @return >> */ >> public int index(); >> >> /** >> * Return the SQL type of the value of this column. >> * >> * @return >> */ >> public SqlType type(); >> >> /** >> * Modify this Column to point to the next value identified by id. >> * >> * @param id >> * @return this Column >> */ >> public Column at(String id); >> >> /** >> * Modify this Column to point to the value at index. The first value >> is at index 1. >> * Negative numbers count back from the last value. The last value is at >> * index -1. >> * >> * @param index >> * @return this Column >> */ >> public Column at(int index); >> >> /** >> * Return a new Column that is a handle to a subsequence of sequence of >> values >> * referenced by this Column. The subsequence consists of the length >> values in >> * order starting with the value this Column points to when this method >> is >> * called. This Column is not modified. >> * >> * @param length >> * @return a new Column. >> */ >> public Column slice(int length); >> >> /** >> * Return a new Column that is a duplicate of this Column. >> * >> * @return a new Column >> */ >> public Column clone(); >> >> /** >> * Modify this Column to point to the next value in the sequence. >> * >> * @return this Column >> */ >> @Override >> public Column next(); >> >> @Override >> public boolean hasNext(); >> >> >> static void sample(Column columns) { >> >> Map map = new HashMap(); >> for (Column m : columns) { >> map.put(m.identifier(), m.get(Integer.class)); >> } >> >> List l = new ArrayList(); >> for (Column m : columns.at >> (3).slice(5)) >> { >> l.add(m.get(String.class)); >> } >> >> Column addr = columns.clone().at("street_address_1"); >> String streetAddress1 = addr.get(String.class); >> String streetAddress2 = addr.next().get(String.class); >> String city = addr.next().get(String.class); >> String state = addr.next().get(String.class); >> String postalCode = addr.next().get(String.class); >> >> String givenName = columns.at >> >> ("GIVEN_NAME").get(String.class); >> String familyName = columns.at >> >> ("FAMILY_NAME").get(String.class); >> >> } >> } >> >> > > From douglas.surber at oracle.com Fri May 4 14:28:06 2018 From: douglas.surber at oracle.com (Douglas Surber) Date: Fri, 4 May 2018 07:28:06 -0700 Subject: referencing columns In-Reply-To: References: <6FF4016A-015F-4F3C-BEE3-35508CE6461D@oracle.com> Message-ID: <5CFCCBF0-37D1-474A-B291-A21FB437F20D@oracle.com> I don?t think separating the types works. Column integrates several concepts and I think the combination is more useful than separating them. - Row, a sequence of columns - ColumnIterator - ColumnCursor points to a particular column and can move to point to other columns - Column provides access to the column value and metadata public interface Row extends Iterable{ public long rowNumber(); public Row cancel(); public ColumnCursor columnCursor(); // forEach, iterator, spliterator } public interface ColumnIterator extends Iterator { // forEachRemaining, hasNext, next, remove } public interface ColumnCursor public ColumnCursor next(); public boolean hasNext(); public ColumnCursor at(String id); public ColumnCursor at(int index); public Column get(); } public interface Column { public T get(Class type); public SqlType sqlType(); public Class javaType(); public String id(); public int index(); } In order to mix access patterns we have to add more methods. For example add getColumnCursor to Column in order to switch from iteration to motion. Next user code has to use those additional methods to navigate between the types to get to the right one. An always has to navigate to a Column to actually get a value. Finally there will be method duplication. All in all I think the result is much more complex and definitely much harder to use. I encourage you to actually write some code using both and see what you think. Douglas > On May 4, 2018, at 12:56 AM, Lukas Eder wrote: > > I agree that iterating over columns is very useful and I've noticed that you've mixed the two paradigms, which is also useful. > > If you pursue the thought of this API, will you consider separating the functionality into two types? > > - Columns extends Iterable (which is essentially ResultMap) > - Column > > If not, what would be the motivation to make Column iterate on itself as a type? > > Lukas > > 2018-05-03 17:33 GMT+02:00 Douglas Surber >: > Lukas, > > This is orthogonal to the Flow.Processor vs Collector discussion. And please note that ADBA has both. > > Using a column cursor to access the columns is an attempt to break out of the get(int) vs get(String) way of thinking. I came up with this by thinking about all the different patterns of column access I?ve seen over the years and trying to wrap them up in a reasonably simple API. It quickly became clear that I needed to separate column selection from value access. Once I did that this class was an obvious consequence. > > It provides baked-in support for many different access patterns rather than requiring the programmer to roll his own. What I especially like is the way it supports mixing access patterns, for example locating a column by name, then iterating over a subsequence of successive columns. > > The advantage is that it should make it easy to avoid counting columns to come up with the desired index and at the same time handle missing and duplicate identifiers. From a framework perspective simple iteration over columns should be incredibly useful. > > Douglas > > >> On May 3, 2018, at 1:23 AM, Lukas Eder > wrote: >> >> Hi Douglas, >> >> This type would be very interesting. Akin to JDBC's ResultSetMetaData type, but more object oriented. Mixed with JDBC's ResultSet's notion of being a cursor with a current position. >> >> Of course, this cursor-ness is precisely the "old JDBC ResultSet" model, which is understandable from the perspective of a result set being a flattened stream of column/value pairs, but I think that few people think about result sets or records in this way. In JDBC, most people would like to fetch a List style type. In ADBA, being asynchronous, a Consumer style type (simplified Collector) seems appropriate. Putting the individual column and its value at the top abstraction level might be surprising. >> >> What would be the benefit of this approach? >> >> >> 2018-05-02 19:42 GMT+02:00 Douglas Surber >: >> Here is another way to approach referencing columns. Replace ResultMap with Column as defined below. This is not a fully thought out proposal. It is instead an attempt to look at the problem from another direction and not get stuck with the same old JDBC ResultSet model. >> >> Douglas >> >> /** >> * A mutable handle to one value of an ordered sequence of columns or of >> * out parameters. Columns have a 1-based index and optionally an identifier. >> * Identifiers are not guaranteed to be unique. >> */ >> public interface Column extends Iterable, Iterator, Cloneable { >> >> /** >> * Return the value of this column as an instance of the given type. >> * >> * @param >> * @param type >> * @return >> */ >> public T get(Class type); >> >> /** >> * Return the identifier of this column. May be null. >> * >> * @return >> */ >> public String identifier(); >> >> /** >> * Return the 1-based index of this Column. >> * >> * @return >> */ >> public int index(); >> >> /** >> * Return the SQL type of the value of this column. >> * >> * @return >> */ >> public SqlType type(); >> >> /** >> * Modify this Column to point to the next value identified by id. >> * >> * @param id >> * @return this Column >> */ >> public Column at(String id); >> >> /** >> * Modify this Column to point to the value at index. The first value is at index 1. >> * Negative numbers count back from the last value. The last value is at >> * index -1. >> * >> * @param index >> * @return this Column >> */ >> public Column at(int index); >> >> /** >> * Return a new Column that is a handle to a subsequence of sequence of values >> * referenced by this Column. The subsequence consists of the length values in >> * order starting with the value this Column points to when this method is >> * called. This Column is not modified. >> * >> * @param length >> * @return a new Column. >> */ >> public Column slice(int length); >> >> /** >> * Return a new Column that is a duplicate of this Column. >> * >> * @return a new Column >> */ >> public Column clone(); >> >> /** >> * Modify this Column to point to the next value in the sequence. >> * >> * @return this Column >> */ >> @Override >> public Column next(); >> >> @Override >> public boolean hasNext(); >> >> >> static void sample(Column columns) { >> >> Map map = new HashMap(); >> for (Column m : columns) { >> map.put(m.identifier(), m.get(Integer.class)); >> } >> >> List l = new ArrayList(); >> for (Column m : columns.at (3).slice(5)) { >> l.add(m.get(String.class)); >> } >> >> Column addr = columns.clone().at("street_address_1"); >> String streetAddress1 = addr.get(String.class); >> String streetAddress2 = addr.next().get(String.class); >> String city = addr.next().get(String.class); >> String state = addr.next().get(String.class); >> String postalCode = addr.next().get(String.class); >> >> String givenName = columns.at ("GIVEN_NAME").get(String.class); >> String familyName = columns.at ("FAMILY_NAME").get(String.class); >> >> } >> } From lukas.eder at gmail.com Fri May 4 15:13:17 2018 From: lukas.eder at gmail.com (Lukas Eder) Date: Fri, 4 May 2018 17:13:17 +0200 Subject: referencing columns In-Reply-To: <5CFCCBF0-37D1-474A-B291-A21FB437F20D@oracle.com> References: <6FF4016A-015F-4F3C-BEE3-35508CE6461D@oracle.com> <5CFCCBF0-37D1-474A-B291-A21FB437F20D@oracle.com> Message-ID: Well, I'm mentioning this because I've never seen a type T extends Iterable. It sounds weird and intriguing, but that's not always a good thing :). It would allow for things like: for (Column c1 : columns) for (Column c2 : c1) for (Column c3 : c2) ; // What do these even mean? In your alternative design, ColumnIterator and ColumnCursor don't seem strictly necessary. This would suffice: public interface Row extends Iterable{ public long rowNumber(); public Row cancel(); public Column at(String id); public Column at(int index); // forEach, iterator, spliterator } public interface Column { public T get(Class type); public SqlType sqlType(); public Class javaType(); public String id(); public int index(); } 2018-05-04 16:28 GMT+02:00 Douglas Surber : > I encourage you to actually write some code using both and see what you > think. > I will definitely do things like in the beginning of this email, trying to "break" the API :) From douglas.surber at oracle.com Fri May 4 15:39:42 2018 From: douglas.surber at oracle.com (Douglas Surber) Date: Fri, 4 May 2018 08:39:42 -0700 Subject: referencing columns In-Reply-To: References: <6FF4016A-015F-4F3C-BEE3-35508CE6461D@oracle.com> <5CFCCBF0-37D1-474A-B291-A21FB437F20D@oracle.com> Message-ID: <8E351210-7D54-44D4-B1B7-54A8B9849AE0@oracle.com> Your alternative does not include the motion methods directly. In order to get to next the app would have to call iterator. Having gotten an iterator so it can call next it cannot get back to Row. Note that Column is mutable and all of the methods mutate the Column except clone and slice. In your example I would expect columns == c1 == c2 == c3. As such when for (Column c3 : c2) completes c3.hasNext() is false hence the same for c2 and c1 and all of the loops would exit. I agree this is a bit odd. What it is doing is getting Iterator and Interable to fit the fluid style. And so far it seems to work. No doubt you can write some odd things, but with a little care in the spec I think it would all be well and simply defined. The thing that makes it work is that, except for slice and clone, there is only one Column and every motion method changes which value it points to. Now it would be reasonable to say that the argument passed to Iterable.forEach is a clone of the Column. That would make your nested for loops do a triangle iteration. I think this adds unnecessary complexity. If that?s what the user wants it is easy enough to write for (Column c1 : columns.clone()) for (Column c2 : c1.clone()) for (Column c3 : c2.clone()) If forEach (and possibly other methods) create clones understanding what this all does becomes more complex. If there is only one mutable Column then I think everything is easy to understand; only one rule to follow. The more I play with this the more I like it. I?d like to hear from the other people on the list before I make the change to ADBA. Douglas > On May 4, 2018, at 8:13 AM, Lukas Eder wrote: > > Well, I'm mentioning this because I've never seen a type T extends Iterable. It sounds weird and intriguing, but that's not always a good thing :). It would allow for things like: > > for (Column c1 : columns) > for (Column c2 : c1) > for (Column c3 : c2) > ; // What do these even mean? > > In your alternative design, ColumnIterator and ColumnCursor don't seem strictly necessary. This would suffice: > > public interface Row extends Iterable{ > public long rowNumber(); > public Row cancel(); > public Column at(String id); > public Column at(int index); > // forEach, iterator, spliterator > } > > public interface Column { > public T get(Class type); > public SqlType sqlType(); > public Class javaType(); > public String id(); > public int index(); > } > > > 2018-05-04 16:28 GMT+02:00 Douglas Surber >: > I encourage you to actually write some code using both and see what you think. > > I will definitely do things like in the beginning of this email, trying to "break" the API :) From douglas.surber at oracle.com Fri May 4 16:02:12 2018 From: douglas.surber at oracle.com (Douglas Surber) Date: Fri, 4 May 2018 09:02:12 -0700 Subject: referencing columns In-Reply-To: <8E351210-7D54-44D4-B1B7-54A8B9849AE0@oracle.com> References: <6FF4016A-015F-4F3C-BEE3-35508CE6461D@oracle.com> <5CFCCBF0-37D1-474A-B291-A21FB437F20D@oracle.com> <8E351210-7D54-44D4-B1B7-54A8B9849AE0@oracle.com> Message-ID: <07AD738E-38CB-4E77-B328-2FA615C0E089@oracle.com> I will say I?m not at all sure what Column.spliterator() has to do. That will take some investigation. My guess is that it will create clones or slices. Douglas > On May 4, 2018, at 8:39 AM, Douglas Surber wrote: > > Your alternative does not include the motion methods directly. In order to get to next the app would have to call iterator. Having gotten an iterator so it can call next it cannot get back to Row. > > Note that Column is mutable and all of the methods mutate the Column except clone and slice. In your example I would expect columns == c1 == c2 == c3. As such when for (Column c3 : c2) completes c3.hasNext() is false hence the same for c2 and c1 and all of the loops would exit. > > I agree this is a bit odd. What it is doing is getting Iterator and Interable to fit the fluid style. And so far it seems to work. No doubt you can write some odd things, but with a little care in the spec I think it would all be well and simply defined. The thing that makes it work is that, except for slice and clone, there is only one Column and every motion method changes which value it points to. > > Now it would be reasonable to say that the argument passed to Iterable.forEach is a clone of the Column. That would make your nested for loops do a triangle iteration. I think this adds unnecessary complexity. If that?s what the user wants it is easy enough to write > > for (Column c1 : columns.clone()) > for (Column c2 : c1.clone()) > for (Column c3 : c2.clone()) > > If forEach (and possibly other methods) create clones understanding what this all does becomes more complex. If there is only one mutable Column then I think everything is easy to understand; only one rule to follow. > > The more I play with this the more I like it. I?d like to hear from the other people on the list before I make the change to ADBA. > > Douglas > >> On May 4, 2018, at 8:13 AM, Lukas Eder > wrote: >> >> Well, I'm mentioning this because I've never seen a type T extends Iterable. It sounds weird and intriguing, but that's not always a good thing :). It would allow for things like: >> >> for (Column c1 : columns) >> for (Column c2 : c1) >> for (Column c3 : c2) >> ; // What do these even mean? >> >> In your alternative design, ColumnIterator and ColumnCursor don't seem strictly necessary. This would suffice: >> >> public interface Row extends Iterable{ >> public long rowNumber(); >> public Row cancel(); >> public Column at(String id); >> public Column at(int index); >> // forEach, iterator, spliterator >> } >> >> public interface Column { >> public T get(Class type); >> public SqlType sqlType(); >> public Class javaType(); >> public String id(); >> public int index(); >> } >> >> >> 2018-05-04 16:28 GMT+02:00 Douglas Surber >>: >> I encourage you to actually write some code using both and see what you think. >> >> I will definitely do things like in the beginning of this email, trying to "break" the API :) From lukas.eder at gmail.com Mon May 7 10:48:44 2018 From: lukas.eder at gmail.com (Lukas Eder) Date: Mon, 7 May 2018 12:48:44 +0200 Subject: referencing columns In-Reply-To: <8E351210-7D54-44D4-B1B7-54A8B9849AE0@oracle.com> References: <6FF4016A-015F-4F3C-BEE3-35508CE6461D@oracle.com> <5CFCCBF0-37D1-474A-B291-A21FB437F20D@oracle.com> <8E351210-7D54-44D4-B1B7-54A8B9849AE0@oracle.com> Message-ID: 2018-05-04 17:39 GMT+02:00 Douglas Surber : > Your alternative does not include the motion methods directly. In order to > get to next the app would have to call iterator. Having gotten an iterator > so it can call next it cannot get back to Row. > Added a row() method, which would be useful regardless of the final design. Akin to JDBC's ResultSet.getStatement() and Statement.getConnection() public interface Column { public T get(Class type); public SqlType sqlType(); public Class javaType(); public String id(); public int index(); public Row row(); } > No doubt you can write some odd things, but with a little care in the spec > I think it would all be well and simply defined. > Sure, this can be specified. But I don't really see the value of the type yet, compared to possible alternatives. E.g. slice (probably not such a frequent use-case) could be achieved by adding columnStream() method: public interface Row extends Iterable{ public long rowNumber(); public Row cancel(); public Column at(String id); public Column at(int index); public Stream columnStream(); // Added this method // forEach, iterator, spliterator } Now you could call row.columnStream().skip(3).limit(5).forEach(c -> { ... }); "Luckily", the skip() method looks as if it were 1-based, too :) Of course, I wish Iterable itself had a stream() method, so we would get this for "free", but that decision has been postponed since Java 8 for a couple of times - I forgot why. Something related to generic specialisation / Valhalla. Lukas From sitnikov.vladimir at gmail.com Mon May 7 11:28:26 2018 From: sitnikov.vladimir at gmail.com (Vladimir Sitnikov) Date: Mon, 07 May 2018 11:28:26 +0000 Subject: referencing columns In-Reply-To: References: <6FF4016A-015F-4F3C-BEE3-35508CE6461D@oracle.com> <5CFCCBF0-37D1-474A-B291-A21FB437F20D@oracle.com> <8E351210-7D54-44D4-B1B7-54A8B9849AE0@oracle.com> Message-ID: Lukas> public interface Column { Lukas> public Row row(); Could you please clarify how that is supposed to advance? Do you mean application would have to iterate over rows, and for each row it should call `Row#at(int column)` then it should access `Column#get(Class)`? It does look like lots of extra Column instantiations, especially for large result sets. Lukas> public interface Column { Lukas> public Class javaType(); What do you mean by that? Suppose the column is backed by a int array at the database side (e.g. int4[] for PostgreSQL). Which Class that `javaType` is supposed to return? Should it be Object[].class? Should it be Integer[].class? Should it be int[].class? Could it depend on the phase of the moon? (e.g. flip between subsequent executions of the same query) Lukas> E.g. slice (probably not such a Lukas> frequent use-case) could be achieved by adding columnStream() method: I agree, slice method looks odd. Vladimir From douglas.surber at oracle.com Mon May 7 15:02:22 2018 From: douglas.surber at oracle.com (Douglas Surber) Date: Mon, 7 May 2018 08:02:22 -0700 Subject: referencing columns In-Reply-To: References: <6FF4016A-015F-4F3C-BEE3-35508CE6461D@oracle.com> <5CFCCBF0-37D1-474A-B291-A21FB437F20D@oracle.com> <8E351210-7D54-44D4-B1B7-54A8B9849AE0@oracle.com> Message-ID: Slice is useful when a subsequence of columns form a larger concept, especially when that subsequence is used multiple times, eg address. A query could return mailing address and shipping address. mailingAddress = readAddress(col.at (?mailing_address?).slice(5)); shippingAddress = readAddress(col.at (?shipping_address).slice(5)); public Address readAddress(Column col) { return new Address(col.get(String.class), // street 1 col.next().get(String.class), // street 2 col.next().get(String.class), // city col.next().get(String.class), // state col.next().get(String.class)); // postal code Using slice isolates the caller from the motion done by the subroutine. It also allows the method to use forEach and other iterator methods. Douglas > On May 7, 2018, at 4:28 AM, Vladimir Sitnikov wrote: > > I agree, slice method looks odd. > From mark at lawinegevaar.nl Mon May 7 16:04:56 2018 From: mark at lawinegevaar.nl (Mark Rotteveel) Date: Mon, 7 May 2018 18:04:56 +0200 Subject: ADBA javadoc issues Message-ID: <77529eb1-3d02-aea0-59f5-4ab652099a6c@lawinegevaar.nl> I notice that in the ADBA javadoc, a lot of @link and @see links are syntactically invalid. For example in DataSource, the {@link getConnection} should be {@link #getConnection()}, and there are a lot of example. I notice these problems in: - AdbaConnectionProperty - AdbaType - Connection - ConnectionProperty - DataSource - Result - SqlBlob - SqlClob - Submission - Transaction The following classes have sparse javadoc and may need more: - Connection.LifeCycle (especially the boolean getters) - SqlException (especially the constructors) - SqlSkippedException Need documentation - DataSource.close() I notice that occasionally covariant overrides get documented, and some times not, while the override is not really adding new information (eg DynamicMultiOperation.onError(Consumer handler) vs other overrides in the same class). Mark -- Mark Rotteveel From lance.andersen at oracle.com Mon May 7 16:08:39 2018 From: lance.andersen at oracle.com (Lance Andersen) Date: Mon, 7 May 2018 12:08:39 -0400 Subject: ADBA javadoc issues In-Reply-To: <77529eb1-3d02-aea0-59f5-4ab652099a6c@lawinegevaar.nl> References: <77529eb1-3d02-aea0-59f5-4ab652099a6c@lawinegevaar.nl> Message-ID: <2B443310-41BC-496C-B632-F37CBF0F3AAA@oracle.com> Yes, the javadocs are a work in progress and will continue to get cleaned up and updated? This is a early draft > On May 7, 2018, at 12:04 PM, Mark Rotteveel wrote: > > I notice that in the ADBA javadoc, a lot of @link and @see links are syntactically invalid. > > For example in DataSource, the {@link getConnection} should be {@link #getConnection()}, and there are a lot of example. > > I notice these problems in: > > - AdbaConnectionProperty > - AdbaType > - Connection > - ConnectionProperty > - DataSource > - Result > - SqlBlob > - SqlClob > - Submission > - Transaction > > The following classes have sparse javadoc and may need more: > > - Connection.LifeCycle (especially the boolean getters) > - SqlException (especially the constructors) > - SqlSkippedException > > Need documentation > > - DataSource.close() > > I notice that occasionally covariant overrides get documented, and some times not, while the override is not really adding new information (eg DynamicMultiOperation.onError(Consumer handler) vs other overrides in the same class). > > Mark > -- > Mark Rotteveel Lance Andersen| Principal Member of Technical Staff | +1.781.442.2037 Oracle Java Engineering 1 Network Drive Burlington, MA 01803 Lance.Andersen at oracle.com From alexander.kjall at gmail.com Wed May 23 17:54:21 2018 From: alexander.kjall at gmail.com (=?UTF-8?Q?Alexander_Kj=C3=A4ll?=) Date: Wed, 23 May 2018 19:54:21 +0200 Subject: minor feedback on OperationGroup.operation() Message-ID: Hi The javadoc on this function states: * Return a new {@link Operation} for a SQL that doesn't return any result, * for example DDL. The result of this Operation is always null. But the signature is public Operation operation(String sql); Is there any reason that it's Operation instead of Operation? And another small thing, the javadoc bread text for connectOperation() says: The lifecycle must be {@link Lifecycle#NEW} or {@link Lifecycle#NEW_INACTIVE} when the {@link Operation} is executed. Otherwise the {@link Operation} will complete exceptionally with {@link SqlException}. but the @throws clause says: @throws IllegalStateException if this {@link Connection} is in a lifecycle state other than {@link Lifecycle#NEW}. Is it only NEW or both NEW and NEW_INACTIVE? best regards Alexander Kj?ll From diego.dupin at gmail.com Fri May 25 12:38:13 2018 From: diego.dupin at gmail.com (diego dupin) Date: Fri, 25 May 2018 14:38:13 +0200 Subject: ADBA primary key retrieving Message-ID: Hi, Modern convention is to have an auto-increment integer as a primary key. When inserting new row, JDBC permit to get this auto-increment value using Statement.getGeneratedKeys(). I've miss to see how ADBA permit getting that auto-increment value. Diego From douglas.surber at oracle.com Tue May 29 18:31:21 2018 From: douglas.surber at oracle.com (Douglas Surber) Date: Tue, 29 May 2018 11:31:21 -0700 Subject: ADBA primary key retrieving In-Reply-To: References: Message-ID: Look at ParameterizedCountOperation.rowOperation. Douglas > On May 25, 2018, at 5:38 AM, diego dupin wrote: > > Hi, > > Modern convention is to have an auto-increment integer as a primary key. > When inserting new row, JDBC permit to get this auto-increment value using > Statement.getGeneratedKeys(). > > I've miss to see how ADBA permit getting that auto-increment value. > > Diego From douglas.surber at oracle.com Tue May 29 19:15:08 2018 From: douglas.surber at oracle.com (Douglas Surber) Date: Tue, 29 May 2018 12:15:08 -0700 Subject: minor feedback on OperationGroup.operation() In-Reply-To: References: Message-ID: <052FF0A1-42B7-4328-A31E-3E970F13F9D6@oracle.com> I recall I had an argument with the type inferencer when I declared that as Operation. I don?t recall the details. I?ll look at it again. The JavaDoc for connectOperation is correct as written. It may not be sufficiently clear as you are the second person to ask this question. The difference is the the method throws if the connection is in any state other than NEW. Execution of the connect Operation fails if the connection is in any state other than NEW or NEW_INACTIVE. Execution of the connect Operation occurs some time after the method call. This is one of the complications of this API. There are two execution timelines to consider. One is the execution of the methods to construct and submit Operations. This is non-blocking and is executed by a user thread. The other is the execution of the operations and result processing. These happen in the database and in other threads, not the user thread. I have worked hard to distinguish these where appropriate and this is one of those cases. Douglas > On May 23, 2018, at 10:54 AM, Alexander Kj?ll wrote: > > Hi > > The javadoc on this function states: > > * Return a new {@link Operation} for a SQL that doesn't return any result, > * for example DDL. The result of this Operation is always null. > > But the signature is > > public Operation operation(String sql); > > Is there any reason that it's Operation instead of Operation? > > And another small thing, the javadoc bread text for connectOperation() says: > > The lifecycle must be {@link Lifecycle#NEW} or > {@link Lifecycle#NEW_INACTIVE} when the {@link Operation} is executed. > Otherwise the {@link Operation} will complete exceptionally with > {@link SqlException}. > > but the @throws clause says: > > @throws IllegalStateException if this {@link Connection} is in a lifecycle > state other than {@link Lifecycle#NEW}. > > Is it only NEW or both NEW and NEW_INACTIVE? > > best regards > Alexander Kj?ll