-
Notifications
You must be signed in to change notification settings - Fork 105
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
refactor(go/adbc/driver): driverbase implementation for connection #1590
Conversation
See #1572 |
1cf64ac
to
40be93d
Compare
@lidavidm I'm just seeing this. Looks like we did some things similarly in our implementations and could likely combine them. One question I had while going through this: Right now the There are benefits I can think of to either approach. Implementing the interface fully makes it easier to get started with a driver that at least compiles with the functionality the author cares about. This has a slight downside that it might make it a bit harder to see what's missing from an implementation to make it complete, at least in terms of static analysis. What are your thoughts on this? |
Fully implementing was my intent, Golang is just a bit annoying in making that hard to check |
@lidavidm That's good to know, I'll give that a try because I think it could help simplify the bases even further. I'm still moving things around, but what do you think about the approach so far? I'd say the most material change here is the consolidation of the |
I think |
How do we want to proceed here? |
I'm in the process of putting things back together after having torn them apart a bit in my PR so far. I think I now better understand the goals of the driverbase and how it is meant to be used. Some parts like the Driver and Database should go back to looking more like they did previously, with some additions. Though perhaps it would be helpful to confirm my current understanding. Using Connection as an example:
Is that an accurate summary? |
@zeroshade @lidavidm Do we ever plan to expose this as a library to external users? I think if we're using it as a means to more efficiently produce our own drivers then |
Yes, pretty much. I expect Statement to be the hard one since I'd like the 'base' implementation to track all the state (do we have parameters? are we prepared? are we in the middle of an incremental query? etc.) and simplify the driver implementor's life as much as possible. |
IMO, we can keep it as internal to start with, and open it up once there's demand. |
Ok great. So if it's alright with you, here's one way we could proceed: I'll pull the statement base out of this PR and save it for later, to help focus the scope. I'm in the process of pulling part of your connection implementation into this PR. I can then reach out again once there's something more fully baked to discuss/review and we can see if it's heading in the right direction. |
Ok, sounds good. I haven't gotten to look at the code here yet but we can proceed here and feel free to steal anything from the other PR. (As you can see I was trying to simplify how GetObjects/GetInfo work) |
I agree here, I'd rather keep it internal until it's requested |
@lidavidm @zeroshade This isn't complete yet, but I've made some changes to they way the Connection gets built and wanted to get your thoughts on this direction. I ended up breaking the previous large interface into several smaller ones, so that implementors may choose whichever ones are appropriate to use. With a single interface, there was a downside that the use of driverbase was "all or nothing". An example of this would be if the By breaking up the interfaces and electing to only use the ones that are relevant, it allows implementors to mix/match custom methods with those provided by the driverbase. I've used a builder pattern to specify the helpers being used which makes it quite easy to discover which helpers are available to implement. Open to feedback on this approach. The way this looks in practice: For driver_test, all of the helpers are used to demonstrate the behavior: func (db *databaseImpl) Open(ctx context.Context) (adbc.Connection, error) {
cnxn := &connectionImpl{ConnectionImplBase: driverbase.NewConnectionImplBase(&db.DatabaseImplBase), db: db}
bldr := driverbase.NewConnectionBuilder(cnxn)
return bldr.
WithAutocommitSetter(cnxn).
WithCurrentNamespacer(cnxn).
WithTableTypeLister(cnxn).
WithDriverInfoPreparer(cnxn).
WithDbObjectsEnumerator(cnxn).
Connection(), nil
} For the flightsql_driver, return driverbase.NewConnectionBuilder(conn).
WithDriverInfoPreparer(conn).
WithAutocommitSetter(conn).
WithDbObjectsEnumerator(conn).
Connection(), nil For the snowflake driver, return driverbase.NewConnectionBuilder(conn).
WithAutocommitSetter(conn).
WithCurrentNamespacer(conn).
WithTableTypeLister(conn).
Connection(), nil A few things to note about this approach: Each method on the builder enforces that those methods are implemented at compile time, which is nice. In these examples the The names for the interfaces are kind of awkward, open to any suggestions. What do you think of this approach? |
I'll try to take a look over the weekend or next week - just want to give you a heads up so you don't feel you're being ignored |
Ok, just scanning through things - I think this approach is reasonable. The naming could go either way to me, it's clear enough |
Thanks @lidavidm, I'll proceed with this approach then. I think that making this module internal and testing the pattern with a few more of our own driver implementations will help us fix anything we may be overlooking now as well. |
b20b71e
to
281ba36
Compare
@lidavidm @zeroshade I think I've just about wrapped this up. The driverbase package is now internal, and I've rebased on top of the recent session options changes and refactored the flightsql current catalog/schema code to use the helper methods. Let me know what you think. There is one remaining issue that I have yet to resolve, if you have any ideas what the issue might be it would be very helpful: There is an integration test that's been failing (
and
although the "actual" values have varied between runs. Any thoughts on what this might be? |
If the value is varying I'd expect some sort of use-after-free, or it's pointing into the wrong part/a garbage part of a buffer |
@joellubi I dug into this a bit and found something: If you follow into See, when we create the string from the underlying buffer we do an unsafe cast: If we're willing to drop Go 1.19 support in Arrow (which is safe now that Go 1.22 is out...) we can switch it to use |
326c1f7
to
20915b1
Compare
Huzzah! Looks like that fixed it |
Thanks @zeroshade! Great timing, I was just looking into this too. Much appreciated. I've gotta say, I learned a bit about Go strings here. I understood them to be "immutable", but of course the devil is in the details with what that actually means. |
With that out of the way, I'd say this is ready for review now. |
@zeroshade we've run into that before, there's a place somewhere in the current codebase with a comment about making an explicit copy |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems reasonable to me.
@zeroshade any comments?
Implementation of Connection driver base, along with a refactor of Driver and Database bases.
The bases have been refactored in the following way:
*Impl
interface (e.g.DatabaseImpl
) now explicitly implements the correspondingadbc
interface (e.g.adbc.Database
).DatabaseImplBase
implements the entireDatabaseImpl
interface with stub methods or default implementations.driverbase.Database
) which contains all methods the output of driverbase constructorNewDatabase()
should be. This helps document and guarantee the "extra" behavior provided by using the driverbase. This interface should be internal to the library.DatabaseImpl
in thedatabase
struct (and similarly for the other bases) it automatically inherits implementations coming from theDatabaseImpl
. This way we don't need to write out all the implementations a second time, hence the deletes.A new
DriverInfo
type has been introduced to help consolidate the collection and validation of metadata forGetInfo()
.There are more small changes such as refactors of the flightsql and snowflake drivers to make use of the added functionality, as well as a new set of tests for the driverbase. Please let me know if anything else could use clarification.
Resolves #1105.