如何修改或破解 jOOQ 生成的 DDL?

huangapple go评论82阅读模式
英文:

What are the ways to modify or hack the jOOQ-generated DDL?

问题

抱歉,我不能提供代码的翻译。如果您有其他非代码部分需要翻译,请告诉我,我会尽力帮助您。

英文:

I am using the schema exporting feature of jOOQ extensively. Unfortunately, in some cases, jOOQ generates incorrect or inaccurate DDL for database objects. Are there any standard ways to slightly modify the generated DDL, besides using replace/regex commands on the generated DDL string?

Let's take a look at an example.

  1. Create a table (disabling NO_ZERO_DATE mode):
set sql_mode='';
create table test_date_types_table (
  timestamp_column_nullable timestamp null,
  timestamp_column_not_null timestamp not null,
  timestamp_column_default timestamp
);
  1. Run this Java code to generate DDL for the table:
        Connection conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:6000/sakila", "root", "admin");
        Configuration configuration = new DefaultConfiguration().set(conn).set(SQLDialect.MYSQL.family());
        Meta currentMeta = using(configuration).meta();


        Query[] queries = currentMeta
                .filterSchemas(v -> v.getName().equalsIgnoreCase("sakila"))
                .ddl()
                .queries();

        for (Query query : queries) {
            System.out.println(query);
        }
  1. As a result, I received this DDL from jOOQ:
create table `sakila`.`test_date_types_table` (
  `timestamp_column_nullable` timestamp,
  `timestamp_column_not_null` timestamp not null default null,
  `timestamp_column_default` timestamp not null default null
)
  1. That DDL doesn't work, because we have not null columns with null value by default:
Invalid default value for 'timestamp_column_not_null'
  1. And our nullable column timestamp_column_default is no longer nullable

  2. I believe the valid DDL script should look something like our source DDL:

create table `sakila`.`test_date_types_table` (
  `timestamp_column_nullable` timestamp,
  `timestamp_column_not_null` timestamp not null,
  `timestamp_column_default` timestamp
)

How could I fix this and similar cases on my end without changing anything in the jOOQ core?

答案1

得分: 1

以下是您要翻译的内容:

"非正则表达式方式修补 jOOQ 表达式树的方法是使用实验性的(截至 jOOQ 3.18 版本)查询对象模型 API,例如来自ExecuteListener。您可以匹配整个查询,直到找到正确的替换位置,或者使用内置的查询对象模型替换 API。这允许在渲染之前替换查询部分。

使用替换 API 的简单示例如下:

System.out.println(ctx
    .parser()
    .parseQuery("create table t (i int not null)")
    .$replace(q -> {
        if (q instanceof QOM.CreateTable ct) {
            UnmodifiableCollection<? extends TableElement> te1 = 
                ct.$tableElements();
            UnmodifiableCollection<? extends TableElement> te2 = 
                (UnmodifiableCollection<? extends TableElement>)
                te1.$replace(x -> x instanceof Field<?> f 
                      && !f.getDataType().nullable()
                    ? DSL.field(
                          f.getQualifiedName(), 
                          f.getDataType().nullable(true)
                      )
                    : x
                );

            if (te1 != te2)
                return ct.$tableElements(te2);
        }
        return q;
    })
);

它将替换所有 NOT NULL 约束在 CREATE TABLE 语句上,结果如下:

create table T (
  I int
)

另一种更复杂的替代方法是使用 VisitListener,它允许在将 QueryPart 渲染为输出 SQL 时替换 QueryPart 类型。

英文:

The non-regular expression way of patching the jOOQ expression tree would be to use the experimental (as of jOOQ 3.18) query object model API, for example from an ExecuteListener. You can either pattern match the entire query until you find the right place to replace, or use the built-in query object model replacement API. This allows for replacing the query parts before rendering it.

A simple example for using the replacement API is this:

System.out.println(ctx
    .parser()
    .parseQuery(&quot;create table t (i int not null)&quot;)
    .$replace(q -&gt; {
        if (q instanceof QOM.CreateTable ct) {
            UnmodifiableCollection&lt;? extends TableElement&gt; te1 = 
                ct.$tableElements();
            UnmodifiableCollection&lt;? extends TableElement&gt; te2 = 
                (UnmodifiableCollection&lt;? extends TableElement&gt;)
                te1.$replace(x -&gt; x instanceof Field&lt;?&gt; f 
                      &amp;&amp; !f.getDataType().nullable()
                    ? DSL.field(
                          f.getQualifiedName(), 
                          f.getDataType().nullable(true)
                      )
                    : x
                );

            if (te1 != te2)
                return ct.$tableElements(te2);
        }
        return q;
    })
);

It will replace all NOT NULL constraints on CREATE TABLE statements, resulting in:

create table T (
  I int
)

An alternative, which is more complicated to do, would be to use a VisitListener, which allows for replacing QueryPart types while they're being rendered to output SQL.

huangapple
  • 本文由 发表于 2023年6月15日 14:58:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/76479872.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定