4.0.14
4.0.14
Release Date: August 11, 2026
Behavior Changes
- A static partition clause in an
INSERTinto an Iceberg or Hive table is now validated even when a target column list is given. A clause that names a column which is not a partition column of the table is rejected with a clear error instead of being silently ignored. EveryINSERTshape that was accepted before is still accepted. #76659 ARRAYandMAPconstructors now fail with aCapacityLimitExceederror when the flattened result of a single chunk exceeds the addressable byte limit, instead of silently returning corrupted values thatCREATE TABLE AS SELECT,INSERT, or a materialized view refresh could persist. For affected queries, reducechunk_sizeor split the constructor expression. #76419- Division expressions whose divisor is not constant (for example,
10 DIV c) are no longer treated as monotonic, which stops unsafe Zone Map pruning from dropping rows that satisfy the predicate. Queries filtering on such an expression may return more rows than in earlier versions; the previous results were incorrect. Monotonic forms such asc DIV 10still benefit from the pruning. #76744 - On a column with a GIN inverted index,
NOT MATCHno longer returns rows whose value isNULL, which brings it in line with SQL three-valued logic. Queries that depended on the previous behavior return fewer rows. #75578 - Under
"compression" = "zstd", flat JSON sub-columns and the synthetic null and offset sub-columns ofARRAY,MAP, andSTRUCTcolumns are now compressed. They were previously written as raw pages, which could make a ZSTD table larger on disk than the same table compressed with LZ4. Only segments written after the upgrade are affected, so existing tables shrink gradually as their segments are rewritten. #76949 - The Iceberg partition cache is now bounded by memory instead of by entry count, through the new catalog property
iceberg_partition_cache_memory_usage_ratio(default0.1), and its footprint is reported in/api/memory_usageand the minute-level memory logs. Under memory pressure the cache may hold fewer entries than before; raise the ratio to restore the previous footprint. #76165 - FE memory estimation now also counts the internal overhead of maps and collections — per-entry nodes and the backing table — instead of only the sampled keys, values, and elements. Weight-bounded caches such as the Iceberg metadata caches therefore report their true footprint and evict earlier for the same
*_memory_usage_ratio, which lowers FE memory usage but may increase cache misses. #75971 - When the keep-alive GC reaps an expired external scan context — left behind by a Spark or Flink connector reader that died without calling
close_scanner— it now cancels the corresponding pipeline fragment. The buffered scan memory is released withinkeep_alive_minplus one GC interval instead of staying pinned untilquery_timeout. #76535 - The audit log of a statement forwarded to the Leader FE now records the relations resolved by the Leader, so
QueriedRelationsholds fully qualified table names with CTE references excluded, matching what the Leader logs. A Follower falls back to local collection only when the statement ran locally or the Leader did not return the list, for example during a rolling upgrade. #76387 - The
Operationcolumn ofSHOW ALTER TABLE OPTIMIZEnow shows a readable description of the optimize operation instead of an internal object address such ascom.starrocks.sql.ast.OptimizeClause@b5dc069. #75948
Improvements
- Supported complex types (
ARRAY,MAP, andSTRUCT) in Paimon tables; querying such columns could previously crash the BE. #66784 - Added the
LAST_REFRESH_TIMEcolumn toinformation_schema.materialized_viewsandSHOW MATERIALIZED VIEWS. It reports the data-freshness timestamp used by themv_rewrite_staleness_secondcheck, which is distinct from the existingLAST_REFRESH_FINISHED_TIME(when the refresh job finished running). #71642 - Added the mutable BE configuration item
object_storage_client_cache_size(default8), which replaces the hard-coded capacity of the S3 and Azure Blob client caches. #75851 - Metadata refresh of a filesystem-backed external table triggered by
INSERT ... SELECTno longer runs while FE internal metadata locks are held, so slow remote metadata access no longer stalls unrelated work on the same path. #73391 - Multi-statement (multi-table) transaction Stream Load now dispatches all per-table channels before waiting for them, instead of dispatching and waiting for each table in turn, which shortens commit time for CDC pipelines that write many tables under one label. #76715
- Reduced lock contention across the
INSERT OVERWRITEcode path by relaxing or shortening the table-level locks held in each phase. #75828 - Error messages for the large-column capacity limit no longer embed internal diagnostics such as the driver address and the operator chain, and the
Capaticytypo in the shared status string is corrected. #76303 - Shared-data Primary Key publish now applies the per-segment delete vectors carried in
op_write.seg_delvecs, so a BE running this version consumes such metadata correctly instead of leaving duplicate primary-key rows live. #76474 - Addressed security vulnerabilities (CVE): upgraded Thrift to 0.24.0 and Netty to 4.1.136.Final, bumped the PostgreSQL JDBC driver to 42.7.12, and removed vulnerable transitive dependencies that shipped alongside their fixed counterparts, namely
bcprov-jdk15on, the end-of-life OkHttp 2.x line,avro-ipc(which bundles jQuery 1.4.2), and the Jetty client and security jars. #76922 #76555 #76783 #76097 #76270
Bug Fixes
The following issues have been fixed:
- The query cache could store an incomplete per-tablet result and serve it to later queries, returning wrong results. #77066 #77404
COUNT(DISTINCT)on an Iceberg table partitioned bybucket()returned an over-count whenenable_bucket_aware_execution_on_lakewas enabled and theGROUP BYlist was a superset of the bucket column. #76601- JSON subfield pushdown returned wrong results when two subfield keys of the same column differed only in case (for example,
get_json_string(c, 'Campaign')andget_json_string(c, 'campaign')), because the generated column names are resolved case-insensitively. Such collisions are now excluded from the pushdown. #76594 #76593 array_differenceon integer input computed each adjacent difference in the 32-bit input type before widening to theBIGINTresult type, so a difference outside theINTrange overflowed and returned a wrong value. #76569- Aggregating a whole
STRUCTcolumn together withROLLUP,CUBE, orGROUPING SETSfailed at plan time withStructType SlotRef must have an non-empty usedStructFiledPos. #76804 - Rebuilding a logical window operator in the optimizer dropped the
inputIsBinaryflag, losing the binary-input merge behavior selected by ranking-window pre-aggregation. #77058 - A query could fail with
Expr evaluate meet error: slot_id N not foundbecause the partition-by columns of a PARTITION TOP-N node were rewritten to a dictionary slot that had already been decoded below the node. #75956 - Query planning, including
EXPLAIN, aborted with anIllegalStateExceptionwhen a contradictory range predicate such ascol > X AND col < Xcollapsed to an empty value set and the same column was also referenced by a column-to-column join predicate. #75011 - Planning aborted when an aggregate over a multi-branch
CASEwith a non-null constantELSEclause was considered for push-down below a join. #75037 - Selecting from views whose definitions form a cycle — which
ALTER VIEWcan create — failed with an opaqueUnknown errorcaused by aStackOverflowError. Cyclic definitions are now detected and reported. #75033 - Grouping key columns of
GROUP BY ROLLUP,CUBE, andGROUPING SETSwere reported as non-nullable at analysis time, which produced an incorrect result schema for Arrow Flight SQL clients. #76149 array_containsandarray_positionfailed withclass com.starrocks.type.NullType cannot be cast to class com.starrocks.type.ArrayTypewhen the first argument was an untypedNULLliteral. #76970- For an
ORpredicate with more than 16 disjuncts, the merged null fraction of a column was always estimated as1instead of the average of the operands' null fractions, which distorted cardinality estimation. #75864 - Loading column statistics failed for a column whose values are all
NULLwhen the globalsql_modeincludesERROR_IF_OVERFLOW, because the stored empty min/max string could not be cast to the column type. #76684 - The FE scan-range heap-safety check ran once per physical partition instead of once per scan node, which burned minutes of FE CPU per plan attempt on a table with tens of thousands of physical partitions. #76978
- A predicate on a wildcard
CHARcolumn, such asCAST(json_col->'$.x' AS char), threwstd::length_errorbecause the column's declared length of-1was used for zero-padding. #77444 - The BE crashed when scan predicates were pulled up through an
array_maplambda, because the rewrite descended into the lambda body. #76380 - The
STRUCToutput ofUNNESTcould be pruned narrower than the element type the BE materializes for the input array, when another consumer keeps that input array fully materialized. #76002 - Analyzing
__iceberg_transform_truncateor__iceberg_transform_bucketmutated the shared builtin function object in place, stamping its wildcard decimal signature with the precision and scale of the first query analyzed. #76777 - Rewriting a query with two aggregates on the same base column of a synchronous materialized view or rollup, such as
min(c)andmax(c), failed during cost estimation withmissing statistic of col: ... mv_min_c. #75528 - A materialized view could serve stale results after
rollback_to_snapshoton its Iceberg base table, because a negative staleness was accepted as within themv_rewrite_staleness_secondbudget. #75924 - With
mv_rewrite_staleness_secondset andquery_rewrite_consistency = checked, a chained partial refresh of one recently committed partition kept renewing the freshness of the whole materialized view while another partition lagged far beyond the tolerance. The staleness baseline is now the time the view was last confirmed fresh. #76758 - A materialized view defined on an un-partitioned Delta Lake or Kudu table was never used for query rewrite, even after a successful refresh. #76359
- The FE Iceberg manifest data-file cache could serve a cached file set that was missing a live data file while still passing the read-side completeness check, so scan planning silently dropped the file and the query returned a short result. #76215
- Queries on an Iceberg V1 table failed after a partition field was dropped, because a dropped V1 partition field is retained in the spec with a void transform and keeps the name of its source column. #75149
- An Iceberg REST catalog configured with an OAuth2 client credential failed every request until the catalog was recreated, once its background token refresh had exhausted its retry budget. The catalog now rebuilds its session and retries the request once, at most one rebuild per 60 seconds; catalogs using
jwtsecurity or a static token are not affected. #76457 - Closing an Iceberg incremental scan-range iterator while the executor thread was still consuming it, which happens on query cancellation, was unsafe. #75953
- Iceberg REST catalog vended credentials for GCS were ignored and FE metadata reads failed with
403 Forbidden, because the gcs-connector 3.x configuration keys were renamed. #75979 - Querying a table in a Hive catalog intermittently failed with
out of sequence responseand thenUnknown table, because thegetTable()fallback reused the same Thrift connection after a read timeout without reconnecting. #76456 - A Paimon predicate that cannot be converted, such as a comparison on a
CASEexpression, discarded the whole conjunction instead of keeping the convertible conjuncts. #66038 BOOLEANcolumns were excluded from page-level predicate pushdown in Parquet files, because the Parquet column index min/max decoder had noBOOLEANcase. #74752- A streaming pre-aggregation running with
enable_spill = truecould run out of memory, because the memory budget latched when the sink downgraded to limited-memory mode was computed only once and could be frozen at0. #76702 - The data load path and the column-mode partial update path could build a chunk whose
ARRAYor string column exceeded the addressable size, leaving the offsets no longer describing the buffer they belong to. Both paths now bound and check the chunk capacity. #77163 - Columns missing from a Parquet file were null-padded to the whole Arrow batch size instead of the bounded chunk size, so a batch processed across several chunks produced unequal column lengths within one chunk and crashed. #75981
- A replica in
DECOMMISSIONstate could be elected as the primary replica of a load. Because it is the replica most likely to be removed while the load is still running, the whole load then failed withFail to get tablet ...instead of the write quorum absorbing a single-replica failure. Such a replica is now skipped unless no other healthy candidate exists. #77035 - The BE crashed during a load spill because
LoadChunkSpillerused an unsynchronized null check as its initialization flag, letting a racing memtable-flush thread use a spiller whose serde was not ready yet. #76098 - A multi-character CSV delimiter that straddled a buffer expansion caused a heap use-after-free in the CSV reader, reachable through the
FILES()table function, Broker Load, and the Hive text connector. #76718 - Loading malformed JSON crashed the BE with a heap buffer overflow, because the data-quality error message was built from an unbounded raw JSON pointer. #76752
- Cancelling a load crashed the BE or CN with a SIGSEGV when tracing was enabled through
jaeger_endpoint, because the sink'sclose_waitwas not idempotent. #76869 - Aborting a failed
INSERT INTO FILES()threw a swallowed NPE, because the abort path looked up a database that a table function table does not have. #75983 INSERT OVERWRITEgarbage collection could journal a failed-state change for a table that had already been dropped, because the target table was resolved before the table write lock was acquired. #77212SHOW CREATE ROUTINE LOADemitted thejsonpathsvalue without escaping its double quotes, producing DDL that cannot be parsed or replayed. #75755- On a Primary Key table with file bundling, retrying an aggregate publish could probe remote storage for a version that exists only in the metadata cache and leave a dangling
prev_garbage_version. Durable metadata is now read when calculating the new base version. #75904 - A shared-data publish could write a bundle tablet metadata file that was missing tablet pages, which left the partition's publish permanently stuck with
can not find tablet ... from shared tablet metadata. Such a file is now refused, so the failure stays transient and retryable. #76850 - A CN crashed on a physical-split scan of an empty tablet, because
SparseRangeIterator::has_more()was not null-safe and a transient lake segment-load failure was swallowed instead of being surfaced as a retryable error. #75985 - A CN crashed while building a segment for a materialized view carrying a legacy NGRAMBF index that older FE versions persisted without its
gram_numproperty. #76989 - The BE crashed when the build side of an aggregation
INruntime filter was a constant column. #74941 - Cancelling a query could cause a use-after-free in the spillable hash-join build operator, because its
set_finishingran the spill-start path even when the runtime state was already cancelled. #76633 - A BE or CN could abort during shutdown with
std::bad_weak_ptr, because the global runtime-filter timer of an abandoned pipeline driver was never unscheduled. #76252 - Memory leaked because the bRPC stub cache cleanup timer task was unscheduled but never removed. #75973
- A query's
ConnectContext, together with the wholeExecPlanobject graph it references, stayed pinned in the thread-local of a pooled query-deploy worker. #76366 PipeObservable::defer_notify_sink()emitted a source event instead of a sink event, so a driver blocked onOUTPUT_FULLcould stay blocked until an unrelated event arrived. #76782- An exception thrown by a
ThreadPooltask was swallowed by default and the task was still counted as finished. #76863 - The BE kept running with the crashing flag set, and therefore kept reporting
SHUTDOWNto the FE, when the fatal-signal handler stalled before re-raising the signal. The process is now forced to exit. #76491 - Dropping a catalog verified its existence under a read lock and removed it under a separate write lock, so two concurrent drops of the same catalog could both pass the check. #76778
- Java UDFs failed on JDK 21 and later with
NoSuchMethodException: java.nio.DirectByteBuffer.(long,int), because that private constructor was removed in JDK 21. #75666 - Behind a load balancer, every ADBC client that opens with a prepared statement failed, because a
CreatePreparedStatementorClosePreparedStatementforwarded to another FE carried the protobuf message name instead of the Flight SQL action type. #76310 - The Arrow LZ4 and ZSTD IPC codecs were missing from the FE classpath of the Arrow Flight SQL service. #76921