Skip to content

EN Mapping and Backend Limits

Alan Zhang edited this page Oct 7, 2026 · 7 revisions

Home · GitHub

English | 简体中文

2.1.3 is published through the GitHub source/tag and Maven Central; same-SHA CI and public artifact verification passed. Current coordinates: 2.1.3; see 2.1.3 release notes.

2.1.3 corrections

Version 2.1.3 tightens structured-filter validation, merges IoTDB physical table-name case variants before whole-batch checks, verifies backend registration in tests/CI, rejects duplicate IoTDB/InfluxDB 3 result keys, and checks direct-adapter batch counts before copying inputs. The public API, Template → SPI → adapter architecture, Java 17/client/server baselines and configuration defaults remain unchanged. 2.1.3 release notes.

Early application-batch count in 2.1.3

All four built-in adapters check the reported input count before copying a nonempty collection and recheck the snapshot after copying. This protects direct adapter callers as well as the existing TGTemplate path. An obviously oversized reported count is rejected before record traversal or database I/O with ARGUMENT_ERROR, NOT_COMMITTED and zero confirmed writes. Existing state and null/empty checks retain their behavior and precedence.

Each backend’s existing max-batch-records remains the application-record limit, with the unchanged default of 10000: tsdb.iotdb.max-batch-records, tsdb.influxdb.max-batch-records, tsdb.influxdb1.max-batch-records and tsdb.opengemini.max-batch-records. Physical HTTP request or Tablet limits remain separate. This correction adds no byte/column budget and cannot bound total allocation performed by an arbitrary custom Collection; it is an early count check, not a hard JVM memory cap. See 2.1.3 release notes for release scope and validation status.

IoTDB writes validate each measurement name and then group records by its Locale.ROOT lowercase physical table identity: Metrics, metrics and METRICS all use metrics. Released 2.1.2 grouped by the original spelling, which could separate records for the same physical table and bypass cross-record column role/type checks. Version 2.1.3 applies those checks to the complete merged physical table before any session is borrowed: conflicts reject the whole application batch with METADATA_ERROR, NOT_COMMITTED, zero confirmed records/Tablets and no database I/O, including otherwise valid records for other tables.

Compatible variants retain their row order within the physical table and share Tablet splitting under the existing tablet-max-row-size. Physical batch counts reflect the actual Tablets after merging; requested and confirmed record counts still refer to input records. Caller TSDBRecord measurement names, tag/field map keys, values and nulls are not rewritten. A failure that identifies an attempted table reports its lowercase physical name in failedMeasurement; preflight or acquisition failures without an identified Tablet may still report null. This does not add a transaction or server-schema preflight and does not change the case behavior of InfluxDB 1.x, InfluxDB 3 or openGemini.

Returned result names in 2.1.3

Before constructing row maps, IoTDB rejects exact duplicate names in the SDK’s output-column list with QUERY_ERROR, even when the result contains no rows. InfluxDB 3’s successful-response JSON parser rejects duplicate keys within one object rather than allowing a later value to overwrite an earlier value. A duplicate in any returned row fails the entire operation. The same guarded paths serve common queries, counts and adapter-native executeQuery results.

For example, IoTDB output columns ["value", "value"] and an InfluxDB 3 response [{"value":null,"value":2}] are rejected. Distinct names such as value and Value, repeated names across separate JSON row objects, legitimate nulls and existing numeric precision behavior remain valid. POJO exact-match priority, case-insensitive fallback and missing-column/default-value behavior are unchanged; this correction does not add strict DTO mapping.

InfluxDB 1.x/openGemini retain their existing duplicate columns and tag/field collision checks. Those checks are not a guarantee that every arbitrary JSON metadata key is rejected on duplication. Borrowed native clients keep their own SDK result handling. See 2.1.3 release notes for release scope and validation status.

Result integrity changes in 2.1.2

Aggregate result names are preflighted using the backend's physical column identity: generated window_start (only when emitted), grouping tags and aliases must be unique. Collisions fail with ARGUMENT_ERROR before I/O in query and count, including template execution. Influx identifiers retain distinct case; IoTDB folds to lowercase. See aggregate output names.

InfluxDB 3 JSON reads reject an absent or whitespace-only HTTP body with QUERY_ERROR. A real JSON [] remains a successful empty result; a missing response must not masquerade as one. Existing malformed JSON, row and decompressed byte budgets remain in force.

Default POJO reads now reuse class-lifecycle read plans for constructors, inherited fields, destination types and column candidates. Plans are separate from write metadata, so unannotated DTOs still work. Exact/annotated/loose lookup priority, explicit null handling, numeric/time conversion and missing-column behavior remain unchanged. The cache retains class-owned reflection metadata, not result rows or application instances, and does not impose a new public mapper API. No throughput claim is made without a benchmark.

InfluxDB 1.x and OpenGemini aggregate responses also include the implicit physical time column, so an exact aggregate alias or grouping tag named time is rejected before I/O. Case-distinct Time remains available. This protocol-specific reservation does not add a reserved time alias to IoTDB or InfluxDB 3.

