Addax 6.1.0
Addax 6.1.0 is a correction release: 32 engine / shared-library / plugin defects fixed since 6.0.13, several of them closing paths that corrupted or dropped data silently, plus a new end-to-end test suite. It also removes the datareader plugin and changes how binary and bit columns are read and written — read the migration notes before upgrading.
The version is 6.1.0 rather than 6.0.14 on purpose: this release contains a new feature and three backward-incompatible changes, which is a minor bump under the versioning scheme.
⚠️ Breaking changes
1. datareader is removed — use streamreader (#1556)
datareader was a copy of streamreader that re-implemented the column model to layer its own data rules on top, and the two copies had drifted apart. The rule item is now the canonical way to configure a column, and the 16 built-in rules of datareader (address, bank, company, creditCard, debitCard, email, idCard, job, lat, lng, name, phone, stockAccount, stockCode, uuid, zipCode) are implemented as generators behind a new Generated rule, so {"rule": "random", "value": "1,10", "type": "long"} and {"random": "1,10"} describe the same column.
- Migration: rename
"name": "datareader"to"name": "streamreader"in the job. The column configuration needs no change. - A column that mixes a
rulewith the legacyrandom/incritems now ignores those items with a warning, and atypethat contradicts the rule fails the job at startup. - A date format that uses the 12-hour field
hhwithout an AM/PM marker now fails at startup instead of silently generating midnight — useHH. - Datareader defects fixed on the way: the reversed range that made
zipCodethrow on every record, theidCardgender digit (always female, written to the 15th instead of the 17th position), the date increment unit truncated to its first character ("month"incremented minutes), and the NPE of anincrrule without atype.
2. Binary columns are base64 in text output, and oversized records now fail (#1568)
- Text output (
txtfilewriter,hdfswriterdelimited and SQL paths) renders a BINARY/BYTES column as base64. It used to decode it as UTF-8, so a 100KB payload came out with 51,200 U+FFFD, and its embedded0x0Abytes split one record into 404 physical lines. Consumers of those files must base64-decode such columns now. - A record larger than
core.transport.channel.byteCapacity(64MB by default, held per queued record) used to be dropped by both exchangers while the job still reported success. It now raisesOVER_LIMIT_ERROR, naming the record size, the limit and the option that raises it — raisecore.transport.channel.byteCapacityif the job legitimately carries records that large. - Dirty-record logging no longer scales with the size of a binary value: a dropped 9.2MB BLOB produced a 33,624,344-character log line, now 239 characters.
3. bit columns are handled consistently in every reader and writer (#1591)
bit(1)stays a boolean andbit varyingstays a string;bit(n>1)round-trips exactly at any width up tobit(64).- Reading a PostgreSQL
bit(n>1)column now yields packed bytes instead of the ASCII text of the bit string. A job that fed that column to a text sink sees the packed value; select it asvarcharorintinquerySqlto keep the previous rendering. - Fixed the MySQL writer parsing packed bytes as a base-2 literal (silently turning 48 into 0, and aborting the task with
NumberFormatExceptionbelow that) and the PostgreSQL writer re-encoding 8 bits per byte (so abit(3)copy never fitted its own column).
🐛 Fixes
Data correctness
- SQL exports write a real
NULLfor null values instead of the quoted literal'null'(#1518). fileFormat=sqlexports with at leastbatchSize(default 2048) rows no longer truncate the batch — every row is emitted (#1517).hdfsreadersequence-file rows keep empty fields, mapping to the same columns asfileType=text(#1521).hdfswriter: pre-1970 timestamps no longer write a negative nanos-of-day into INT96, DATE lands on the correct calendar day east of UTC and agrees between ORC and parquet, two ARRAY columns of different element types no longer die withClassCastException, and TIME matches every other rendering of the same value (#1533).hdfswriterwrites LZ4 parquet files asLZ4_RAW(#1538). Readers built on parquet-mr older than 1.12 — Hive 3.1.x, for instance — cannot decode codec 7, so jobs feeding such consumers need another codec.- TIME/TIMESTAMP(6) keep sub-second precision on both TIME and TIMESTAMP targets (#1509).
- Strings out of range for a BIGINT target are rejected instead of silently wrapped (#1508).
oraclewriterbinds LOBs directly ininsertmode instead of spending a round trip per value through a temporary LOB, and only falls back above the MERGE template limit (#1565, #1567).clickhousewriterkeeps its synchronous insert semantics with clickhouse-jdbc 0.10 (#1585).
Splitting and query building (lib-rdbms)
- A user
whereclause is parenthesized in split queries (#1499); NULL split keys are counted in the same min/max scan (#1500); string split keys are escaped when building range SQL (#1501); split-point arithmetic is overflow-safe (#1502). - The auto primary-key probe SQL is repaired for Sybase and ClickHouse (#1503); TDengine is detected from driver metadata rather than class-name equality (#1511).
Stability and performance
- Connection pools get sane defaults, a borrow timeout and socket/query timeouts; an exhausted pool now fails with a clear timeout error instead of hanging (#1510).
- Connections are returned to the pool after wildcard column expansion (#1512).
doriswriterreuses pooled connections and fixes the flush lifecycle: one unhealthy load host no longer fails the task, and a hung connection times out.batchSizekeeps its meaning and 2048 default (#1552).- Core: fail-fast scheduling, corrected channel wait metrics and job lifecycle repairs (#1496); lock-free statistics, cached record constructors and precompiled regexes (#1497); JDK 17 modernization (#1498).
lib-storage: compress modes are validated at writer startup (#1529, #1530), gzip/bz2 aliases are accepted on read with locale-safe name folding (#1520), an immutable date formatter replacesSimpleDateFormat(#1524), and sequence-file column configuration is parsed once per file rather than per record (#1526).hdfsreaderdelegates its configuration validation to the shared storage utilities (#1527), andhdfswriterresolves its column plan once per task (#1535).
Scripts and packaging
install.shreads prompts from the terminal, socurl -fsSL … | bashworks (#1554); deploys create missing remote directories (#1553);build-module.shbase paths and CLI options are repaired.
🧪 Testing
A new end-to-end suite (e2e/) assembles the real distribution, starts throwaway MySQL and PostgreSQL instances and asserts the result of every job under e2e/cases/ — 18 cases covering RDBMS round trips, upserts, text/CSV, HDFS text/parquet/ORC, datetime and timezone handling, and bit columns in both directions.
⚠️ Known issues
txtfilewriterwithwriteMode=appendfails when the target file already exists:prepare()keeps the existing files, andTask.startWrite()then requirescreateNewFile()to succeed — which returns false exactly in that case. This is a pre-existing defect, present in 6.0.13 as well; the E2E case110_mysql2txt_appendasserts it and reportsXFAIL. The fix is planned for 6.1.1.
📦 Dependencies
39 dependency updates, including clickhouse-jdbc 0.9.8 → 0.10.0, kudu-client 1.16.0 → 1.18.1, ngdbc 2.24.8 → 2.28.8, jackson 2.20.1 → 2.22.2, fastjson2 2.0.60 → 2.0.65, commons-io 2.19.0 → 2.22.0, netty 4.2.18, and a move to the maintained io.github.spannm fork of ucanaccess.
⬆️ Upgrading
- Distribution:
addax-6.1.0.tar.gzandaddax-6.1.0.tar.gz.sha256sum.asc— check the checksum before unpacking. - Docker:
wgzhao/addax:6.1.0(Docker Hub) andquay.io/wgzhao/addax:6.1.0. - Maven Central:
com.wgzhao.addax:addax-core:6.1.0. - Check first if your jobs use
datareader, send binary columns to a text sink, read PostgreSQLbit(n>1)columns, or carry records above 64MB. - Plugin documentation: https://github.com/wgzhao/addax-docs
Addax 6.1.0(中文版)
Addax 6.1.0 是一个修复版本:自 6.0.13 以来修掉了 32 个引擎 / 公共库 / 插件缺陷,其中多个是静默写坏或丢弃数据的问题,同时新增了端到端测试套件。本版本还删除了 datareader 插件,并改变了 binary 列与 bit 列的读写方式,升级前请先看下面的迁移说明。
版本号定为 6.1.0 而不是 6.0.14 是有意的:本版本包含新特性与三处不兼容变更,按版本命名规范应走小版本号。
⚠️ 破坏性变更
1. datareader 插件已删除,改用 streamreader (#1556)
datareader 是 streamreader 的副本,它重新实现了一套列模型来叠加自己的数据规则,两个副本已经各自漂移。现在列配置以 rule 项为准,datareader 的 16 条内置规则(address、bank、company、creditCard、debitCard、email、idCard、job、lat、lng、name、phone、stockAccount、stockCode、uuid、zipCode)通过新的 Generated 规则实现,因此 {"rule": "random", "value": "1,10", "type": "long"} 与 {"random": "1,10"} 描述的是同一个列。
- 迁移方式: 把作业里的
"name": "datareader"改成"name": "streamreader",列配置无需改动。 - 同一列里混用
rule和旧的random/incr项时,旧项会被忽略并给出警告;与 rule 冲突的type会在启动时直接失败。 - 日期格式使用 12 小时制
hh且没有 AM/PM 标记时,现在启动即失败(以前会静默生成午夜),请改用HH。 - 顺带修掉的原 datareader 缺陷:
zipCode的反向区间导致每条记录都抛异常、idCard性别位恒定女性且写在第 15 位而非第 17 位、日期增量单位被截断成首字母("month"实际按分钟递增)、无type的incr规则 NPE。
2. binary 列在文本输出中改为 base64,超限记录不再被静默丢弃 (#1568)
- 文本输出(
txtfilewriter、hdfswriter的分隔符与 SQL 路径)现在把 BINARY/BYTES 列渲染为 base64。此前按 UTF-8 解码,100KB 的载荷会变成 51,200 个 U+FFFD,载荷里内嵌的0x0A还会把一条记录拆成 404 行。消费这些文件的作业现在需要对这些列做 base64 解码。 - 超过
core.transport.channel.byteCapacity(默认 64MB,按排队记录占用)的记录,此前会被两个 exchanger 直接丢弃而作业仍报成功;现在会抛出OVER_LIMIT_ERROR,并给出记录大小、上限值以及可调整的选项——如果作业确实携带这么大的记录,请调大core.transport.channel.byteCapacity。 - 脏记录日志不再随二进制值的大小膨胀:一个被丢弃的 9.2MB BLOB 曾产生 33,624,344 字符的日志行,现在是 239 字符。
3. bit 列在所有读写插件中行为一致 (#1591)
bit(1)仍是 boolean,bit varying仍是字符串;bit(n>1)在bit(64)以内的任意宽度都能精确往返。- PostgreSQL 的
bit(n>1)列现在读出的是 packed bytes,不再是位串的 ASCII 文本。 如果这个列此前喂给了文本 sink,看到的就是 packed 值;可以在querySql里用varchar或int取出以保留原有渲染。 - 修掉了 MySQL writer 把 packed 字节按二进制字面量解析(值 48 被静默解析为 0,更小的值直接
NumberFormatException中断任务)和 PostgreSQL writer 按 8 位一字节重新编码(导致bit(3)的数据装不进自己的列)的问题。
🐛 修复
数据正确性
- SQL 导出中的 null 值写出真正的
NULL,不再是带引号的字面量'null'(#1518)。 fileFormat=sql且行数达到batchSize(默认 2048)时不再截断批次,每一行都会输出 (#1517)。hdfsreader读取 sequence file 时保留空字段,列位置与fileType=text一致 (#1521)。hdfswriter:1970 年以前的时间戳不再向 INT96 写入负的当日纳秒数;UTC 以东时 DATE 落在正确的日历日,ORC 与 parquet 结果一致;两个元素类型不同的 ARRAY 列不再抛ClassCastException;TIME 与同一值的其他渲染方式一致 (#1533)。hdfswriter的 LZ4 parquet 文件改写为LZ4_RAW(#1538)。parquet-mr 1.12 之前的读取端(例如 Hive 3.1.x)无法解码 codec 7,若下游是这类消费者请改用其他压缩方式。- TIME/TIMESTAMP(6) 在 TIME 与 TIMESTAMP 目标上都保留亚秒精度 (#1509)。
- 超出 BIGINT 目标范围的字符串会被拒绝,不再静默回绕 (#1508)。
oraclewriter在insert模式下直接绑定 LOB,不再为每个值走一次临时 LOB 的往返;仅在超过 MERGE 模板上限时才回退 (#1565、#1567)。clickhousewriter在 clickhouse-jdbc 0.10 下保持同步写入语义 (#1585)。
切分与 SQL 构造(lib-rdbms)
- 切分查询中用户
where条件加括号 (#1499);NULL 切分键计入同一次 min/max 扫描 (#1500);字符串切分键在构造范围 SQL 时转义 (#1501);切分点计算避免溢出 (#1502)。 - 修复 Sybase 与 ClickHouse 的自增主键探测 SQL (#1503);TDengine 改为按驱动元数据识别,不再比较类名 (#1511)。
稳定性与性能
- 连接池有了合理的默认值、借用超时以及 socket/查询超时;连接池耗尽时会以明确的超时错误失败,不再挂死 (#1510)。
- 通配符展开列之后连接会归还连接池 (#1512)。
doriswriter复用池化连接并修复 flush 生命周期:单个 load 主机不可用不再导致任务失败,连接挂起会超时。batchSize的语义与 2048 默认值保持不变 (#1552)。- core:调度快速失败、修正 channel 等待指标、修复作业生命周期 (#1496);无锁统计、缓存 Record 构造器、预编译正则 (#1497);JDK 17 现代化 (#1498)。
lib-storage:writer 启动时校验 compress 取值 (#1529、#1530);读取时接受 gzip/bz2 别名,压缩名大小写折叠不受 locale 影响 (#1520);用不可变日期格式化器替换SimpleDateFormat(#1524);sequence file 的列配置按文件解析一次,不再按记录解析 (#1526)。hdfsreader把配置校验交给公共 storage 工具 (#1527);hdfswriter每个 task 只解析一次列计划 (#1535)。
脚本与打包
install.sh从终端读取交互输入,curl -fsSL … | bash可以正常使用 (#1554);部署时会创建缺失的远端目录 (#1553);修复build-module.sh的基础路径与命令行选项。
🧪 测试
新增端到端测试套件(e2e/):构建真实的发行包,拉起一次性的 MySQL 与 PostgreSQL 实例,对 e2e/cases/ 下的每个作业断言结果——共 18 个用例,覆盖 RDBMS 往返、upsert、文本/CSV、HDFS text/parquet/ORC、日期时间与时区,以及双向的 bit 列。
⚠️ 已知问题
txtfilewriter在writeMode=append且目标文件已存在时必然失败:prepare()会保留已存在的文件,随后startWrite()又要求createNewFile()成功,而该调用在这时恰好返回 false。这是既有缺陷,6.0.13 同样存在,已由 E2E 用例110_mysql2txt_append断言并标记为XFAIL,计划在 6.1.1 修复。
📦 依赖升级
共 39 项依赖升级,包括 clickhouse-jdbc 0.9.8 → 0.10.0、kudu-client 1.16.0 → 1.18.1、ngdbc 2.24.8 → 2.28.8、jackson 2.20.1 → 2.22.2、fastjson2 2.0.60 → 2.0.65、commons-io 2.19.0 → 2.22.0、netty 4.2.18,并切换到仍在维护的 io.github.spannm ucanaccess 分支。
⬆️ 升级方式
- 发行包:
addax-6.1.0.tar.gz与addax-6.1.0.tar.gz.sha256sum.asc,解压前请校验校验和。 - Docker:
wgzhao/addax:6.1.0(Docker Hub)与quay.io/wgzhao/addax:6.1.0。 - Maven Central:
com.wgzhao.addax:addax-core:6.1.0。 - 升级前请先确认作业是否用到:
datareader插件、把 binary 列写入文本 sink、读取 PostgreSQLbit(n>1)列,或存在超过 64MB 的记录。 - 插件文档:https://github.com/wgzhao/addax-docs
📜 Full changelog (6.0.13 → 6.1.0)
- 294a6d5 [maven-release-plugin] prepare release 6.1.0
- 68f07e8 fix(ci): let maven-release-plugin commits through the header lint
- 4e54844 docs(release): point the release example at 6.1.0
- 424b773 docs(release): add the 6.1.0 release notes
- 36dc115 chore(deps): bump com.fasterxml.woodstox:woodstox-core (#1594)
- 4be69d7 chore(deps): bump ognl:ognl from 3.4.12 to 3.4.13 (#1593)
- 0ab3c3c chore(deps): bump io.github.spannm:ucanaccess from 5.1.7 to 5.1.8 (#1592)
- 3e8078b fix(lib-rdbms)!: make bit columns exact in every reader and writer (#1591)
- c80bc9c ci(github-actions): add plugin E2E suite
- 7dbf427 chore(deps): bump com.github.luben:zstd-jni from 1.5.7-15 to 1.5.7-16 (#1589)
- 0ce7574 chore(deps): bump com.sap.cloud.db.jdbc:ngdbc from 2.24.8 to 2.28.8 (#1588)
- 6eaed5c chore(deps): bump commons-codec:commons-codec from 1.22.0 to 1.22.1 (#1587)
- e04c6e6 chore(deps): bump com.alibaba.fastjson2:fastjson2 from 2.0.60 to 2.0.65 (#1586)
- 8e02fff chore(deps): bump com.clickhouse:clickhouse-jdbc from 0.9.8 to 0.10.0 (#1582)
- b0bd2cd fix(lib-rdbms): keep ClickHouse writer inserts synchronous (#1585)
- cad25ab chore(deps): bump org.apache.commons:commons-text from 1.13.1 to 1.15.0 (#1583)
- c2c2b64 chore(deps): bump commons-net:commons-net from 3.11.1 to 3.13.0 (#1580)
- 407d834 chore(deps): bump org.tukaani:xz from 1.10 to 1.12 (#1584)
- 2165703 ci(dependabot): stop proposing cassandra-driver-core 4.x (#1579)
- 1a73b55 chore(deps): bump netty.version from 4.2.17.Final to 4.2.18.Final (#1578)
- 049ede9 chore(deps): bump org.fusesource.jansi:jansi from 2.4.2 to 2.4.3 (#1576)
- 6b609a8 chore(deps): bump commons-logging:commons-logging from 1.3.5 to 1.4.0 (#1575)
- 5fc932c chore(deps): bump ognl:ognl from 3.4.7 to 3.4.12 (#1574)
- bf65dd8 chore(deps): bump joda-time:joda-time from 2.14.2 to 2.14.3 (#1572)
- 1e00b26 chore(deps-dev): bump org.sonatype.central:central-publishing-maven-plugin (#1571)
- 0fe989b chore(deps): bump com.google.code.gson:gson from 2.13.2 to 2.14.0 (#1570)
- 0562517 chore(deps): bump org.apache.commons:commons-configuration2 (#1569)
- 18433d1 fix(core)!: stop losing binary columns and oversized records silently (#1568)
- fc8c6e6 chore(git): ignore local Claude Code settings
- 2631ec1 docs(agents): extract git and PR workflow into a shared skill
- 7fd6124 fix(plugin-oraclewriter): bind LOBs directly except above the merge template limit (#1567)
- b77a1de fix(plugin-oraclewriter): bind small LOBs inline instead of through a temporary LOB (#1565)
- 451a1a2 chore(build): drop the stale plexus-compiler-javac pin
- 5156ccd chore(deps-dev): bump org.apache.maven.plugins:maven-dependency-plugin (#1558)
- 07dff1e chore(deps): bump com.databend:databend-jdbc from 0.4.6 to 0.4.8 (#1559)
- a039b16 chore(deps): bump org.apache.kudu:kudu-client from 1.16.0 to 1.18.1 (#1560)
- 5abb0dc chore(deps): bump actions/setup-java from 6.0.0 to 6.0.1 (#1561)
- afbadd1 chore(deps-dev): bump org.apache.maven.plugins:maven-compiler-plugin (#1562)
- b5144cc chore(deps): bump org.slf4j:log4j-over-slf4j from 2.0.18 to 2.0.19 (#1563)
- 1a33afc chore(deps): bump github/codeql-action from 4.37.9 to 4.38.0 (#1564)
- 4624d18 fix(deps): clear the open Dependabot alerts by upgrading five dependencies
- b7895fb feat(plugin-streamreader)!: merge the data rules of datareader into streamreader (#1556)
- f3e7cb8 fix(plugin-streamreader): drop the shared increment state and rework the column model (#1555)
- 150185e fix(script): read installer prompts from the terminal so curl | bash works (#1554)
- 1481bad fix(script): create missing remote directories during deploy (#1553)
- e3a3e44 perf(plugin-doriswriter): reuse pooled connections and fix the flush lifecycle (#1552)
- a7b4084 chore(deps): bump commons-io:commons-io from 2.19.0 to 2.22.0 (#1549)
- 7c1fdf1 chore(deps-dev): bump org.apache.maven.plugins:maven-site-plugin (#1548)
- 1963c30 chore(deps): bump jackson.version from 2.20.1 to 2.22.2 (#1547)
- 83ffb8e chore(deps-dev): bump com.github.spotbugs:spotbugs-maven-plugin (#1546)
- e74cb87 chore(deps): hold the Arrow and Paimon bumps dependabot keeps proposing (#1545)
- ba6096b chore(deps): bump org.apache.commons:commons-exec from 1.5.0 to 1.6.0 (#1542)
- c683ced chore(deps-dev): bump org.apache.maven.plugins:maven-javadoc-plugin (#1543)
- 0274d81 chore(deps): bump org.yaml:snakeyaml from 2.6 to 2.7 (#1544)
- cc1b6ca chore(deps): ignore flight-sql-jdbc-core 19.x in dependabot
- 92f6e92 chore(deps): bump maven-enforcer-plugin from 3.6.1 to 3.6.3
- 26f92cd chore(deps): bump commons-lang3 from 3.18.0 to 3.20.0
- 70c070f chore(deps): bump jsch from 2.27.5 to 2.28.7
- deb4741 fix(plugin-hdfswriter): write LZ4 parquet files as LZ4_RAW (#1538)
- e49f211 fix(ci): lint the actual PR commits and ignore GitHub's squash suffix (#1537)
- 7d7194b chore(dep): bump github/codeql-action from 4.37.8 to 4.37.9 (#1495)
- 3bf68bf chore(deps): switch ucanaccess to the maintained io.github.spannm fork (#1532)
- 0f6248a refactor(plugin-hdfswriter): drop dead code and share the day-fraction constants (#1536)
- 96c54ee perf(plugin-hdfswriter): resolve the column plan once per task (#1535)
- 3522a75 fix(plugin-hdfswriter): harden failure paths, type handling and parameters (#1534)
- c559446 fix(plugin-hdfswriter): correct timestamp, date and collection encoding (#1533)
- c02e56e fix(plugin-hdfswriter): add lz4-java dependency so LZ4 codec works (#1531)
- 88fecb0 fix(lib-storage): scope compress validation to commons-compress writers (#1530)
- e8faff8 fix(lib-storage): read and write newline fieldDelimiter without commons-csv (#1528)
- 0496485 fix(lib-storage): reject unsupported compress modes during writer validation (#1529)
- 0999a43 refactor(plugin-hdfsreader): delegate plugin config validation to shared storage utils (#1527)
- 91cb090 perf(lib-storage): parse sequence-file column config once per file, not per record (#1526)
- 5849de9 refactor(lib-storage): replace SimpleDateFormat with a shared immutable formatter (#1524)
- 581a456 refactor(lib-storage): decode local files with one open and single-source wildcard normalization (#1523)
- b969d57 chore(ci): relax commit subject case and dot rules (#1525)
- 7a5d9c6 refactor(lib-storage): delete dead helper and narrow the public API surface (#1522)
- 3272319 fix(lib-storage): keep empty fields when splitting per-line records (#1521)
- 4cc383a fix(lib-storage): accept gzip/bz2 aliases on read and case-fold compress names safely (#1520)
- b5de8a3 fix(lib-storage): guard null fields in the untyped column branch (#1519)
- 5e5a308 fix(lib-storage): emit SQL NULL instead of the quoted literal 'null' (#1518)
- bdd3099 fix(lib-storage): repair writeToSql batch flush truncation and restore column-count guard (#1517)
- 3f9c744 docs(readme) update star history embeded code
- 958ae0f fix(script): repair build-module.sh base paths and CLI options
- d90c874 fix(lib-rdbms): probe localtime support instead of trusting time scale metadata (#1515)
- b7f479f fix(lib-rdbms): align merge key matching between template and record partition (#1506)
- 491c739 chore(lib-rdbms): remove dead code and misleading comments (#1514)
- 4562af9 perf(lib-rdbms): precompute binding metadata and reuse the batch statement (#1507)
- e42d8c7 refactor(lib-rdbms): scope writer task and pretreatment state per instance (#1513)
- 5582bf6 fix(lib-rdbms): return connection to the pool after wildcard column expansion (#1512)
- d687a92 fix(lib-rdbms): detect tdengine by driver metadata, not class-name equality (#1511)
- 55e1183 fix(lib-rdbms): sane connection pool, borrow timeout and timeouts (#1510)
- b303541 fix(lib-rdbms): preserve sub-second precision for time and timestamp targets (#1509)
- 948111d fix(lib-rdbms): reject out-of-range strings bound to bigint targets (#1508)
- c742b98 refactor(lib-rdbms): cache column metadata and fix null handling in row conversion (#1505)
- c9df922 fix(lib-rdbms): stop forwarding null records after dirty collection (#1504)
- 13f09fb fix(lib-rdbms): repair auto pk probe sql for sybase and clickhouse (#1503)
- cba7b81 fix(lib-rdbms): compute split points overflow-safe (#1502)
- c0dffc4 fix(lib-rdbms): escape string split keys when building range sql (#1501)
- cae197f fix(lib-rdbms): count null split keys in the same min/max scan (#1500)
- 7f3c4a2 fix(lib-rdbms): parenthesize user where clause in split queries (#1499)
- bf27f8f refactor(core): JDK 17 modernization of the core module (#1498)
- ced80e3 perf(core): lock-free statistics, cached record constructors and precompiled regexes (#1497)
- 04ca0cb fix(core): fail-fast scheduling, channel wait metrics and job lifecycle repairs (#1496)
- 1f31efb docs(javadoc): add missing comments for public APIs across modules
- 298c46a docs(release): add verified release workflow and CI failure troubleshooting
- de610c2 fix(ci): export both passphrase env names for the deploy step
- 46855ac fix(ci): point the deploy command at the generated settings file
- 808fe9a fix(ci): export ossrh credentials env in the deploy step
- e6ab570 fix(ci): export passphrase env for gpg signing in publish workflow
- 80e691f fix(build): bump maven-gpg-plugin for setup-java v6 GPG handling
- 3d0ad83 [maven-release-plugin] prepare for next development iteration