<?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>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>