Backend capabilities and boundaries

Capability IoTDB table model InfluxDB 3 Core InfluxDB OSS 1.x openGemini default engine
POJO / batch writes, ordinary reads, tag/field predicates Supported Supported Supported Supported
Native query language SQL SQL InfluxQL InfluxQL
Time-cursor / offset pagination Supported Supported Supported, subject to time-cursor limitations when multiple rows share a timestamp Supported, subject to time-cursor limitations when multiple rows share a timestamp
FIELD sorting / strict composite cursors Supported Supported Explicit UNSUPPORTED_OPERATION Explicit UNSUPPORTED_OPERATION
Aggregation / tag grouping / UTC or fixed-offset windows Supported Supported Supported; window aggregation requires explicit start and end times Supported; window aggregation requires explicit start and end times
Regional calendar-day windows / DST Bounded calendar-day CASE bucketing Bounded calendar-day CASE bucketing Unsupported; explicitly rejected Unsupported; explicitly rejected
Pagination totals Server-side COUNT / subqueries Server-side COUNT / subqueries Streaming count of logical result rows, bounded by the response byte limit Streaming count of logical result rows, bounded by the response byte limit
Native client bean ITableSessionPool com.influxdb.v3.client.InfluxDBClient org.influxdb.InfluxDB Compatible org.influxdb.InfluxDB

The openGemini column describes the 2.1.0 adapter, which composes the InfluxDB1 compatibility implementation and retains its common-query limits. It covers verified 1.4.1/1.5.2 default-engine deployments, not COLUMNSTORE, Arrow or every native openGemini feature. Exact verification is recorded in OpenGemini integration.

The OpenGemini adapter applies its own measurement-name preflight, exact missing-measurement normalization and native health bridge. New measurement/tag-series indexes can become query-visible after the write acknowledgment; application reads needing that point should poll with a deadline. Structured common query returns no rows and count returns zero only for the exact measurement not found error, with an explicit measurement. Native executeQuery and borrowed native DTOs preserve server errors, including errors from multiple measurements or subqueries. Measurement names containing ,, ;, / or \, equaling . / .., or containing non-printable characters are rejected for the whole batch before I/O. Its stable compatible native proxy reads the real X-Geminidb-Version header for ping() / version(); other native methods delegate normally.

InfluxDB 3 strict-cursor compatibility depends on the server and configured SQL strategy: tsdb.influxdb.strict-cursor-sql defaults to or; union-all is an explicit alternative for structured continuation queries. Use the exact combinations in compatibility and validation, rather than assuming every 3.x release supports both query shapes. The switch does not rewrite native SQL or add strict cursors to InfluxDB 1.x. Strict cursors combined with aggregation fail with UNSUPPORTED_OPERATION in union-all mode, including on the first page.

With m final cursor keys, the UNION strategy emits at most m mutually exclusive branches with repeated business predicates and time bounds, followed by global ordering and pagination. It preserves mixed ASC/DESC ordering, the template's completed time/tag keys and response row/byte protection. It may increase server scans and sorting; these response limits do not limit database scan work or CPU. Neither strategy provides a snapshot spanning multiple pages, makes incomplete/null cursors valid, or increases timestamp precision. See pagination.

InfluxDB 1.x maps the shared AVG operation to MEAN and translates IN/BETWEEN into equivalent predicates. It does not receive InfluxDB 3 SQL unchanged.

InfluxQL applies LIMIT/OFFSET per series. Tag-grouped queries therefore read the bounded set of grouped results before applying global sorting and pagination. They fail when the grouped result exceeds max-query-rows or the response byte limit, even if the requested page is small. Ordinary counts scan rows without retaining the full result, avoiding incorrect total-row counts caused by COUNT(*) counting non-null values per field.

Explicit projections in InfluxDB 1.x require an annotated entity and at least one @TGField. Tag-only projections are rejected instead of returning misleading empty results. A raw TSDBQuery without entity metadata may leave selectColumns empty to use SELECT *, or use native InfluxQL instead. Window queries must not use window_start as an aggregate alias or group tag. The InfluxDB 1.x physical time column is always time; custom time columns are unsupported. Native queries cannot return multiple statement results, and partial server results are rejected explicitly.

Shared contract checks and IoTDB column identity

Version 2.1.1 reuses test-only backend contract assertions and records supported, unsupported and configuration-required capabilities in a machine-readable test matrix. This matrix is validation infrastructure, not a new public capability API. Unsupported operations must assert UNSUPPORTED_OPERATION; configuration-dependent operations must use the stated setting. The human-readable table above remains bounded by the exact server evidence in Compatibility and validation.

The reusable interface is SharedAdapterContract. Backend registrations and capability assertions are checked against adapter-capabilities.csv. The capability states are SUPPORTED, UNSUPPORTED and CONFIG_REQUIRED. The companion adapter-conditions.csv links exact server versions/settings to their regression methods: InfluxDB 3 Core 3.0.0/3.0.3 strict cursors require union-all, and IoTDB 2.0.2 requires Tablet RPC compression disabled. A mock contract pass does not certify an untested server.

