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
Add support for returning clause, when running plain SQL #2943
Comments
When this issue is going to be resolved ?? |
Hi @shubham-vl. Thank you very much for your message. Implementing this feature is, very unfortunately, more complex than it may initially seem, especially in the context of the 21 RDBMS that jOOQ currently supports. However, there's always a workaround. If you're using PostgreSQL, for instance, you can put the I hope this helps |
For mysql is there something like this or not ?? |
No, not right now |
Ok. Thanks
Regards
Shubham Jaju
…On Mon, Apr 24, 2017 at 4:10 PM, Lukas Eder ***@***.***> wrote:
No, not right now
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#2943 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AS200-hHF0_muU-3kpPkq4yaiN2cgHxjks5rzHwfgaJpZM4BZPWm>
.
|
Hi, I'm now in the process of migrating our persistence layer to JOOQ, and I'm stuck on the problem described above. The only way of doing it I found, is by doing it all manually inside ConnectionCallable, but I have to manually bind params, loose logging functionality etc, so basically I lose all JOOQ's goodies. The way I think it should work would be something like: In the meantime, I tried using ExecuteListener to call statement.getGeneratedKeys() after the insert has been executed, but I'm getting exception because the statement has been created without RETURN_GENERATED_KEYS flag.
|
@grzegorzbor Your suggestion is well intended, but unfortunately, it is incomplete. It may work for you immediately, but not for many others working with other databases, where an "insert result query" returns results not through I wouldn't get too invested in this rather funky JDBC feature. Configuring / tweaking things at this level will be way too complicated to document / maintain / use. If there's any solution at all, it must be completely transparent, work on all databases, and not be surprising. This is simply not a priority to solve right now, I'm afraid. What keeps you from using the code generator, by the way? |
The reason for not using code generator is that we are migrating the old project, where there are thousands of plain-text queries. Migrating them would take ages. So what we do, is that we want to change the database access layer to use JOOQ internally, but still have this layer providing a method which takes any insert query (as an opaque String), and returns generated ID. The old implementation used the Statement.getGeneratedKeys() for this purpose. I understand it may be too complex to make it work for all the databases; on the other hand, completely blocking a feature which works nicely in a partical database (mysql), is too restrictive. As i mentioned, I found a workaround by using ExecutorListener to plug into the lifecycle and call the getGeneratedKeys() after query was executed. That's totally fine with me, the only thing I need is also a way to override the place in the code which calls connection.createStatement and connection.prepareStatement, and pass Statement.RETURN_GENERATED_KEYS flag to it - without that, it won't work. There are several methods to create a Statement, so the interface should probably have all of them. Something like below:
This way is quite non-intrusive, because most of the users will just use a default implementation without even being aware of other options. |
Sure, but I'm assuming you will migrate eventually, so why not migrate these particular queries already? I'm quite positive that this will be done quicker than an appropriate implementation for this feature here.
That's easy for you to say :) You'd be happy with any feature that would get you this block out of the way. We'll have to maintain it for the next 10 years.
If you're open to that level of patching, then you could proxy the JDBC API and replace jOOQ's ordinary Specifically, you could write: class MyConnection extends DefaultConnection {
// ...
@Override
public PreparedStatement prepareStatement(String sql) throws SQLException {
if (someFlagActivatingGeneratedKeys)
return super.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
else
return super.prepareStatement(sql);
}
} This actually works just like your I'd really prefer this approach over actual new API, because I'm not convinced that this kind of API will be very useful to a lot of users compared to the cost of maintaining the API. |
Ok thanks for the hint, this works for me. I had to to wrap a couple of things (ConnectionProvider, Connection itself, and Statement) but it's working fine now. |
Thanks for the feedback. I have created a separate feature request for your original idea. Perhaps, there is a way to enhance the |
Hi, is there any plan for progressing with that issue? To recap, my scenario is following: I think it should work liek this: The new "returningGenKeys()" method transfers the Query into ResultQuery, but the actual ResultSet is going to be retrieved by calling underlying getGeneratedKeys(). The returningGenKeys method would also make sure the underlying Statement is created with the RETURN_GENERATED_KEYS flag. |
Thanks for following up on this, @grzegorzbor. Ultimately, the problem will boil down to finding a way to communicate the I understand your argument comparing JDBC's
When using the meta model, and type safe querying, most of the above issues are being worked around by jOOQ. When using plain SQL, it will be a mess again, just like in JDBC. You may have your feature, but others will find that just as annoying. This is why what you perceive as a really simple addition is in fact not that simple.
Maybe, would you like to elaborate on this? Because using the DSL with generated code really does solve your problems most thoroughly, so I'd like to understand why that's not an option. Of course, another workaround is this: public static Record generatedKey(String sql) {
return dsl.connectionResult(c -> {
try (PreparedStatement ps = c.prepareStatement(sql, RETURN_GENERATED_KEYS)) {
ps.execute();
try (ResultSet rs = ps.getGeneratedKeys()) {
return dsl.fetchOne(rs);
}
}
});
} That doesn't look too bad, does it? |
The workaround is helpful, though using it, i'm losing some of nice Jooq features: binding of the statement parameters, and logging of the executed statement (with those params). Though it's still an option to consider. Generally, I understand your point and your constraints as a framework author. But I don't agree with two points.
Point b) is debatable and is definitely not a recommended software architecture, but world is not perfect, and I'm sure it is not an uncommon case. But even in a perfect world, in a greenfield app, point a) would make me consider using plain SQLs instead of DSL with generated classes. |
You don't because you only use MySQL :)
I disagree here.
Most of the projects using jOOQ use the code generator... So, if we draw a Venn diagram...
I never disagreed. I just told you about a couple of reasons why things aren't as simple as you thought. This doesn't mean I don't recognise the utility of supporting this kind of feature.
It totally is. But some features are really just much simple to implement if meta data is available.
Sure, but jOOQ's main value proposition is the DSL. I mean, if you're just here for a bit of JDBC pain easing, then JDBI or Spring JdbcTemplate could've been a choice as well. You did choose jOOQ, though, because it can do much more, right? If you do want to write complex, re-usable SQL with jOOQ, one great option is to use views. An interesting application design model that works very well with jOOQ is this one:
I don't fully understand this argument :) I mean, if columns "come and go", it's a great thing to know that your code breaks at compile time, right? If columns "go" and your SQL code still references it, you won't notice the bug until you run the query. So, jOOQ definitely adds value here... In any case. Again, rest assured, it would be great indeed for plain SQL queries to be able to fetch generated keys also from database products that do not support a clause like PostgreSQL's |
Searching for the perfect solution... In the meanwhile we have none. DataType<Long> type = DefaultDataType.getDataType(SQLDialect.DEFAULT, java.lang.Long.class, true)
field(name("id"), type)
// or
...returningId(field(...)).fetch() |
Thank you very much for your suggestion, @shumy-tools. It should be possible to use I'll look into whether this can be done for jOOQ 3.14 |
A workaround has been implemented in #10400, which may not work for plain SQL queries like in this issue's description, but for cases like this: ctx.insertInto(table("t"))
.columns(field("col", INTEGER))
.values(1)
.returning(field("id", INTEGER.identity(true)))
.fetch(); |
When using plain SQL, users are not able to return generated IDs in examples like these:
While some databases support a native
RETURNING
clause:Others need JDBC's
Statement.getGeneratedKeys()
for this. jOOQ should support an additionalreturning()
clause, which transforms anyQuery
into aResultQuery
:See also:
The text was updated successfully, but these errors were encountered: