<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: zoro ma</title>
    <description>The latest articles on DEV Community by zoro ma (@zoro7).</description>
    <link>https://dev.to/zoro7</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4124609%2F8d0d7a06-1556-4504-b2af-b6c9615b2fea.png</url>
      <title>DEV Community: zoro ma</title>
      <link>https://dev.to/zoro7</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/zoro7"/>
    <language>en</language>
    <item>
      <title>When the Dialect IS the API: Reading Army and jOOQ Side by Side, Through PostgreSQL Source</title>
      <dc:creator>zoro ma</dc:creator>
      <pubDate>Sun, 20 Sep 2026 16:58:24 +0000</pubDate>
      <link>https://dev.to/zoro7/when-the-dialect-is-the-api-reading-army-and-jooq-side-by-side-through-postgresql-source-14h8</link>
      <guid>https://dev.to/zoro7/when-the-dialect-is-the-api-reading-army-and-jooq-side-by-side-through-postgresql-source-14h8</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Army (the subject of this article)&lt;/strong&gt;: &lt;a href="https://github.com/PillArmy/army" rel="noopener noreferrer"&gt;https://github.com/PillArmy/army&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;jOOQ (the comparison target)&lt;/strong&gt;: &lt;a href="https://github.com/jOOQ/jOOQ" rel="noopener noreferrer"&gt;https://github.com/jOOQ/jOOQ&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Versions &amp;amp; methodology&lt;/strong&gt;: Army at &lt;code&gt;0.6.8-SNAPSHOT&lt;/code&gt; (Java 25); jOOQ from a local source checkout at &lt;code&gt;3.22.0-SNAPSHOT&lt;/code&gt; (commit &lt;code&gt;41e84edc85&lt;/code&gt;, 2026-06-25, &lt;code&gt;git describe&lt;/code&gt; = &lt;code&gt;version-3.21.0.RC1-140-g41e84edc85&lt;/code&gt;, root pom &lt;code&gt;&amp;lt;java.version&amp;gt;25&amp;lt;/java.version&amp;gt;&lt;/code&gt;). &lt;strong&gt;Every Army code block below is a verbatim excerpt&lt;/strong&gt; (file path + line numbers given). The jOOQ open-source checkout contains &lt;strong&gt;no tests and no example modules&lt;/strong&gt; (see §7.3), so jOOQ code appears in two flavors: &lt;strong&gt;verbatim quotes of source signatures/javadoc&lt;/strong&gt; (cited) and &lt;strong&gt;hand-written sketches against verified API signatures&lt;/strong&gt; (explicitly marked). Every claim is reproducible from both codebases unless stated otherwise. Data collected 2026-09-20.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  0. TL;DR
&lt;/h2&gt;

&lt;p&gt;Both projects let you write SQL in Java, type-safely — with opposite philosophies:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Army&lt;/th&gt;
&lt;th&gt;jOOQ (open-source edition)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;What a dialect is&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;The API itself&lt;/strong&gt; — dialect capabilities are visible on &lt;code&gt;Postgres.java&lt;/code&gt;'s method chains&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;A render parameter&lt;/strong&gt; — one &lt;code&gt;DSL&lt;/code&gt; serves all dialects; &lt;code&gt;SQLDialect.POSTGRES&lt;/code&gt; is just a switch&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PostgreSQL statements&lt;/td&gt;
&lt;td&gt;RETURNING, ON CONFLICT, MERGE, &lt;strong&gt;server-side DECLARE/FETCH/MOVE/CLOSE cursors&lt;/strong&gt;, DISTINCT ON, SET/SHOW&lt;/td&gt;
&lt;td&gt;RETURNING, ON CONFLICT, DISTINCT ON, MERGE (also used as an UPSERT emulation)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Types&lt;/td&gt;
&lt;td&gt;54 array types, 6 range + 6 multirange, RECORD, REF_CURSOR (&lt;code&gt;PgType&lt;/code&gt; fallback catalog; strongly-typed mappings in §3.5 deep dive)&lt;/td&gt;
&lt;td&gt;Strongly-typed &lt;code&gt;Range&amp;lt;T&amp;gt;&lt;/code&gt; family, &lt;code&gt;Inet&lt;/code&gt;/&lt;code&gt;Hstore&lt;/code&gt;/&lt;code&gt;Ltree&lt;/code&gt;/&lt;code&gt;Citext&lt;/code&gt; (extensions module)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Advanced types&lt;/td&gt;
&lt;td&gt;arrays: 54 prefab types; range→Guava &lt;code&gt;Range&lt;/code&gt;/&lt;code&gt;RangeSet&lt;/code&gt; (optional module); composite→&lt;code&gt;@DefinedType&lt;/code&gt; POJO; &lt;strong&gt;pgvector built in&lt;/strong&gt; (&lt;code&gt;float[]&lt;/code&gt; + 6 distance operators)&lt;/td&gt;
&lt;td&gt;arrays: generic lifting; range: built-in value family; composite: codegen &lt;code&gt;UDTRecord&lt;/code&gt;; no pgvector in OSS (grep-verified)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shared gaps&lt;/td&gt;
&lt;td&gt;COPY and LISTEN/NOTIFY absent on both sides (grep-verified) — the only shared starting line&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A delightful coincidence in scale: &lt;strong&gt;jOOQ's single &lt;code&gt;DSL.java&lt;/code&gt; is 39,746 lines — almost exactly the size of Army's entire army-postgre module: 39,742 lines.&lt;/strong&gt; One file holds the API for every dialect; one module holds the API for one dialect. That's where this article begins.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. The Contenders
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Army&lt;/th&gt;
&lt;th&gt;jOOQ&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Self-description&lt;/td&gt;
&lt;td&gt;README: "Army is not an ORM framework. It doesn't generate schemas, manage connections, or cache result sets…"&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;README.md:52&lt;/code&gt;: "jOOQ's main feature is &lt;strong&gt;typesafe, embedded SQL&lt;/strong&gt;, allowing for IDE auto completion of SQL syntax…"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Java baseline&lt;/td&gt;
&lt;td&gt;25 (compiler release in pom)&lt;/td&gt;
&lt;td&gt;25 (root &lt;code&gt;pom.xml:51&lt;/code&gt; &lt;code&gt;&amp;lt;java.version&amp;gt;25&lt;/code&gt;) — yes, identical baselines&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;License&lt;/td&gt;
&lt;td&gt;Apache-2.0&lt;/td&gt;
&lt;td&gt;Open-source edition Apache-2.0 (commercial editions separate)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Size&lt;/td&gt;
&lt;td&gt;army-postgre module: &lt;strong&gt;78 files / 39,742 LOC&lt;/strong&gt;; dialect grammar-contract package &lt;code&gt;io.army.criteria.postgre&lt;/code&gt;: 17 files / 2,180 LOC&lt;/td&gt;
&lt;td&gt;jOOQ core: &lt;strong&gt;2,126 files / 663,534 LOC&lt;/strong&gt;; jOOQ-postgres-extensions: 63 files / 4,790 LOC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stage&lt;/td&gt;
&lt;td&gt;0.6.x&lt;/td&gt;
&lt;td&gt;3.22.0-SNAPSHOT (a 20+ year project)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Doc anchoring&lt;/td&gt;
&lt;td&gt;1,243 links to postgresql.org inside army-postgre sources&lt;/td&gt;
&lt;td&gt;Only 18 postgresql.org links in jOOQ core (dialect knowledge lives in code, not comments)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Line counts measured with &lt;code&gt;find + wc&lt;/code&gt; (2026-09-20); link counts via &lt;code&gt;grep -rho postgresql.org | wc -l&lt;/code&gt;. Neither number says who is "better" — they show two styles: Army stitches the PostgreSQL manual into its Javadoc; jOOQ weaves dialect knowledge into its renderer.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  2. Two Worldviews: Dialect-as-API vs Dialect-as-Render-Parameter
&lt;/h2&gt;

&lt;h3&gt;
  
  
  2.1 Army: &lt;code&gt;Postgres.java&lt;/code&gt;, one door per dialect
&lt;/h3&gt;

&lt;p&gt;Every Army database gets its own entry class. PostgreSQL's is &lt;a&gt;Postgres.java&lt;/a&gt; with &lt;strong&gt;18 static factories&lt;/strong&gt; (verified one by one):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;singleInsert&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;   &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;            &lt;span class="n"&gt;batchQuery&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;       &lt;span class="n"&gt;subQuery&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;scalarSubQuery&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="n"&gt;singleUpdate&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;     &lt;span class="n"&gt;batchSingleUpdate&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="n"&gt;singleDelete&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;batchSingleDelete&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="n"&gt;valuesStmt&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;    &lt;span class="n"&gt;subValues&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;        &lt;span class="n"&gt;declareStmt&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;closeCursor&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;closeAllCursor&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="n"&gt;singleMerge&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;     &lt;span class="n"&gt;setStmt&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;     &lt;span class="n"&gt;showAll&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two observations:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;No &lt;code&gt;multiUpdate()/multiDelete()&lt;/code&gt;&lt;/strong&gt; — grep for &lt;code&gt;multiUpdate|multiDelete|batchMulti&lt;/code&gt; across army-postgre returns zero hits. Multi-table UPDATE/DELETE is a MySQL-module-only API; on the PG side the method simply does not exist. &lt;strong&gt;Nonexistence = unsupported = the compiler blocks it on the database's behalf.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;declareStmt()&lt;/code&gt; is PG-exclusive&lt;/strong&gt; — server-side cursors have no counterpart on the MySQL entry class. Dialect capability shows up directly as "which factories exist".&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  2.2 jOOQ: one DSL plus one enum switch
&lt;/h3&gt;

&lt;p&gt;All jOOQ dialects share a single &lt;code&gt;DSL&lt;/code&gt; facade (&lt;code&gt;org/jooq/impl/DSL.java&lt;/code&gt;, 39,746 lines). The dialect is a &lt;code&gt;SQLDialect&lt;/code&gt; enum plus render-time branches. In the open-source checkout there is &lt;strong&gt;exactly one PostgreSQL constant&lt;/strong&gt; — the family (&lt;a&gt;SQLDialect.java:425-435&lt;/a&gt;, verbatim):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * The PostgreSQL dialect family.
 * &amp;lt;p&amp;gt;
 * This family behaves like the versioned dialect {@link #POSTGRES_18}.
 ...
 */&lt;/span&gt;
&lt;span class="no"&gt;POSTGRES&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Postgres"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RequiredVersion&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="nc"&gt;SQLDialectCategory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;POSTGRES&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Its class javadoc (&lt;code&gt;SQLDialect.java:70-74&lt;/code&gt;) is blunt: &lt;em&gt;"The open source jOOQ distributions only support the dialect family, which corresponds to the latest supported dialect version of the commercial distribution."&lt;/em&gt; — &lt;strong&gt;the OSS edition ships exactly one PostgreSQL flavor: "latest" (18). Versioned dialects (POSTGRES_9_3…POSTGRES_14 etc.) are a commercial-edition capability&lt;/strong&gt; (in this checkout those names appear only in javadoc prose, not as enum constants).&lt;/p&gt;

&lt;h3&gt;
  
  
  2.3 Three corollaries of the philosophy gap
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Corollary 1: when errors surface.&lt;/strong&gt; Army expresses "this dialect doesn't support it" as "this method doesn't exist" — the error stops at compile time. jOOQ expresses it as a render branch: the same statement behaves differently under a different &lt;code&gt;SQLDialect&lt;/code&gt;. jOOQ pays with &lt;strong&gt;emulation&lt;/strong&gt;; e.g., ILIKE is rewritten as &lt;code&gt;LOWER(x) LIKE LOWER(y)&lt;/code&gt; on dialects that lack it (&lt;a&gt;Like.java:193-198&lt;/a&gt;, verbatim):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// [#1423] [#9889] PostgreSQL and H2 support ILIKE natively. Other dialects&lt;/span&gt;
&lt;span class="c1"&gt;// need to emulate this as LOWER(lhs) LIKE LOWER(rhs)&lt;/span&gt;
&lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nl"&gt;LIKE_IGNORE_CASE:&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nl"&gt;NOT_LIKE_IGNORE_CASE:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;NO_SUPPORT_ILIKE&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;contains&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;dialect&lt;/span&gt;&lt;span class="o"&gt;()))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the Army side, ILIKE appears only in the PG keyword table (&lt;a&gt;_PostgreDialectUtils.java:253&lt;/a&gt;: &lt;code&gt;keywords.add("ILIKE")&lt;/code&gt;) — where there is nothing to emulate, there is no emulation; where the database is native, the SQL goes native.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Corollary 2: portability is paid for differently.&lt;/strong&gt; With jOOQ one statement can run its unit tests on H2 and its production on PostgreSQL (emulation bridges the gap). With Army, switching from &lt;code&gt;SQLs.query()&lt;/code&gt; to &lt;code&gt;Postgres.query()&lt;/code&gt; locks the dialect — in exchange for determinism about target-database behavior.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Corollary 3: the shape of documentation.&lt;/strong&gt; Army anchors 1,243 official-doc links into its Javadoc; jOOQ encodes the same knowledge as dialect-branch code comments. The first favors learners; the second favors maintaining 660k lines.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Type Systems: Two Different PG Dictionaries
&lt;/h2&gt;

&lt;h3&gt;
  
  
  3.1 Army: &lt;code&gt;PgType&lt;/code&gt; — broad and literal
&lt;/h3&gt;

&lt;p&gt;The full PG type set lives in &lt;a&gt;PgType.java&lt;/a&gt; (in army-core). Its dialect slice, verbatim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="no"&gt;JSON&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"JSON"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ArmyType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;JSON&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
&lt;span class="no"&gt;JSONB&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"JSONB"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ArmyType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;JSONB&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
&lt;span class="no"&gt;JSONPATH&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"JSONPATH"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ArmyType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;DIALECT_TYPE&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
&lt;span class="no"&gt;MACADDR&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MACADDR"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ArmyType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;DIALECT_TYPE&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
&lt;span class="no"&gt;MACADDR8&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MACADDR8"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ArmyType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;DIALECT_TYPE&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
&lt;span class="no"&gt;INET&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"INET"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ArmyType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;DIALECT_TYPE&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
&lt;span class="no"&gt;CIDR&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CIDR"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ArmyType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;DIALECT_TYPE&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;

&lt;span class="no"&gt;INT4RANGE&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"INT4RANGE"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ArmyType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;RANGE&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
&lt;span class="no"&gt;INT8RANGE&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"INT8RANGE"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ArmyType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;RANGE&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
&lt;span class="no"&gt;NUMRANGE&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"NUMRANGE"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ArmyType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;RANGE&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
&lt;span class="no"&gt;TSRANGE&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"TSRANGE"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ArmyType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;RANGE&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
&lt;span class="no"&gt;TSTZRANGE&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"TSTZRANGE"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ArmyType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;RANGE&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
&lt;span class="no"&gt;DATERANGE&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DATERANGE"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ArmyType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;RANGE&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;