IoTDB batch column role/type checks and prepared row values use one lowercase physical identity. Duplicate case variants within one record are rejected before I/O; compatible variants across records merge without losing values or nulls. Cross-row role/type conflicts reject the complete batch as METADATA_ERROR / NOT_COMMITTED. Caller maps keep their original keys. See write behavior.

Result mapping

Results map to application objects with an accessible no-argument constructor. Ordinary Java records cannot directly serve as query DTOs.

  • Annotated fields match annotation-defined physical column names. A missing physical column does not fall back to the Java field name.
  • Unannotated fields first match exact returned column names, followed by case-insensitive and snake_case-to-camelCase matching.
  • Unannotated DTO fields named time / timestamp can also match returned time aliases time, Time, _time and timestamp. Annotated fields continue to follow physical-column rules.
  • Extra result columns are ignored. Object fields without matching columns retain their values after construction.
  • Conversion to long/int/short/byte/BigInteger requires an exactly representable integer. Invalid text, fractional truncation and overflow throw METADATA_ERROR, rather than substituting 0 or null.
  • Boolean text accepts only true / false, ignoring case and surrounding whitespace. Other text, including 1 and yes, fails instead of silently becoming false.
  • Float / double reject NaN, infinity, overflow and nonzero underflow to zero. Ordinary IEEE 754 rounding still applies. Both InfluxDB adapters and the openGemini compatibility adapter parse JSON decimals as BigDecimal instead of first converting them to Double. Mapping to BigDecimal preserves the decimal digits present in the response, but cannot restore precision already lost before database storage. Values already obtained from other sources as Float / Double retain only that binary value; their original precision cannot be recovered.
  • Text conversion to Instant retains nanoseconds; long / Date time values use milliseconds. A source null remains null for reference types and leaves the constructed field value unchanged for primitives.
  • Mapping errors include the field, source type and target type, retaining the underlying conversion exception as their cause.

Map result types

Map.class and LinkedHashMap.class return LinkedHashMap and preserve result-column order. HashMap.class returns HashMap; TreeMap.class returns a key-sorted TreeMap. Other Map interfaces or subclasses are rejected with ARGUMENT_ERROR before database I/O, including queries that would return no rows. No arbitrary reflective Map constructor is invoked. These rules apply to template query/result APIs and leave normal POJO mapping unchanged.

General limitations

Portable tests and reusable Docker configuration are version controlled under module src/test/ directories. Local fixtures, credentials and execution reports under .local-test/ remain ignored. The shared runner and GitHub workflow provide reproducible checks; see testing and publishing.

  • Only IoTDB's table model is supported; there is no tree-model conversion adapter.
  • TGTemplate targets the single enabled adapter. Multiple starter dependencies may coexist, but simultaneous active backends and dual writes are unsupported.
  • Fluent-query support follows the backend capability table. Use executeQuery(...) or the borrowed native client for complex joins, subqueries or database-specific functions, subject to native-query restrictions.
  • Keep each field's type stable within a database/table to avoid IoTDB type conflicts or InfluxDB field-type inconsistencies.

← Pagination and native queries · Compatibility, validation and readiness →

OpenGemini in 2.1.0

The tested 1.4.1/1.5.2 Influx-compatible HTTP write path converts integer fields through float64 before storing them. An integer protocol suffix does not prevent this conversion: 9007199254740993i reads back as 9007199254740992. The OpenGemini adapter therefore checks the complete batch before I/O and accepts integer-typed fields only within signed-int64 bounds and when their exact value is representable by IEEE 754 float64. All integers from -2^53 to 2^53 are exact; some larger values, including 2^53+2 and Long.MIN_VALUE, are also exact. 2^53+1, Long.MAX_VALUE and Long.MIN_VALUE+1 are rejected with ARGUMENT_ERROR, NOT_COMMITTED and zero physical requests, without coercion or string encoding. Structured query/count also preflight exact integer filter literals, including every IN/BETWEEN value, because backend numeric comparisons can round them. Extreme integer-valued BigDecimal predicates are compared with signed-int64 bounds before integer expansion, so very large exponents cannot bypass validation or force unbounded allocation. Float/Double and fractional query literals retain ordinary floating-point semantics; existing BigDecimal field checks still apply. Epoch-millisecond timestamps use their separate time path. Native SQL and borrowed native writes bypass these checks and retain backend precision limitations; aggregate overflow and floating-point accumulation are not made exact by this validation. This restriction is specific to the HTTP adapter, not a claim about every OpenGemini engine or alternate ingestion protocol.

TsGate 2.1.0 includes the independent OpenGemini adapter and starter. See OpenGemini integration for configuration, default-engine limits and exact-version testing, and 2.1.0 release notes for release changes.

Clone this wiki locally