JOOQ: generating update SQL for table named by String - java

I just want to use JOOQ to generate SQL without it validating tables, columns, etc., and without it generating classes for said tables, columns, etc.
How can I generate a SQL update, and just specify the name of the schema & table with Strings?
Maybe later I'll setup the table-generated Java code, but it's not necessary right now. If I can't use JOOQ without such generated code, then I'll use some other library for now.
Thanks.

You don't have to use source code generation to use jOOQ's DSL API. See, for instance:
http://www.jooq.org/doc/latest/manual/getting-started/use-cases/jooq-as-a-standalone-sql-builder
http://www.jooq.org/doc/latest/manual/sql-building/plain-sql
http://www.jooq.org/doc/latest/manual/sql-building/names
In your case, given you want to generate a SQL update, how about:
// Assuming this static import
import static org.jooq.impl.DSL.*;
using(configuration)
.update(table("my_table"))
.set(field("id", Integer.class), 1)
.set(field("value", String.class), "A")
.where("x > ?", 3)
.execute();

Related

Parse a SELECT query and get the JOINS with JOOQ

Using JOOQ, is it possible to parse an SQL query and then obtain the parts of the query? Fields, From, Joins, Where... Something like that:
String sql = "SELECT x.a, x.b, y.c
FROM my_table x
LEFT JOIN other_table y
on x.a = y.a
WHERE x.a > 1000";
SelectQuery<Record> query = (SelectQuery<Record>) context.parser().parseSelect(sql);
query.getFrom();
query.getFields();
query.getJoins();
query.getWhere();
...
With jOOQ 3.15, you cannot access the internals of the jOOQ expression tree. There is a big project on the way to re-design these internals to make them publicly accessible precisely for this use-case:
Project: https://github.com/jOOQ/jOOQ/projects/2
Main issue: https://github.com/jOOQ/jOOQ/issues/9163
Until then, you need to either work around this by using reflection, putting some logic in the org.jooq.impl package to access package-private internals on the classpath (not possible on the module path), or by patching jOOQ - each at your own risk.

Can jOOQ be used to check native SQL string

I want to integrate jOOQ in a project which uses native SQL and org.springframework.jdbc.core.JdbcTemplate. The database schema changes often and developers have to search the code for a column that has been removed and update the queries. Hibernate or another ORM solution isn't an option as queries are sometimes very large and developers get them and just have to insert into the application code. This is very error-prune. So I thought to integrate jOOQ but gradually.
Can jOOQ throw compile time errors if a native SQL cannot be executed?
I've tried the following:
// Existing code
JdbcTemplate jdbcTemplate = ...
String sql = "select ...";
// Check code
try {
DSLContext dslContext = DSL.using(jdbcTemplate.getDataSource().getConnection());
Query query = dslContext.parser().parseQuery(sql + " order by NON_EXISTING_COLUMN");
} catch (SQLException e) {
...
}
// Existing code
return jdbcTemplate.query(sql, ...)
But it compiles well although NON_EXISTING_COLUMN doesn't really exist. Maybe I know the jOOQ API not very well yet. But I thought that it should be capable of doing it. The table classes are generated, so it can check whether the query which is build from a native SQL string is executable without executing it. Isn't it?
why don't use generated class files rather than typing native SQL?
dslContext.selectFrom(GENERATED_TABLE)...
PS: If you use JOOQ DSL(with generated classes) for generating SQL it would be work but not completely in some cases if you do mistakes even on generated classes (relations or some aggregate functions) it will not complain about it and will compile successfully.
Older versions of jOOQ did not implement meta data lookups in the parser, or only to some limited extent, and just accepted all valid identifiers. Starting with jOOQ 3.14, there will be an improved implementation as of:
https://github.com/jOOQ/jOOQ/issues/9061
You will need to provide jOOQ with a Configuration.metaProvider() (it defaults to the JDBC DatabaseMetaData backed implementation. You might prefer using generated code), and then jOOQ will try to resolve all identifiers.
Prior to jOOQ 3.14, you could implement a VisitListener which traverses the parsed SQL query, and validate all the identifiers yourself.

Duplicate table in jooq with foreignkey and primary key

