-
Notifications
You must be signed in to change notification settings - Fork 565
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
Jdbc mode #599
Jdbc mode #599
Conversation
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.
Thanks! I got plenty of time now so I should be much more responsive. Can you rebase to latest master and take a look at my other notes? Looking forward to this in 5.1.
when :jdbc | ||
result = begin | ||
@connection.fetch(sql).all | ||
rescue => e |
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.
This rescue feels risky. Why would an empty result set to fetch raise an exception? Is it due to the .all
method call? If so, can we avoid the rescue trap?
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.
The problem is, that I can't detect if the sql statement returns a result set or not.
#fetch uses jdbcs executeQuery (https://docs.oracle.com/javase/7/docs/api/java/sql/Statement.html#executeQuery(java.lang.String)) which throws an exception when the statement does not yield a result (like ddl statements, in which case the execute(sql) method should be used).
The statement is executed none the less.
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.
I have a similar concern to @metaskills. Is there a reason we're rescuing all exceptions as "statement invalid", instead of just the ones the method throws that we know to mean "statement invalid"?
results = | ||
begin | ||
handle.all(query_options) | ||
rescue => e |
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.
Same trap on rescue, would you mind letting me know why no results returns an error. Can that be avoided? I'd really like to know why the JDBC connection wold do that.
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.
See above.
@@ -20,11 +20,11 @@ def current_database | |||
end | |||
|
|||
def charset | |||
select_value "SELECT DATABASEPROPERTYEX(DB_NAME(), 'SqlCharSetName')" | |||
select_value "SELECT CAST(DATABASEPROPERTYEX(DB_NAME(), 'SqlCharSetName') AS NVARCHAR(128))" |
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.
Nice change. But I think we need to update sql_counter_sqlserver.rb
with the ignored SQL format too right?
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.
Not sure why this needs to be done. Isn't this statement execute in isolation all the time and never with count?
@@ -194,7 +196,7 @@ def reset! | |||
|
|||
def tables_with_referential_integrity | |||
schemas_and_tables = select_rows <<-SQL.strip_heredoc | |||
SELECT s.name, o.name | |||
SELECT s.name sc, o.name tab |
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.
Another nice change. Did JDBC throw a warning here or did you notice the ambiguity?
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.
The method handle.all which is used to retrieve the result within DatabaseStatements#handle_to_names_and_values_jdbc returns a hash with {column: value}.
Without the aliases there would only be one column.
end | ||
end | ||
|
||
module ActiveRecordSqlServerAdapter |
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.
We have made a concerted effort to not add more/abstract things to the top level namespace. Could you please change ActiveRecordSqlServerAdapter::Jdbc
to ActiveRecord::ConnectionAdapters::SQLServer::Jdbc
namespace with a file in the correct spot at lib/active_record/connection_adapters/sqlserver/jdbc.rb
. This may seem persnickety, but it is import to use the namespace we setup and file convention.
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.
Yes. This place looks much better.
|
||
def synchronize(&block) | ||
@cache_mutex.synchronize(&block) | ||
end |
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.
I have concerns on adding stuff like this and why it is needed so I would first like to know the full details on what this is used for? Is the JDBC connection not thread safe? I though most of Rails v5.1 and upward are leveraging concurrent-ruby now too? But first, I'd just like to know more about this.
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.
The jdbc connection should be thread save, but our ruby jdbc wrapper is not.
One example is the implementation of Database#execute which does executes two statements in one after another for inserts on the same connection. If this connection would be used in between these statements the result of the second statement would be probably wrong.
Maybe this is not necessary because AR does pooling anyways, but I'm not sure.
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.
but our ruby jdbc wrapper is not.
Maybe this is not necessary because AR does pooling anyways, but I'm not sure.
Exactly! We don't have to do this for them. It is code Sequl has to do, but again, not us.
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.
Ok. I did remove the synchronize stuff for Jdbc::Database.
I think the cache still needs it.
# as access to the cache is not thread safe without a mutex if other | ||
# threads can reference the dataset. Symbol keys prefixed with an | ||
# underscore are reserved for internal use. | ||
attr_reader :cache |
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.
Should we even use the cache? How much of this Sequel code can we get rid of?
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.
The cache is hit frequently. It saves one query each time which is needed to fetch the column information. The column information is used for the type conversion from java to ruby types and for the column names of the results dataset.
Maybe we can streamline the code none the less. But first I would like to get the test suite completely green.
@@ -0,0 +1,96 @@ | |||
module ActiveRecordSqlServerAdapter |
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.
Reminder to make a jdbc folder in lib/active_record/connection_adapters/sqlserver/jdbc
and put all these files in there with the other namespace.
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.
Yep.
The rebase is done. The test suite is not yet totaly green:
Especially the uuid identity columns do not work for insert. It looks like the 'select identity' statements do not yield the generated ids. Do you have a hint how to get these? I didn't find any code the handles this for tiny_tds which confuses me because this seems to be an issue with SQL-Server in general. |
$ONLY_SQLSERVER=1 jruby -S bundle exec rake test:jdbc The tests now look even better. Two tests still fail, but the errors stem from the same issue. The 'select identity' statements do not yield the generated ids.
|
Ok. I fixed the uuid issue. The ONLY_SQLSERVER tests are now all green!
|
Hi. I worked some more on the jdbc mode. Travisci now also runs with jruby.
This test fails due to a bug in jruby, see: jruby/jruby#4705 Do you like what you see so far? Please lets talk about the next steps. |
Hi @metaskills |
I'll be spending this week climbing into all PRs and issues. |
Hi @metaskills. I would merge my branch with master and see how it works, but I would first like to hear your plans concerning this PR. |
Hi @metaskills. New year, new chance ;) |
Hi @iaddict and @metaskills, great job in the project! Since the MS SQL Support of activerecord-jdbc-adapter has been in decline for a while (cf. jruby/activerecord-jdbc-adapter#784) and I don't think that will change anytime soon, having activerecord-sqlserver-adapter as a high quality option for JRuby users would be great! |
Hey all, has there been any more movement on this? We're stuck at Rails 4.2 until there is a viable MSSQL adapter. So, if there's anything I can do to help move it along, I'd be more than happy to put some time into it. |
I would like to see this pull request also to make it into the adapter. What can we do to make this a reality? |
@iaddict Is it possible to use the |
@iaddict Would you consider to fork activerecord-sqlserver-adapter with you jdbc changes and upload your own gem? The maintainer seems to be MIA and there are lots of people waiting for it to be easily integratable in their projects (esp. to be able to upgrade to Rails 5.x). |
@seizmo agree 100%. This work is FAR too important to neglect like this. I for one will chip in any way I can to help move this along. The lack of 5.x Rails support for Jruby has been a really major concern for us. Our code is fully invested in Jruby and SQL Server right now - we need this to keep up with the rest of the Rails world. I say fork - make it clear why and that we want to rejoin ASAP. And make it really clear what are the implications (if any) for any user of this forked code. |
Leave it up to me to fat-finger a close request while trying to type a response... |
@jayjlawrence @seizmo and @iaddict You are, of course, welcome to fork the code and create whatever you need to in order to move your work forward. However before forking I recommend getting the code into a build-able state with passing tests and requesting further review. Maybe even start a conversation about taking management of review and support of mssql jdbc changes? If the speed of the review has not matched your expectations there's also a third option. Perhaps consider contributing to the jruby/activerecord-jdbc-adapter project? It looks like they have been looking to support MSSQL for quite a while and would likely welcome contribution as well. I feel your pain with respect to the delay in review, but I wouldn't give up yet. |
In the interim for your existing projects, might the existing |
Hi @coderjoe, I'm a contributor to the activerecord-jdbc family of gems and the My employer uses jruby and has a legacy system in mssql that we will need to interface with for at least the next few years, so I would be more than happy to help maintain it (or a fork of it if that is the ultimate resolution.) Another option would be to make some changes to enable the drivers to not be as tightly integrated and then have the new mssql jdbc driver all live in a separate gem that has this gem as a dependency. Then when the new gem is loaded, it can load the driver agnostic pieces and only has to implement the pieces that touch the driver (this is the approach we took with the other |
@rdubya thanks for chiming in! Do you mean that the Ultimately forking or not will depend on @metaskills' goals for the project and whatever development direction he wants jdbc support to take. Either way I'm hoping that your offer to help with review and maintenance can grease the wheels a bit and help avoid a fork unless absolutely necessary. |
@coderjoe There hasn't been a lot of support for the |
for context, AR-JDBC has been quite under utilized - 3.x/4.x support was pretty much a one man show with all adapters (MySQL, SQLite, Postgre, DB2, Oracle, SQLServer, HSQLDB+H2, Derby) the 5.x work was more in line of a community effort, with folks such as @rdubya taking action and doing great work - really turned out great. Rob pretty much adopted the Postgres adapter with contributions towards the base part and performance improvements that might be a gain for all adapters. I myself did hope for some "commercial" support to somehow 'lead' the 5.x way, but it did not materialize much. have talked with 2-3 folks (actually all where MS-SQL) that wanted to provide backing, but none of them actually did - for various reasons.
just the adapter gem, the jdbc-jtds is just a slim wrapper for the driver, altough jtds seemed a dead project for years. the adapter was tested (at least I recall testing it) with the official driver but AR-JDBC does not maintain that driver wrapper gem. all being said, I believe AR-JDBC could provide a base 'JDBC' adapter but atm we can not support more adapters esp. note "heavy" commercial ones such as Oracle or SQLServer (mean it would be great but why should anyone expect it from people that do not use or need it on a regular basis). have also seen trade-offs with MS-SQL parts in AR-JDBC, at some point I tried following MRI adapter but some 'compromises' I did not like (believe the 2 projects failed some custom limit-offset queries differently) so I ended up complicating things by keeping the existing hacks instead of porting over more from mssql-adapter gem. believe there's 2 (obvious) options left on the table - have it here along side native or have a jdbc gem for JRuby depending on AR-JDBC. |
@rdubya and @kares thanks for the insight, I feel like I understand the availability of support a bit better now. Since nothing works, it sounds like anything that does work is the priority. That said, taking a cursory glance at the gem, the following things worry me:
If we can find someone interested in resolving this problems we should have a much cleaner potential merge. That would probably make it more likely to get reviewed and would also make it easier to fork into a jdbc version if the outcome isn't what you guys want (or takes too long). Now I don't have any personal interest or time to spend writing or maintaining this stuff. I have no projects today that depend on the |
So the jdbc adapter also fetches the identity. And also rename to exec_jdbc_dml because its not ddl.
Use #execute_insert.
Especially remove Jdbc#synchronize because AR already does connection pooling and threadsafety stuff.
Guess from string encoding if this should by handled as a varbinary. Fixes tests for varbinary column inserts.
This needs to be changed as soon as there is a build on gemserver.
This should make bundler work on tracisci.
If there is anyone still interested on an Active Record SQL Server adapter the works with JRuby The is a fork of the https://rubygems.org/gems/activerecord-jdbc-alt-adapter It is strongly advised to read the README file of the forked repository for more information and differences compared to platforms :jruby do
gem 'activerecord-jdbc-alt-adapter', '~> 60.0.0'
gem 'jdbc-mssql', '~> 0.6.0'
end Some of our apps are already running in production and one of them is a huge ancient finance Rails app originally created with Rails 2.0 and JRuby. |
Closing as stale. If there's still interest, a new PR seems likely necessary. Thanks for all your work! |
This pull request resembles the discussion from #579.