Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to check query bind values in jOOQ?

Tags:

java

sql

jooq

We have a problem with queries that contain IN conditions with many bind params, because they have many variations and quickly overflow the query cache.

I want to check in condition clause of my sql statement and throw an exception, if there more than 30 bind values specified for in clause.

Can I use VisitListener for that?

I can use org.jooq.VisitContext#clause to find in or not in condition, but I can’t check org.jooq.impl.InCondition#values size without reflection.

Now I'm forced to do something like this:

public class MyVisitListener extends DefaultVisitListener {
    @Override
    public void visitStart(VisitContext context) {
        if (context.clause() == Clause.CONDITION_IN || context.clause() == Clause.CONDITION_NOT_IN) {
            try {
                Field field = context.queryPart().getClass().getDeclaredField("values");
                field.setAccessible(true);
                Object value = field.get(context.queryPart());
                if (((Object[]) value).length > 30) {
                    throw new IllegalArgumentException("More than 30 bind values specified!");
                }
            } catch (NoSuchFieldException | IllegalAccessException e) {
                //throw new UnknownException("Can`t check size of field 'values' in " + context.queryPart().getClass().getName(), e);
            }
        }
    }
}

Is there a more convenient way (jOOQ 3.10.8 pro)?

like image 423
Андрей Деревянко Avatar asked Dec 03 '25 23:12

Андрей Деревянко


2 Answers

Another option, an often acceptable workaround to your problem, is enabling the optional in-list padding in jOOQ:

<settings xmlns="http://www.jooq.org/xsd/jooq-runtime-3.10.8.xsd">
  <inListPadding>true</inListPadding>
</settings>

It's not exactly what you want, but it might be exactly what you need. In short, it makes jOOQ generate IN conditions that are always power-of-2 long. This makes it much easier on the query cache.

Instead of this (8 queries):

-- Original
SELECT * FROM AUTHOR WHERE ID IN (?)
SELECT * FROM AUTHOR WHERE ID IN (?, ?)
SELECT * FROM AUTHOR WHERE ID IN (?, ?, ?)
SELECT * FROM AUTHOR WHERE ID IN (?, ?, ?, ?)
SELECT * FROM AUTHOR WHERE ID IN (?, ?, ?, ?, ?)
SELECT * FROM AUTHOR WHERE ID IN (?, ?, ?, ?, ?, ?)
SELECT * FROM AUTHOR WHERE ID IN (?, ?, ?, ?, ?, ?, ?)
SELECT * FROM AUTHOR WHERE ID IN (?, ?, ?, ?, ?, ?, ?, ?)

you'll see this (4 queries, and getting better as the length grows):

-- Padded
SELECT * FROM AUTHOR WHERE ID IN (?)
SELECT * FROM AUTHOR WHERE ID IN (?, ?)
SELECT * FROM AUTHOR WHERE ID IN (?, ?, ?, ?)
SELECT * FROM AUTHOR WHERE ID IN (?, ?, ?, ?)
SELECT * FROM AUTHOR WHERE ID IN (?, ?, ?, ?, ?, ?, ?, ?)
SELECT * FROM AUTHOR WHERE ID IN (?, ?, ?, ?, ?, ?, ?, ?)
SELECT * FROM AUTHOR WHERE ID IN (?, ?, ?, ?, ?, ?, ?, ?)
SELECT * FROM AUTHOR WHERE ID IN (?, ?, ?, ?, ?, ?, ?, ?)
like image 60
Petr Janeček Avatar answered Dec 06 '25 15:12

Petr Janeček


I came here to suggest IN list padding (as Petr did very nicely, in his answer). Other than that, the proper VisitListener solution would be to listen to the CONDITION_IN clause, remember that information in some sort of stack, and then count all the FIELD clauses that come immediately afterwards, until the CONDITION_IN clause ends again. And keep in mind that instead of a bind value, there might also be an expression (again containing several FIELD clauses) in the IN list.

Clearly, Petr's suggestion is much easier.

like image 43
Lukas Eder Avatar answered Dec 06 '25 14:12

Lukas Eder



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!