&lt;span class="no"&gt;INT4MULTIRANGE&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"INT4MULTIRANGE"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ArmyType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;RANGE&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt; &lt;span class="n"&gt;multiranges&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;L112&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;117&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(From &lt;a&gt;PgType.java:95-117&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Also present: &lt;code&gt;MONEY&lt;/code&gt;, &lt;code&gt;PG_LSN&lt;/code&gt;, &lt;code&gt;PG_SNAPSHOT&lt;/code&gt;, &lt;code&gt;TSVECTOR/TSQUERY&lt;/code&gt;, the geometric family (&lt;code&gt;POINT/CIRCLE/PATH/BOX/LINE/LSEG/POLYGON&lt;/code&gt;, all mapped to &lt;code&gt;String&lt;/code&gt;), &lt;code&gt;RECORD&lt;/code&gt; (→ &lt;code&gt;SqlRecord&lt;/code&gt;), &lt;code&gt;REF_CURSOR&lt;/code&gt;, &lt;code&gt;ACLITEM&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Arrays are Army's showcase&lt;/strong&gt;: from &lt;code&gt;ACLITEM_ARRAY&lt;/code&gt; to &lt;code&gt;RECORD_ARRAY&lt;/code&gt; there are &lt;strong&gt;54 &lt;code&gt;*_ARRAY&lt;/code&gt; constants&lt;/strong&gt;, built by a constructor referencing the element type (&lt;a&gt;PgType.java:126-135&lt;/a&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="no"&gt;ACLITEM_ARRAY&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;ACLITEM&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
&lt;span class="no"&gt;BOOLEAN_ARRAY&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;BOOLEAN&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="no"&gt;TIMESTAMPTZ_ARRAY&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;TIMESTAMPTZ&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
&lt;span class="no"&gt;JSONB_ARRAY&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;JSONB&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
&lt;span class="no"&gt;INT4RANGE_ARRAY&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;INT4RANGE&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
&lt;span class="no"&gt;INT4MULTIRANGE_ARRAY&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;INT4MULTIRANGE&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even range/multirange get their own arrays. The parser counterpart is &lt;code&gt;PostgreArrays&lt;/code&gt; in army-postgre (&lt;code&gt;parseArrayText&lt;/code&gt; handles &lt;code&gt;'{{1 , 2} , { 3, 4}}'&lt;/code&gt; and custom-subscript forms like &lt;code&gt;'[-1:0][-2:-1]=...'&lt;/code&gt; — see the test comments in &lt;a&gt;PostgreArraysUnitTests.java:38-67&lt;/a&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  3.2 jOOQ: an internal core catalog plus a strongly-typed extensions module
&lt;/h3&gt;

&lt;p&gt;jOOQ's PG types come in two layers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Internal core catalog&lt;/strong&gt;: &lt;code&gt;org/jooq/impl/SQLDataTypes.java&lt;/code&gt; hosts a &lt;strong&gt;package-private&lt;/strong&gt; &lt;code&gt;PostgresDataType&lt;/code&gt; (L2606-2608) covering system types like &lt;code&gt;INT2/INT4/INT8/FLOAT8/BOOL/TEXT/TIMESTAMPTZ/BYTEA/INTERVAL/OIDVECTOR&lt;/code&gt; — internal implementation, no public &lt;code&gt;PostgreSQLDataType&lt;/code&gt; class.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The open-source jOOQ-postgres-extensions module&lt;/strong&gt; (63 files / 4,790 LOC): the real "PG dictionary" — a &lt;code&gt;Range&amp;lt;T&amp;gt;&lt;/code&gt; interface with discrete-range base classes, plus one class per type:&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;PG type&lt;/th&gt;
&lt;th&gt;jOOQ extension class (all in &lt;code&gt;org.jooq.postgres.extensions.types&lt;/code&gt;)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;int4range&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;IntegerRange&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;int8range&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;LongRange&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;numrange&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;BigDecimalRange&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;daterange&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;LocalDateRange&lt;/code&gt; (alias &lt;code&gt;DateRange&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tsrange&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;LocalDateTimeRange&lt;/code&gt; (alias &lt;code&gt;TimestampRange&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tstzrange&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;OffsetDateTimeRange&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ltree&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Ltree&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;inet&lt;/code&gt; / &lt;code&gt;cidr&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Inet&lt;/code&gt; / &lt;code&gt;Cidr&lt;/code&gt; (with IP-prefix semantics)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;hstore&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Hstore&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;citext&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Citext&lt;/code&gt; (as converters)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Each type ships a &lt;code&gt;Converter/Binding&lt;/code&gt; (including &lt;code&gt;*ArrayBinding&lt;/code&gt; variants).&lt;/p&gt;

&lt;h3&gt;
  
  
  3.3 Range types: &lt;code&gt;String&lt;/code&gt; vs &lt;code&gt;Range&amp;lt;T&amp;gt;&lt;/code&gt; — the biggest fork in this comparison
&lt;/h3&gt;

&lt;p&gt;The same &lt;code&gt;tstzrange&lt;/code&gt; column:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Army maps it to &lt;code&gt;String&lt;/code&gt; at the &lt;code&gt;PgType&lt;/code&gt; level&lt;/strong&gt; (&lt;code&gt;TSTZRANGE(..., String.class)&lt;/code&gt;). Pro: zero magic, WYSIWYG. Con: range arithmetic happens at the string/SQL-expression level, by hand. But that is only the fallback layer — object semantics are one optional module away: attach army-guava and you get Guava &lt;code&gt;Range&amp;lt;T&amp;gt;&lt;/code&gt; directly (§3.7).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;jOOQ maps it to an &lt;code&gt;OffsetDateTimeRange&lt;/code&gt; object&lt;/strong&gt; with a &lt;code&gt;Range&amp;lt;T&amp;gt;&lt;/code&gt; interface (contains, discrete stepping, etc.) and a dedicated Binding. Pro: business code manipulates objects. Con: one more abstraction and binding protocol.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A direct clash of design values: &lt;strong&gt;Army picks "literal + broad" (54 arrays, RECORD, REF_CURSOR all present); jOOQ picks "deeply typed" (Range family, Inet prefixes, Hstore).&lt;/strong&gt; It depends on the team — and let me preempt a misconception you get from reading &lt;code&gt;PgType&lt;/code&gt; alone: although Army's range/multirange map to String at the SQL-catalog level, there is a strongly-typed channel at the MappingType layer (the optional army-guava module maps them to Guava &lt;code&gt;Range&amp;lt;T&amp;gt;&lt;/code&gt;/&lt;code&gt;RangeSet&amp;lt;T&amp;gt;&lt;/code&gt;, detailed in §3.7); the jOOQ open-source extensions still have &lt;strong&gt;no multirange classes&lt;/strong&gt; (none exist in the module).&lt;/p&gt;

&lt;h3&gt;
  
  
  3.4 pgvector: a correction — Army has it; the jOOQ OSS edition does not
&lt;/h3&gt;

&lt;p&gt;The first draft of this article claimed "pgvector is absent on both sides" — a wrong conclusion reached by grepping only the &lt;code&gt;PgType&lt;/code&gt; constants. Corrected here, with apologies: Army's &lt;code&gt;PgType&lt;/code&gt; enum genuinely has &lt;strong&gt;no&lt;/strong&gt; VECTOR constant (vector is an extension type, not a built-in SQL type), but pgvector is &lt;strong&gt;fully supported&lt;/strong&gt; at three layers — MappingType, the expression DSL, and the Spring AI integration; the jOOQ open-source checkout genuinely lacks it. Evidence and comparison in §3.9.&lt;/p&gt;




&lt;h2&gt;
  
  
  3.5 Deep-dive map: array / range / composite / vector across four dimensions
&lt;/h2&gt;

&lt;p&gt;The next four sections compare each type family with the same framework: &lt;strong&gt;mapping&lt;/strong&gt; (how Java types correspond to PG types), &lt;strong&gt;design&lt;/strong&gt; (why it is modeled that way), &lt;strong&gt;implementation&lt;/strong&gt; (what actually happens on the JDBC wire), and &lt;strong&gt;usage&lt;/strong&gt; (what user code looks like).&lt;/p&gt;

&lt;p&gt;Start with one counter-intuitive finding that runs through all four: &lt;strong&gt;neither framework uses the JDBC 4 &lt;code&gt;java.sql.Array&lt;/code&gt; / &lt;code&gt;java.sql.Struct&lt;/code&gt; channels.&lt;/strong&gt; A grep for &lt;code&gt;createArrayOf&lt;/code&gt;/&lt;code&gt;createStruct&lt;/code&gt; across the whole army-jdbc module returns zero hits; jOOQ core does not call them either (matches only in the JDBC wrappers &lt;code&gt;DefaultConnection&lt;/code&gt;/&lt;code&gt;MockConnection&lt;/code&gt;). The two projects independently made the same choice — &lt;strong&gt;PostgreSQL's text input/output protocol&lt;/strong&gt; (arrays &lt;code&gt;'{1,2,3}'&lt;/code&gt;, ranges &lt;code&gt;'[1,5)'&lt;/code&gt;, composites &lt;code&gt;'(a,b)'&lt;/code&gt;, vectors &lt;code&gt;'[1,2,3]'&lt;/code&gt; plus a server-side cast), letting PostgreSQL parse the complex types itself. jOOQ even writes the reason into its code (§3.6). So the comparison is not about which protocol — it is about &lt;strong&gt;what kind of type system each side built on top of it&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.6 ARRAY
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Mapping.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Army: a two-tier "prefab catalog + auto-inference" system.&lt;/strong&gt; The SQL-catalog tier is &lt;code&gt;PgType&lt;/code&gt;'s 54 &lt;code&gt;*_ARRAY&lt;/code&gt; constants (§3.1); the MappingType tier is the standalone &lt;strong&gt;army-array module&lt;/strong&gt; — 43 named array types (&lt;code&gt;IntegerArrayType&lt;/code&gt;, &lt;code&gt;TextArrayType&lt;/code&gt;, &lt;code&gt;UUIDArrayType&lt;/code&gt;, &lt;code&gt;JsonbArrayType&lt;/code&gt;, &lt;code&gt;BitSetArrayType&lt;/code&gt;, &lt;code&gt;IntervalArrayType&lt;/code&gt;… and even &lt;code&gt;CompositeArrayType&lt;/code&gt;, &lt;code&gt;VectorArrayType&lt;/code&gt;, &lt;code&gt;MappingTypeArrayType&lt;/code&gt;). Primitive/primitive-wrapper array fields are inferred automatically (&lt;a&gt;PgMappingHandler.java:134-173&lt;/a&gt; returns &lt;code&gt;XxxArrayType.UNLIMITED&lt;/code&gt; per element type); other arrays fall back to &lt;code&gt;StringArrayType&lt;/code&gt; (L179-180: &lt;code&gt;type.isArray()&lt;/code&gt; → &lt;code&gt;StringArrayType&lt;/code&gt;), or are declared explicitly with &lt;code&gt;@Mapping&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;jOOQ: one "generic lifting" mechanism.&lt;/strong&gt; Any &lt;code&gt;DataType&amp;lt;T&amp;gt;&lt;/code&gt; becomes &lt;code&gt;DataType&amp;lt;T[]&amp;gt;&lt;/code&gt; via &lt;code&gt;getArrayDataType()&lt;/code&gt; (&lt;a&gt;ArrayDataType.java:66-81&lt;/a&gt;; the constructor takes &lt;code&gt;elementType.getBinding().arrayBinding()&lt;/code&gt; and converts elements reflectively with &lt;code&gt;Array.newInstance&lt;/code&gt;); DDL rendering emits the suffix &lt;code&gt;"[]"&lt;/code&gt; for the POSTGRES family (&lt;a&gt;ArrayDataType.java:227-244&lt;/a&gt;). Arrays of Range/Inet/Hstore etc. are covered by the extensions' &lt;code&gt;*ArrayBinding&lt;/code&gt; classes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Design.&lt;/strong&gt; The catalog gives every PG array flavor (multi-dimensional, fixed bit, interval) a named home with docs; the generic mechanism is orthogonal — a new element type gains arrays automatically, no 44th class needed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implementation.&lt;/strong&gt; Army's text codec is &lt;a&gt;PostgreArrays.java&lt;/a&gt; in army-core (note: core, not the dialect module — the text protocol is shared knowledge). The default serializer/deserializer is comma-delimited (L45-53); element decoding follows the PG manual's array I/O syntax (the L68-72 javadoc links &lt;em&gt;Array Input and Output Syntax&lt;/em&gt; — double-quote wrapping and backslash escaping). jOOQ's bind site is &lt;a&gt;DefaultBinding.java:1610-1615&lt;/a&gt;; the POSTGRES branch, verbatim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nl"&gt;POSTGRES:&lt;/span&gt;
    &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;statement&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;setObject&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;index&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;toPGArrayString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="nc"&gt;Types&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;OTHER&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inline (non-prepared) contexts render &lt;code&gt;cast(inline(PostgresUtils.toPGArrayString(value)), arrayType)&lt;/code&gt; (DefaultBinding.java:1482-1492); &lt;code&gt;toPGArrayString&lt;/code&gt; handles &lt;code&gt;{…}&lt;/code&gt; wrapping, quoting non-numbers, escaping, and multi-dim arrays (&lt;a&gt;PostgresUtils.java:546-583&lt;/a&gt;). On read, jOOQ calls &lt;code&gt;rs.getArray()&lt;/code&gt; and binds element by element; Army's &lt;code&gt;*ArrayType&lt;/code&gt;s restore from text via &lt;code&gt;PostgreArrays&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Usage.&lt;/strong&gt; Army side — verbatim from the real entity &lt;a&gt;PostgreTypes.java&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// L370-376: 1-D auto-inferred, 2-D declared explicitly&lt;/span&gt;
&lt;span class="c1"&gt;//@Mapping("io.army.mapping.array.IntegerArrayType")&lt;/span&gt;
&lt;span class="nd"&gt;@Column&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;comment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"int array type"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;intArray&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@Mapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"io.army.mapping.array.IntegerArrayType"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@Column&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;comment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"int 2d array type"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;[][]&lt;/span&gt; &lt;span class="n"&gt;int2dArray&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same mechanism covers composite arrays and vector arrays (L460-466: &lt;code&gt;@Mapping("...CompositeArrayType") public ProductInfo[] productInfoArray;&lt;/code&gt;, &lt;code&gt;@Mapping("...VectorArrayType") public float[][] vectorArray;&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;jOOQ side (no tests in the OSS checkout; this quotes the &lt;strong&gt;DSL javadoc verbatim&lt;/strong&gt;, &lt;a&gt;DSL.java:32579-32584&lt;/a&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;The&lt;/span&gt; &lt;span class="n"&gt;PostgreSQL&lt;/span&gt; &lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;select&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="err"&gt;…&lt;/span&gt;
&lt;span class="n"&gt;Example&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;union&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="k"&gt;union&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;unnest(Object[])&lt;/code&gt; javadoc (DSL.java:13502-13513) states: rendered as &lt;code&gt;UNNEST&lt;/code&gt; on Postgres, &lt;code&gt;TABLE&lt;/code&gt; on H2, and "emulated using several &lt;code&gt;UNION ALL&lt;/code&gt; connected subqueries" elsewhere — one function, three renderings. jOOQ's philosophy in an array-shaped specimen.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.7 RANGE / MULTIRANGE
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Mapping.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;jOOQ&lt;/strong&gt;: the extensions module ships a complete set of &lt;strong&gt;dependency-free value types&lt;/strong&gt;. The &lt;code&gt;Range&amp;lt;T&amp;gt;&lt;/code&gt; interface has exactly five methods (&lt;a&gt;Range.java:47-75&lt;/a&gt;, verbatim): &lt;code&gt;isEmpty()&lt;/code&gt;, &lt;code&gt;lower()&lt;/code&gt;, &lt;code&gt;lowerIncluding()&lt;/code&gt;, &lt;code&gt;upper()&lt;/code&gt;, &lt;code&gt;upperIncluding()&lt;/code&gt;; six concrete types &lt;code&gt;IntegerRange/LongRange/BigDecimalRange/LocalDateRange/OffsetDateTimeRange/...&lt;/code&gt;; &lt;strong&gt;no multirange classes&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Army&lt;/strong&gt;: it does not invent Range objects — the strongly-typed mapping lives in the optional &lt;strong&gt;army-guava module&lt;/strong&gt;: &lt;a&gt;GuavaRangeType.java:47&lt;/a&gt; — &lt;code&gt;public abstract class GuavaRangeType ... implements MappingType.SqlRange, UnaryGenericsMapping&lt;/code&gt; — mapping a column to Guava's &lt;code&gt;Range&amp;lt;T&amp;gt;&lt;/code&gt;; multirange maps via &lt;code&gt;GuavaRangeSetType&lt;/code&gt; to Guava &lt;code&gt;RangeSet&amp;lt;T&amp;gt;&lt;/code&gt;; arrays via &lt;code&gt;GuavaRangeArrayType&lt;/code&gt;. Projects without Guava fall back to the &lt;code&gt;PgType&lt;/code&gt; String mapping.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Design.&lt;/strong&gt; Both faithfully implement PG's bound/empty-range semantics. jOOQ hard-codes the rules in &lt;a&gt;AbstractRange.java:51-68&lt;/a&gt;: &lt;code&gt;// In PostgreSQL, there is no [,] range, only (,)&lt;/code&gt; (null bounds forced open), &lt;code&gt;isEmpty()&lt;/code&gt; = &lt;code&gt;lowerIncluding &amp;amp;&amp;amp; !upperIncluding &amp;amp;&amp;amp; Objects.equals(lower, upper)&lt;/code&gt;, and &lt;code&gt;toString()&lt;/code&gt; renders the &lt;code&gt;[1,5)&lt;/code&gt; text. Army reuses Guava &lt;code&gt;Range&lt;/code&gt;'s mature open/closed-interval semantics, and its deserializer knows PG empty ranges and infinite bounds (&lt;code&gt;allowNothing(true)&lt;/code&gt;). An archaeological detail: &lt;a&gt;PgRangeTypeUniteTests.java&lt;/a&gt; has its &lt;strong&gt;entire body commented out&lt;/strong&gt; (the referenced &lt;code&gt;PgRangeType&lt;/code&gt;/&lt;code&gt;Int4Range&lt;/code&gt; classes no longer exist in the source) — a fossil of an attempted in-house value type; the final design choice was to reuse Guava instead of reinventing &lt;code&gt;Range&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implementation.&lt;/strong&gt; Text protocol again. Army's range text parser is a configurable builder (&lt;a&gt;GuavaRangeType.java:57-73&lt;/a&gt;, verbatim excerpt):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;RangeDeserializer&lt;/span&gt; &lt;span class="no"&gt;PG_DESERIALIZER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;RangeDeserializer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;dataTypeLabel&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"PostgreSQL Range"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;leftBoundaries&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;[]{&lt;/span&gt;&lt;span class="sc"&gt;'['&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;'('&lt;/span&gt;&lt;span class="o"&gt;})&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;delim&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_Constant&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;COMMA&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;rightBoundaries&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;[]{&lt;/span&gt;&lt;span class="sc"&gt;']'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;')'&lt;/span&gt;&lt;span class="o"&gt;})&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;quoteChar&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_Constant&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;DOUBLE_QUOTE&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;backSlashEscapeOn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;quoteEscapeOn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nullAsNull&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;allowQuote&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;allowNothing&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;// unbounded&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;allowWhitespace&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;jOOQ's &lt;code&gt;AbstractRangeConverter&lt;/code&gt; (&lt;a&gt;L60-96&lt;/a&gt;): &lt;code&gt;if ("empty".equals(s)) return empty();&lt;/code&gt;; otherwise split on &lt;code&gt;,&lt;/code&gt;, read the first char for &lt;code&gt;[&lt;/code&gt;/&lt;code&gt;(&lt;/code&gt;, strip double quotes, blank bound → null; the Binding extends &lt;code&gt;AbstractPostgresVarcharBinding&lt;/code&gt; (setString/getString), and &lt;code&gt;IntegerRangeBinding.castType()&lt;/code&gt; returns &lt;code&gt;"int4range"&lt;/code&gt; (&lt;a&gt;IntegerRangeBinding.java:50-67&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Usage.&lt;/strong&gt; Army side — &lt;a&gt;PostgreTypes.java:192-247&lt;/a&gt;, verbatim excerpt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Column&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;comment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"int4range type"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Range&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;int4RangeGuava&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@Mapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"io.army.mapping.guava.GuavaRangeType"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Range&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;OffsetDateTime&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;tstzrange&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="nd"&gt;@Mapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"io.army.mapping.guava.array.GuavaRangeArrayType"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Range&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;OffsetDateTime&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;[]&lt;/span&gt; &lt;span class="n"&gt;tstzrangeArray&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="nd"&gt;@Mapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"io.army.mapping.guava.GuavaRangeSetType"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;RangeSet&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Long&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;int8multirange&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the jOOQ side you attach &lt;code&gt;IntegerRangeBinding&lt;/code&gt; to a column in the codegen configuration and the generated field type becomes &lt;code&gt;Field&amp;lt;IntegerRange&amp;gt;&lt;/code&gt; (mechanism description, not a code quote — no examples exist in the OSS checkout).&lt;/p&gt;

&lt;p&gt;Army also has a DDL ace: &lt;a&gt;PostgreDdlParser.java:365-378&lt;/a&gt;, &lt;code&gt;createType()&lt;/code&gt; emits &lt;code&gt;CREATE TYPE/DOMAIN&lt;/code&gt; for the four user-defined categories &lt;code&gt;SqlComposite / SqlEnum / SqlDefinedRange / SqlDomain&lt;/code&gt;; and the database's "ranges can't be altered" limit is encoded as a deterministic error message (L391-392: &lt;code&gt;"PostgreSQL don't support alter range type"&lt;/code&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  3.8 COMPOSITE (CREATE TYPE … AS)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Mapping.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Army (Java-first)&lt;/strong&gt;: &lt;a&gt;CompositeType.java:47-62&lt;/a&gt; maps a top-level POJO annotated with &lt;code&gt;@DefinedType(category = COMPOSITE, fieldOrder = {...})&lt;/code&gt; to a PG composite type; &lt;code&gt;from()&lt;/code&gt; validates annotation completeness and class placement at build time. The real example &lt;a&gt;ProductInfo.java:14-41&lt;/a&gt; — note composite fields can &lt;strong&gt;embed arrays and another composite type&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@MappedSuperclass&lt;/span&gt;
&lt;span class="nd"&gt;@DefinedType&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"PRODUCT_INFO"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;fieldOrder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"productId"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"productName"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"price"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"available"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"releaseDate"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"intArray"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"textArray"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"managerInfo"&lt;/span&gt;&lt;span class="o"&gt;})&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProductInfo&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;FieldAccessPojo&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Column&lt;/span&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;productId&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="nd"&gt;@Column&lt;/span&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;intArray&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nd"&gt;@Column&lt;/span&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;textArray&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nd"&gt;@Column&lt;/span&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ManagerInfo&lt;/span&gt; &lt;span class="n"&gt;managerInfo&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// nested composite&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The annotation processor recognizes &lt;code&gt;FieldType.COMPOSITE&lt;/code&gt; and generates the metamodel (&lt;code&gt;MirrorFieldTypeParser&lt;/code&gt;, &lt;code&gt;CompositeSourceCodeGen&lt;/code&gt; in army-annotation).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;jOOQ (database-first)&lt;/strong&gt;: composites are reverse-generated &lt;strong&gt;UDTs&lt;/strong&gt; — &lt;a&gt;UDT.java:53-62&lt;/a&gt;: "Instances of this type cannot be created directly. They are available from generated code.", plus the ROW-construction expression &lt;code&gt;Field&amp;lt;R&amp;gt; construct(Field&amp;lt;?&amp;gt;... args)&lt;/code&gt; (&lt;a&gt;L99-104&lt;/a&gt;, &lt;code&gt;@Support({DUCKDB, POSTGRES, YUGABYTEDB})&lt;/code&gt;); the runtime carrier is &lt;code&gt;UDTRecord&lt;/code&gt;/&lt;code&gt;UDTRecordImpl&lt;/code&gt;, the data type is &lt;code&gt;UDTDataType&lt;/code&gt; holding the UDT reference (&lt;a&gt;UDTDataType.java:50-63&lt;/a&gt;). Reverse engineering is done by jOOQ-meta's &lt;code&gt;PostgresUDTDefinition&lt;/code&gt; (querying &lt;code&gt;information_schema.ATTRIBUTES&lt;/code&gt;/pg_catalog) and jOOQ-codegen's &lt;code&gt;JavaGenerator.generateUDTRecords&lt;/code&gt;. jOOQ also deliberately distinguishes &lt;strong&gt;EmbeddableRecord&lt;/strong&gt; — "implemented purely as a code generation feature where columns in a &lt;code&gt;Table&lt;/code&gt; should be grouped to form a synthetic &lt;code&gt;UDTRecord&lt;/code&gt; type" (&lt;a&gt;EmbeddableRecord.java:42-46&lt;/a&gt;): a UDT is a real database type; an embeddable is pure client-side column grouping. The two are not conflated.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Implementation.&lt;/strong&gt; Text protocol again, arrived at independently. Army uses a dedicated PG composite text parser (&lt;a&gt;CompositeType.java:65-80&lt;/a&gt;): &lt;code&gt;( )&lt;/code&gt; boundaries, comma delimiters, double-quote escaping, &lt;code&gt;nothing&lt;/code&gt; for null, whitespace kept inside field values. jOOQ's &lt;code&gt;DefaultRecordBinding.set0&lt;/code&gt; does &lt;code&gt;setString(..., PostgresUtils.toPGString(value))&lt;/code&gt; for the PG family (&lt;a&gt;DefaultBinding.java:4629-4633&lt;/a&gt;), with a UDT-name cast when inlined (&lt;code&gt;pgRenderRecordCast&lt;/code&gt; detecting &lt;code&gt;UDTDataType&lt;/code&gt;, L4596-4606).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Metadata &amp;amp; DDL.&lt;/strong&gt; On the reverse side Army fetches ENUM/RANGE/DOMAIN/COMPOSITE metadata in one big SQL (&lt;a&gt;PostgreParser.java:112-164&lt;/a&gt;: &lt;code&gt;CASE(t.typcategory) WHEN 'C' THEN 'COMPOSITE' WHEN 'E' THEN 'ENUM' WHEN 'R' THEN 'RANGE' ...&lt;/code&gt;, composite attributes coming from a &lt;code&gt;pg_attribute&lt;/code&gt; LATERAL subquery); on the forward side it can not only CREATE TYPE but &lt;code&gt;modifyType()&lt;/code&gt; also emits &lt;code&gt;ALTER TYPE ... ADD/DROP/ALTER ATTRIBUTE&lt;/code&gt; diffs for composites (the &lt;code&gt;compositeDropFieldList/compositeNewFieldList/compositeModifyFieldList&lt;/code&gt; at PostgreDdlParser.java:983/1007/1044) — field-level schema evolution of composite types is inside the DDL sync.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Usage.&lt;/strong&gt; Army side, &lt;a&gt;PostgreTypes.java:347-348,460-462&lt;/a&gt;: &lt;code&gt;public ProductInfo productInfo;&lt;/code&gt;, &lt;code&gt;public ManagerInfo managerInfo;&lt;/code&gt;, &lt;code&gt;public ProductInfo[] productInfoArray;&lt;/code&gt; — inside the domain object they are plain POJO fields, stored and fetched like ordinary columns.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.9 VECTOR (pgvector)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Army: a built-in citizen, three layers complete.&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Mapping&lt;/strong&gt;: &lt;a&gt;VectorType.java:41-79&lt;/a&gt;, verbatim excerpt — one type serves both pgvector and MySQL 9:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;VectorType&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;_ArmyNoInjectionType&lt;/span&gt;
        &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;MappingType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SqlUserDefined&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;MappingType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SqlVector&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Class&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;javaType&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="o"&gt;[].&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;DataType&lt;/span&gt; &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ServerMeta&lt;/span&gt; &lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;UnsupportedDialectException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;serverDatabase&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nl"&gt;PostgreSQL:&lt;/span&gt; &lt;span class="n"&gt;dataType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;obtainDataType&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// CustomType "VECTOR"&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nl"&gt;MySQL:&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;meetsMinimum&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="n"&gt;dataType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MySQLType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;VECTOR&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="n"&gt;mapError&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;dataType&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The array form is &lt;code&gt;VectorArrayType&lt;/code&gt; in army-array (&lt;code&gt;arrayTypeOfThis()&lt;/code&gt; → &lt;code&gt;float[][]&lt;/code&gt;).&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Query operators&lt;/strong&gt;: &lt;a&gt;TypedField.java:243-277&lt;/a&gt; defines six pgvector distance operators, all &lt;code&gt;@Support({PostgreSQL})&lt;/code&gt;: &lt;code&gt;spaceL1Distance&lt;/code&gt; (&lt;code&gt;&amp;lt;+&amp;gt;&lt;/code&gt; L1), &lt;code&gt;spaceL2Distance&lt;/code&gt; (&lt;code&gt;&amp;lt;-&amp;gt;&lt;/code&gt; L2), &lt;code&gt;spaceCosineDistance&lt;/code&gt; (&lt;code&gt;&amp;lt;=&amp;gt;&lt;/code&gt; cosine), &lt;code&gt;spaceHammingDistance&lt;/code&gt; (&lt;code&gt;&amp;lt;~&amp;gt;&lt;/code&gt; binary-vector Hamming), &lt;code&gt;spaceJaccardDistance&lt;/code&gt; (&lt;code&gt;&amp;lt;%&amp;gt;&lt;/code&gt; Jaccard), &lt;code&gt;spaceNegDot&lt;/code&gt; (&lt;code&gt;&amp;lt;#&amp;gt;&lt;/code&gt; negative inner product); implementation in &lt;code&gt;OperationTypedField&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ecosystem&lt;/strong&gt;: the army-spring-ai-vector-store module's &lt;a&gt;ArmyVectorStore.java:64&lt;/a&gt; class javadoc says "Built-in pgvector integration for similarity search", with a companion &lt;code&gt;PgVectorFilterExpressionConverter&lt;/code&gt;. Real entity field: &lt;code&gt;public float[][] vectorArray;&lt;/code&gt; at &lt;a&gt;PostgreTypes.java:464-466&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;jOOQ: absent in OSS; do-it-yourself via the Binding SPI.&lt;/strong&gt; Repo-wide (all modules) greps for &lt;code&gt;pgvector&lt;/code&gt;, &lt;code&gt;halfvec&lt;/code&gt;, &lt;code&gt;&amp;lt;=&amp;gt;&lt;/code&gt;, &lt;code&gt;cosine_distance&lt;/code&gt; return zero hits; the jOOQ-postgres-extensions supported-types list (cidr/citext/daterange/hstore/inet/int4range/int8range/ltree/numrange/tsrange/tstzrange) contains no vector (official docs: &lt;a href="https://www.jooq.org/doc/latest/manual/code-generation/codegen-extensions/codegen-extension-postgres/" rel="noopener noreferrer"&gt;https://www.jooq.org/doc/latest/manual/code-generation/codegen-extensions/codegen-extension-postgres/&lt;/a&gt; ); the community approach is a hand-written Binding with a &lt;code&gt;::vector&lt;/code&gt; cast in SQL (example: &lt;a href="https://gist.github.com/yahorbarkouski/bcfbf2bf1b10ff7757f2c629eab33a46" rel="noopener noreferrer"&gt;https://gist.github.com/yahorbarkouski/bcfbf2bf1b10ff7757f2c629eab33a46&lt;/a&gt; ). To be precise: this conclusion is based on source plus the official supported-types page; a commercial-roadmap item may exist — but in the open-source checkout under comparison, it is genuinely absent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Commentary&lt;/strong&gt;: this contrast shows the two temperaments best — Army treats the post-2024 AI infrastructure as a dialect first-class citizen (type + operators + Spring AI, one stop), while jOOQ leaves the extension point and lets users plug in via the Binding SPI. The former is batteries-included for AI scenarios; the latter refuses to compromise on "stable core, externalized extensions".&lt;/p&gt;

&lt;h3&gt;
  
  
  3.10 Cross-family summary
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Army: mapping / carrier&lt;/th&gt;
&lt;th&gt;jOOQ: mapping / carrier&lt;/th&gt;
&lt;th&gt;Shared implementation trait&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ARRAY&lt;/td&gt;
&lt;td&gt;54 &lt;code&gt;PgType&lt;/code&gt; constants + 43 named &lt;code&gt;*ArrayType&lt;/code&gt; MappingTypes in army-array; &lt;code&gt;int[]&lt;/code&gt; auto, &lt;code&gt;int[][]&lt;/code&gt;/complex via &lt;code&gt;@Mapping&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;generic &lt;code&gt;DataType&amp;lt;T[]&amp;gt;&lt;/code&gt; lifting + extension &lt;code&gt;*ArrayBinding&lt;/code&gt;; &lt;code&gt;array()/unnest()&lt;/code&gt; rendered multi-dialect&lt;/td&gt;
&lt;td&gt;neither uses &lt;code&gt;createArrayOf&lt;/code&gt;; PG text &lt;code&gt;'{…}'&lt;/code&gt; + cast, each side has its own multi-dim/escape codec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RANGE&lt;/td&gt;
&lt;td&gt;army-guava &lt;code&gt;GuavaRangeType&lt;/code&gt; → Guava &lt;code&gt;Range&amp;lt;T&amp;gt;&lt;/code&gt; (String without Guava)&lt;/td&gt;
&lt;td&gt;built-in &lt;code&gt;IntegerRange/OffsetDateTimeRange…&lt;/code&gt; implementing &lt;code&gt;Range&amp;lt;T&amp;gt;&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;both parse &lt;code&gt;[1,5)&lt;/code&gt;/&lt;code&gt;( , )&lt;/code&gt;/&lt;code&gt;empty&lt;/code&gt; text, bind via setString&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MULTIRANGE&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;GuavaRangeSetType&lt;/code&gt; → Guava &lt;code&gt;RangeSet&amp;lt;T&amp;gt;&lt;/code&gt; (&lt;strong&gt;present&lt;/strong&gt;)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;no corresponding classes&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;COMPOSITE&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;@DefinedType(COMPOSITE)&lt;/code&gt; POJO + processor metamodel; nested composites/arrays; CREATE/ALTER TYPE in DDL sync&lt;/td&gt;
&lt;td&gt;reverse-generated &lt;code&gt;UDTRecord&lt;/code&gt; (&lt;code&gt;UDT.construct&lt;/code&gt;); embeddables are a separate client-only path&lt;/td&gt;
&lt;td&gt;neither uses &lt;code&gt;createStruct&lt;/code&gt;; PG record text &lt;code&gt;(a,b)&lt;/code&gt; + cast&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;VECTOR&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;built-in&lt;/strong&gt; &lt;code&gt;VectorType&lt;/code&gt; (&lt;code&gt;float[]&lt;/code&gt;, PG + MySQL 9), 6 &lt;code&gt;@Support(PostgreSQL)&lt;/code&gt; distance operators, Spring AI integration&lt;/td&gt;
&lt;td&gt;absent in OSS; hand-written Binding + &lt;code&gt;::vector&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Army likewise binds via serialized text&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;One-line verdict: &lt;strong&gt;jOOQ's type extension is "one orthogonal core + external extension modules"; Army's is "an explicit catalog + optional ecosystem modules (guava/array/spring-ai)".&lt;/strong&gt; Fewer abstractions versus more out-of-the-box types — the same worldview as the statement layer's "dialect-as-parameter vs dialect-as-API" divide, continued into the type layer.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Statement Capabilities, Item by Item
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Capability&lt;/th&gt;
&lt;th&gt;Army (army-postgre)&lt;/th&gt;
&lt;th&gt;jOOQ (open-source checkout)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;INSERT … RETURNING&lt;/td&gt;
&lt;td&gt;✅ &lt;code&gt;asReturningInsert()&lt;/code&gt; (&lt;a&gt;PostgreInserts.java:1247&lt;/a&gt;)&lt;/td&gt;
&lt;td&gt;✅ &lt;code&gt;InsertReturningStep.returning()/returningResult()&lt;/code&gt; (&lt;a&gt;InsertReturningStep.java:111-178&lt;/a&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;UPDATE … RETURNING&lt;/td&gt;
&lt;td&gt;✅ &lt;code&gt;asReturningUpdate()&lt;/code&gt; (&lt;a&gt;PostgreUpdates.java:549&lt;/a&gt;)&lt;/td&gt;
&lt;td&gt;✅ &lt;code&gt;UpdateReturningStep&lt;/code&gt; (&lt;a&gt;UpdateReturningStep.java:112&lt;/a&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DELETE … RETURNING&lt;/td&gt;
&lt;td&gt;✅ &lt;code&gt;asReturningDelete()&lt;/code&gt; (&lt;a&gt;PostgreDeletes.java:536&lt;/a&gt;)&lt;/td&gt;
&lt;td&gt;✅ &lt;code&gt;DeleteReturningStep&lt;/code&gt; (&lt;a&gt;DeleteReturningStep.java:110&lt;/a&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;INSERT … ON CONFLICT&lt;/td&gt;
&lt;td&gt;✅ &lt;code&gt;.onConflict()&lt;/code&gt; + conflict target (index columns/collation/operator class/&lt;code&gt;onConstraint&lt;/code&gt;/&lt;code&gt;WHERE&lt;/code&gt; predicate) + &lt;code&gt;doNothing()/doUpdate()&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;✅ &lt;code&gt;onConflict(keys)/onConflictOnConstraint(...)/onConflictDoNothing()/doUpdate()&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MERGE&lt;/td&gt;
&lt;td&gt;✅ &lt;code&gt;Postgres.singleMerge()&lt;/code&gt; (PG15 MERGE) + tests&lt;/td&gt;
&lt;td&gt;✅ MERGE API; also used to &lt;strong&gt;emulate&lt;/strong&gt; multi-unique-key UPSERT on PG&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DECLARE/FETCH/MOVE/CLOSE cursors&lt;/td&gt;
&lt;td&gt;✅ &lt;strong&gt;full server-side family&lt;/strong&gt; (&lt;code&gt;declareStmt()/closeCursor()/closeAllCursor()&lt;/code&gt; + &lt;code&gt;SyncStmtCursor&lt;/code&gt; + &lt;code&gt;Direction&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;❌ no DECLARE CURSOR DSL; &lt;code&gt;Cursor&lt;/code&gt; is a JDBC fetchSize streaming wrapper&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DISTINCT ON&lt;/td&gt;
&lt;td&gt;✅ rendered at &lt;a&gt;PostgreDialectParser.java:1170-1190&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;✅ &lt;code&gt;SelectDistinctOnStep.distinctOn(...)&lt;/code&gt; (&lt;a&gt;SelectDistinctOnStep.java:163&lt;/a&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-table UPDATE/DELETE&lt;/td&gt;
&lt;td&gt;❌ doesn't exist (MySQL-only)&lt;/td&gt;
&lt;td&gt;➖ single API, rendered per dialect&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;pgvector&lt;/td&gt;
&lt;td&gt;✅ &lt;code&gt;VectorType&lt;/code&gt; + 6 distance operators + Spring AI (see §3.9)&lt;/td&gt;
&lt;td&gt;❌ absent in OSS (grep-verified; hand-written Binding)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;COPY / LISTEN / NOTIFY&lt;/td&gt;
&lt;td&gt;❌ (grep-verified)&lt;/td&gt;
&lt;td&gt;❌ (&lt;code&gt;CopyManager&lt;/code&gt;: 0 hits repo-wide, grep-verified)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SET / SHOW&lt;/td&gt;
&lt;td&gt;✅ &lt;code&gt;setStmt()/show()/showAll()&lt;/code&gt; factories&lt;/td&gt;
&lt;td&gt;(not audited in this pass)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  4.1 ON CONFLICT: different strengths
&lt;/h3&gt;

&lt;p&gt;Army's conflict target goes down to &lt;strong&gt;collation and operator classes&lt;/strong&gt; (&lt;a&gt;PostgreInsert.java:109-160&lt;/a&gt;: &lt;code&gt;_ConflictCollateSpec.collation(...)&lt;/code&gt;, &lt;code&gt;_ConflictOpClassSpec.space(String operatorClass)&lt;/code&gt;, &lt;code&gt;_ConflictTargetOptionSpec.onConstraint(String)&lt;/code&gt;, plus indexed columns and a &lt;code&gt;WHERE&lt;/code&gt; index predicate inside &lt;code&gt;parens(...)&lt;/code&gt;); jOOQ's &lt;code&gt;onConflictOnConstraint&lt;/code&gt; accepts &lt;strong&gt;typed &lt;code&gt;UniqueKey&amp;lt;R&amp;gt;&lt;/code&gt;/&lt;code&gt;Constraint&lt;/code&gt;/&lt;code&gt;Name&lt;/code&gt;&lt;/strong&gt; directly (&lt;a&gt;InsertOnDuplicateStep.java:114-161&lt;/a&gt;) — stronger when combined with codegen metadata. On the action side the two align (jOOQ signature verbatim):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// InsertOnConflictDoUpdateStep.java:90-99&lt;/span&gt;
&lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nd"&gt;@CheckReturnValue&lt;/span&gt;
&lt;span class="nd"&gt;@Support&lt;/span&gt;&lt;span class="o"&gt;({&lt;/span&gt; &lt;span class="no"&gt;CUBRID&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;DERBY&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;DUCKDB&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;FIREBIRD&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;H2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;HSQLDB&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;MARIADB&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;MYSQL&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;POSTGRES&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;SQLITE&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;YUGABYTEDB&lt;/span&gt; &lt;span class="o"&gt;})&lt;/span&gt;
&lt;span class="nc"&gt;InsertOnDuplicateSetStep&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;R&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;doUpdate&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="nc"&gt;InsertReturningStep&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;R&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;doNothing&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4.2 MERGE: an entrée vs an emulator
&lt;/h3&gt;

&lt;p&gt;MERGE, introduced in PG 15, is a &lt;strong&gt;first-class factory&lt;/strong&gt; in Army (&lt;code&gt;singleMerge()&lt;/code&gt;, javadoc linking the official doc), and &lt;a&gt;MergeTests.java&lt;/a&gt; contains real &lt;code&gt;MERGE ... RETURNING&lt;/code&gt; tests (L59, L111). jOOQ has MERGE APIs too — but the more interesting part is its cameo on PG: when an UPSERT conflict involves multiple unique keys and there's no RETURNING, it rewrites into MERGE as an emulation (&lt;a&gt;InsertQueryImpl.java:479-494&lt;/a&gt;, excerpt):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nl"&gt;POSTGRES:&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;dialect&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;supports&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;POSTGRES&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;dialect&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;supports&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;DUCKDB&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;onConstraint&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;onConflict&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
        &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;returning&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getKeys&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;acceptMerge&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same statement: one is "the user orders it off the menu", the other is "a stage prop inside the renderer" — the two philosophies in miniature.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.3 Cursors: the deepest block of Army's PG dialect
&lt;/h3&gt;

&lt;p&gt;Army ships a complete &lt;strong&gt;server-side cursor statement family&lt;/strong&gt;: &lt;code&gt;declareStmt()&lt;/code&gt; (the &lt;code&gt;PostgreCursor&lt;/code&gt; chain) → execute to &lt;code&gt;ResultStates&lt;/code&gt; → on &lt;code&gt;SyncStmtCursor&lt;/code&gt;: &lt;code&gt;next()/fetchOneObject(Direction...)/move(Direction.LAST)/fetch(Direction.FORWARD_ALL...)&lt;/code&gt;, plus &lt;code&gt;closeCursor(name)/closeAllCursor()&lt;/code&gt;. The &lt;code&gt;declareStmt()&lt;/code&gt; javadoc embeds a complete runnable example (&lt;a&gt;Postgres.java:280-317&lt;/a&gt;, verbatim excerpt):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;stmt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Postgres&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;declareStmt&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;declare&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"my_china_region_cursor"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;cursor&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;forSpace&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;select&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"c"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;PERIOD&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;T&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;T&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;AS&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"c"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;in&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;SQLs:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;rowParam&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;extractRegionIdList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;regionList&lt;/span&gt;&lt;span class="o"&gt;)))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;orderBy&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;limit&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;SQLs:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;literal&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;regionList&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asQuery&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asCommand&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;states&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;updateAsStates&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stmt&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SyncStmtCursor&lt;/span&gt; &lt;span class="n"&gt;cursor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;states&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nonNullOf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SyncStmtCursor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SYNC_STMT_CURSOR&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="n"&gt;region&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;CLASS&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;move&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Direction&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;LAST&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fetch&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Direction&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;FORWARD_ALL&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;CLASS&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ResultStates&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;IGNORE_STATES&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;forEach&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;jOOQ's counterpart is &lt;strong&gt;client-side streaming&lt;/strong&gt;: no DECLARE CURSOR DSL (0 grep hits repo-wide); the &lt;code&gt;Cursor&lt;/code&gt; interface describes itself as &lt;em&gt;"Cursors allow for lazy, sequential access to an underlying JDBC ResultSet."&lt;/em&gt; (&lt;a&gt;Cursor.java:59-63&lt;/a&gt;), entered via &lt;code&gt;ResultQuery.fetchLazy()&lt;/code&gt; (&lt;a&gt;ResultQuery.java:438&lt;/a&gt;), with its own javadoc example (&lt;a&gt;Cursor.java:120&lt;/a&gt;, verbatim):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Cursor&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;lt&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;&lt;span class="nc"&gt;TRecord&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;cursor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;select&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;A&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;B&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;fetchLazy&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Fairness first&lt;/strong&gt;: this is not better-vs-worse. jOOQ's fetchSize streaming is sufficient for most business code and portable across dialects; but "explicit DECLARE / named cursors / bidirectional FETCH/MOVE" can only be expressed in Army's API.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Head-to-Head: Four Same-Problem Use Cases
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Round 1: batch UPSERT + RETURNING (both flexing)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Army&lt;/strong&gt; — verbatim from &lt;a&gt;InsertTests.java:274-286&lt;/a&gt; (note the row alias &lt;code&gt;as("c")&lt;/code&gt; and the existence comment on &lt;code&gt;ignoreReturnIds()&lt;/code&gt; — this is real test code):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ReturningInsert&lt;/span&gt; &lt;span class="n"&gt;stmt&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;stmt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Postgres&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;singleInsert&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ignoreReturnIds&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;  &lt;span class="c1"&gt;// required ,because exists doNothing&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;insertInto&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;T&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;as&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"c"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parens&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;space&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parentId&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;comma&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;regionGdp&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;defaultValue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;visible&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;SQLs:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;literal&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;TRUE&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;values&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;regionList&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;onConflict&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;doNothing&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;returningAll&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asReturningInsert&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;jOOQ&lt;/strong&gt; — the open-source checkout has no tests, so this is a &lt;strong&gt;hand-written sketch against verified API signatures&lt;/strong&gt; (&lt;code&gt;onConflict(Field...)&lt;/code&gt; at InsertOnDuplicateStep.java:114, &lt;code&gt;doUpdate()&lt;/code&gt; at :92, &lt;code&gt;set(Field,T)&lt;/code&gt; at InsertOnDuplicateSetStep.java:117, &lt;code&gt;excluded(Field)&lt;/code&gt; at DSL.java:19243, &lt;code&gt;returningResult&lt;/code&gt; at InsertReturningStep.java:178):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Sketch (hand-written), not a verbatim excerpt; every method signature verified in 3.22.0-SNAPSHOT sources&lt;/span&gt;
&lt;span class="nc"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Record1&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Long&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;insertInto&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;REGION&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;columns&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;REGION&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;NAME&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;REGION&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PARENT_ID&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;REGION&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;GDP&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;values&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"South China"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"78000"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;onConflict&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;REGION&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ID&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;doUpdate&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;REGION&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;GDP&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;excluded&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;REGION&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;GDP&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;returningResult&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;REGION&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ID&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fetch&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Impressions&lt;/strong&gt;: equal information density. Army's &lt;code&gt;.as("c")&lt;/code&gt; row alias makes the &lt;code&gt;excluded&lt;/code&gt; semantics explicit as a reference to &lt;code&gt;c&lt;/code&gt; (same design spirit as MySQL 8.0.19 row aliases); jOOQ's &lt;code&gt;excluded()&lt;/code&gt; reads closer to the PG manual. Army's staged interfaces mean &lt;strong&gt;wrong clause order doesn't compile&lt;/strong&gt; (e.g., trying &lt;code&gt;.doUpdate()&lt;/code&gt; before a conflict target — no such type path exists).&lt;/p&gt;

&lt;h3&gt;
  
  
  Round 2: cursors (see §4.3 — a shape difference, decisively in Army's favor)
&lt;/h3&gt;

&lt;h3&gt;
  
  
  Round 3: range-typed columns
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Army: &lt;code&gt;@Column&lt;/code&gt; metadata declares &lt;code&gt;PgType.TSTZRANGE&lt;/code&gt;; the entity field is &lt;code&gt;String&lt;/code&gt;; comparisons (&lt;code&gt;=, &amp;amp;&amp;amp;, @&amp;gt;&lt;/code&gt;) happen in SQL expressions.&lt;/li&gt;
&lt;li&gt;jOOQ: the record field is &lt;code&gt;OffsetDateTimeRange&lt;/code&gt;; the extension Binding converts between PG text and the object.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Round 4: array columns
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Army: 54 prefab &lt;code&gt;*_ARRAY&lt;/code&gt; static types + the &lt;code&gt;PostgreArrays&lt;/code&gt; parser (multi-dimensional and custom-subscript forms included — see §3.1 test comments).&lt;/li&gt;
&lt;li&gt;jOOQ: any &lt;code&gt;DataType&amp;lt;T&amp;gt;&lt;/code&gt; upgrades to &lt;code&gt;DataType&amp;lt;T[]&amp;gt;&lt;/code&gt; via &lt;code&gt;getArrayDataType()&lt;/code&gt; (&lt;a&gt;ArrayDataType.java:65-69&lt;/a&gt;) plus &lt;code&gt;DSL.array()/unnest()&lt;/code&gt; and the extensions' &lt;code&gt;*ArrayBinding&lt;/code&gt;. &lt;strong&gt;A general mechanism vs a prefab catalog&lt;/strong&gt; — philosophy again.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  6. Version Strategy: Explicit Enum vs Commercial Versioned Dialects
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Army&lt;/strong&gt;'s PG version enum, verbatim (&lt;a&gt;PostgreDialect.java:24-36&lt;/a&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="no"&gt;POSTGRE11&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
&lt;span class="no"&gt;POSTGRE12&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
&lt;span class="no"&gt;POSTGRE13&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
&lt;span class="no"&gt;POSTGRE14&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
&lt;span class="no"&gt;POSTGRE15&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
&lt;span class="no"&gt;POSTGRE16&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
&lt;span class="no"&gt;POSTGRE18&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three remarks (all reproducible from source):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;from(ServerMeta)&lt;/code&gt; maps 11–16 explicitly; &lt;strong&gt;everything else (including 17) falls to the default branch → POSTGRE18&lt;/strong&gt; (L74-99) — there is genuinely no POSTGRE17 constant.&lt;/li&gt;
&lt;li&gt;Version constants are referenced barely once inside army-postgre main code (&lt;code&gt;PostgreUtils.DIALECT = POSTGRE16&lt;/code&gt;, a parse-time constant) — a contrast with army-mysql's dense version gating; the PG module leans on the static "capability absent = API absent" expression instead.&lt;/li&gt;
&lt;li&gt;Version detection happens at runtime (&lt;code&gt;ServerMeta.major()&lt;/code&gt;); a mismatched statement errors at render time rather than being quietly emulated.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;jOOQ&lt;/strong&gt;'s OSS edition ships only the family constant (≙POSTGRES_18); the &lt;code&gt;RequiredVersion(18,null,null)&lt;/code&gt; and &lt;code&gt;precedes()&lt;/code&gt; machinery (&lt;code&gt;SQLDialect.java:1438-1500&lt;/code&gt;) serve the commercial edition's versioned dialects. For open-source users this means: &lt;strong&gt;everything renders as "latest PG"; compatibility with older servers comes from emulation branches, not version switches.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  7. Metamodel Direction, Doc Density, and Openness of Tests
&lt;/h2&gt;

&lt;h3&gt;
  
  
  7.1 Metamodel: Java-first vs database-first
&lt;/h3&gt;

&lt;p&gt;Army's metamodel comes from an &lt;strong&gt;annotation processor&lt;/strong&gt;: &lt;code&gt;@Table&lt;/code&gt; entities → generated &lt;code&gt;ChinaRegion_&lt;/code&gt; static metamodel (&lt;code&gt;T&lt;/code&gt;, &lt;code&gt;FieldMeta&amp;lt;T&amp;gt;&lt;/code&gt; fields); type safety grows from the Java side. army-postgre also reaches the other way: &lt;code&gt;PostgreParser&lt;/code&gt; can query PG custom-type metadata (ENUM/RANGE/DOMAIN/COMPOSITE, reading &lt;code&gt;pg_range&lt;/code&gt; subtype/operClass — &lt;a&gt;PostgreParser.java:109-194&lt;/a&gt;) for DDL comparison.&lt;/p&gt;

&lt;p&gt;jOOQ is classic &lt;strong&gt;database-first&lt;/strong&gt;: jOOQ-codegen + jOOQ-meta reverse-generate Records/metamodels from schema (this checkout contains the &lt;code&gt;jOOQ-codegen*&lt;/code&gt; and &lt;code&gt;jOOQ-meta*&lt;/code&gt; modules). Opposite directions, different fits: legacy-schema-first teams pick codegen; domain-model-first teams pick annotation processing.&lt;/p&gt;

&lt;h3&gt;
  
  
  7.2 Doc density: 1,243 vs 18
&lt;/h3&gt;

&lt;p&gt;army-postgre main sources contain &lt;strong&gt;1,243&lt;/strong&gt; postgresql.org links — &lt;code&gt;PostgreSyntax&lt;/code&gt; and the function classes cite the PG manual function by function (geometry, text search, JSON, windows…). jOOQ core has &lt;strong&gt;18&lt;/strong&gt;. Not a quality verdict — a maintenance strategy: jOOQ relies on its commercial team and tests; Army nails the evidence into the source where readers can see it.&lt;/p&gt;

&lt;h3&gt;
  
  
  7.3 Test openness: a difference that matters to this article's methodology
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;All of Army's use cases are open source&lt;/strong&gt;: army-example carries a full PG sync-session suite (&lt;code&gt;session/sync/postgre/&lt;/code&gt;: &lt;code&gt;InsertTests/UpdateTests/DeleteTests/MergeTests/CursorTests&lt;/code&gt;, …), mapping tests (&lt;code&gt;PostgreFullType&lt;/code&gt;, &lt;code&gt;PostgreArraysUnitTests&lt;/code&gt;), dialect tests (&lt;code&gt;PostgreDdlTests&lt;/code&gt;), and criteria unit tests (&lt;code&gt;criteria/postgre/statement/PostgreUnitTests&lt;/code&gt;); army-postgre itself has &lt;code&gt;PostgreDialectUtilsTests&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;jOOQ's open-source checkout contains no tests at all&lt;/strong&gt;: no examples module at the top level, &lt;code&gt;jOOQ/src&lt;/code&gt; has only &lt;code&gt;main&lt;/code&gt; (repo-wide &lt;code&gt;find -type d -name test&lt;/code&gt;: zero hits). jOOQ's PostgreSQL integration tests live in its commercial codebase. Hence the signature-level citations plus marked hand-written sketches for jOOQ in this article — not laziness, but an objective difference in open-source transparency that happens to be one of Army's quiet advantages: &lt;strong&gt;anyone can clone and run every one of its use cases.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  8. Summary Table
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;Army&lt;/th&gt;
&lt;th&gt;jOOQ (OSS checkout 3.22.0-SNAPSHOT)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Philosophy&lt;/td&gt;
&lt;td&gt;Dialect-as-API, one door per database&lt;/td&gt;
&lt;td&gt;One DSL, dialect-as-parameter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PG entry&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Postgres.java&lt;/code&gt;, 18 factories&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;DSL&lt;/code&gt; facade + &lt;code&gt;SQLDialect.POSTGRES&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RETURNING (I/U/D)&lt;/td&gt;
&lt;td&gt;✅ all three&lt;/td&gt;
&lt;td&gt;✅ all three&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ON CONFLICT&lt;/td&gt;
&lt;td&gt;target supports collation/operator class/constraint name/WHERE predicate&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;onConflict(keys)&lt;/code&gt;/&lt;code&gt;onConflictOnConstraint(UniqueKey)&lt;/code&gt; — stronger typing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MERGE&lt;/td&gt;
&lt;td&gt;first-class (PG15) + RETURNING tests&lt;/td&gt;
&lt;td&gt;has the API; doubles as multi-unique-key UPSERT emulation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Server-side cursors&lt;/td&gt;
&lt;td&gt;✅ full DECLARE/FETCH/MOVE/CLOSE&lt;/td&gt;
&lt;td&gt;❌ (client-side &lt;code&gt;fetchLazy&lt;/code&gt; streaming)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DISTINCT ON&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Range/Multirange&lt;/td&gt;
&lt;td&gt;12 constants (String fallback) + Guava &lt;code&gt;Range&amp;lt;T&amp;gt;&lt;/code&gt;/&lt;code&gt;RangeSet&amp;lt;T&amp;gt;&lt;/code&gt; (optional module, §3.7)&lt;/td&gt;
&lt;td&gt;strongly-typed built-in value family (no multirange classes)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Arrays&lt;/td&gt;
&lt;td&gt;54 prefab &lt;code&gt;*_ARRAY&lt;/code&gt; + 43 named MappingTypes in army-array + dedicated text parser (§3.6)&lt;/td&gt;
&lt;td&gt;general &lt;code&gt;DataType&amp;lt;T[]&amp;gt;&lt;/code&gt; mechanism + extension Bindings&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Composite&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;@DefinedType&lt;/code&gt; POJO (nestable) + DDL CREATE/ALTER TYPE (§3.8)&lt;/td&gt;
&lt;td&gt;codegen &lt;code&gt;UDTRecord&lt;/code&gt; (+ client-only EmbeddableRecord)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;inet/hstore/ltree/citext&lt;/td&gt;
&lt;td&gt;INET/CIDR present (String); no hstore/ltree/citext&lt;/td&gt;
&lt;td&gt;all present in extensions, strongly typed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;pgvector&lt;/td&gt;
&lt;td&gt;✅ built in: &lt;code&gt;float[]&lt;/code&gt; + 6 operators + Spring AI (§3.9)&lt;/td&gt;
&lt;td&gt;❌ absent in OSS (grep-verified)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;COPY / LISTEN-NOTIFY&lt;/td&gt;
&lt;td&gt;❌ (verified)&lt;/td&gt;
&lt;td&gt;❌ (verified)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Version strategy&lt;/td&gt;
&lt;td&gt;enum 11–16+18 (no 17; default→18), runtime detection&lt;/td&gt;
&lt;td&gt;OSS family ≙18 only; versioned dialects are commercial&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Metamodel&lt;/td&gt;
&lt;td&gt;annotation processor (Java-first) + DDL comparison&lt;/td&gt;
&lt;td&gt;codegen (database-first)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Java baseline&lt;/td&gt;
&lt;td&gt;25&lt;/td&gt;
&lt;td&gt;25&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Size&lt;/td&gt;
&lt;td&gt;army-postgre 78 files/39,742 LOC&lt;/td&gt;
&lt;td&gt;core 2,126 files/663,534 LOC + extensions 63 files/4,790 LOC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Test openness&lt;/td&gt;
&lt;td&gt;all tests open source and runnable&lt;/td&gt;
&lt;td&gt;no tests in OSS checkout&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  9. Closing: This Comparison Is Really Army's Self-Introduction
&lt;/h2&gt;

&lt;p&gt;Having used jOOQ as a mirror, here is a fair introduction to Army's PostgreSQL dialect:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;It expresses dialect capability through API existence, not emulation&lt;/strong&gt; — everything PG offers that the module covers (RETURNING, ON CONFLICT, MERGE, DISTINCT ON, named cursors, SET/SHOW, 54 array types, 12 range/multirange, RECORD, REF_CURSOR, pgvector) has a typed place on &lt;code&gt;Postgres&lt;/code&gt;'s chains; what it doesn't cover (COPY, LISTEN/NOTIFY, multi-table UPDATE/DELETE) simply doesn't exist in the API. &lt;strong&gt;The compiler is its first piece of documentation.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;On server-side semantics it goes further than the jOOQ open-source edition&lt;/strong&gt;: the full named-cursor family, conflict targets down to collation and operator classes — evidence of people who know PostgreSQL writing the API.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It is equally honest about being young&lt;/strong&gt;: strongly-typed ranges live in an optional Guava module rather than as a built-in value type, no version-17 constant, use cases concentrated on the sync session — concrete, checkable "not dones" you can file as issues one by one, not vague beta warnings.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Its biggest lever is transparency&lt;/strong&gt;: every use case is open source and runnable; every javadoc anchors the official manual. For teams willing to read source, Army's PG dialect is a mine you can assay yourself.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And jOOQ remains the respected yardstick: 660k lines, 20 years, a cross-dialect emulation machine. &lt;strong&gt;Choose jOOQ to buy "one API everywhere + commercial versioned dialects"; choose Army to buy "dialect capability fixed at compile time + fully open test cases."&lt;/strong&gt; If your team lives heavily in PostgreSQL and wants database capability to live explicitly inside the Java type system, &lt;a href="https://github.com/PillArmy/army" rel="noopener noreferrer"&gt;Army's army-postgre&lt;/a&gt; deserves an afternoon of cloning and running its tests — after all, only claims that can be verified verbatim deserve to be called an introduction.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;All Army-side citations are reproducible from &lt;a href="https://github.com/PillArmy/army" rel="noopener noreferrer"&gt;https://github.com/PillArmy/army&lt;/a&gt;; jOOQ-side citations are based on the locally checked-out open-source sources (3.22.0-SNAPSHOT). Hand-written sketches are marked as such. Corrections welcome.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>backend</category>
      <category>database</category>
      <category>java</category>
      <category>sql</category>
    </item>
    <item>
      <title>Army vs Hibernate</title>
      <dc:creator>zoro ma</dc:creator>
      <pubDate>Thu, 17 Sep 2026 16:08:13 +0000</pubDate>
      <link>https://dev.to/zoro7/army-vs-hibernate-1m2l</link>
      <guid>https://dev.to/zoro7/army-vs-hibernate-1m2l</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Army on GitHub: &lt;a href="https://github.com/PillArmy/army" rel="noopener noreferrer"&gt;https://github.com/PillArmy/army&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every claim about Army below comes from its source (&lt;code&gt;0.6.8-SNAPSHOT&lt;/code&gt;, Java 25) and the army-example test suite. Hibernate claims are benchmarked against the current stable release as of September 2026 — &lt;strong&gt;7.4.8.Final&lt;/strong&gt; (2026-09-13, Jakarta Persistence 3.2) — plus official documentation (hibernate.org, docs.hibernate.org). Line counts were measured locally with &lt;code&gt;wc -l&lt;/code&gt; on 2026-09-17.&lt;/p&gt;

&lt;p&gt;Source layering: every Army code block is copied from project source/tests; the Hibernate/JPA block in §2.1 is &lt;strong&gt;my own hand-written sketch&lt;/strong&gt; against the standard JPA API (not taken from any project), included only to contrast the programming models.&lt;/p&gt;

&lt;p&gt;Bias disclaimer: no winner is declared. The main difference is not "who is stronger" — these two were never trying to do the same job.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  0. Meet the Contestants
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Army&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Hibernate ORM&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;What it is&lt;/td&gt;
&lt;td&gt;A type-safe &lt;strong&gt;SQL DSL&lt;/strong&gt; ("not an ORM", its words)&lt;/td&gt;
&lt;td&gt;Java's oldest, fullest &lt;strong&gt;ORM / JPA implementation&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Current version&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;0.6.8-SNAPSHOT&lt;/code&gt; (0.6.7 latest on Maven Central)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;7.4.8.Final&lt;/code&gt; stable; 8.0 in Beta&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Java baseline&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Java 25&lt;/strong&gt; (&lt;code&gt;maven.compiler.source=25&lt;/code&gt;, non-negotiable)&lt;/td&gt;
&lt;td&gt;Java 17 / 21 / 25 / 26&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;License&lt;/td&gt;
&lt;td&gt;Apache 2.0&lt;/td&gt;
&lt;td&gt;Apache 2.0 since 7.0 (6.x was LGPL 2.1)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Standard alignment&lt;/td&gt;
&lt;td&gt;None — proprietary API&lt;/td&gt;
&lt;td&gt;Most mainstream Jakarta Persistence 3.2 (JPA) implementation — JPA itself was heavily influenced by Hibernate, but the official RI is EclipseLink&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Age&lt;/td&gt;
&lt;td&gt;A young 0.x project&lt;/td&gt;
&lt;td&gt;1.0 series in 2002 — a twenty-something "living fossil"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ecosystem&lt;/td&gt;
&lt;td&gt;army-spring integration + two Spring AI modules (Chat Memory / Vector Store); bring your own pool&lt;/td&gt;
&lt;td&gt;Spring Data JPA, Quarkus, WildFly, Envers, Search, Reactive…&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Army's README opens with a deliberately stubborn self-definition:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Army is a type-safe, composable SQL DSL for Java — not an ORM, not a code generator, not a template engine.&lt;/strong&gt; It treats SQL as the right abstraction and gives you an API that matches its power without hiding it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Hibernate's own "A Short Guide to Hibernate 7" describes its central job differently: reading &lt;strong&gt;normalized relational data&lt;/strong&gt;, then &lt;strong&gt;renormalizing it into an object graph&lt;/strong&gt;, and synchronizing in-memory dirty state back to the database.&lt;/p&gt;

&lt;p&gt;The worldview gap in one sentence:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hibernate wants you to write less SQL&lt;/strong&gt; — manipulate an object graph, and the framework generates SQL and manages object state for you.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Army wants what you write to &lt;em&gt;be&lt;/em&gt; SQL&lt;/strong&gt; — expressed through a compile-time type-safe Java chain, with every resulting byte of SQL under your control.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  1. Size: Hold the "Lightweight" Thought
&lt;/h2&gt;

&lt;p&gt;"SQL DSL = small and cute" is a natural assumption. Measured main-source line counts:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Module&lt;/th&gt;
&lt;th&gt;Java files&lt;/th&gt;
&lt;th&gt;Main LOC&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;army-core (DSL contracts + rendering skeleton + metamodel + mapping)&lt;/td&gt;
&lt;td&gt;805&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;120,470&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;army-postgre (PostgreSQL dialect)&lt;/td&gt;
&lt;td&gt;78&lt;/td&gt;
&lt;td&gt;39,742&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;army-mysql (MySQL dialect)&lt;/td&gt;
&lt;td&gt;79&lt;/td&gt;
&lt;td&gt;30,479&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;army-jdbc (JDBC executor)&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;8,437&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;army-sync (synchronous Session API)&lt;/td&gt;
&lt;td&gt;35&lt;/td&gt;
&lt;td&gt;5,193&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;army-annotation (annotations + annotation processor)&lt;/td&gt;
&lt;td&gt;46&lt;/td&gt;
&lt;td&gt;5,099&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;army-spring (Spring integration)&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;1,903&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;army-sqlite&lt;/td&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;1,472&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;army-oracle&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;315 (essentially a placeholder)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;So Army is not light in lines — the core alone is 120k. Its "lightness" is a &lt;strong&gt;simple runtime model&lt;/strong&gt;: no persistence context, no proxies, no cache, no dirty checking. The complexity went into a typed transcription of SQL grammar — 70k lines for just the MySQL and PostgreSQL dialects.&lt;/p&gt;

&lt;p&gt;hibernate-core is a several-hundred-thousand-line engineering product built over two decades, with complexity spent in entirely different places: object-graph management, caching, fetch strategies, the HQL translator, bytecode enhancement.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Complexity is conserved — the only question is whether it lives on the SQL side or the object side.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  2. One Requirement, Two Worldviews
&lt;/h2&gt;

&lt;p&gt;A boring requirement: insert one row, then fetch 20 rows by condition.&lt;/p&gt;

&lt;h3&gt;
  
  
  2.1 Hibernate / JPA (standard API, implementation-agnostic)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Entity&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Stock&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Id&lt;/span&gt; &lt;span class="nd"&gt;@GeneratedValue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strategy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;GenerationType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;IDENTITY&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nd"&gt;@Enumerated&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;EnumType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;STRING&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;StockStatus&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// getters/setters...&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;em&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getTransaction&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;begin&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="nc"&gt;Stock&lt;/span&gt; &lt;span class="n"&gt;stock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Stock&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;                                         &lt;span class="c1"&gt;// plain new, set fields&lt;/span&gt;
&lt;span class="n"&gt;stock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setCode&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"600519"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;stock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setStatus&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;StockStatus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ACTIVE&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;em&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;persist&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stock&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;                                                 &lt;span class="c1"&gt;// now a managed entity in the persistence context&lt;/span&gt;
&lt;span class="nc"&gt;Stock&lt;/span&gt; &lt;span class="n"&gt;again&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;em&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;find&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Stock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1L&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;                            &lt;span class="c1"&gt;// by PK (L1 cache first)&lt;/span&gt;
&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Stock&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;em&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;createQuery&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;"select s from Stock s where s.status = :st order by s.offerPrice desc"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Stock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setParameter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"st"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;StockStatus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ACTIVE&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setMaxResults&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getResultList&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;em&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getTransaction&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;commit&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;                                      &lt;span class="c1"&gt;// dirty checking flush&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You face &lt;strong&gt;objects&lt;/strong&gt;: after &lt;code&gt;persist&lt;/code&gt;, the object joins the persistence context; mutate its fields freely, and at commit/flush Hibernate computes the UPDATEs via dirty checking. You don't even need to know how many statements fire — which, of course, is also the birthplace of every N+1 horror story.&lt;/p&gt;

&lt;h3&gt;
  
  
  2.2 Army (README + real army-example code)
&lt;/h3&gt;

&lt;p&gt;The entity is a plain POJO with just &lt;code&gt;@Table/@Column&lt;/code&gt; — no &lt;code&gt;@Entity&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Table&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"stock"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;indexes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;@Index&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"uni_stock_exchange_code"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fieldList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"exchange"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"code"&lt;/span&gt;&lt;span class="o"&gt;},&lt;/span&gt; &lt;span class="n"&gt;unique&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;comment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"stock"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Stock&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Generator&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"io.army.generator.snowflake.Snowflake8Generator"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;@Param&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"startTime"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"1779012232202"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
    &lt;span class="nd"&gt;@Column&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nd"&gt;@Column&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;LocalDateTime&lt;/span&gt; &lt;span class="n"&gt;createTime&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nd"&gt;@Column&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;notNull&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;precision&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;defaultValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"'NORMAL'"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;StockStatus&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;ArmyMetaModelDomainProcessor&lt;/code&gt; annotation processor generates a static metamodel &lt;code&gt;Stock_&lt;/code&gt; at compile time (visually reminiscent of the JPA static metamodel, but carrying something completely different):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Stock_&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;SimpleTableMeta&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Stock&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;PrimaryFieldMeta&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Stock&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;FieldMeta&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Stock&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;field&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;NAME&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For queries you face &lt;strong&gt;the structured shape of a SQL statement&lt;/strong&gt; (from the README):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Select&lt;/span&gt; &lt;span class="n"&gt;stmt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SQLs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;select&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;space&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Stock_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Stock_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Stock_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Stock_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;offerPrice&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;comma&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Exchange_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Exchange_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;country&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Stock_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;T&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;AS&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"s"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Exchange_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;T&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;AS&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"e"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Stock_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;exchange&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Exchange_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Stock_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;StockStatus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ACTIVE&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;and&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Stock_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;listingDate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;greaterEqual&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;LocalDate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2020&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;orderBy&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Stock_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;offerPrice&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;desc&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;limit&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asQuery&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;StockSummary&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;queryObjectList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stmt&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;StockSummary:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Insertion goes through &lt;code&gt;save&lt;/code&gt; (see &lt;code&gt;ArmySyncSession.save&lt;/code&gt; — it immediately builds and executes an INSERT):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stock&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;save&lt;/code&gt; returns the affected-row count; its body hands the domain to &lt;code&gt;SQLStmts.insertStmt(...)&lt;/code&gt;, executes it, and verifies the count. &lt;strong&gt;No managed state, no snapshot, no flush-timing puzzles&lt;/strong&gt; — you can see exactly when SQL goes out.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Session Layer: A Stateful Object World vs a Stateless SQL Channel
&lt;/h2&gt;

&lt;p&gt;This is the most fundamental difference, and the source evidence is hard.&lt;/p&gt;

&lt;p&gt;Hibernate's &lt;code&gt;Session&lt;/code&gt;/&lt;code&gt;EntityManager&lt;/code&gt; is a &lt;strong&gt;Unit of Work plus a first-level cache&lt;/strong&gt;: &lt;code&gt;find/persist/merge/refresh/remove/flush/evict/clear&lt;/code&gt; form a full object state machine, on top of an optional second-level cache (JCache), query cache, and EntityGraph fetch control.&lt;/p&gt;

&lt;p&gt;I grepped the entire &lt;code&gt;io.army.session&lt;/code&gt; / &lt;code&gt;io.army.dao&lt;/code&gt; source of both army-core and army-sync for state-machine methods — &lt;code&gt;persist(&lt;/code&gt;, &lt;code&gt;merge(&lt;/code&gt;, &lt;code&gt;refresh(&lt;/code&gt;, &lt;code&gt;remove(&lt;/code&gt;, &lt;code&gt;flush(&lt;/code&gt;, &lt;code&gt;evict(&lt;/code&gt;, &lt;code&gt;detach(&lt;/code&gt; — &lt;strong&gt;zero hits&lt;/strong&gt; (the only &lt;code&gt;merge&lt;/code&gt; matches are PostgreSQL MERGE statements and an internal optionMap utility). What &lt;code&gt;SyncSession&lt;/code&gt; offers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Queries: &lt;code&gt;queryOne / queryList / queryObjectList(stmt, ctor ref) / queryRecordList / query(Stream) / paging&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Writes: &lt;code&gt;update(stmt)&lt;/code&gt; / &lt;code&gt;save(domain)&lt;/code&gt; / &lt;code&gt;batchSave(domainList)&lt;/code&gt; / &lt;code&gt;batchUpdate(stmt)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Transactions: &lt;code&gt;startTransaction / commit / rollback / setSavePoint&lt;/code&gt; (on &lt;code&gt;SyncLocalSession&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A fairness note, to avoid overstating it: Army is &lt;em&gt;not&lt;/em&gt; unable to fetch by primary key. &lt;code&gt;SyncBaseDao&lt;/code&gt; in army-sync (and &lt;code&gt;SyncBaseService&lt;/code&gt; in army-spring) offer &lt;code&gt;get(class, id)&lt;/code&gt;, &lt;code&gt;findById&lt;/code&gt;, &lt;code&gt;getByUnique&lt;/code&gt;, &lt;code&gt;existsById&lt;/code&gt;, &lt;code&gt;rowCount&lt;/code&gt;. But look at the implementation — &lt;code&gt;ArmySyncBaseDao.get&lt;/code&gt; simply delegates to &lt;code&gt;findByUnique&lt;/code&gt;, which runs an immediate SELECT. They return plain POJOs that never enter a persistence context; that is a different thing from Hibernate's managed entities.&lt;/p&gt;

&lt;p&gt;Result mapping is equally magic-free: &lt;code&gt;session.queryObjectList(stmt, StockSummary::new)&lt;/code&gt; instantiates a plain object with your constructor/Supplier and fills fields by name. The README is visibly proud of this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;No &lt;code&gt;RecordN&amp;lt;T1,T2,...,TN&amp;gt;&lt;/code&gt; with &lt;code&gt;value1()&lt;/code&gt;/&lt;code&gt;value2()&lt;/code&gt;. No &lt;code&gt;attached&lt;/code&gt;/&lt;code&gt;detached&lt;/code&gt; lifecycle. No lazy-loading proxy that explodes when the session closes. You can serialize it, cache it, pass it across threads — it's just data.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In fairness, Hibernate also knows a heavy state model isn't for everything — it ships &lt;code&gt;StatelessSession&lt;/code&gt;: no L1 cache, no dirty checking, no cascades, reserved for batch jobs. The mental model of Army's main session is roughly &lt;strong&gt;"what if Hibernate's StatelessSession sideline had been promoted to the main event"&lt;/strong&gt; — except Army equipped that path with a complete compile-time SQL DSL.&lt;/p&gt;

&lt;h3&gt;
  
  
  What happens to caching?
&lt;/h3&gt;

&lt;p&gt;Army's README answers "not my problem":&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Army deliberately does NOT manage:&lt;/strong&gt; Database connections → use your preferred connection pool; Transactions → use Spring &lt;code&gt;@Transactional&lt;/code&gt; or JTA; Caches → use Redis, Caffeine, or your own; Schema migrations → use Flyway or Liquibase.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You supply the pool (&lt;code&gt;SyncFactoryBuilder.builder().datasource(hikariDataSource)&lt;/code&gt;); you bring Redis/Caffeine. Hibernate ships a mandatory L1 cache, optional JCache L2, and a query cache — out of the box, at the price of learning &lt;code&gt;CacheMode&lt;/code&gt;, invalidation strategies, and (new in 7.4) even &lt;code&gt;CacheMode.REFRESH_SESSION&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. The Mapping Model: Seventeen Annotations and Zero Relationships
&lt;/h2&gt;

&lt;p&gt;Army's annotation package contains exactly 17 files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Codec, Column, DdlMode, DiscriminatorValue, FieldParam, Generator, GeneratorType,
Index, IndexField, Inheritance, MappedSuperclass, Mapping, NullsOrder,
OverrideParams, Param, SortOrder, Table
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look for &lt;code&gt;ManyToOne&lt;/code&gt;, &lt;code&gt;OneToMany&lt;/code&gt;, &lt;code&gt;ManyToMany&lt;/code&gt;, &lt;code&gt;OneToOne&lt;/code&gt;, &lt;code&gt;JoinColumn&lt;/code&gt;, &lt;code&gt;ElementCollection&lt;/code&gt;, &lt;code&gt;Embedded&lt;/code&gt; — &lt;strong&gt;not there&lt;/strong&gt;. Army does not map object associations. In the example project, &lt;code&gt;ChinaProvince&lt;/code&gt; referencing its parent region is just an unglamorous FK column:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Table&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"china_province"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...)&lt;/span&gt;
&lt;span class="nd"&gt;@DiscriminatorValue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"PROVINCE"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ChinaProvince&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;ChinaRegion&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ChinaProvince&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Column&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;defaultValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;notNull&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;updatable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;comment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"relation Id"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;relationId&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Want related data? Write a JOIN. Hibernate's entire apparatus — &lt;code&gt;@ManyToOne(fetch=LAZY)&lt;/code&gt;, &lt;code&gt;join fetch&lt;/code&gt;, &lt;code&gt;@EntityGraph&lt;/code&gt;, &lt;code&gt;@BatchSize&lt;/code&gt;, &lt;code&gt;FetchMode.SUBSELECT&lt;/code&gt; for "renormalizing the object graph" — physically does not exist in Army. The N+1 problem is gone with it (but so is lazy-loading convenience; every JOIN is now yours to write).&lt;/p&gt;

&lt;p&gt;The ORM-flavored capabilities Army keeps are all within the "single table / table family" scope:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Inheritance + discriminator&lt;/strong&gt;: &lt;code&gt;@Inheritance("regionType")&lt;/code&gt; + &lt;code&gt;@DiscriminatorValue("PROVINCE")&lt;/code&gt;; parent &lt;code&gt;ChinaRegion&lt;/code&gt; maps to &lt;code&gt;china_region&lt;/code&gt;, child &lt;code&gt;ChinaProvince&lt;/code&gt; to &lt;code&gt;china_province&lt;/code&gt;, managed by the &lt;code&gt;ComplexTableMeta&lt;/code&gt; family.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;@MappedSuperclass&lt;/code&gt;&lt;/strong&gt;: &lt;code&gt;AbstractChinaRegion&lt;/code&gt; pulls up shared columns (id, createTime, version…).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ID generation&lt;/strong&gt;: &lt;code&gt;@Generator(type = POST)&lt;/code&gt; identity, or a configured Snowflake (&lt;code&gt;Snowflake8Generator&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Built-in logical delete&lt;/strong&gt;: the &lt;code&gt;Visible&lt;/code&gt; enum (&lt;code&gt;ONLY_VISIBLE / ONLY_NON_VISIBLE / BOTH&lt;/code&gt;) plus &lt;code&gt;ArmyKey.VISIBLE_MODE&lt;/code&gt;; the parser appends visibility predicates automatically to domain queries/updates/deletes. This parallels Hibernate's &lt;code&gt;@SoftDelete&lt;/code&gt;, only added in 6.4 — Army put it in the SQL rendering layer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Built-in optimistic locking&lt;/strong&gt;: domain DML handles version automatically. This real test from army-example's &lt;code&gt;DomainUpdateTests&lt;/code&gt; passes a deliberately wrong version and asserts &lt;code&gt;OptimisticLockException&lt;/code&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;stmt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SQLs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;domainUpdate&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;update&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;T&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;AS&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"c"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;regionGdp&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;SQLs:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;plusEqual&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;SQLs:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gdpAmount&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;in&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;SQLs:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;rowParam&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;extractRegionIdList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;regionList&lt;/span&gt;&lt;span class="o"&gt;)))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;and&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;createTime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;between&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;SQLs:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;minusMinutes&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="no"&gt;AND&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;and&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;regionGdp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;plus&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;SQLs:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gdpAmount&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;greaterEqual&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;and&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;SQLs:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;// error version&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asUpdate&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hibernate's counterpart is &lt;code&gt;@Version&lt;/code&gt; with conditions auto-added during dirty-checking flush; Army injects them while rendering an explicit domain DML — same optimistic lock, one via state machine, one via SQL generation.&lt;/p&gt;

&lt;p&gt;On type mapping, Army splits &lt;code&gt;DataType&lt;/code&gt; (what the database type &lt;em&gt;is&lt;/em&gt;) from &lt;code&gt;MappingType&lt;/code&gt; (how Java talks to JDBC). The showcase: unsigned integers auto-resolve to "the smallest Java type that can't overflow" (&lt;code&gt;INT UNSIGNED→Long&lt;/code&gt;, &lt;code&gt;BIGINT UNSIGNED→BigInteger&lt;/code&gt;), and the three enum strategies &lt;code&gt;CodeEnum/LabelEnum/NameEnum&lt;/code&gt; work with zero annotations. Hibernate offers the JPA-standard &lt;code&gt;AttributeConverter&lt;/code&gt;, &lt;code&gt;@JdbcTypeCode&lt;/code&gt;, &lt;code&gt;UserType&lt;/code&gt; — a bigger, more configurable system.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Querying: An HQL Translator vs Clause-by-Clause SQL Modeling
&lt;/h2&gt;

&lt;h3&gt;
  
  
  On Hibernate's side
&lt;/h3&gt;

&lt;p&gt;Four cards to play:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;HQL/JPQL&lt;/strong&gt;: entity-oriented string query language; the 6.0 translator rewrite (SQM) is very capable (fetch joins, subqueries, CTEs, window functions following along). In fairness, HQL is not an unsupervised raw string: the Hibernate Processor can validate HQL syntax and typing at compile time, and IntelliJ IDEA provides live completion/validation — but the language itself remains string-based rather than a Java-typed chain like Army's DSL;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JPA Criteria API&lt;/strong&gt;: type-safe but famously verbose;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;QuerySpecification&lt;/code&gt; (7.0) and Jakarta Data repositories&lt;/strong&gt;: Data Repositories shipped as a tech preview in 6.5 and went GA in 6.6, with an annotation processor generating repositories at compile time to close the type-safety gap;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Native SQL&lt;/strong&gt;: &lt;code&gt;createNativeQuery&lt;/code&gt;, the escape hatch any time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The abstraction sits higher: &lt;code&gt;from Stock s join s.exchange e&lt;/code&gt; derives the join condition from mappings. Code barely moves when dialects or tables change — at the price of understanding HQL-to-SQL translation, fetch timing, and Cartesian-product warnings.&lt;/p&gt;

&lt;h3&gt;
  
  
  On Army's side
&lt;/h3&gt;

&lt;p&gt;There is no query language string. &lt;strong&gt;The DSL is everything&lt;/strong&gt;, and rendering is direct: a DSL statement is just a data holder; &lt;code&gt;ArmyParser&lt;/code&gt; walks it in SQL grammar order (WITH→SELECT→FROM→WHERE→GROUP BY→…→LIMIT→locks), each expression node writes itself into one shared StringBuilder, and parameters land in one ordered list (army-core README documents the whole pipeline).&lt;/p&gt;

&lt;p&gt;Dialect differences land as template methods on concrete parsers — backticks and MySQL's &lt;code&gt;LIMIT offset,count&lt;/code&gt;, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Override&lt;/span&gt; &lt;span class="kd"&gt;protected&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="nf"&gt;identifierDelimitedQuote&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;BACKTICK&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// MySQL native: LIMIT offset, rowCount (not standard LIMIT n OFFSET m)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two direct consequences:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Database-specific power is a first-class citizen.&lt;/strong&gt; MySQL's &lt;code&gt;STRAIGHT_JOIN&lt;/code&gt;, &lt;code&gt;USE/FORCE INDEX&lt;/code&gt;, the 36 &lt;code&gt;HintType&lt;/code&gt; enum constants of &lt;code&gt;/*+ */&lt;/code&gt; optimizer hints, &lt;code&gt;LOAD DATA&lt;/code&gt;, &lt;code&gt;ON DUPLICATE KEY UPDATE&lt;/code&gt; (including the 8.0.19 row alias), &lt;code&gt;SET @row:=0&lt;/code&gt; user variables; PostgreSQL's 12 range/multirange types, 54 array types, six pgvector distance operators, &lt;code&gt;RETURNING&lt;/code&gt;, &lt;code&gt;DECLARE CURSOR&lt;/code&gt; — each has a typed place on the chain, and version gating happens at render time (a CTE on 5.7 throws immediately instead of failing at the server). Hibernate is catching these too: JDBC Array support arrived in 6.1, array functions in 6.4, Extended Array Support in 6.6; the &lt;code&gt;hibernate-vector&lt;/code&gt; module already existed in 6.4 (SQL Server vectors only landed in 7.2); soft-delete likewise dates to 6.4 — but they surface as HQL functions, extra module dependencies, or native SQL: seams under a unified abstraction.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Portability is one-directional.&lt;/strong&gt; Build with &lt;code&gt;MySQLs.query()&lt;/code&gt; and you are bound to MySQL; portability requires staying on the &lt;code&gt;SQLs.query()&lt;/code&gt; common subset — which deliberately removes about half of the goodies above. Hibernate is "portable by default, extra work for specifics." The arrows point opposite ways.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A real query (army-example &lt;code&gt;QueryTests&lt;/code&gt;): CTE + JOIN + window function + subquery + bind params in one statement:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;stmt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SQLs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"cte"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;as&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;select&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;T&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;AS&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"c"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;in&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;SQLs:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;rowParam&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;regionIdList&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asQuery&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;space&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;select&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaProvince_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Windows&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sum&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;regionGdp&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;over&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"w"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;as&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"gdpSum"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaProvince_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;T&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;AS&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"p"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;T&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;AS&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"c"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaProvince_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;equal&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaProvince_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;SQLs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;subQuery&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;select&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;space&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SQLs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;refField&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"cte"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ID&lt;/span&gt;&lt;span class="o"&gt;)))&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"cte"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asQuery&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;window&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"w"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;as&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;partitionBy&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;orderBy&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;regionGdp&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;desc&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;rows&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;UNBOUNDED_PRECEDING&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;orderBy&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaProvince_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;limit&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;SQLs:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;regionSize&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asQuery&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;rowList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;queryObjectList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stmt&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;RowMaps:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;hashMap&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The price is a huge interface surface: the mysql grammar-contract package alone (&lt;code&gt;io.army.criteria.mysql&lt;/code&gt;, 23 files) contains 3,519 lines of nested interfaces, and staged chains like &lt;code&gt;_PrimaryOptionSpec → _PartitionSpec → …&lt;/code&gt; are a notorious learning cliff. It buys "illegal SQL does not compile" with sheer interface count.&lt;/p&gt;




&lt;h2&gt;
  
  
  6. Dialect Coverage: Wide Net vs Deep Wells
&lt;/h2&gt;

&lt;p&gt;In 7.4, Hibernate ships 16 officially tested dialects inside hibernate-core (MySQL, PostgreSQL, Oracle, SQL Server, the three DB2 flavors, Sybase, H2, HSQL, MariaDB, HANA, Spanner, etc. — per the official Dialect report), while a separate &lt;code&gt;hibernate-community-dialects&lt;/code&gt; module maintains ~30 community/legacy dialects on a best-effort basis (Informix, Ingres, Teradata, TiDB, SQLite…). The mechanism is a unified HQL translator plus dialect classes registering function differences.&lt;/p&gt;

&lt;p&gt;Army's &lt;code&gt;Database&lt;/code&gt; enum lists only five — MySQL, PostgreSQL, H2, SQLite, Oracle — with very different levels of honesty:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dialect&lt;/th&gt;
&lt;th&gt;Module LOC&lt;/th&gt;
&lt;th&gt;Real state&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;MySQL&lt;/td&gt;
&lt;td&gt;30,479&lt;/td&gt;
&lt;td&gt;Deep: 5.5–8.0 version gating, LOAD DATA, multi-table DML, full optimizer hints&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PostgreSQL&lt;/td&gt;
&lt;td&gt;39,742&lt;/td&gt;
&lt;td&gt;Deeper: ranges/arrays/composites/pgvector/RETURNING/DECLARE CURSOR&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SQLite&lt;/td&gt;
&lt;td&gt;1,472&lt;/td&gt;
&lt;td&gt;Basically usable (with its own SchemaComparer)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;H2&lt;/td&gt;
&lt;td&gt;inside core&lt;/td&gt;
&lt;td&gt;Mostly serves tests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Oracle&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;315&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Just the &lt;code&gt;Oracles&lt;/code&gt; entry and a few grammar interfaces — a placeholder&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SQL Server&lt;/td&gt;
&lt;td&gt;none&lt;/td&gt;
&lt;td&gt;Research notes still lying around in &lt;code&gt;local-doc/sql/SqlServer.sql&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;At the executor level, the army-jdbc README itself states support for only &lt;strong&gt;MySQL / PostgreSQL / SQLite&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So, objectively: Army is "two ultra-deep dialects + one lightweight + two uncashed checks"; Hibernate is "16 officially backed dialects + ~30 community ones, whose depth bows to a unified abstraction." This table matters more than any marketing line when choosing.&lt;/p&gt;




&lt;h2&gt;
  
  
  7. Transactions, DDL, Engineering: Where Marketing Can Mislead
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Transactions.&lt;/strong&gt; Army doesn't take over declarative transactions, but its capabilities are solid: &lt;code&gt;SyncLocalSession&lt;/code&gt; offers programmatic &lt;code&gt;startTransaction(option, mode)&lt;/code&gt; (rendering dialect-specific &lt;code&gt;SET TRANSACTION ISOLATION LEVEL … ; START TRANSACTION …&lt;/code&gt;, even multi-statement on MySQL/PG), savepoints, rollback-only marking, plus XA via &lt;code&gt;RmSession&lt;/code&gt;. The recommended daily driver is army-spring's &lt;code&gt;ArmySyncLocalTransactionManager&lt;/code&gt; (a standard &lt;code&gt;PlatformTransactionManager&lt;/code&gt;); tests simply use &lt;code&gt;@Transactional&lt;/code&gt;. Hibernate is a long-standing JTA/Jakarta Transactions citizen with near-default Spring declarative transactions. &lt;strong&gt;Bottom line: in Spring both end up as &lt;code&gt;@Transactional&lt;/code&gt;; you just configure one extra TransactionManager with Army.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DDL.&lt;/strong&gt; Time to gently contradict Army's own README — it claims "doesn't … generate schemas," yet &lt;code&gt;DdlMode&lt;/code&gt; offers five levels: &lt;code&gt;NONE / VALIDATE_UNIQUE / VALIDATE / DROP_CREATE / UPDATE&lt;/code&gt;. &lt;code&gt;ArmySyncFactoryBuilder.initializingSchema&lt;/code&gt; extracts metadata at factory bootstrap → compares via &lt;code&gt;SchemaComparer&lt;/code&gt; → executes DDL automatically; the global &lt;code&gt;ddl.mode&lt;/code&gt; key even defaults to &lt;code&gt;UPDATE&lt;/code&gt;, and the example's &lt;code&gt;FactoryUtils&lt;/code&gt; explicitly sets &lt;code&gt;DdlMode.UPDATE&lt;/code&gt;. That maps almost one-to-one to Hibernate's &lt;code&gt;hbm2ddl.auto=validate/update/create/create-drop&lt;/code&gt;. The difference: Army's docs recommend Flyway/Liquibase, and Hibernate's docs likewise discourage &lt;code&gt;update&lt;/code&gt; in production — &lt;strong&gt;both projects actually agree that automated DDL is a dev-time convenience; Army's README is just unusually humble about what the code already does.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Batch writing.&lt;/strong&gt; Both support JDBC batching. In Army batching is an explicit first-class citizen: separate &lt;code&gt;batchQuery/batchSingleUpdate/batchMultiUpdate/batchSingleDelete/batchMultiDelete&lt;/code&gt; factories with namedParamList — SQL rendered once, parameters bound in batches. In Hibernate you tune &lt;code&gt;hibernate.jdbc.batch_size&lt;/code&gt;, flush order, and &lt;code&gt;order_inserts&lt;/code&gt;; powerful, but you must learn its rhythm.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reactive.&lt;/strong&gt; Hibernate has a separate Hibernate Reactive product line, independent of hibernate-core (Vert.x/Netty drivers; one of the default options in Quarkus's reactive data stack). Army's core Javadoc references &lt;code&gt;io.army.reactive.ReactiveSession&lt;/code&gt; in several places, and commented-out reactive bootstrap code survives in the example factory — but &lt;strong&gt;no reactive module ships in this repository&lt;/strong&gt;; today the only executable path is synchronous + JDBC.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Enterprise features.&lt;/strong&gt; Hibernate has the long-standing Envers auditing module; 7.4 additionally introduced &lt;code&gt;@Audited&lt;/code&gt;/&lt;code&gt;@Temporal&lt;/code&gt; temporal/audited entities in core as an incubating feature (officially a re-implementation of Envers' ideas, with Envers-compatible audit logs), plus Search (full-text), L2 cache, multi-tenancy, and GraalVM. Army's closest neighbors are the two &lt;code&gt;army-spring-ai-*&lt;/code&gt; modules (Chat Memory, Vector Store). No auditing, multi-tenancy, or caching.&lt;/p&gt;




&lt;h2&gt;
  
  
  8. The Big Table
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;Army&lt;/th&gt;
&lt;th&gt;Hibernate ORM 7.4&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Essence&lt;/td&gt;
&lt;td&gt;Type-safe SQL DSL (direct dialect SQL)&lt;/td&gt;
&lt;td&gt;Full ORM / JPA 3.2 implementation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Abstraction center&lt;/td&gt;
&lt;td&gt;SQL statements&lt;/td&gt;
&lt;td&gt;Entity object graph + persistence context&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Query language&lt;/td&gt;
&lt;td&gt;Staged Java DSL (&lt;code&gt;SQLs/MySQLs/Postgres&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;HQL/JPQL, JPA Criteria, Jakarta Data repository methods, native SQL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Compile-time safety&lt;/td&gt;
&lt;td&gt;Headline feature: illegal syntax doesn't compile&lt;/td&gt;
&lt;td&gt;Criteria/static metamodel/Data Repositories fully compile-time; HQL validated at compile time by Hibernate Processor and IDEs, but remains string-based&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Object state machine&lt;/td&gt;
&lt;td&gt;None (no persist/merge/flush/evict)&lt;/td&gt;
&lt;td&gt;Yes, and central (plus the StatelessSession sideline)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;L1/L2 cache&lt;/td&gt;
&lt;td&gt;None; wire your own&lt;/td&gt;
&lt;td&gt;Mandatory L1, JCache L2, query cache&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lazy loading / associations / cascade&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;No association mappings&lt;/strong&gt;; relations are FK columns + hand-written JOINs&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;@ManyToOne/@OneToMany/…&lt;/code&gt;, fetch joins, EntityGraph, cascade&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;N+1 exposure&lt;/td&gt;
&lt;td&gt;Structurally impossible (but every JOIN is manual)&lt;/td&gt;
&lt;td&gt;Continuous governance (EntityGraph/FetchProfile/batch size)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Soft delete / optimistic lock&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Visible&lt;/code&gt; built into renderer; version auto-added to domain DML&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;@SoftDelete&lt;/code&gt; (6.4+), &lt;code&gt;@Version&lt;/code&gt; auto-injection&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Inheritance&lt;/td&gt;
&lt;td&gt;Discriminator table families (&lt;code&gt;@Inheritance/@DiscriminatorValue&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Full SINGLE_TABLE/JOINED/TABLE_PER_CLASS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dialect depth&lt;/td&gt;
&lt;td&gt;MySQL/PG extremely deep (70k LOC), SQLite basic, Oracle placeholder&lt;/td&gt;
&lt;td&gt;16 core-supported dialects + ~30 community dialects; depth subordinate to unified HQL abstraction&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Proprietary SQL&lt;/td&gt;
&lt;td&gt;First-class (LOAD DATA, hints, ranges, vectors…)&lt;/td&gt;
&lt;td&gt;Mostly supported, often via HQL extensions/annotations/native SQL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auto DDL&lt;/td&gt;
&lt;td&gt;Yes (VALIDATE/UPDATE/DROP_CREATE), default UPDATE&lt;/td&gt;
&lt;td&gt;Yes (five hbm2ddl modes), plus hibernate-tools ecosystem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pool / transactions&lt;/td&gt;
&lt;td&gt;Bring a DataSource; Spring/JTA transactions&lt;/td&gt;
&lt;td&gt;Embedded or external pools; deep Spring/JTA integration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reactive&lt;/td&gt;
&lt;td&gt;Interface traces in core, no shipping module&lt;/td&gt;
&lt;td&gt;Separate Hibernate Reactive product line&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Java baseline&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;25 required&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;17+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Standardization&lt;/td&gt;
&lt;td&gt;None, single vendor&lt;/td&gt;
&lt;td&gt;Jakarta Persistence; massive talent/docs pool&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Maturity&lt;/td&gt;
&lt;td&gt;0.6.x, API may still move&lt;/td&gt;
&lt;td&gt;24 years of evolution; 7.4 stable, 8.0 underway&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  9. So, Which Do You Pick?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The case for Hibernate is straightforward:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your team wants standard skills, Stack Overflow coverage for everything, and plug-and-play hiring;&lt;/li&gt;
&lt;li&gt;The business is entity-CRUD, form-driven admin/back-office work where object-graph navigation and cascades genuinely remove code;&lt;/li&gt;
&lt;li&gt;You need L2 caching, auditing (Envers), multi-tenancy, many database vendors, or a complete reactive stack;&lt;/li&gt;
&lt;li&gt;You are willing (and able) to govern its classic traps: N+1, flush timing, equals/hashCode, lazy-loading session boundaries, cache invalidation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The case for Army is pickier:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your team knows SQL cold and insists "every SQL statement hitting production must be readable and reviewable," yet is tired of string concatenation and MyBatis XML;&lt;/li&gt;
&lt;li&gt;The system leans hard on MySQL/PostgreSQL-specific power: multi-table DML, UPSERT, LOAD DATA, index/optimizer hints, ranges/arrays/pgvector;&lt;/li&gt;
&lt;li&gt;You want proxy-free, state-machine-free, freely serializable POJO results, and distinct &lt;em&gt;types&lt;/em&gt; for single/batch/multi-table INSERT/UPDATE/DELETE;&lt;/li&gt;
&lt;li&gt;You can accept a Java 25 baseline, 0.x API churn, missing Oracle/SQL Server, and a support model that is basically "read the source" (fortunately the READMEs are unusually good and the 120k-line core is densely commented).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hibernate's own guide offers the fair verdict: "should I use ORM, or plain SQL? The answer is usually: use both." Army happens to fill the long-neglected half of "both" — the half previously improvised with JdbcTemplate, MyBatis, or hand-written SQL — with a compile-time type-safe option that genuinely believes in dialects.&lt;/p&gt;

&lt;p&gt;Of course, faith has a price: Army hands you the database's full complexity back, dressed in type-safe clothing. Every Hibernate pitfall you escape gets repaid in the form of a JOIN you write yourself.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Army: &lt;a href="https://github.com/PillArmy/army" rel="noopener noreferrer"&gt;https://github.com/PillArmy/army&lt;/a&gt;&lt;/strong&gt; (runnable cases in &lt;code&gt;army-example/src/test/java/io/army/session/sync/&lt;/code&gt;)&lt;br&gt;
&lt;strong&gt;Hibernate: &lt;a href="https://hibernate.org/orm/" rel="noopener noreferrer"&gt;https://hibernate.org/orm/&lt;/a&gt;&lt;/strong&gt; (7.4 docs: &lt;a href="https://docs.hibernate.org/orm/7.4/" rel="noopener noreferrer"&gt;https://docs.hibernate.org/orm/7.4/&lt;/a&gt;)&lt;/p&gt;

</description>
      <category>backend</category>
      <category>database</category>
      <category>java</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Inside Army's MySQL Dialect: When SQL Dialects Are First-Class Citizens</title>
      <dc:creator>zoro ma</dc:creator>
      <pubDate>Wed, 16 Sep 2026 19:03:22 +0000</pubDate>
      <link>https://dev.to/zoro7/inside-armys-mysql-dialect-when-sql-dialects-are-first-class-citizens-1b87</link>
      <guid>https://dev.to/zoro7/inside-armys-mysql-dialect-when-sql-dialects-are-first-class-citizens-1b87</guid>
      <description>&lt;h1&gt;
  
  
  Inside Army's MySQL Dialect: When SQL Dialects Are First-Class Citizens
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;GitHub: &lt;a href="https://github.com/PillArmy/army" rel="noopener noreferrer"&gt;https://github.com/PillArmy/army&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Module: &lt;code&gt;io.qinarmy:army-mysql&lt;/code&gt; (built on &lt;code&gt;army-core&lt;/code&gt; / &lt;code&gt;army-jdbc&lt;/code&gt;) · Supports MySQL 5.5 / 5.6 / 5.7 / 8.0&lt;/p&gt;

&lt;p&gt;Every claim in this article comes from the actual &lt;code&gt;army-mysql&lt;/code&gt; and &lt;code&gt;army-core&lt;/code&gt; source, and every code snippet is copied verbatim from the framework source or the &lt;code&gt;army-example&lt;/code&gt; test suite — nothing is invented.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Most Java SQL libraries treat a "dialect" as one enum, one common syntax tree, and a handful of if/else branches. You get portable CRUD — but the moment you need &lt;code&gt;STRAIGHT_JOIN&lt;/code&gt;, &lt;code&gt;LOAD DATA&lt;/code&gt;, &lt;code&gt;ON DUPLICATE KEY UPDATE&lt;/code&gt;, or &lt;code&gt;SET @row := 0&lt;/code&gt;, you are back to string concatenation.&lt;/p&gt;

&lt;p&gt;Army takes the opposite route. In Army, &lt;strong&gt;MySQL is not a flag — it is an independent grammar modeled clause by clause from the MySQL reference manual&lt;/strong&gt;. The &lt;code&gt;army-mysql&lt;/code&gt; module is about 30,000 lines of main code, of which the MySQL-specific SQL rendering layer alone is over 3,700 lines. Its entry class &lt;code&gt;MySQLs&lt;/code&gt; exposes 18 statement factories covering SELECT/INSERT/REPLACE/UPDATE/DELETE (single-table, multi-table, and batch variants), VALUES, LOAD DATA, SET, and SHOW.&lt;/p&gt;

&lt;p&gt;This article walks through that dialect from the source, showing what "dialect as a first-class citizen" actually means.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Module Anatomy: Three Layers
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;army-mysql&lt;/code&gt; code separates cleanly into three layers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;io.army.criteria.mysql     — Contract layer: MySQLQuery / MySQLInsert / MySQLUpdate /
                            MySQLDelete / MySQLLoadData / MySQLReplace / MySQLShow ...
                            (all nested staged interfaces — they describe only what
                             you are allowed to write)

io.army.criteria.impl     — Builder layer: MySQLQueries / MySQLInserts / MySQLMultiUpdates /
                            MySQLHints / MySQLJsonFunctions / MySQLSpatialFunctions ...
                            (the MySQLs entry class lives here too)

io.army.dialect           — Rendering layer: MySQLParser → MySQLDialectParser (1,292 lines),
                            MySQLDdlParser (507 lines), MySQLIdentifierHandler,
                            MySQLLiteralHandler, MySQLMappingHandler, MySQLParserFactory
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wiring goes through a factory selected only when the target database is MySQL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Override&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;DialectParser&lt;/span&gt; &lt;span class="nf"&gt;createDialectParser&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;DialectEnv&lt;/span&gt; &lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;MySQLDialect&lt;/span&gt; &lt;span class="n"&gt;dialect&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;dialect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MySQLDialect&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;ParserFactoryUtils&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;targetDialect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Database&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;MySQL&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;MySQLDialectParser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dialect&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The concrete version comes from &lt;code&gt;ServerMeta&lt;/code&gt; — the metadata read from the live connection. &lt;code&gt;MySQLDialect&lt;/code&gt; is a four-constant enum with deliberately simple version mapping:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;enum&lt;/span&gt; &lt;span class="nc"&gt;MySQLDialect&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Dialect&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;MySQL55&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;55&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="nc"&gt;MySQL56&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;56&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="nc"&gt;MySQL57&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;57&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="nc"&gt;MySQL80&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;MySQLDialect&lt;/span&gt; &lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ServerMeta&lt;/span&gt; &lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;major&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;minor&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;MySQLDialect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;MySQL55&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
                    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;MySQLDialect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;MySQL56&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
                    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;MySQLDialect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;MySQL57&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
                    &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nc"&gt;Database&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;unsupportedVersion&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;MySQLDialect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;MySQL80&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That &lt;code&gt;Dialect&lt;/code&gt; object is not decorative — the rendering layer uses it everywhere for &lt;strong&gt;version gating&lt;/strong&gt;. CTEs, for example (only available in MySQL 8.0), are hard-blocked in &lt;code&gt;MySQLParser.parseWithClause&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Override&lt;/span&gt;
&lt;span class="kd"&gt;protected&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;parseWithClause&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;_Statement&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;_WithClauseSpec&lt;/span&gt; &lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;_SqlContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;_Cte&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;cteList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;cteList&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cteList&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asOf80&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="n"&gt;_Exceptions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;dontSupportWithClause&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;dialect&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;withSubQuery&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isRecursive&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;cteList&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;_SQLConsultant:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;assertStandardCte&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;asOf80&lt;/code&gt; is a boolean computed once at construction (&lt;code&gt;dialect.compareWith(MySQLDialect.MySQL80) &amp;gt;= 0&lt;/code&gt;) and shared across the whole module. Writing &lt;code&gt;.with("cte")&lt;/code&gt; against a 5.7 server does not produce SQL that fails on execution — it fails during statement rendering, before anything touches the database.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. The Entry Point: 18 Factories on &lt;code&gt;MySQLs&lt;/code&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MySQLs&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;MySQLSyntax&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// —— Queries: primary / batch / subquery / scalar subquery ——&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;MySQLQuery&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;WithSpec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Select&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;                          &lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;MySQLQuery&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;WithSpec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Statement&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;_BatchSelectParamSpec&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;batchQuery&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;MySQLQuery&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;WithSpec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SubQuery&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;                      &lt;span class="nf"&gt;subQuery&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;MySQLQuery&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;WithSpec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Expression&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;                   &lt;span class="nf"&gt;scalarSubQuery&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// —— Writes: single-table / multi-table / batch, one factory each ——&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;MySQLInsert&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;_PrimaryOptionSpec&lt;/span&gt;                     &lt;span class="nf"&gt;singleInsert&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;MySQLReplace&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;_PrimaryOptionSpec&lt;/span&gt;                    &lt;span class="nf"&gt;singleReplace&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;MySQLUpdate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;_SingleWithSpec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Update&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;                &lt;span class="nf"&gt;singleUpdate&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;MySQLUpdate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;_SingleWithSpec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;...&lt;/span&gt;&lt;span class="na"&gt;Batch&lt;/span&gt;&lt;span class="o"&gt;...&amp;gt;&lt;/span&gt;            &lt;span class="nf"&gt;batchSingleUpdate&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;MySQLUpdate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;_MultiWithSpec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Update&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;                  &lt;span class="nf"&gt;multiUpdate&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;MySQLUpdate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;_MultiWithSpec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;...&lt;/span&gt;&lt;span class="na"&gt;Batch&lt;/span&gt;&lt;span class="o"&gt;...&amp;gt;&lt;/span&gt;            &lt;span class="nf"&gt;batchMultiUpdate&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;MySQLDelete&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;_SingleWithSpec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Delete&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;                &lt;span class="nf"&gt;singleDelete&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;MySQLDelete&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;_SingleWithSpec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;...&lt;/span&gt;&lt;span class="na"&gt;Batch&lt;/span&gt;&lt;span class="o"&gt;...&amp;gt;&lt;/span&gt;           &lt;span class="nf"&gt;batchSingleDelete&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;MySQLDelete&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;_MultiWithSpec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Delete&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;                 &lt;span class="nf"&gt;multiDelete&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;MySQLDelete&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;_MultiWithSpec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;...&lt;/span&gt;&lt;span class="na"&gt;Batch&lt;/span&gt;&lt;span class="o"&gt;...&amp;gt;&lt;/span&gt;            &lt;span class="nf"&gt;batchMultiDelete&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// —— MySQL-specific statements ——&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;MySQLLoadData&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;_LoadDataClause&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DmlCommand&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;            &lt;span class="nf"&gt;loadDataStmt&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;MySQLSet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;_SetSpec&lt;/span&gt;                                   &lt;span class="nf"&gt;setStmt&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;MySQLValues&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ValuesSpec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Values&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;                     &lt;span class="nf"&gt;valuesStmt&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;MySQLValues&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ValuesSpec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SubValues&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;                   &lt;span class="nf"&gt;subValues&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note the design decisions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Single-table and multi-table DML are different types.&lt;/strong&gt; &lt;code&gt;singleUpdate()&lt;/code&gt; and &lt;code&gt;multiUpdate()&lt;/code&gt; return entirely different spec interfaces, because &lt;code&gt;UPDATE t SET ...&lt;/code&gt; and &lt;code&gt;UPDATE t JOIN j ON ... SET ...&lt;/code&gt; are different statements in MySQL. Army refuses to stuff both into one interface and punish you with a runtime error.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Batch is not a boolean flag, it is a separate factory.&lt;/strong&gt; &lt;code&gt;batchMultiUpdate()&lt;/code&gt; returns &lt;code&gt;Statement._BatchUpdateParamSpec&lt;/code&gt;, whose parameter-binding contract differs from a single statement — the distinction is in the type.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;REPLACE is a standalone statement&lt;/strong&gt;, not an &lt;code&gt;insert().replace()&lt;/code&gt; modifier — in MySQL it is genuinely different (delete-then-insert, with different auto-increment and trigger behavior).&lt;/li&gt;
&lt;li&gt;Every factory is a &lt;strong&gt;zero-state static method&lt;/strong&gt; returning an immutable chained builder.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  3. The Type System: MySQL's Quirks Encoded in an Enum
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;MySQLType&lt;/code&gt; enum in &lt;code&gt;army-core&lt;/code&gt; is MySQL's type dictionary; each entry is a triple of &lt;code&gt;(SQL type name, cross-dialect semantic tag (ArmyType), default Java class)&lt;/code&gt;. The MySQL-specific half is the most revealing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;enum&lt;/span&gt; &lt;span class="nc"&gt;MySQLType&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;SQLType&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="no"&gt;TINYINT_UNSIGNED&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"TINYINT UNSIGNED"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;  &lt;span class="nc"&gt;ArmyType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;TINYINT_UNSIGNED&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;  &lt;span class="nc"&gt;Short&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
    &lt;span class="no"&gt;SMALLINT_UNSIGNED&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SMALLINT UNSIGNED"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;  &lt;span class="nc"&gt;ArmyType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SMALLINT_UNSIGNED&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
    &lt;span class="no"&gt;MEDIUMINT_UNSIGNED&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MEDIUMINT UNSIGNED"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ArmyType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;MEDIUMINT_UNSIGNED&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
    &lt;span class="no"&gt;INT_UNSIGNED&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"INT UNSIGNED"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;           &lt;span class="nc"&gt;ArmyType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;INTEGER_UNSIGNED&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
    &lt;span class="no"&gt;BIGINT_UNSIGNED&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"BIGINT UNSIGNED"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;     &lt;span class="nc"&gt;ArmyType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;BIGINT_UNSIGNED&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;  &lt;span class="nc"&gt;BigInteger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
    &lt;span class="no"&gt;DECIMAL_UNSIGNED&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DECIMAL UNSIGNED"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;    &lt;span class="nc"&gt;ArmyType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;DECIMAL_UNSIGNED&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;

    &lt;span class="no"&gt;YEAR&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"YEAR"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ArmyType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;YEAR&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Year&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
    &lt;span class="no"&gt;ENUM&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ENUM"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ArmyType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ENUM&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
    &lt;span class="no"&gt;SET&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SET"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ArmyType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;DIALECT_TYPE&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
    &lt;span class="no"&gt;JSON&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"JSON"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ArmyType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;JSON&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
    &lt;span class="no"&gt;VECTOR&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"VECTOR"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ArmyType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;VECTOR&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="o"&gt;[].&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;       &lt;span class="c1"&gt;// MySQL 9.x vector type&lt;/span&gt;

    &lt;span class="no"&gt;POINT&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"POINT"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="no"&gt;LINESTRING&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"LINESTRING"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="no"&gt;POLYGON&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"POLYGON"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
    &lt;span class="no"&gt;MULTIPOINT&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MULTIPOINT"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="no"&gt;MULTIPOLYGON&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MULTIPOLYGON"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
    &lt;span class="no"&gt;MULTILINESTRING&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MULTILINESTRING"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="no"&gt;GEOMETRYCOLLECTION&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GEOMETRYCOLLECTION"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
    &lt;span class="no"&gt;GEOMETRY&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GEOMETRY"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ArmyType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;GEOMETRY&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="o"&gt;[].&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;              &lt;span class="c1"&gt;// WKB binary&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two details worth expanding on.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.1 Unsigned integers: the smallest Java type that cannot overflow
&lt;/h3&gt;

&lt;p&gt;MySQL's five unsigned integer ranges misalign naturally with Java's signed types. Army's default mapping:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;MySQL type&lt;/th&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;th&gt;Army's default Java type&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;TINYINT UNSIGNED&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0 ~ 255&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Short&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;255 does not fit in &lt;code&gt;byte&lt;/code&gt; (-128~127)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SMALLINT UNSIGNED&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0 ~ 65,535&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Integer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;65535 does not fit in &lt;code&gt;short&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;MEDIUMINT UNSIGNED&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0 ~ 16,777,215&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Integer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Still within int range&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;INT UNSIGNED&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0 ~ 4.29 billion&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Long&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Does not fit in &lt;code&gt;int&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;BIGINT UNSIGNED&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0 ~ 2^64−1&lt;/td&gt;
&lt;td&gt;&lt;code&gt;BigInteger&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Beyond &lt;code&gt;long&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This is not a marketing promise; both layers enforce it. &lt;code&gt;TinyIntUnsignedType.javaType()&lt;/code&gt; returns &lt;code&gt;Short.class&lt;/code&gt;, and the dispatch table in &lt;code&gt;AbstractMappingType&lt;/code&gt; routes each &lt;code&gt;ArmyType.*_UNSIGNED&lt;/code&gt; to its implementation. You write no &lt;code&gt;@TypeHandler&lt;/code&gt; — conversion behavior is a property of the type itself.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.2 Where the proprietary types land
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;SET&lt;/code&gt; maps to Java &lt;code&gt;EnumSet&lt;/code&gt;; &lt;code&gt;ENUM&lt;/code&gt; works through one of Army's three enum strategies (&lt;code&gt;CodeEnum&lt;/code&gt; / &lt;code&gt;LabelEnum&lt;/code&gt; / &lt;code&gt;NameEnum&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;All eight spatial types bind as WKB (Well-Known Binary) &lt;code&gt;byte[]&lt;/code&gt;, paired with a spatial function library of 154 static methods (see Section 8).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;VECTOR&lt;/code&gt; targets the MySQL 9.x native vector type and shares the same &lt;code&gt;ArmyType.VECTOR&lt;/code&gt; semantic tag and &lt;code&gt;VectorType&lt;/code&gt; mapping class as PostgreSQL's pgvector — cross-dialect vector code stays largely reusable.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  4. SELECT: A Typed Transcription of the MySQL Manual
&lt;/h2&gt;

&lt;p&gt;This is where the dialect's depth is most visible. Each feature below maps to a real method (or method family) on the &lt;code&gt;MySQLQuery&lt;/code&gt; chain.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.1 SELECT modifiers: all 16 keywords modeled
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;MySQLs&lt;/code&gt; exposes every SELECT modifier from the manual as a type-safe constant:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Modifier&lt;/span&gt; &lt;span class="no"&gt;ALL&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Modifier&lt;/span&gt; &lt;span class="no"&gt;DISTINCTROW&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Modifier&lt;/span&gt; &lt;span class="no"&gt;HIGH_PRIORITY&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Modifier&lt;/span&gt; &lt;span class="no"&gt;STRAIGHT_JOIN&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Modifier&lt;/span&gt; &lt;span class="no"&gt;SQL_SMALL_RESULT&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Modifier&lt;/span&gt; &lt;span class="no"&gt;SQL_BIG_RESULT&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Modifier&lt;/span&gt; &lt;span class="no"&gt;SQL_BUFFER_RESULT&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Modifier&lt;/span&gt; &lt;span class="no"&gt;SQL_NO_CACHE&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Modifier&lt;/span&gt; &lt;span class="no"&gt;SQL_CALC_FOUND_ROWS&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// plus LOW_PRIORITY / DELAYED / QUICK / IGNORE / CONCURRENT / LOCAL,&lt;/span&gt;
&lt;span class="c1"&gt;// reused by INSERT / UPDATE / DELETE / LOAD DATA&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Modifiers are passed as a &lt;code&gt;List&amp;lt;Modifier&amp;gt;&lt;/code&gt;, and the renderer validates legality — &lt;code&gt;SQL_CALC_FOUND_ROWS&lt;/code&gt; is only valid in SELECT, &lt;code&gt;QUICK&lt;/code&gt; only in UPDATE/DELETE. A misplaced one fails at render time rather than producing SQL the server rejects.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.2 Partition selection: &lt;code&gt;.partition(p0, p1)&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;MySQL supports pruning directly on table references (&lt;code&gt;FROM t PARTITION (p0,p1)&lt;/code&gt;). Army models this as a distinct chain stage right after the table reference (and alias). The real example below is from the &lt;code&gt;MySQLCriteriaUnitTests&lt;/code&gt; in army-example; it also demonstrates DELETE modifiers and single-table DELETE ORDER BY + LIMIT in one chain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;stmt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MySQLs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;singleDelete&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;delete&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hintSupplier&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Arrays&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MySQLs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;LOW_PRIORITY&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;MySQLs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;QUICK&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;MySQLs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;IGNORE&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;T&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;AS&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"r"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;partition&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"p1"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;createTime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;between&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;SQLs:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;literal&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"startTime"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="no"&gt;AND&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"endTIme"&lt;/span&gt;&lt;span class="o"&gt;)))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;and&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;updateTime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;between&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;SQLs:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"startTime"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="no"&gt;AND&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"endTIme"&lt;/span&gt;&lt;span class="o"&gt;)))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ifAnd&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;equal&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;SQLs:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;literal&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"version"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;orderBy&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;desc&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ifLimit&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"rowCount"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asDelete&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Single-table UPDATE, multi-table DML, and LOAD DATA carry the same partition clause.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.3 Index hints: USE / IGNORE / FORCE INDEX × three purposes
&lt;/h3&gt;

&lt;p&gt;This is the DBA's daily tuning tool, and Army models both of MySQL's orthogonal hint systems in full. The first is the &lt;strong&gt;table-level index hint&lt;/strong&gt;, attached right after a table reference:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// USE / IGNORE / FORCE INDEX, each with optional FOR JOIN / FOR ORDER BY / FOR GROUP BY&lt;/span&gt;
&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;update&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaProvince_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;T&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;AS&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"p"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;useIndex&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;FOR&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;JOIN&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"PRIMARY"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;T&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;AS&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"c"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;useIndex&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;FOR&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;JOIN&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"PRIMARY"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;equal&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ChinaProvince_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Those lines are not mine — they are copied verbatim from &lt;code&gt;MultiUpdateTests&lt;/code&gt; in army-example. One table can carry multiple hints, and every hint supports three styles: static enumeration, dynamic &lt;code&gt;Consumer&lt;/code&gt;, and conditional &lt;code&gt;ifUseIndex(BooleanSupplier)&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.4 Optimizer hints: the full ~30-item &lt;code&gt;/*+ ... */&lt;/code&gt; catalog
&lt;/h3&gt;

&lt;p&gt;The second system is the MySQL 8.0 &lt;strong&gt;optimizer hint comment&lt;/strong&gt;. The &lt;code&gt;MySQLHints.HintType&lt;/code&gt; enum is essentially a table of contents of the manual:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;enum&lt;/span&gt; &lt;span class="nc"&gt;HintType&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="no"&gt;JOIN_FIXED_ORDER&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;JOIN_ORDER&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;JOIN_PREFIX&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;JOIN_SUFFIX&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="no"&gt;BKA&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;NO_BKA&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;BNL&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;NO_BNL&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="no"&gt;DERIVED_CONDITION_PUSHDOWN&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;NO_DERIVED_CONDITION_PUSHDOWN&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="no"&gt;HASH_JOIN&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;NO_HASH_JOIN&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;MERGE&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;NO_MERGE&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="no"&gt;GROUP_INDEX&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;NO_GROUP_INDEX&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;INDEX&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;NO_INDEX&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;INDEX_MERGE&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;NO_INDEX_MERGE&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="no"&gt;JOIN_INDEX&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;NO_JOIN_INDEX&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;MRR&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;NO_MRR&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;NO_ICP&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;NO_RANGE_OPTIMIZATION&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="no"&gt;ORDER_INDEX&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;NO_ORDER_INDEX&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;SKIP_SCAN&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;NO_SKIP_SCAN&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="no"&gt;SEMIJOIN&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;NO_SEMIJOIN&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="no"&gt;MAX_EXECUTION_TIME&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;SET_VAR&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;RESOURCE_GROUP&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;QB_NAME&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Factories are public on &lt;code&gt;MySQLSyntax&lt;/code&gt; (&lt;code&gt;joinFixedOrder(qbName)&lt;/code&gt;, &lt;code&gt;joinOrder(...)&lt;/code&gt;, &lt;code&gt;indexLevelHint(...)&lt;/code&gt;, &lt;code&gt;subQueryHint(...)&lt;/code&gt;, &lt;code&gt;maxExecutionTime(ms)&lt;/code&gt;, &lt;code&gt;setVar("k=v")&lt;/code&gt;, &lt;code&gt;qbName(name)&lt;/code&gt;, etc.). Each hint is a self-describing node (&lt;code&gt;_SelfDescribed.appendSql&lt;/code&gt;) that renders its own syntax and performs its own version check — &lt;code&gt;JOIN_FIXED_ORDER&lt;/code&gt;, for example, throws "dontSupportHint" below 8.0.&lt;/p&gt;

&lt;p&gt;Hints enter the statement lazily as a &lt;code&gt;Supplier&amp;lt;List&amp;lt;Hint&amp;gt;&amp;gt;&lt;/code&gt;, alongside the modifiers. Again from &lt;code&gt;MultiUpdateTests&lt;/code&gt;, a real case that hangs both &lt;code&gt;/*+ SET_VAR(foreign_key_checks=OFF) */&lt;/code&gt; and &lt;code&gt;LOW_PRIORITY&lt;/code&gt; on one multi-table UPDATE:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Supplier&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Hint&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;hintSupplier&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
        &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Collections&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;singletonList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MySQLs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setVar&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"foreign_key_checks=OFF"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;

&lt;span class="n"&gt;stmt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MySQLs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;multiUpdate&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"cte"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;as&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sw&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;sw&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;select&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;T&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;AS&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"c"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;in&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;SQLs:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;rowParam&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;extractRegionIdList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;regionList&lt;/span&gt;&lt;span class="o"&gt;)))&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;and&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;regionType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;SQLs:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;RegionType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PROVINCE&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asQuery&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;space&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;update&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hintSupplier&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Collections&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;singletonList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MySQLs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;LOW_PRIORITY&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;space&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaProvince_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;T&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;AS&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"p"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;useIndex&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;FOR&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;JOIN&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"PRIMARY"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;T&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;AS&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"c"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;useIndex&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;FOR&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;JOIN&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"PRIMARY"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;equal&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ChinaProvince_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"cte"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;equal&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;SQLs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;refField&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"cte"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ID&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;regionGdp&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;SQLs:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;plusEqual&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;SQLs:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gdpAmount&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;SQLs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;subQuery&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;select&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;space&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SQLs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;refField&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"subCte"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ID&lt;/span&gt;&lt;span class="o"&gt;)))&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"cte"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;AS&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"subCte"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asQuery&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;and&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;createTime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;between&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;SQLs:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;minusMinutes&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="no"&gt;AND&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;plusSeconds&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asUpdate&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One statement demonstrates: CTE → multi-table UPDATE → optimizer hint → legacy modifier → index hint → compound assignment (&lt;code&gt;+= gdp&lt;/code&gt;) → subquery → dynamic predicate. This is what dialect depth means: every item in a MySQL DBA's playbook has a typed place in the API.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.5 STRAIGHT_JOIN, WITH ROLLUP, and locking clauses
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;STRAIGHT_JOIN&lt;/strong&gt;: &lt;code&gt;.straightJoin(table).on(...)&lt;/code&gt; forces the optimizer to join in the given order; a statement-level &lt;code&gt;STRAIGHT_JOIN&lt;/code&gt; SELECT modifier is also available.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WITH ROLLUP&lt;/strong&gt;: there is a separate &lt;code&gt;.withRollup()&lt;/code&gt; after GROUP BY and after ORDER BY (matching MySQL's two positions), each with an &lt;code&gt;ifWithRollup(BooleanSupplier)&lt;/code&gt; variant.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Locks&lt;/strong&gt;: &lt;code&gt;.forUpdate()&lt;/code&gt; / &lt;code&gt;.forShare()&lt;/code&gt;, with &lt;code&gt;.of(table...)&lt;/code&gt; to restrict locked tables, &lt;code&gt;.nowait()&lt;/code&gt; / &lt;code&gt;.skipLocked()&lt;/code&gt; (8.0), and the legacy &lt;code&gt;.lockInShareMode()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SELECT INTO variables&lt;/strong&gt;: &lt;code&gt;.into("@id", "@name")&lt;/code&gt; maps to &lt;code&gt;SELECT ... INTO @id, @name&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Set operations&lt;/strong&gt;: MySQL 8.0's &lt;code&gt;INTERSECT&lt;/code&gt; / &lt;code&gt;EXCEPT&lt;/code&gt; (with ALL/DISTINCT variants) sit on the chain alongside UNION.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4.6 MySQL-ization in the renderer: backticks and &lt;code&gt;LIMIT m, n&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The shared &lt;code&gt;ArmyParser&lt;/code&gt; exposes dialect differences as template methods, overridden by &lt;code&gt;MySQLParser&lt;/code&gt;. The two most typical overrides:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MySQLParser&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;_ArmyDialectParser&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="no"&gt;BACKTICK&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sc"&gt;'`'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;protected&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="nf"&gt;identifierDelimitedQuote&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;BACKTICK&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;                 &lt;span class="c1"&gt;// MySQL identifiers: backticks; Postgres: double quotes&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;protected&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;standardLimitClause&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;_Expression&lt;/span&gt; &lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                                            &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;_Expression&lt;/span&gt; &lt;span class="n"&gt;rowCount&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_SqlContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;rowCount&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// MySQL native form: LIMIT offset, rowCount (not the standard LIMIT n OFFSET m)&lt;/span&gt;
            &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sqlBuilder&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;append&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_Constant&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SPACE_LIMIT&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;appendSql&lt;/span&gt;&lt;span class="o"&gt;(...);&lt;/span&gt;
            &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sqlBuilder&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;append&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_Constant&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SPACE_COMMA&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;rowCount&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;appendSql&lt;/span&gt;&lt;span class="o"&gt;(...);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The constructor also validates escape policy up front: the MySQL dialect accepts only &lt;code&gt;EscapeMode.DEFAULT&lt;/code&gt; for identifier escaping and &lt;code&gt;DEFAULT&lt;/code&gt;/&lt;code&gt;BACK_SLASH&lt;/code&gt; for literals — because the MySQL server defaults to backslash escaping, and allowing anything else would only generate SQL the server cannot parse.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. DML: UPSERT, REPLACE, and Multi-Table Syntax
&lt;/h2&gt;

&lt;h3&gt;
  
  
  5.1 ON DUPLICATE KEY UPDATE — down to the 8.0.19 row alias
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;MySQLInsert._OnDuplicateKeyUpdateSpec&lt;/code&gt; offers two entry styles:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;_StaticConflictUpdateClause&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;I&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;onDuplicateKey&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;        &lt;span class="c1"&gt;// field-by-field chaining&lt;/span&gt;
&lt;span class="n"&gt;_DmlInsertClause&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;I&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;onDuplicateKeyUpdate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Consumer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;...&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// batched via Consumer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Real example, verbatim from &lt;code&gt;InsertTests&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;stmt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MySQLs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;singleInsert&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ignoreReturnIds&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;insertInto&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;T&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parens&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;space&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;regionGdp&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;comma&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;population&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parentId&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;defaultValue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;regionGdp&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;SQLs:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"88888.88"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;defaultValue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;visible&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;SQLs:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;defaultValue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parentId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;SQLs:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;values&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;regionList&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;as&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"c"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;                                    &lt;span class="c1"&gt;// MySQL 8.0.19+ row alias AS new_row&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;onDuplicateKey&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;update&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;population&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;SQLs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;field&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"c"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;population&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;comma&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;regionGdp&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;SQLs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;field&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"c"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;regionGdp&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asInsert&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;.as("c")&lt;/code&gt; corresponds to the &lt;code&gt;... AS new ON DUPLICATE KEY UPDATE col = new.col&lt;/code&gt; syntax introduced in MySQL 8.0.19 — hence the &lt;code&gt;SQLs.field("c", ...)&lt;/code&gt; references to the incoming row. The older &lt;code&gt;VALUES(col)&lt;/code&gt; function style is supported as well; both eras coexist on the chain.&lt;/p&gt;

&lt;p&gt;Even better, the &lt;code&gt;singleInsert()&lt;/code&gt; Javadoc turns MySQL's official affected-rows semantics (1 = inserted, 2 = updated, 0 = set to current values — which "actually never 0" in Army because the framework maintains &lt;code&gt;updateTime&lt;/code&gt;) into an API contract, and states three limitations explicitly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;if the table has a &lt;code&gt;visible&lt;/code&gt; logical-delete field, UPSERT works only in &lt;code&gt;Visible.BOTH&lt;/code&gt; mode;&lt;/li&gt;
&lt;li&gt;auto-increment PK + multi-row child-table domain insert cannot use ON DUPLICATE (the server cannot return correct multi-row generated keys on conflict);&lt;/li&gt;
&lt;li&gt;auto-increment PK + multi-row domain syntax with conflicts requires &lt;code&gt;.ignoreReturnIds()&lt;/code&gt; beforehand.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are not excuses for framework gaps — they are limitations of the MySQL server protocol, surfaced in the API contract before you hit them.&lt;/p&gt;

&lt;h3&gt;
  
  
  5.2 REPLACE: a standalone statement with its own limits
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;singleReplace()&lt;/code&gt; produces a dedicated &lt;code&gt;MySQLReplace&lt;/code&gt; statement (rendered as &lt;code&gt;REPLACE INTO&lt;/code&gt;), with its own entry Javadoc — including the same "multi-row domain replace of auto-increment keys requires &lt;code&gt;ignoreReturnIds()&lt;/code&gt;" rule and the logical-delete visibility constraint.&lt;/p&gt;

&lt;h3&gt;
  
  
  5.3 Multi-table UPDATE / DELETE
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;multiUpdate()&lt;/code&gt;: &lt;code&gt;UPDATE t [hint] JOIN j [hint] ON ... SET ... WHERE ...&lt;/code&gt;. SET supports compound assignment operators (&lt;code&gt;SQLs::plusEqual&lt;/code&gt; renders &lt;code&gt;gdp = gdp + ?&lt;/code&gt;), and everything FROM supports — CTEs, derived tables, index hints — is available.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;multiDelete()&lt;/code&gt;: both MySQL multi-table DELETE shapes are modeled — &lt;code&gt;DELETE t1 FROM t1 JOIN t2 ...&lt;/code&gt; and &lt;code&gt;DELETE FROM t1 USING t1 JOIN t2 ...&lt;/code&gt;, distinguished by how the target tables are chosen.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Single-table UPDATE/DELETE keep MySQL's ORDER BY + LIMIT&lt;/strong&gt;: the &lt;code&gt;_OrderBySpec → _LimitSpec&lt;/code&gt; chain makes &lt;code&gt;UPDATE t SET ... ORDER BY id LIMIT 100&lt;/code&gt; and &lt;code&gt;DELETE FROM t WHERE ... ORDER BY id LIMIT 100&lt;/code&gt; — MySQL's unique batching idiom — a legal path.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On the rendering side, &lt;code&gt;MySQLDialectParser&lt;/code&gt; (1,292 lines) has a dedicated method per shape — &lt;code&gt;parseSingleUpdate / parseMultiUpdate / parseSingleDelete / parseMultiDelete&lt;/code&gt; — rather than one giant switch. Multi-delete rendering is annotated step by step in the source: WITH → DELETE keyword → hint comment block → modifiers → …&lt;/p&gt;




&lt;h2&gt;
  
  
  6. LOAD DATA: An "Ops Command" Made Type-Safe
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;LOAD DATA INFILE&lt;/code&gt; is MySQL's ultimate CSV-import weapon, and the area most ORMs refuse to touch. Army's &lt;code&gt;MySQLLoadData&lt;/code&gt; interface models the entire manual syntax, and the chain order &lt;em&gt;is&lt;/em&gt; the syntax order:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;LOAD&lt;/span&gt; &lt;span class="k"&gt;DATA&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;LOCAL&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;INFILE&lt;/span&gt; &lt;span class="s1"&gt;'file'&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;REPLACE&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="k"&gt;IGNORE&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;tbl&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;PARTITION&lt;/span&gt; &lt;span class="p"&gt;(...)]&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;CHARACTER&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;charset&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="n"&gt;FIELDS&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;COLUMNS&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;TERMINATED&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="s1"&gt;'x'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;OPTIONALLY&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;ENCLOSED&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="s1"&gt;'x'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ESCAPED&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="s1"&gt;'x'&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;LINES&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;STARTING&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="s1"&gt;'x'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;TERMINATED&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="s1"&gt;'x'&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;IGNORE&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;LINES&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="k"&gt;ROWS&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;
    &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="n"&gt;col1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;col2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...)]&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;col&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;expr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The example from the entry Javadoc (mirrored by the real &lt;code&gt;LoadDataTests&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;stmt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MySQLs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;loadDataStmt&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;loadData&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MySQLs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;LOCAL&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;infile&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;csvFile&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ignore&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;intoTable&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;T&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;characterSet&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"utf8mb4"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;columns&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;terminatedBy&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;","&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lines&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;terminatedBy&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"\n"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ignore&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;SQLs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;LINES&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;visible&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;SQLs:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;literal&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;regionType&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;SQLs:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;literal&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;RegionType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;NONE&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asCommand&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;update&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stmt&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;SyncStmtOption&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;preferServerPrepare&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Deep details:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Parent/child tables can be imported in a chain&lt;/strong&gt;: &lt;code&gt;.intoTable(ParentTableMeta)&lt;/code&gt; returns a &lt;code&gt;_ChildLoadData&lt;/code&gt; spec, after which &lt;code&gt;.child().loadData(LOCAL).infile(childCsv)...intoTable(ChildTableMeta)...asCommand()&lt;/code&gt; composes a parent CSV and a child CSV into one command sequence — serving Army's own parent/child domain model, a need no generic ETL framework would anticipate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Escape policy is forced&lt;/strong&gt;: the characters in &lt;code&gt;TERMINATED BY&lt;/code&gt; / &lt;code&gt;ENCLOSED BY&lt;/code&gt; / &lt;code&gt;ESCAPED BY&lt;/code&gt; are always parsed with &lt;code&gt;EscapeMode.BACK_SLASH&lt;/code&gt; regardless of the global &lt;code&gt;LITERAL_ESCAPE_MODE&lt;/code&gt;, and the Javadoc explicitly requires the server's &lt;code&gt;NO_BACKSLASH_ESCAPES&lt;/code&gt; SQL mode to be disabled — LOAD DATA escaping rules are hard-wired by MySQL.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Execution prerequisites are a contract&lt;/strong&gt;: &lt;code&gt;local_infile=ON&lt;/code&gt;, the JDBC &lt;code&gt;allowLoadLocalInfile=true&lt;/code&gt; property, and the requirement for a client-prepared or static statement (the LOCAL INFILE Request protocol) are all listed in the entry Javadoc with links to the official docs.&lt;/li&gt;
&lt;li&gt;The renderer &lt;code&gt;parseLoadData&lt;/code&gt; builds the statement in numbered steps: LOAD DATA keyword → modifier validation (anything other than LOCAL/CONCURRENT throws) → INFILE → REPLACE/IGNORE → table and partitions → charset → FIELDS/LINES → IGNORE count → SET.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  7. SET Statements and User Variables: Home for MySQL Procedural Tricks
&lt;/h2&gt;

&lt;h3&gt;
  
  
  7.1 &lt;code&gt;setStmt()&lt;/code&gt;: four scopes
&lt;/h3&gt;

&lt;p&gt;MySQL 8.x SET syntax has four scopes — GLOBAL, SESSION, PERSIST, and PERSIST_ONLY. Army distinguishes them with typed &lt;code&gt;VarScope&lt;/code&gt; constants (&lt;code&gt;MySQLs.PERSIST&lt;/code&gt; / &lt;code&gt;PERSIST_ONLY&lt;/code&gt; reuse core's &lt;code&gt;KeyWordVarScope&lt;/code&gt;), corresponding to dynamic server-variable persistence.&lt;/p&gt;

&lt;h3&gt;
  
  
  7.2 User variables and inline &lt;code&gt;:=&lt;/code&gt; assignment
&lt;/h3&gt;

&lt;p&gt;This is the classic MySQL trick: generating row numbers inside one query with a user variable. Army not only supports it — it is a real test in army-example (&lt;code&gt;VariableTests&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;stmt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MySQLs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;select&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;space&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MySQLs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;at&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"my_row_number"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;increment&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;as&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"rowNumber"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;comma&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"t"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;PERIOD&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;T&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;T&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;AS&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"t"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;crossJoin&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SQLs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;subQuery&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;select&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MySQLs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;at&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"my_row_number"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;SQLs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;COLON_EQUAL&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;SQLs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;LITERAL_0&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;as&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"n"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asQuery&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;as&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"s"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;in&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;SQLs:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;rowParam&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;extractRegionIdList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;regionList&lt;/span&gt;&lt;span class="o"&gt;)))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;orderBy&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asQuery&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The generated SQL is the textbook pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;my_row_number&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;my_row_number&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;rowNumber&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;china_region&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;
&lt;span class="k"&gt;CROSS&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;my_row_number&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="p"&gt;(...)&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;MySQLs.at(name)&lt;/code&gt; builds a user-variable reference, &lt;code&gt;MySQLs.at(name, COLON_EQUAL, init)&lt;/code&gt; builds inline assignment, and &lt;code&gt;atAtSession("sql_mode")&lt;/code&gt; / &lt;code&gt;atAtGlobal(...)&lt;/code&gt; reference &lt;code&gt;@@session.&lt;/code&gt; / &lt;code&gt;@@global.&lt;/code&gt; system variables. The inline comment — "defer SELECT clause, so SELECT clause is executed after FROM clause" — shows the author knows exactly how MySQL's evaluation timing enables this trick. Modeling it type-safely is only possible if the builder understands how the server executes the SQL.&lt;/p&gt;

&lt;p&gt;Additionally, the &lt;code&gt;MySQLShow&lt;/code&gt; interface turns &lt;code&gt;SHOW BINLOG EVENTS ... FROM ... IN ... LIMIT&lt;/code&gt;, &lt;code&gt;SHOW CHARACTER SET LIKE/WHERE&lt;/code&gt;, &lt;code&gt;SHOW COLUMNS&lt;/code&gt;, and &lt;code&gt;SHOW COLLATION&lt;/code&gt; into DQL statements (returning &lt;code&gt;DqlStatement&lt;/code&gt;, executable through the session) — bringing MySQL client-style commands into the same unified execution pipeline.&lt;/p&gt;




&lt;h2&gt;
  
  
  8. The Function Libraries: JSON, Spatial, and Aggregate Depth
&lt;/h2&gt;

&lt;p&gt;Army does not expose functions as a &lt;code&gt;func(String name, Object... args)&lt;/code&gt; escape hatch. MySQL-specific functions are statically implemented by family:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Implementation&lt;/th&gt;
&lt;th&gt;Static methods&lt;/th&gt;
&lt;th&gt;Representative functions&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;MySQLJsonFunctions&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;52&lt;/td&gt;
&lt;td&gt;JSON_TABLE, JSON_VALUE, JSON_SEARCH, JSON_CONTAINS, &lt;code&gt;-&amp;gt;&lt;/code&gt; / &lt;code&gt;-&amp;gt;&amp;gt;&lt;/code&gt; operators&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;MySQLSpatialFunctions&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;154&lt;/td&gt;
&lt;td&gt;ST_DISTANCE / ST_CONTAINS (OpenGIS family) plus the MBR family (mbrContains, mbrWithin, …)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;MySQLStringFunctions&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;60&lt;/td&gt;
&lt;td&gt;ELT, EXPORT_SET, FROM_BASE64, FIND_IN_SET, …&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;MySQLTimeFunctions&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;67&lt;/td&gt;
&lt;td&gt;MySQL date/time functions and interval units&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;MySQLMiscellaneousFunctions&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;73&lt;/td&gt;
&lt;td&gt;GROUP_CONCAT and friends&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;MySQLWindowFunctions&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;48&lt;/td&gt;
&lt;td&gt;MySQL-side window function bindings&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The JSON_TABLE depth deserves its own demonstration. A real example from &lt;code&gt;FunctionTests&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;stmt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MySQLs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;select&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;space&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"t"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;PERIOD&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;ASTERISK&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jsonTable&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jsonDocument&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"$[*]"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;COLUMNS&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;space&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"rowId"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;FOR_ORDINALITY&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;comma&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ac"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;MySQLType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;VARCHAR&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parens&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;characterSet&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"utf8mb4"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;collate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"utf8mb4_unicode_ci"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
                        &lt;span class="no"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"$.a"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;spaceDefault&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"111"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;onEmpty&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                                          &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;spaceDefault&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"999"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;onError&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;comma&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"aj"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;MySQLType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;JSON&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"$.a"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;spaceDefault&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{\"x\":333}"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;onEmpty&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;comma&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"bx"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;MySQLType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;INT&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;EXISTS&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"$.b"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;as&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"t"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asQuery&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This covers every JSON_TABLE column kind: &lt;code&gt;FOR ORDINALITY&lt;/code&gt; ordinal columns, &lt;code&gt;PATH&lt;/code&gt; columns (with SQL type, character set, and collation), &lt;code&gt;EXISTS PATH&lt;/code&gt; boolean columns, and the two-level &lt;code&gt;DEFAULT ... ON EMPTY / ON ERROR&lt;/code&gt; clauses. Note that &lt;code&gt;MySQLType.VARCHAR.parens(100).characterSet(...).collate(...)&lt;/code&gt; returns a &lt;code&gt;TypeDef&lt;/code&gt; — DDL-style type definitions are themselves composible chain objects, not concatenated strings.&lt;/p&gt;

&lt;p&gt;MySQL's proprietary &lt;code&gt;GROUP_CONCAT&lt;/code&gt; is equally complete (DISTINCT, multiple expressions, ORDER BY, SEPARATOR):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;select&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;groupConcat&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SQLs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;DISTINCT&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;space&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;comma&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;createTime&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;comma&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;regionGdp&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;orderBy&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;separator&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;","&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;as&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"nameGroup"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  9. DDL: Table Options Are Part of the Dialect Too
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;MySQLDdlParser&lt;/code&gt; (507 lines) renders schema diffs to DDL, including MySQL-proprietary table options: auto-increment columns render &lt;code&gt;AUTO_INCREMENT&lt;/code&gt;, and &lt;code&gt;CREATE TABLE&lt;/code&gt; statements carry &lt;code&gt;ENGINE=InnoDB&lt;/code&gt; / &lt;code&gt;CHARACTER SET=utf8mb4&lt;/code&gt; table options. Type-name rendering is gated by &lt;code&gt;MySQLParser.typeName&lt;/code&gt; — only data types that are &lt;code&gt;instanceof MySQLType&lt;/code&gt; may appear in MySQL DDL/DML; sneaking in a PostgreSQL &lt;code&gt;INT4RANGE&lt;/code&gt; is rejected at render time with &lt;code&gt;unrecognizedTypeName&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  10. Philosophy and Costs
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What it gets right
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Syntactic correctness is guaranteed by the type system, not by experience.&lt;/strong&gt; Partitions, index hints, modifiers, locks, ROLLUP, and row aliases each occupy an unskippable chain stage; wrong clauses fail to compile in Java, and wrong versions (CTEs on 5.7, 8.0 hints on 5.7) fail immediately at render time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dialect differences live in template methods, not scattered ifs.&lt;/strong&gt; Backticks, &lt;code&gt;LIMIT m,n&lt;/code&gt;, WITH version gates, and lock syntax are &lt;code&gt;final&lt;/code&gt; overrides of &lt;code&gt;ArmyParser&lt;/code&gt; in &lt;code&gt;MySQLParser&lt;/code&gt;; MySQL-specific statements self-render through &lt;code&gt;_SelfDescribed&lt;/code&gt; nodes. The boundary between the shared skeleton and dialect flesh is clean.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Server-protocol limits are written as contracts.&lt;/strong&gt; LOAD DATA's three prerequisites, the ON DUPLICATE conflicts with auto-increment keys and logical deletes, and the hard escape-mode constraints all live in entry Javadoc and build-time validation — not in production deadlocks or corrupted generated keys.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MySQL operational culture is respected.&lt;/strong&gt; LOW_PRIORITY, QUICK, IGNORE, SET_VAR, SKIP LOCKED, user-variable row numbering, SHOW commands, multi-table deletes — the real DBA's toolbox, which most "database abstraction layers" pretend does not exist.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  The costs are equally real
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A huge interface surface.&lt;/strong&gt; The &lt;code&gt;criteria/mysql&lt;/code&gt; package alone is roughly 7,200 lines of nested interfaces. Chains like &lt;code&gt;_PrimaryOptionSpec → _PartitionSpec → _ColumnListSpec → _OnAsRowAliasSpec&lt;/code&gt; are a high wall for newcomers; the framework trades syntactic correctness for staged interfaces and passes the learning cost straight to the user.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Version span carries baggage.&lt;/strong&gt; Still supporting MySQL 5.5 means WITH, windows, INTERSECT/EXCEPT, and JSON_TABLE must all exist behind version gates; an 8.0-only baseline would be simpler.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Portability is one-directional.&lt;/strong&gt; A chain built with &lt;code&gt;MySQLs.query()&lt;/code&gt; is bound to MySQL; cross-database code must stay on the &lt;code&gt;SQLs.query()&lt;/code&gt; common subset — which deliberately removes about half of the features in this article. That is a conscious trade-off, but know it before adopting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No string-concatenation escape hatch is a double-edged sword.&lt;/strong&gt; Every new MySQL syntax addition (newer JSON functions, for example) waits for framework modeling — but the release cadence is controlled by the maintainer.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Closing
&lt;/h3&gt;

&lt;p&gt;Army's MySQL dialect answers a question few take seriously: &lt;strong&gt;if you do not aim for "write once, run anywhere," but instead for "write everything MySQL can, on MySQL," how far can a Java SQL DSL go?&lt;/strong&gt; Its answer spans version awareness from 5.5 to 9.x, rendering overrides from backticks to &lt;code&gt;LIMIT m,n&lt;/code&gt;, Java type selection for all five unsigned integers, parent/child LOAD DATA imports, 30 optimizer hints, and all four JSON_TABLE column kinds. The MySQL reference manual's table of contents is, quite literally, this module's package structure.&lt;/p&gt;

&lt;p&gt;If your systems depend heavily on MySQL-specific power — multi-table DML, UPSERT, LOAD DATA, index hints, spatial/JSON — and you are not willing to give up compile-time checking, this dialect is worth an afternoon reading the MySQL suites in army-example.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Source code and runnable examples: &lt;a href="https://github.com/PillArmy/army" rel="noopener noreferrer"&gt;https://github.com/PillArmy/army&lt;/a&gt;&lt;/strong&gt; (&lt;code&gt;army-mysql&lt;/code&gt; module; examples in &lt;code&gt;army-example/src/test/java/io/army/session/sync/mysql/&lt;/code&gt;)&lt;/p&gt;

</description>
      <category>backend</category>
      <category>database</category>
      <category>java</category>
      <category>sql</category>
    </item>
    <item>
      <title>Army vs jOOQ</title>
      <dc:creator>zoro ma</dc:creator>
      <pubDate>Tue, 15 Sep 2026 17:25:40 +0000</pubDate>
      <link>https://dev.to/zoro7/army-vs-jooq-1fg7</link>
      <guid>https://dev.to/zoro7/army-vs-jooq-1fg7</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Project on GitHub: &lt;a href="https://github.com/PillArmy/army" rel="noopener noreferrer"&gt;github.com/PillArmy/army&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Every code sample in this article is copied (with minor import trimming) from Army's own source tree — either the &lt;code&gt;army-example&lt;/code&gt; module or generated build output. Every measurement of jOOQ was taken by me on a local checkout of the current jOOQ trunk. You can reproduce all of it.&lt;/p&gt;

&lt;h1&gt;
  
  
  A SQL DSL where JDBC is just one executor: studying Army against jOOQ
&lt;/h1&gt;

&lt;p&gt;We have had type-safe SQL DSLs in Java for a long time. QueryDSL appeared in 2007, jOOQ in 2009. You would be forgiven for thinking the design space was closed — that everything left to do was polish, dialects, and code generation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/PillArmy/army" rel="noopener noreferrer"&gt;Army&lt;/a&gt; is a small, pre-1.0 (0.6.x), single-maintainer Java ORM that disagrees. After reading through its ~237,000 lines of main source across 16 Maven modules, I think it makes &lt;strong&gt;four design decisions worth studying even if you never adopt it&lt;/strong&gt; — including one architecture-level bet I have not seen anywhere else in the Java ORM space.&lt;/p&gt;

&lt;p&gt;This is not a "jOOQ is bad" article. jOOQ is an excellent, mature, commercially proven product. The interesting question is narrower: &lt;em&gt;given identical language features, which trade-offs did each project choose, and what do those choices cost?&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  1. JDBC is not the foundation. It is one pluggable executor
&lt;/h2&gt;

&lt;p&gt;This is the single most important thing in the codebase.&lt;/p&gt;

&lt;p&gt;In MyBatis, a session holds a &lt;code&gt;java.sql.Connection&lt;/code&gt;. In jOOQ, JDBC is the center of the universe; R2DBC support was added years later as a secondary adapter. In Army:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ grep -rn "import java.sql" army-core/src/main/java | wc -l
       0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The entire core module contains zero JDBC imports&lt;/strong&gt;, and its &lt;code&gt;pom.xml&lt;/code&gt; has no JDBC dependency. The executor contract is driver-neutral by construction. From the actual Javadoc of &lt;code&gt;io.army.executor.ExecutorFactory&lt;/code&gt; in &lt;code&gt;army-core&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;/// For example:&lt;/span&gt;
&lt;span class="c1"&gt;///&lt;/span&gt;
&lt;span class="c1"&gt;/// - JDBC&lt;/span&gt;
&lt;span class="c1"&gt;/// - JDBD&lt;/span&gt;
&lt;span class="c1"&gt;/// - ODBC&lt;/span&gt;
&lt;span class="c1"&gt;///&lt;/span&gt;
&lt;span class="c1"&gt;/// @return driver spi name&lt;/span&gt;
&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;driverSpiName&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;/// @return JDBC always return false, JDBD always return true.&lt;/span&gt;
&lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;isResultItemDriverSpi&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;


&lt;span class="c1"&gt;/// For example: io.army.jdbc or io.army.jdbd&lt;/span&gt;
&lt;span class="c1"&gt;/// @return executor vendor&lt;/span&gt;
&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;executorVendor&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;JDBC is listed as &lt;em&gt;one&lt;/em&gt; driver SPI alongside JDBD (a reactive driver) and ODBC. The blocking JDBC implementation — all 3,566 lines of &lt;code&gt;JdbcExecutor&lt;/code&gt; — lives in a &lt;strong&gt;separate module&lt;/strong&gt;, &lt;code&gt;army-jdbc&lt;/code&gt;, and can be replaced without touching the SQL engine, the dialect layer, or the session API.&lt;/p&gt;

&lt;p&gt;Why does this matter? Two reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Reactive was never "a thread pool around JDBC".&lt;/strong&gt; Army's git history contains a full reactive implementation (&lt;code&gt;reactive session impl v1&lt;/code&gt; → &lt;code&gt;v3&lt;/code&gt;, typed reactor sessions, reactive transaction management, reactive MySQL/optimistic-lock test cases) targeting a genuine reactive driver, later removed in two commits (&lt;code&gt;drop reactor module&lt;/code&gt;, &lt;code&gt;drop reactive package&lt;/code&gt;) when the maintainer could no longer afford to maintain both stacks. Removing the module did not damage core — which is the proof that the abstraction is real rather than decorative.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SQL generation is decoupled from the wire protocol.&lt;/strong&gt; The dialect renders SQL against an internal context; the executor binds and ships it. The same rendered statement can be consumed by a blocking driver today and a reactive driver tomorrow.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Contrast this with the cost of retrofitting reactiveness onto a JDBC-centric design, and you see why this is a bet, not a decoration.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. A compile-time clause state machine — hidden behind exactly one public entry point
&lt;/h2&gt;

&lt;p&gt;Here is real user-facing query code, from &lt;code&gt;army-example/.../bank/dao/sync/region/StandardRegionDao.java&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Select&lt;/span&gt; &lt;span class="n"&gt;stmt&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;stmt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SQLs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;select&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;T&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;AS&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"t"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;SQLs:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;regionName&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;and&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;regionType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;SQLs:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;literal&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;regionType&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asQuery&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sessionContext&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;currentSession&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;queryOne&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stmt&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;SQLs.query()&lt;/code&gt; does not return a "wide query object". It returns &lt;code&gt;StandardQuery.WithSpec&amp;lt;Select&amp;gt;&lt;/code&gt; — a narrow entry type. Each clause method's return type is parameterized to the &lt;strong&gt;next legal stage&lt;/strong&gt;. From &lt;code&gt;army-core/.../criteria/standard/StandardQuery.java&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// the ONLY public entry; Javadoc: "public interface that developer can directly use"&lt;/span&gt;
&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;WithSpec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;I&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Item&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;_StandardDynamicWithClause&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SelectSpec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;I&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;,&lt;/span&gt;
        &lt;span class="n"&gt;_StandardStaticWithClause&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SelectSpec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;I&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;,&lt;/span&gt;
        &lt;span class="nc"&gt;SelectSpec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;I&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// select() lands you here...&lt;/span&gt;
&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;_StandardSelectClause&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;I&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Item&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;_ModifierListSelectClause&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SQLs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Modifier&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_StandardSelectCommaClause&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;I&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;,&lt;/span&gt;
        &lt;span class="n"&gt;_DynamicModifierSelectClause&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SQLs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Modifier&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_FromSpec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;I&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// ...from() lands you here, and joins branch/merge as a type-level graph:&lt;/span&gt;
&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;_JoinSpec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;I&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Item&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;_StandardJoinClause&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;_JoinSpec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;I&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;,&lt;/span&gt; &lt;span class="n"&gt;_OnClause&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;_JoinSpec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;I&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;,&lt;/span&gt;
        &lt;span class="n"&gt;_JoinCteClause&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;_OnClause&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;_JoinSpec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;I&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;,&lt;/span&gt;
        &lt;span class="n"&gt;_CrossJoinCteClause&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;_OnClause&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;_JoinSpec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;I&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;,&lt;/span&gt;
        &lt;span class="n"&gt;_WhereSpec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;I&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;_WhereSpec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;I&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Item&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Statement&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;_QueryWhereClause&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;_GroupBySpec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;I&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;,&lt;/span&gt; &lt;span class="n"&gt;_WhereAndSpec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;I&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;,&lt;/span&gt; &lt;span class="n"&gt;_GroupBySpec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;I&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Follow the chain and you get the complete SQL grammar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WithSpec → SelectSpec → _FromSpec → _JoinSpec → _WhereSpec
        → _GroupBySpec → _HavingSpec → _WindowSpec
        → _OrderBySpec → _LimitSpec → _LockSpec → terminal
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Write a clause out of order and &lt;strong&gt;the compiler rejects it&lt;/strong&gt;, with the same strictness jOOQ offers. The branching is real too: &lt;code&gt;_JoinSpec&lt;/code&gt; extends both further-join capability &lt;em&gt;and&lt;/em&gt; &lt;code&gt;_WhereSpec&lt;/code&gt;, so "keep joining or move to WHERE" is expressed in types, not runtime checks.&lt;/p&gt;

&lt;p&gt;The twist: every intermediate spec is a nested interface whose Javadoc reads:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Application developer isn't allowed to directly use this interface... army don't guarantee compatibility to future distribution.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The user sees one entry (&lt;code&gt;WithSpec&lt;/code&gt;) and four terminal statement families (&lt;code&gt;Query&lt;/code&gt;, &lt;code&gt;Insert&lt;/code&gt;, &lt;code&gt;Update&lt;/code&gt;, &lt;code&gt;Delete&lt;/code&gt;). The ~15-stage state machine exists in full — it is just locked in a black box.&lt;/p&gt;

&lt;h3&gt;
  
  
  How jOOQ encodes the same grammar
&lt;/h3&gt;

&lt;p&gt;jOOQ uses a &lt;strong&gt;public linear inheritance chain&lt;/strong&gt;. Walking the actual &lt;code&gt;extends&lt;/code&gt; clauses on a current trunk checkout:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SelectSelectStep → SelectDistinctOnStep → SelectIntoStep → SelectFromStep
→ SelectWhereStep → SelectConnectByStep → SelectGroupByStep → SelectHavingStep
→ SelectWindowStep → SelectQualifyStep → SelectOrderByStep → SelectLimitStep
→ SelectForUpdateStep → SelectForStep → SelectOptionStep → SelectUnionStep
→ SelectCorrelatedSubqueryStep → SelectFinalStep → Select
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is &lt;strong&gt;19 levels of public interface&lt;/strong&gt;. There are &lt;strong&gt;68 &lt;code&gt;Select*Step&lt;/code&gt; source files&lt;/strong&gt;. And the god-entry-point &lt;code&gt;DSLContext.java&lt;/code&gt; measures:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;16,556 lines
  ~848 method declarations
  280 distinct method base names
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(The &lt;code&gt;fetch*&lt;/code&gt; family alone includes &lt;code&gt;fetch&lt;/code&gt;, &lt;code&gt;fetchSingle&lt;/code&gt;, &lt;code&gt;fetchOne&lt;/code&gt;, &lt;code&gt;fetchLazy&lt;/code&gt;, &lt;code&gt;fetchAsync&lt;/code&gt;, &lt;code&gt;fetchStream&lt;/code&gt;, &lt;code&gt;fetchOptional&lt;/code&gt;, &lt;code&gt;fetchGroups&lt;/code&gt;, &lt;code&gt;fetchMap&lt;/code&gt;... each with many overloads.)&lt;/p&gt;

&lt;p&gt;This is not a mistake by stupid people — it is a precise trade-off. The public chain gives human developers the most aggressively narrowed IDE autocomplete in the industry, and every one of those 68 types is a compatibility contract that paying enterprise customers depend on. jOOQ even did one breaking rewrite (3.0, splitting &lt;code&gt;Factory&lt;/code&gt; into &lt;code&gt;DSL&lt;/code&gt;/&lt;code&gt;DSLContext&lt;/code&gt;) and &lt;strong&gt;kept the Step chain&lt;/strong&gt; — they are not incapable of surgery; the chain is load-bearing.&lt;/p&gt;

&lt;p&gt;The difference is purely in &lt;em&gt;where the state machine lives&lt;/em&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;QueryDSL&lt;/th&gt;
&lt;th&gt;jOOQ&lt;/th&gt;
&lt;th&gt;Army&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Clause order enforced&lt;/td&gt;
&lt;td&gt;At runtime&lt;/td&gt;
&lt;td&gt;Compile time (inheritance chain)&lt;/td&gt;
&lt;td&gt;Compile time (generic spec graph)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;State machine visibility&lt;/td&gt;
&lt;td&gt;User's problem&lt;/td&gt;
&lt;td&gt;68 public Steps, all contracts&lt;/td&gt;
&lt;td&gt;~15 specs, all forbidden; 1 public entry&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost of adding a clause&lt;/td&gt;
&lt;td&gt;Add a method&lt;/td&gt;
&lt;td&gt;Insert a level, change all return types&lt;/td&gt;
&lt;td&gt;Compose a spec into the right stages&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  A 2009 fork, not a 2023 discovery
&lt;/h3&gt;

&lt;p&gt;It is tempting to excuse this as "Java didn't allow anything else back then". It did. Generics shipped in 2004; package-private types and multiple interface composition existed since Java 1; Army's clause layer itself uses &lt;strong&gt;zero&lt;/strong&gt; &lt;code&gt;default&lt;/code&gt; methods and &lt;strong&gt;zero&lt;/strong&gt; &lt;code&gt;sealed&lt;/code&gt; keywords — it would compile on Java 5.&lt;/p&gt;

&lt;p&gt;And the alternative was already running in production: QueryDSL (created 2007) shipped a wide-interface fluent SQL API. Lukas Eder himself wrote in 2014: &lt;em&gt;"In the beginning of jOOQ in 2009, QueryDSL was ahead of us."&lt;/em&gt; (&lt;a href="https://blog.jooq.org/querydsl-vs-jooq-feature-completeness-vs-now-more-than-ever/" rel="noopener noreferrer"&gt;blog.jooq.org&lt;/a&gt;, &lt;a href="https://querydsl.com/static/querydsl/1.2.0/reference/pdf/Querydsl_Reference.pdf" rel="noopener noreferrer"&gt;QueryDSL 1.2.0 manual, ©2007–2009&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Three roads were on the table simultaneously in 2009: wide interfaces (QueryDSL), public inheritance steps (jOOQ), and composed generic specs (the construction Army later chose). All three were legal then.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. The parameter/literal/type decision happens at expression-node creation
&lt;/h2&gt;

&lt;p&gt;Look again at that WHERE clause:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;SQLs:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;regionName&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;and&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;regionType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;SQLs:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;literal&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;regionType&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;equal(SQLs::param, x)&lt;/code&gt; binds &lt;code&gt;x&lt;/code&gt; as a JDBC &lt;code&gt;?&lt;/code&gt; parameter. &lt;code&gt;equal(SQLs::literal, x)&lt;/code&gt; inlines x as a SQL literal. The choice is made &lt;strong&gt;where the expression node is born&lt;/strong&gt;, and the node carries its mapping type with it. There is no separate, parallel list of parameter mappings walking alongside rendered text (as in MyBatis' &lt;code&gt;BoundSql&lt;/code&gt; + &lt;code&gt;ParameterMapping&lt;/code&gt;) and no &lt;code&gt;eq(Object)&lt;/code&gt; escape hatch that silently accepts anything.&lt;/p&gt;

&lt;p&gt;This matters most where the database type &lt;em&gt;changes the SQL syntax&lt;/em&gt;. A PostgreSQL &lt;code&gt;jsonb&lt;/code&gt; value may need a cast, an array literal needs &lt;code&gt;ARRAY[...]&lt;/code&gt; construction, an enum has three different storage conventions. Army models those as first-class mapping types in &lt;code&gt;army-core/.../mapping/&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NameEnumType      CodeEnumType      LabelEnumType
JsonType / JsonbType / JsonMappingType / JsonbMappingType
ArrayMappingType  CompositeType     VectorType     XmlType ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In jOOQ, enums are second-class citizens handled by configuring a &lt;code&gt;Converter&lt;/code&gt;/&lt;code&gt;EnumConverter&lt;/code&gt; (forced types); the rendering knowledge is not intrinsic to the expression node. And while &lt;code&gt;Field&amp;lt;T&amp;gt;.eq(T)&lt;/code&gt; is type-safe, jOOQ's wide surface also offers &lt;code&gt;eq(Object)&lt;/code&gt;, plain-SQL fields, and &lt;code&gt;DSL.field(String, DataType)&lt;/code&gt; — paths through which the wrong operand type compiles and fails at bind time. The generic parameter largely decides what you get &lt;em&gt;out&lt;/em&gt; of a fetch; it does not fully police what goes &lt;em&gt;into&lt;/em&gt; the AST.&lt;/p&gt;

&lt;p&gt;The generated metamodel reinforces this at compile time. This is actual annotation-processor output from the project's build directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Generated&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"io.army.modelgen.ArmyMetaModelDomainProcessor"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProductInfo_&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;ProductInfo_&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;UnsupportedOperationException&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;CompositeType&lt;/span&gt; &lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CompositeType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ProductInfo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;fieldSize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fieldList&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fieldSize&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="n"&gt;_TableMetaFactory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;compositeFieldSizeError&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ProductInfo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fieldSize&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;CompositeField&lt;/span&gt; &lt;span class="n"&gt;productId&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;field&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"productId"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;CompositeField&lt;/span&gt; &lt;span class="n"&gt;productName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;field&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"productName"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;CompositeField&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;field&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"price"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The processor also rejects illegal table names (camelCase) and index declarations referencing non-existent fields — schema mistakes that cannot reach a running database.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. The public API is interfaces, sealed; implementations are package-private
&lt;/h2&gt;

&lt;p&gt;Building a factory, verbatim from &lt;code&gt;army-example/src/test/java/io/army/session/FactoryUtils.java&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;SyncSessionFactory&lt;/span&gt; &lt;span class="nf"&gt;createArmyBankSyncFactory&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Database&lt;/span&gt; &lt;span class="n"&gt;database&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;SyncFactoryBuilder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mapDatabaseToFactoryName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;database&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;packagesToScan&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Collections&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;singletonList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"io.army.example.bank.domain"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;datasource&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;DataSourceUtils&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;createDataSource&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;database&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;createEnvironment&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;database&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;jsonCodec&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;FastJsonCodec&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getInstance&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fieldGeneratorFactory&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SimpleFieldGeneratorFactory&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Static factory entry, fluent options, final immutable factory. The interfaces are &lt;code&gt;sealed&lt;/code&gt; and permit exactly one package-private implementation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;sealed&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;SyncSessionFactory&lt;/span&gt; &lt;span class="n"&gt;permits&lt;/span&gt; &lt;span class="nc"&gt;ArmySyncSessionFactory&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;sealed&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;SyncFactoryBuilder&lt;/span&gt;  &lt;span class="n"&gt;permits&lt;/span&gt; &lt;span class="nc"&gt;ArmySyncFactoryBuilder&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ArmySyncFactoryBuilder&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;   &lt;span class="c1"&gt;// package-private&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ArmySyncSessionFactory&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// package-private&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You cannot instantiate the implementation, you cannot write your own &lt;code&gt;implements SyncSessionFactory&lt;/code&gt; (the &lt;code&gt;permits&lt;/code&gt; clause forbids it), and you cannot subclass the builder. There is no public &lt;code&gt;DefaultXxx&lt;/code&gt; class doubling as unofficial API — compare with MyBatis, where &lt;code&gt;DefaultSqlSessionFactory&lt;/code&gt; and its constructor are both &lt;code&gt;public&lt;/code&gt; under a &lt;code&gt;defaults&lt;/code&gt; package that is only a &lt;em&gt;gentleman's agreement&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;(Small honest wart: the builder's &lt;code&gt;datasource(...)&lt;/code&gt; parameter is typed &lt;code&gt;Object&lt;/code&gt; so it can accept both &lt;code&gt;javax.sql.DataSource&lt;/code&gt; and Army's own read/write-splitting datasource. That is a real, if small, compile-time-safety leak.)&lt;/p&gt;

&lt;p&gt;Executing statements stays narrow too — the whole sync session surface is ~63 methods, with query consumption unified behind &lt;code&gt;ResultItem&lt;/code&gt; (rows, update counts, and metadata as one numbered stream), instead of hundreds of &lt;code&gt;fetchXxx&lt;/code&gt; variants:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;SyncLocalSession&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;localSession&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

&lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;queryOne&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stmt&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;                       &lt;span class="c1"&gt;// one value&lt;/span&gt;
&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;queryObjectList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stmt&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;HashMap:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;update&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;insertStmt&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;                                         &lt;span class="c1"&gt;// DML&lt;/span&gt;
&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;domain&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;                                               &lt;span class="c1"&gt;// active-record-style&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  5. Why I think this matters for AI — beyond hype
&lt;/h2&gt;

&lt;p&gt;The point is not "AI likes Army". It is that AI coding agents are essentially &lt;strong&gt;program transformers under compiler supervision&lt;/strong&gt;, and their failure mode is generating structurally plausible text.&lt;/p&gt;

&lt;p&gt;Facing the three SQL-DSL architectures, an agent gets structurally different feedback:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Wide interfaces (QueryDSL-style):&lt;/strong&gt; every method is callable in every state; wrong clause order fails latest — at runtime.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;19 public Step types (jOOQ-style):&lt;/strong&gt; autocomplete narrowing is superb for humans, but those 68 &lt;code&gt;SelectConnectByAfterStartWithConditionStep&lt;/code&gt;-shaped names are vanishingly rare in training data; an agent must reason about &lt;em&gt;which step am I on&lt;/em&gt; across a huge public type graph.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One entry + hidden generic specs (Army-style):&lt;/strong&gt; the public vocabulary the model must hold is tiny (one entry, four terminal statements, a handful of clause functions), while wrong order is still killed by the compiler. Full constraint strength, roughly an order of magnitude fewer public types to reason about.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When the expression node also carries its mapping type, the agent doesn't merely emit text that &lt;em&gt;looks&lt;/em&gt; like PostgreSQL — the renderer produces the required cast/array/enum syntax deterministically. The type system is, in effect, a cheap, unforgiving environment: a compiler error is feedback that does not depend on anyone's language.&lt;/p&gt;




&lt;h2&gt;
  
  
  6. The honest counter-section
&lt;/h2&gt;

&lt;p&gt;You should not read this as "Army beats jOOQ". It does not, on most axes that matter for production:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Maturity:&lt;/strong&gt; jOOQ has ~17 years of releases, 30+ dialects, commercial support, enormous manuals, and tens of thousands of deployments. Army is 0.6.x with essentially one user.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dialect depth is concentrated:&lt;/strong&gt; PostgreSQL and MySQL are deep (single files like &lt;code&gt;PostgreDocumentFunctions.java&lt;/code&gt; run over 6,000 lines), SQLite/H2 are thinner, and Oracle is a five-file skeleton.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tests are thin relative to scope:&lt;/strong&gt; ~20.8k lines of test code against ~237k lines of main code. jOOQ's test matrix is larger than its main source.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The reactive stack was removed&lt;/strong&gt;, not merely unbuilt — consciously, for lack of maintainer resources — so today only the blocking/SPI story is shipped.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Risk:&lt;/strong&gt; single maintainer, no commercial entity, pre-1.0 API churn is possible despite the sealing discipline.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What Army &lt;em&gt;does&lt;/em&gt; provide is existence proof: that a Java SQL DSL can (1) treat JDBC as a swappable detail, (2) enforce full clause order at compile time through a single public entry, (3) bind parameter/literal/mapping semantics into the expression node, and (4) seal the entire runtime surface — all using language features that have existed since 2004.&lt;/p&gt;

&lt;p&gt;The strongest sentence I am willing to write is this: &lt;strong&gt;jOOQ optimized its public surface for human discovery across two decades of compatibility; Army optimized its public surface for minimality and compiler-enforced structure. In a world where an increasing share of SQL is written by agents and judged by compilers, the second bet deserves to be seen.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Appendix: how to verify
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# jOOQ (current trunk checkout)&lt;/span&gt;
&lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt; jOOQ/src/main/java/org/jooq/DSLContext.java
&lt;span class="nb"&gt;ls &lt;/span&gt;jOOQ/src/main/java/org/jooq | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'^Select.*Step'&lt;/span&gt;

&lt;span class="c"&gt;# Army&lt;/span&gt;
&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-rn&lt;/span&gt; &lt;span class="s2"&gt;"import java.sql"&lt;/span&gt; army-core/src/main/java | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt;        &lt;span class="c"&gt;# 0&lt;/span&gt;
find &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-path&lt;/span&gt; &lt;span class="s1"&gt;'*/src/main/java/*.java'&lt;/span&gt; | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt;                     &lt;span class="c"&gt;# 1361&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Sources: &lt;a href="https://github.com/PillArmy/army" rel="noopener noreferrer"&gt;github.com/PillArmy/army&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;QueryDSL 1.2.0 reference (© 2007–2009 Mysema Ltd): &lt;a href="https://querydsl.com/static/querydsl/1.2.0/reference/pdf/Querydsl_Reference.pdf" rel="noopener noreferrer"&gt;PDF&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Lukas Eder on QueryDSL vs jOOQ (2014): &lt;a href="https://blog.jooq.org/querydsl-vs-jooq-feature-completeness-vs-now-more-than-ever/" rel="noopener noreferrer"&gt;blog.jooq.org&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;jOOQ 3.0 migration notes (Factory split, Row[N] 8→22): &lt;a href="https://www.jooq.org/doc/latest/manual/reference/migrating-to-3.0/" rel="noopener noreferrer"&gt;manual&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Measurements taken September 2026 on jOOQ trunk and Army 0.6.x source. I have no affiliation with either project.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>database</category>
      <category>java</category>
      <category>opensource</category>
      <category>sql</category>
    </item>
    <item>
      <title>Army: A Deep Dive into Java's Most Dialect-Aware Type-Safe SQL DSL</title>
      <dc:creator>zoro ma</dc:creator>
      <pubDate>Mon, 14 Sep 2026 14:44:59 +0000</pubDate>
      <link>https://dev.to/zoro7/army-a-deep-dive-into-javas-most-dialect-aware-type-safe-sql-dsl-i43</link>
      <guid>https://dev.to/zoro7/army-a-deep-dive-into-javas-most-dialect-aware-type-safe-sql-dsl-i43</guid>
      <description>&lt;h1&gt;
  
  
  Army: A Deep Dive into Java's Most Dialect-Aware Type-Safe SQL DSL
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;GitHub: &lt;a href="https://github.com/PillArmy/army" rel="noopener noreferrer"&gt;https://github.com/PillArmy/army&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Apache 2.0 · Java 25 · Maven coordinates &lt;code&gt;io.qinarmy:army-*&lt;/code&gt; · current version &lt;code&gt;0.6.8-SNAPSHOT&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you write Java against relational databases, you have basically four options: hand-written JDBC (verbose, unsafe), a JPA/Hibernate layer (powerful, but SQL becomes an implementation detail), a template engine like MyBatis (full SQL, stringly typed), or a fluent DSL like jOOQ (type-safe, but its dialect-specific story is thin).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/PillArmy/army" rel="noopener noreferrer"&gt;Army&lt;/a&gt; is a fifth point on that map — and a fairly extreme one. Its README opens with a design philosophy that is almost a manifesto:&lt;/p&gt;

&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;Don't create new world, just mapping real world.&lt;/li&gt;
&lt;li&gt;We need standard, we need dialect, it's real world.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;Army is &lt;strong&gt;not an ORM&lt;/strong&gt; by its own definition. It does not manage connections, transactions, caches, lazy loading, or schema migrations. It does one thing: let you construct SQL statements in Java with the full power of the underlying dialect, checked at compile time, and map the result back to plain POJOs.&lt;/p&gt;

&lt;p&gt;I spent time reading the actual source — roughly 220,000 lines of Java across 16 Maven modules, including a 120k-line core and dialect modules that re-implement the PostgreSQL and MySQL grammars separately. This article is what I found: the architecture, the clever type tricks, and the trade-offs.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. What the Codebase Looks Like
&lt;/h2&gt;

&lt;p&gt;The module layout tells the story before you read a single class:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Module&lt;/th&gt;
&lt;th&gt;Java LOC (approx.)&lt;/th&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;army-core&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;120,000&lt;/td&gt;
&lt;td&gt;Criteria interfaces, dialect SPI, type system, sessions, metadata&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;army-postgre&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;40,000&lt;/td&gt;
&lt;td&gt;PostgreSQL grammar: CTE, &lt;code&gt;RETURNING&lt;/code&gt;, ranges, arrays, &lt;code&gt;DECLARE CURSOR&lt;/code&gt;, MERGE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;army-mysql&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;30,000&lt;/td&gt;
&lt;td&gt;MySQL grammar: hints, &lt;code&gt;STRAIGHT_JOIN&lt;/code&gt;, &lt;code&gt;LOAD DATA&lt;/code&gt;, unsigned types&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;army-array&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;7,500&lt;/td&gt;
&lt;td&gt;Per-element array mapping for every supported type&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;army-sync&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;5,200&lt;/td&gt;
&lt;td&gt;Blocking session/executor layer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;army-annotation&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;5,100&lt;/td&gt;
&lt;td&gt;Annotation processor generating the static metamodel&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;army-jdbc&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;8,400&lt;/td&gt;
&lt;td&gt;JDBC binding over any &lt;code&gt;DataSource&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;army-spring&lt;/code&gt;, &lt;code&gt;army-spring-ai-*&lt;/code&gt;, &lt;code&gt;army-guava&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;Spring tx manager, Spring AI vector store &amp;amp; chat memory integrations&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Dialects are not adapters over a common SQL subset — PostgreSQL and MySQL each get their own grammar package (&lt;code&gt;io.army.criteria.postgre&lt;/code&gt;, &lt;code&gt;io.army.criteria.mysql&lt;/code&gt;) with their own entry class, clause interfaces, and keyword objects. What follows explains why.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. The Query You Actually Write
&lt;/h2&gt;

&lt;p&gt;This is a real test from the project's example suite (&lt;code&gt;army-example&lt;/code&gt;, &lt;code&gt;QuerySuiteTests&lt;/code&gt;), slightly trimmed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Select&lt;/span&gt; &lt;span class="n"&gt;stmt&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;stmt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Postgres&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;select&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"c"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;PERIOD&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;T&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;T&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;AS&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"c"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;limit&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;SQLs:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;literal&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asQuery&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Supplier&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ChinaRegion&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;constructor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nl"&gt;ChinaRegion:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;syncSession&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;queryObject&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stmt&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;constructor&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;forEach&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;LOG&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;debug&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{}"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;()));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Several things are happening here that define Army's style:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;Postgres.query()&lt;/code&gt; is the &lt;strong&gt;dialect-specific&lt;/strong&gt; entry point. A portable statement starts with &lt;code&gt;SQLs.query()&lt;/code&gt; instead.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ChinaRegion_.T&lt;/code&gt; is a generated static-metamodel table reference; &lt;code&gt;ChinaRegion_.id&lt;/code&gt;, &lt;code&gt;ChinaRegion_.name&lt;/code&gt; are typed field metadata, not strings.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;AS&lt;/code&gt;, &lt;code&gt;PERIOD&lt;/code&gt; are not enum literals imported for ceremony — they are &lt;strong&gt;typed SQL words&lt;/strong&gt;. &lt;code&gt;AS&lt;/code&gt; is a &lt;code&gt;WordAs&lt;/code&gt;; passing &lt;code&gt;ON&lt;/code&gt; where &lt;code&gt;AS&lt;/code&gt; belongs does not compile.&lt;/li&gt;
&lt;li&gt;The chain ends with a &lt;strong&gt;terminal method&lt;/strong&gt;, &lt;code&gt;.asQuery()&lt;/code&gt;, which returns a sealed &lt;code&gt;Select&lt;/code&gt; statement. Until you call it, you don't have an executable statement — you have a builder state.&lt;/li&gt;
&lt;li&gt;The result is &lt;em&gt;your&lt;/em&gt; class, built through a method reference (&lt;code&gt;ChinaRegion::new&lt;/code&gt;). No &lt;code&gt;Record12&amp;lt;...&amp;gt;&lt;/code&gt;, no proxy, no session-attached entity.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Staged interfaces: the clause order is the type system
&lt;/h3&gt;

&lt;p&gt;Look at the factory signatures in &lt;code&gt;Postgres.java&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;PostgreQuery&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;WithSpec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Select&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;PostgreQueries&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;simpleQuery&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;PostgreInsert&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;_PrimaryOptionSpec&lt;/span&gt; &lt;span class="nf"&gt;singleInsert&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;PostgreInserts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;singleInsert&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;PgSingleDeleteSpec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Delete&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ReturningDelete&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;singleDelete&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;PostgreDeletes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;simpleDelete&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each chain method returns a &lt;em&gt;different&lt;/em&gt; interface representing a legal state of the statement. The generic parameter (&lt;code&gt;Select&lt;/code&gt;, &lt;code&gt;Expression&lt;/code&gt;, &lt;code&gt;SubQuery&lt;/code&gt;, &lt;code&gt;Statement._BatchSelectParamSpec&lt;/code&gt;) tells you what the terminal method will produce. That is how Army encodes the SQL grammar into Java's type system: you literally cannot call &lt;code&gt;.where()&lt;/code&gt; before &lt;code&gt;.from()&lt;/code&gt;, because the intermediate interface does not declare it, and you cannot accidentally execute a half-built statement, because only the terminal interfaces (&lt;code&gt;...Spec&lt;/code&gt;) expose &lt;code&gt;.asQuery()&lt;/code&gt; / &lt;code&gt;.asInsert()&lt;/code&gt; / &lt;code&gt;.asDelete()&lt;/code&gt; / &lt;code&gt;.asReturningDelete()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The README's own example makes the point bluntly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;SQLs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Stock_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;T&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;AS&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"s"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;     &lt;span class="c1"&gt;// ✅ WordAs&lt;/span&gt;
&lt;span class="c1"&gt;//  .from(Stock_.T, ON, "s")    // ❌ COMPILE ERROR: wrong type&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the "phantom builder" pattern carried to the scale of a full SQL grammar. The cost is a very large interface surface — the &lt;code&gt;criteria&lt;/code&gt; package alone has ~90 top-level types (&lt;code&gt;_PrimaryOptionSpec&lt;/code&gt;, &lt;code&gt;_SingleWithSpec&lt;/code&gt;, &lt;code&gt;PgSingleDeleteSpec&lt;/code&gt;, ...) — but the payoff is that misuse is mostly unrepresentable.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. From Fluent Chain to SQL Text: the Parse Pipeline
&lt;/h2&gt;

&lt;p&gt;When you hold a &lt;code&gt;Select&lt;/code&gt;, you hold an immutable criteria object — no SQL yet. The rendering pipeline is small conceptually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Criteria statement (Select / Insert / Update / Delete / Values)
        │
        ▼
DialectParser  ── sealed permits ArmyParser (3,551 lines)
        │
        ▼
Stmt  (SimpleStmt | BatchStmt | GeneratedKeyStmt | PairStmt)
        │
        ▼
StmtExecutor  ── JDBC (army-jdbc) or the reactive driver layer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The SPI is a sealed interface in &lt;code&gt;army-core&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;sealed&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;DialectParser&lt;/span&gt; &lt;span class="n"&gt;permits&lt;/span&gt; &lt;span class="nc"&gt;ArmyParser&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nc"&gt;Stmt&lt;/span&gt; &lt;span class="nf"&gt;insert&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;InsertStatement&lt;/span&gt; &lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;SessionSpec&lt;/span&gt; &lt;span class="n"&gt;sessionSpec&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="nc"&gt;Stmt&lt;/span&gt; &lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;UpdateStatement&lt;/span&gt; &lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;useMultiStmt&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;SessionSpec&lt;/span&gt; &lt;span class="n"&gt;sessionSpec&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="nc"&gt;Stmt&lt;/span&gt; &lt;span class="nf"&gt;delete&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;DeleteStatement&lt;/span&gt; &lt;span class="n"&gt;delete&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;useMultiStmt&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;SessionSpec&lt;/span&gt; &lt;span class="n"&gt;sessionSpec&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="nc"&gt;Stmt&lt;/span&gt; &lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SelectStatement&lt;/span&gt; &lt;span class="n"&gt;select&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;useMultiStmt&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;SessionSpec&lt;/span&gt; &lt;span class="n"&gt;sessionSpec&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="nc"&gt;Stmt&lt;/span&gt; &lt;span class="nf"&gt;values&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Values&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;SessionSpec&lt;/span&gt; &lt;span class="n"&gt;sessionSpec&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nc"&gt;Stmt&lt;/span&gt; &lt;span class="nf"&gt;dialectDml&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;DmlStatement&lt;/span&gt; &lt;span class="n"&gt;statement&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;SessionSpec&lt;/span&gt; &lt;span class="n"&gt;sessionSpec&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;UnsupportedOperationException&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// ... printStmt(Stmt, boolean beautify), identifier quoting, typeName(...)&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two details matter. First, &lt;code&gt;sealed ... permits ArmyParser&lt;/code&gt;: there is exactly one parser implementation, and dialect differences are handled inside it through context objects (&lt;code&gt;_SelectContext&lt;/code&gt;, &lt;code&gt;_InsertContext&lt;/code&gt;, &lt;code&gt;_ValuesContext&lt;/code&gt;, ...), one per statement kind. Second, &lt;code&gt;dialectDml&lt;/code&gt; / &lt;code&gt;dialectDql&lt;/code&gt; exist precisely so PostgreSQL's &lt;code&gt;RETURNING&lt;/code&gt; and MySQL's &lt;code&gt;LOAD DATA&lt;/code&gt; don't have to be forced into the portable shape — dialect escape hatches are first-class SPI methods, not reflection-based hacks.&lt;/p&gt;

&lt;p&gt;Every parameter is bound (there is no string concatenation path), and &lt;code&gt;printStmt&lt;/code&gt; can render the exact SQL with &lt;code&gt;?&lt;/code&gt; placeholders or inlined literals for logging — useful when debugging a 40-line generated query.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. The Static Metamodel: Compile-Time Table and Field Metadata
&lt;/h2&gt;

&lt;p&gt;jOOQ generates its metamodel from the live database. Army goes the JPA route but without a runtime metamodel: an &lt;strong&gt;annotation processor&lt;/strong&gt; reads your &lt;code&gt;@Table&lt;/code&gt; classes and emits a sibling class.&lt;/p&gt;

&lt;p&gt;The processor is refreshingly small and direct (&lt;code&gt;ArmyMetaModelDomainProcessor&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@SupportedAnnotationTypes&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"io.army.annotation.Table"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@SupportedSourceVersion&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SourceVersion&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;RELEASE_25&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ArmyMetaModelDomainProcessor&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;AbstractProcessor&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;TypeElement&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;annotations&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;RoundEnvironment&lt;/span&gt; &lt;span class="n"&gt;roundEnv&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Element&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;elementSet&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;elementSet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;roundEnv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getElementsAnnotatedWith&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Table&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;elementSet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;TableAnnotationHandler&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;TableAnnotationHandlerImpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;processingEnv&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;StringBuilder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
        &lt;span class="n"&gt;generateTableStaticModelClass&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;elementSet&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// ... error aggregation, then Filer writes sources in batches of 50&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;@Table&lt;/code&gt; carries real schema metadata — name, comment, catalog, schema, indexes, DDL mode — and its Javadoc even documents a placeholder system (&lt;code&gt;${DEFAULT}&lt;/code&gt;, &lt;code&gt;${RUNTIME}&lt;/code&gt;) resolved at startup from &lt;code&gt;META-INF/army/TableMeta.properties&lt;/code&gt;, so generated names can be overridden per environment without recompiling domain classes.&lt;/p&gt;

&lt;p&gt;The output is the &lt;code&gt;X_&lt;/code&gt; class you saw in the query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Stock_&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;SimpleTableMeta&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Stock&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="no"&gt;NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="no"&gt;OFFER_PRICE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"offerPrice"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;FieldMeta&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Stock&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;field&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;NAME&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;PrimaryFieldMeta&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Stock&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;FieldMeta&amp;lt;Stock&amp;gt;&lt;/code&gt; is where type safety pays off. &lt;code&gt;Stock_.offerPrice.desc()&lt;/code&gt;, &lt;code&gt;Stock_.status.equal(StockStatus.ACTIVE)&lt;/code&gt;, &lt;code&gt;Stock_.id.in(SQLs::rowParam, ids)&lt;/code&gt; — every predicate is a typed expression on a typed field. Rename the Java field, and every query referencing it fails to compile; the string &lt;code&gt;"offer_price"&lt;/code&gt; lives in exactly one place.&lt;/p&gt;

&lt;p&gt;The primary-key story is also worth a glance: the README example wires a Snowflake generator per field:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Generator&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"io.army.generator.snowflake.Snowflake8Generator"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;@Param&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"startTime"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"1779012232202"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
&lt;span class="nd"&gt;@Column&lt;/span&gt;
&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  5. DataType and MappingType: Why Dialects Need Two Layers
&lt;/h2&gt;

&lt;p&gt;This is, in my opinion, the best-designed part of the framework, and it answers the question "why is this not just jOOQ?"&lt;/p&gt;

&lt;p&gt;Most tools flatten type mapping into one step: database type name → Java class. Army splits it into two sealed hierarchies with different jobs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;DataType&lt;/code&gt; answers "what &lt;em&gt;is&lt;/em&gt; this database type?"&lt;/strong&gt; Every dialect enum implements it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;enum&lt;/span&gt; &lt;span class="nc"&gt;PgType&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;SQLType&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="no"&gt;BOOLEAN&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"BOOLEAN"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ArmyType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;BOOLEAN&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
    &lt;span class="no"&gt;BIGINT&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"BIGINT"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ArmyType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;BIGINT&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
    &lt;span class="no"&gt;DOUBLE&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DOUBLE PRECISION"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ArmyType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;DOUBLE&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Double&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
    &lt;span class="no"&gt;TIMESTAMPTZ&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"TIMESTAMPTZ"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ArmyType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;TIMESTAMP_WITH_TIMEZONE&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;OffsetDateTime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
    &lt;span class="no"&gt;JSONB&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"JSONB"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ArmyType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;JSONB&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
    &lt;span class="no"&gt;UUID&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"UUID"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ArmyType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;DIALECT_TYPE&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;util&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;UUID&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;

    &lt;span class="no"&gt;INT4RANGE&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"INT4RANGE"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ArmyType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;RANGE&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
    &lt;span class="no"&gt;TSTZRANGE&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"TSTZRANGE"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ArmyType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;RANGE&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
    &lt;span class="no"&gt;INT4MULTIRANGE&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"INT4MULTIRANGE"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ArmyType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;RANGE&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;

    &lt;span class="no"&gt;BOOLEAN_ARRAY&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;BOOLEAN&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
    &lt;span class="c1"&gt;// dozens more array constants built from their component type&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each constant bundles three facts: the SQL type name, a cross-dialect semantic tag (&lt;code&gt;ArmyType&lt;/code&gt;), and a default Java class. That middle column is the trick: &lt;code&gt;MySQLType.BIGINT_UNSIGNED&lt;/code&gt; and &lt;code&gt;PgType.BIGINT&lt;/code&gt; are different database types, but &lt;code&gt;ArmyType&lt;/code&gt; lets framework code ask semantic questions — &lt;code&gt;isUnsigned()&lt;/code&gt;, &lt;code&gt;isTimeType()&lt;/code&gt;, &lt;code&gt;isDecimalType()&lt;/code&gt; — without knowing the dialect.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;MappingType&lt;/code&gt; answers "how does &lt;em&gt;Java&lt;/em&gt; talk to JDBC for this value?"&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;sealed&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;MappingType&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;TypeMeta&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;TypeInfer&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;TypeItem&lt;/span&gt;
        &lt;span class="n"&gt;permits&lt;/span&gt; &lt;span class="nc"&gt;AbstractMappingType&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;StructMappingType&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nc"&gt;Class&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;javaType&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="nc"&gt;DataType&lt;/span&gt; &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ServerMeta&lt;/span&gt; &lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;UnsupportedDialectException&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="nf"&gt;beforeBind&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;DataType&lt;/span&gt; &lt;span class="n"&gt;dataType&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;MappingEnv&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="nf"&gt;afterGet&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;DataType&lt;/span&gt; &lt;span class="n"&gt;dataType&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;MappingEnv&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Given a running server (&lt;code&gt;ServerMeta&lt;/code&gt;), &lt;code&gt;map&lt;/code&gt; resolves the actual &lt;code&gt;DataType&lt;/code&gt;; &lt;code&gt;beforeBind&lt;/code&gt; converts a Java object to what the JDBC driver expects, and &lt;code&gt;afterGet&lt;/code&gt; converts it back. Conversion behavior is therefore a property of the &lt;strong&gt;type&lt;/strong&gt;, not of a per-column annotation or a per-query call.&lt;/p&gt;

&lt;p&gt;The payoff is visible in the unsigned-integer handling, which I checked in source rather than taking the README's word for it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// TinyIntUnsignedType.java&lt;/span&gt;
&lt;span class="c1"&gt;/// This class representing the mapping from Short to (unsigned TINY) INT.&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Class&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;javaType&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Short&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;MySQL &lt;code&gt;TINYINT UNSIGNED&lt;/code&gt; ranges 0–255, which does not fit a Java &lt;code&gt;byte&lt;/code&gt; (-128–127), so Army maps it to &lt;code&gt;Short&lt;/code&gt;. &lt;code&gt;SMALLINT UNSIGNED&lt;/code&gt; → &lt;code&gt;Integer&lt;/code&gt;, &lt;code&gt;INT UNSIGNED&lt;/code&gt; → &lt;code&gt;Long&lt;/code&gt;, &lt;code&gt;BIGINT UNSIGNED&lt;/code&gt; → &lt;code&gt;BigInteger&lt;/code&gt; — the smallest type that cannot overflow, chosen for you. The dispatch table lives in &lt;code&gt;AbstractMappingType&lt;/code&gt; (&lt;code&gt;TINYINT_UNSIGNED → TinyIntUnsignedType&lt;/code&gt;, and so on). In a single-layer design this kind of range-aware choice ends up scattered across hand-written converters.&lt;/p&gt;

&lt;p&gt;The same mechanism makes enums work with zero ceremony: &lt;code&gt;CodeEnum&lt;/code&gt; (integer code), &lt;code&gt;LabelEnum&lt;/code&gt; (string label), and &lt;code&gt;NameEnum&lt;/code&gt; (Java name) are mapping types — no &lt;code&gt;@Enumerated&lt;/code&gt;, no &lt;code&gt;TypeHandler&lt;/code&gt; registration.&lt;/p&gt;




&lt;h2&gt;
  
  
  6. PostgreSQL Is a First-Class Citizen, Not a Setting on a Dialect Enum
&lt;/h2&gt;

&lt;p&gt;The dialect-neutral API gets you SELECT/INSERT/UPDATE/DELETE with joins, CTEs, windows, and predicates. But the PostgreSQL module exposes the &lt;em&gt;whole&lt;/em&gt; grammar. Browsing &lt;code&gt;Postgres.java&lt;/code&gt; is like reading a PostgreSQL keyword index:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;DoubleColon&lt;/span&gt; &lt;span class="no"&gt;DOUBLE_COLON&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PostgreWords&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SymbolDoubleColon&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;DOUBLE_COLON&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;SQLs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;DualOperator&lt;/span&gt; &lt;span class="no"&gt;DARROW&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DualExpOperator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;DARROW&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// -&amp;gt;&amp;gt;&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;SQLs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;DualOperator&lt;/span&gt; &lt;span class="no"&gt;BI_ARROW&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DualExpOperator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;BI_ARROW&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// -&amp;gt;&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;SQLs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;BiOperator&lt;/span&gt; &lt;span class="no"&gt;AT_GT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PgDualBoolOperator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;AT_GT&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;      &lt;span class="c1"&gt;// @&amp;gt;&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ExtractTimeField&lt;/span&gt; &lt;span class="no"&gt;TIMESTAMPTZ&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;...;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The example tests exercise features most Java SQL libraries don't reach at all. Recursive CTEs with SQL-standard &lt;code&gt;SEARCH BREADTH FIRST&lt;/code&gt; ordering (PostgreSQL 14+):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;stmt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Postgres&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withRecursive&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"cte"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;as&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sw&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;sw&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;select&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parentId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                                &lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;createTime&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;T&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;AS&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"t"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;in&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;SQLs:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;rowLiteral&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;extractRegionIdList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;regionList&lt;/span&gt;&lt;span class="o"&gt;)))&lt;/span&gt;
                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;union&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;select&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="cm"&gt;/* ... */&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;T&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;AS&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"t"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"cte"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;equal&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                                &lt;span class="nc"&gt;SQLs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;refField&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"cte"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PARENT_ID&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asQuery&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;search&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;breadthFirstBy&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ID&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;CREATE_TIME&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"orderCol"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;space&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;select&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;space&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"cte"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;PERIOD&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;ASTERISK&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"cte"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asQuery&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Server-side cursors via &lt;code&gt;DECLARE&lt;/code&gt;/&lt;code&gt;FETCH&lt;/code&gt; are a statement type, with the cursor surfaced as a &lt;code&gt;SyncStmtCursor&lt;/code&gt; from &lt;code&gt;ResultStates&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;stmt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Postgres&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;declareStmt&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;declare&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"my_china_region_cursor"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;cursor&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;forSpace&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;select&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"c"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;PERIOD&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;T&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;T&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;AS&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"c"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;in&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;SQLs:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;rowParam&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;extractRegionIdList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;regionList&lt;/span&gt;&lt;span class="o"&gt;)))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;orderBy&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;limit&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;SQLs:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;literal&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;regionList&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asQuery&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asCommand&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SyncStmtCursor&lt;/span&gt; &lt;span class="n"&gt;cursor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;states&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nonNullOf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SyncStmtCursor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SYNC_STMT_CURSOR&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;ChinaRegion&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="n"&gt;region&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChinaRegion_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;CLASS&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Domain inserts (parent/child tables in one statement), &lt;code&gt;RETURNING&lt;/code&gt; with generated keys, MERGE, and VALUES statements each have their own test class and clause interfaces.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ranges, arrays, JSONB, and vectors.&lt;/strong&gt; &lt;code&gt;PgType&lt;/code&gt; declares all six range and six multirange types, JSON/JSONB, UUID, geometric types, and arrays built compositionally (&lt;code&gt;BOOLEAN_ARRAY(BOOLEAN)&lt;/code&gt;, and the pattern extends to &lt;code&gt;INT4RANGE_ARRAY&lt;/code&gt;, &lt;code&gt;JSONB_ARRAY&lt;/code&gt;, ...). &lt;code&gt;MappingType.arrayTypeOfThis()&lt;/code&gt; means every scalar mapping knows how to construct its array counterpart — the 7.5k-line &lt;code&gt;army-array&lt;/code&gt; module is the systematic execution of that one method.&lt;/p&gt;

&lt;p&gt;For pgvector, &lt;code&gt;VectorType&lt;/code&gt; maps &lt;code&gt;float[]&lt;/code&gt; and documents both pgvector and MySQL 9.7's native vector type as targets, while the six distance operators are typed methods on &lt;code&gt;TypedField&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Expression&lt;/span&gt; &lt;span class="nf"&gt;spaceL2Distance&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BiFunction&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TypedField&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Expression&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;namedOperator&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;Expression&lt;/span&gt; &lt;span class="nf"&gt;spaceCosineDistance&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BiFunction&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TypedField&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Expression&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;namedOperator&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;Expression&lt;/span&gt; &lt;span class="nf"&gt;spaceHammingDistance&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BiFunction&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TypedField&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Expression&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;namedOperator&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;Expression&lt;/span&gt; &lt;span class="nf"&gt;spaceJaccardDistance&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BiFunction&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TypedField&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Expression&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;namedOperator&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(The &lt;code&gt;BiFunction&lt;/code&gt; style — passing &lt;code&gt;SQLs::param&lt;/code&gt; or &lt;code&gt;SQLs::literal&lt;/code&gt; to choose binding strategy — recurses through the whole API.)&lt;/p&gt;

&lt;p&gt;The MySQL side mirrors this with its own vocabulary. &lt;code&gt;MySQLs&lt;/code&gt; exposes the modifier keywords as constants (&lt;code&gt;DISTINCTROW&lt;/code&gt;, &lt;code&gt;HIGH_PRIORITY&lt;/code&gt;, &lt;code&gt;STRAIGHT_JOIN&lt;/code&gt;, &lt;code&gt;SQL_CALC_FOUND_ROWS&lt;/code&gt;, &lt;code&gt;LOW_PRIORITY&lt;/code&gt;, &lt;code&gt;DELAYED&lt;/code&gt;, &lt;code&gt;QUICK&lt;/code&gt;, &lt;code&gt;IGNORE&lt;/code&gt;), a dedicated &lt;code&gt;loadDataStmt()&lt;/code&gt; factory for &lt;code&gt;LOAD DATA INFILE&lt;/code&gt;, and multi-table UPDATE/DELETE grammars. Nothing here is simulated on a lowest-common-denominator AST.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dialect compatibility at the call site
&lt;/h3&gt;

&lt;p&gt;For portable code, there's a tiny SOURCE-retention annotation IDEs can surface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Target&lt;/span&gt;&lt;span class="o"&gt;({&lt;/span&gt;&lt;span class="nc"&gt;ElementType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;METHOD&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ElementType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;FIELD&lt;/span&gt;&lt;span class="o"&gt;})&lt;/span&gt;
&lt;span class="nd"&gt;@Retention&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RetentionPolicy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SOURCE&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nd"&gt;@interface&lt;/span&gt; &lt;span class="nc"&gt;Support&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Database&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="nf"&gt;value&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mark a pgvector expression &lt;code&gt;@Support(PostgreSQL)&lt;/code&gt; and the IDE tells you at the call site what database it requires.&lt;/p&gt;




&lt;h2&gt;
  
  
  7. Sessions: Plain Objects In, Plain Objects Out
&lt;/h2&gt;

&lt;p&gt;The session API deliberately keeps execution separate from statement construction. &lt;code&gt;Session&lt;/code&gt; is sealed (&lt;code&gt;permits LocalSession, RmSession, PackageSession&lt;/code&gt;); blocking code uses &lt;code&gt;SyncSession&lt;/code&gt; / &lt;code&gt;SyncLocalSession&lt;/code&gt; from &lt;code&gt;army-sync&lt;/code&gt;, which offers the result-mapping variants you'd expect:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;R&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;R&lt;/span&gt; &lt;span class="nf"&gt;queryOne&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SimpleDqlStatement&lt;/span&gt; &lt;span class="n"&gt;statement&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Class&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;R&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;resultClass&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;R&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;R&lt;/span&gt; &lt;span class="nf"&gt;queryOneObject&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SimpleDqlStatement&lt;/span&gt; &lt;span class="n"&gt;statement&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Supplier&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;R&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;constructor&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;R&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;R&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;queryObjectList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;DqlStatement&lt;/span&gt; &lt;span class="n"&gt;statement&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Supplier&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;R&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;constructor&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;R&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Stream&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;R&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;queryObject&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;DqlStatement&lt;/span&gt; &lt;span class="n"&gt;statement&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Supplier&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;R&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;constructor&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;R&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;R&lt;/span&gt; &lt;span class="nf"&gt;pagingObject&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PagingPair&lt;/span&gt; &lt;span class="n"&gt;pagingPair&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Supplier&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;constructor&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                      &lt;span class="nc"&gt;PageConstructor&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;R&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;pageConstructor&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three mapping modes, deliberately:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Class&amp;lt;R&amp;gt;&lt;/code&gt; — scalar/simple mapping;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Supplier&amp;lt;R&amp;gt;&lt;/code&gt; constructor reference — &lt;strong&gt;your POJO&lt;/strong&gt;, assembled reflectively through its constructor or accessors, then fully detached;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Function&amp;lt;CurrentRecord, R&amp;gt;&lt;/code&gt; — ad-hoc row mapping when the shape is local to the query (the example suite uses &lt;code&gt;RowMaps::hashMap&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Factory construction is a conventional builder, taken verbatim from the example test support:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;SyncSessionFactory&lt;/span&gt; &lt;span class="n"&gt;factory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SyncFactoryBuilder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mapDatabaseToFactoryName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;database&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;packagesToScan&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Collections&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;singletonList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"io.army.example.bank.domain"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;datasource&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;DataSourceUtils&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;createDataSource&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;database&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;createEnvironment&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;database&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;jsonCodec&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;FastJsonCodec&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getInstance&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fieldGeneratorFactory&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SimpleFieldGeneratorFactory&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note what is &lt;em&gt;not&lt;/em&gt; there: no transaction demarcation API in user code. Spring users get &lt;code&gt;ArmySyncLocalTransactionManager&lt;/code&gt; and &lt;code&gt;SpringSyncSessionContext&lt;/code&gt; from &lt;code&gt;army-spring&lt;/code&gt;, so &lt;code&gt;@Transactional&lt;/code&gt; works as usual — Army honors its own boundary ("transactions → use Spring or JTA") even inside its codebase. DDL generation exists as a parser capability (&lt;code&gt;schemaDdl(SchemaResult)&lt;/code&gt;), but migrations themselves are left to Flyway/Liquibase.&lt;/p&gt;

&lt;p&gt;The ecosystem modules extend the same philosophy upward: &lt;code&gt;army-spring-ai-vector-store&lt;/code&gt; implements Spring AI's &lt;code&gt;VectorStore&lt;/code&gt; over the JSONB + vector mapping types (&lt;code&gt;ArmyVectorStore&lt;/code&gt;, with a dedicated &lt;code&gt;PgVectorFilterExpressionConverter&lt;/code&gt; for metadata filters), and &lt;code&gt;army-spring-ai-model-chat-memory&lt;/code&gt; persists chat memory through criteria statements rather than raw JDBC.&lt;/p&gt;




&lt;h2&gt;
  
  
  8. What the Trade-offs Actually Are
&lt;/h2&gt;

&lt;p&gt;A deep-dive should be honest about costs, and Army has clear ones.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The interface surface is enormous.&lt;/strong&gt; Staged builders for the complete PostgreSQL &lt;em&gt;and&lt;/em&gt; MySQL grammars produce hundreds of &lt;code&gt;*Spec&lt;/code&gt; / &lt;code&gt;*Clause&lt;/code&gt; interfaces. That is inherent to encoding grammar legality in types, but the learning curve is real: you learn the method chain as much as the library. The project maintains extensive internal chain documentation (its &lt;code&gt;.trae/skills&lt;/code&gt; directory contains dozens of method-chain guides, e.g. &lt;code&gt;Postgres.singleDelete() → ... → asDelete()&lt;/code&gt;), which is both evidence of the depth and of how much depth there is to learn.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Java 25 is required.&lt;/strong&gt; &lt;code&gt;@SupportedSourceVersion(RELEASE_25)&lt;/code&gt;, &lt;code&gt;maven.compiler.source = 25&lt;/code&gt;. You cannot adopt this on a conservative LTS shop. (The code also uses a project convention worth knowing: types starting with &lt;code&gt;_&lt;/code&gt; are framework-private — &lt;code&gt;_SelectContext&lt;/code&gt;, &lt;code&gt;_ArmyNoInjectionType&lt;/code&gt; — and user code should never depend on them.)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Version and maturity.&lt;/strong&gt; &lt;code&gt;0.6.8-SNAPSHOT&lt;/code&gt;, with &lt;code&gt;0.6.7&lt;/code&gt; the Maven Central release. Oracle and SQLite modules are thin (a few hundred lines) compared with PostgreSQL/MySQL, and the reactive layer is mid-evolution (the example factory contains a commented-out &lt;code&gt;ReactiveFactoryBuilder&lt;/code&gt; path driven by an external &lt;code&gt;io.jdbd&lt;/code&gt; driver SPI). This is an ambitious single-maintainer project, not a foundation-governed one — evaluate accordingly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Philosophical.&lt;/strong&gt; If your objection to ORMs is that they hide SQL, Army may feel like &lt;em&gt;more&lt;/em&gt; machinery than writing SQL, not less — you must learn its vocabulary (&lt;code&gt;PERIOD&lt;/code&gt;, &lt;code&gt;space()&lt;/code&gt;, &lt;code&gt;comma()&lt;/code&gt;, &lt;code&gt;SQLs::param&lt;/code&gt; vs &lt;code&gt;SQLs::literal&lt;/code&gt;, ref-field helpers) to express what &lt;code&gt;sql/&lt;/code&gt; files give you directly. The bet is that the compile-time checking, dialect awareness, and composability repay that vocabulary.&lt;/p&gt;




&lt;h2&gt;
  
  
  Verdict
&lt;/h2&gt;

&lt;p&gt;Army is one of the most thorough attempts I've seen to answer a specific question: &lt;strong&gt;what would a Java SQL API look like if dialect fidelity, rather than portability, were the primary design goal?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Its answers are internally consistent and visible in code rather than just claimed in docs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;grammar legality encoded as staged builder interfaces, with terminal methods producing sealed statements;&lt;/li&gt;
&lt;li&gt;a &lt;code&gt;DataType&lt;/code&gt;/&lt;code&gt;MappingType&lt;/code&gt; split that separates "what the database is" from "how Java binds it," which makes unsigned integers, enums, arrays, JSONB, ranges, and vectors systematic instead of ad hoc;&lt;/li&gt;
&lt;li&gt;an annotation-processed metamodel so field references are compiler-checked symbols;&lt;/li&gt;
&lt;li&gt;a sealed &lt;code&gt;DialectParser&lt;/code&gt; SPI with explicit dialect-only escape hatches;&lt;/li&gt;
&lt;li&gt;and a disciplined refusal to become an ORM — connections, transactions, caching, and migrations stay in the surrounding ecosystem.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you are on modern Java, work heavily in PostgreSQL or MySQL, regularly use features JPA pretends don't exist (&lt;code&gt;RETURNING&lt;/code&gt;, multi-table deletes, range types, &lt;code&gt;LOAD DATA&lt;/code&gt;, server-side cursors, vector search), and still want compile-time checking and plain POJO results, Army is worth an afternoon with the example module. The bar for "fluent SQL in Java" is high mostly because jOOQ exists — but nobody is going to confuse the two after seeing a &lt;code&gt;withRecursive(...).search(breadthFirstBy(...))&lt;/code&gt; chain that compiles.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Source, specification, and runnable examples: &lt;a href="https://github.com/PillArmy/army" rel="noopener noreferrer"&gt;https://github.com/PillArmy/army&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Maven: &lt;code&gt;io.qinarmy:army-jdbc&lt;/code&gt; + &lt;code&gt;io.qinarmy:army-postgre&lt;/code&gt; (or &lt;code&gt;army-mysql&lt;/code&gt;). Start with the &lt;code&gt;army-example&lt;/code&gt; test suite — it is the most accurate documentation in the repository.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>database</category>
      <category>java</category>
      <category>opensource</category>
      <category>sql</category>
    </item>
  </channel>
</rss>