i have a question, i duplicated a table with:
Table<?> table = DSL.table(DSL.name("dc2", "process"));
dsl.createTable(table).as(dsl.select().from("dc1.process")).withNoData().execute();
but doesn't copy a primary key and foreignkey, how i do?
and if i want to duplicate schema in jooq?
thanks
Giuseppe
If you're using the code generator to produce your original schema, you can duplicate it relatively easily using:
Runtime schema mapping: https://www.jooq.org/doc/latest/manual/code-generation/codegen-advanced/codegen-config-database/codegen-database-catalog-and-schema-mapping/
DSLContext.ddl() and/or Meta.ddl()
A more convenient syntax will be supported in the future via standard SQL CREATE TABLE (.. LIKE othertable) syntax:
https://github.com/jOOQ/jOOQ/issues/8860
Or a synthetic CREATE SCHEMA .. LIKE otherschema syntax:
https://github.com/jOOQ/jOOQ/issues/9527

Using MSSQL database types aliases, jooq 3.7.3 converted them to the proper Java type, but 3.12.3 converts them all to java type Object

For example, I have a database type alias defined as follows:
create type aml_acct from varchar(50) not null
Then in the SQL for creating a table, I would have a column definition like this:
create table ACCOUNTS (
.
acct aml_acct,
.
)
In 3.7.3 the Jooq generated code was this:
public final TableField<AmlAccountsRecord, String> ACCT =
createField("acct", org.jooq.impl.SQLDataType.VARCHAR.length(50).nullable(false), this, "");
In 3.12.3 the Jooq generated code is this:
/**
* #deprecated Unknown data type. Please define an explicit {#link org.jooq.Binding} to specify how this type should be handled. Deprecation can be turned off using {#literal <deprecationOnUnknownTypes/>} in your code generator configuration.
*/
#java.lang.Deprecated
public final TableField<AmlAccountsRecord, Object> ACCT = createField(DSL.name("acct"), org.jooq.impl.SQLDataType.OTHER.nullable(false), this, "");
But I can't figure out how to make a Binding class to make this properly handle the aml_acct database type and generate the code as before. Or is there a way to handle this with a ForcedType?
Any ideas or help would be appreciated...
A bug in jOOQ
This is a bug in the jOOQ 3.12 code generator (probably also present in previous releases). Recent releases of the jOOQ code generator have added support for table valued functions and table valued parameters in SQL Server. For that, new SYS and INFORMATION_SCHEMA queries have been written to fetch meta data for SQL Server's code generation. In this case, SYS.ALL_COLUMNS is joined to SYS.TYPES on the USER_TYPE_ID column rather than the SYSTEM_TYPE_ID column.
This will be fixed in 3.13.0 and 3.12.4: https://github.com/jOOQ/jOOQ/issues/9551.
Workaround
The workaround is to use a <forcedType> configuration to force the type of your columns to the wanted data type:
https://www.jooq.org/doc/latest/manual/code-generation/codegen-advanced/codegen-config-database/codegen-database-forced-types/
For example:
<forcedType>
<name>VARCHAR</name>
<includeTypes>aml_acct</includeTypes>
</forcedType>
If you have many such types, you can also use <sql> in the above configuration to match all the columns that should have this forced type applied. This could look as follows:
<forcedType>
<name>VARCHAR</name>
<sql>
select string_agg(o.name + '\.' + c.name, '|')
from sys.all_objects o
join sys.all_columns c on o.object_id = c.object_id
join sys.types u on c.user_type_id = u.user_type_id
join sys.types t on u.system_type_id = t.system_type_id
where u.is_user_defined = 1
and t.name = 'varchar'
</sql>
</forcedType>
See the above documentation link for details.

jOOQ addConditions: in SQL question mark appears instead of the value

I would like to launch simple code:
SelectQuery query = dsl.select(field ("id"), field("title")).from("dict.models").getQuery();
if (modelId > 0) query.addConditions(field("model_id", SQLDataType.INTEGER).equal(modelId));
But infortunately in getSQL() I can only see:
select id, title from dict.models where model_id = ?
Where is a mistake?
Thanks.
Query.getSQL() generates the SQL statement as it would be generated if you let jOOQ execute a PreparedStatement - with bind variables. The bind variables can be extracted in the right order via Query.getBindValues()
If you want to inline all bind values into the generated SQL, you have various options through the jOOQ API (all equivalent):
Using Query.getSQL(ParamType) with ParamType.INLINE
Using dsl.renderInlined(QueryPart)
Using StatementType.STATIC_STATEMENT in your Settings

Categories

Resources