This release introduces new SQL capabilities including the COPY PERMISSIONS statement for cloning access profiles between principals, per-column Parquet encoding and compression controls, and dynamic window ranges in WINDOW JOIN queries. Performance improvements span faster ORDER BY on TCA queries, expanded vectorized GROUP BY coverage, and improved Parquet I/O throughput. The release also addresses several critical bug fixes including data corruption in DECIMAL columns, JVM crashes during backup coordination, and WAL replication race conditions.
New Features
This feature introduces three new permission constants:
CONVERT PARTITION TO PARQUET,CONVERT PARTITION TO NATIVE, andSET PARQUET ENCODING. Authorization checks are wired into all enterpriseSecurityContextimplementations, includingEntSecurityContextBase,AdminSecurityContext, andAbstractReplicaSecurityContext. ThePermissionParserwas updated to handle multi-word permission names containing SQL keywords (such asTOinCONVERT PARTITION TO PARQUET) by addingisPermissionPrefix()to disambiguate keywords from permission name continuations. All three operations are denied on replica security contexts. Previously, theseALTER TABLEoperations piggybacked onauthorizeAlterTableAlterColumnTypeand could not be granted or revoked independently.
Bug Fixes
The WAL uploader could enter an infinite retry loop when it encountered a segment whose
upload.pendingmarker file was never created. This occurred whenWalWriter.openNewSegment()advancedminSegmentLockedeven whencreateSegmentDir()threw due to a transient disk error. When the distressed WalWriter was later closed, asegmentClosedevent fired for a segment that never had itsupload.pendingfile created, causing the Rust uploader to retry deleting the non-existent file indefinitely. This fix makesclear_segment_pending_filein the Rust uploader treatENOENTas success, since the desired end state —upload.pendingabsent — is already achieved. This is safe with respect to the WAL cleaner because phantom segments are harmless: object stores return success when deleting non-existent keys, and the cleaner's compaction watermark has gap protection that prevents it from skipping real segments.In QuestDB Enterprise, exporting to Parquet via
COPYcould produce spurious "cancelled by user" errors. TheSecurityCheckFactorywas inserted as aRecordCursorFactorywrapper for allSELECTqueries, even though it only mattered forUPDATEqueries where it revalidated column-level permissions. This broke an assumption that the outermost factory for aSELECTis alwaysQueryProgress, causing the code to fail to unwrap the factory chain correctly.QueryProgressthen interacted badly with theCOPYjob, triggering the spurious errors. This fix moves authorization revalidation directly intoUpdateOperation, eliminating the need for theSecurityCheckFactorywrapper.After a server restart,
collect_missed_segmentswalks WAL directories to find segments withupload.pendingfiles left over from a previous run. Because the walk is processed asynchronously, it could encounter WAL directories created after the bounce and queue them as "closed" with a stalelast_txnset to the sequencer's startup transaction. This caused theupload.pendingclearing loop to remove the file prematurely, after whichWalPurgeJobdeleted the unprotected segment. The uploader, still needing the segment, entered an infinite retry loop and the table's replication became permanently stuck. This fix passescurrent_wal_idintocollect_missed_segmentsand skips any segment wherewal_id > current_wal_id. Sincecurrent_wal_idis read from_wal_index.dbefore ingestion starts, it reliably represents the last pre-bounce WAL ID. Post-bounce segments are handled through the normalSegmentClosedevent flow and do not need recovery viacollect_missed_segments.Without this fix, revoking a user's
ALTERorUPDATEpermission did not take effect for already-cached prepared statements in the PostgreSQL Wire Protocol, allowing the user to continue executing those operations until the connection was closed. Previously,ALTERstatements were not cached before the PostgreSQL Wire Protocol layer rewrite, so authorizing them at compile time only was sufficient. Since the PostgreSQL Wire Protocol layer can now cache these commands, this fix ensures that authorization happens at execution time as well.