Tags

Tags give the ability to mark specific points in history as being important
  • 26.2.1

    protected
    10b112a2 · release: 26.2.1 ·
    [26.2.1] - 2026-08-31
    
    Bug fixes
    
    webui
    
    - Fixed `instancesCurrentStateOffline` in `/api/v1/cluster` counting
      expelled instances as offline; it now counts only instances whose
      current state is actually `Offline`
    
    - Changed the empty state for tier services from "No data" to the more descriptive
      "No services"
  • 26.2.1-rc3

    protected
    90971984 · release: 26.2.1-rc3 ·
    [26.2.1-rc3] - 2026-08-27
    
    Bug fixes
    
    webui
    
    - Improve instance address display by truncating long FQDNs while keeping
      the port always visible for easier node identification
    
    - make copypaste button work on non https origins
    
    - Improved filter tag display in search-building mode by replacing
      technical keys with user-friendly names
    
    - Updated  translation for the Raft leader role: raft leader was replaced with governor
      to use the correct role terminology
    
    - Added an indicator showing that the instance is the leader in the Replication section
      of the instance pop-up card
    
    - Added an informative empty state for unavailable upstream and downstream
      connections in the Replication section of the instance pop-up card
  • 26.2.1-rc2

    protected
    dcd72bc9 · release: 26.2.1-rc2 ·
    [26.2.1-rc2] - 2026-08-21
    
    Features
    
    sql
    
    - The `WHERE bucket_id = <CONST>` filter now avoids `Motion(Full)` insertion and
      routes the query to a single storage. This optimization also helps execute
      transactions locally and queries with `OPTION(forward = off)`.
    
    - Columns in `PRIMARY KEY` and `CREATE INDEX` now accept an optional `ASC`
      or `DESC` sort order modifier. For example, `PRIMARY KEY (a DESC, b ASC)`,
      `id UNSIGNED PRIMARY KEY DESC`, and `CREATE INDEX ... (a ASC, b DESC)`.
      The default order remains `ASC`. Explicit sort order is supported only
      for `TREE` indexes.
    - The virtual `bucket_id` column can be the first part of a primary key with
      its own sort order, for example `PRIMARY KEY (bucket_id DESC, id ASC)`.
    
    Bug fixes
    
    sql
    
    - The `||` operator now has PostgreSQL-compatible precedence: a dedicated
      tier below `+`/`-` instead of sharing the `*`/`/` tier. Unparenthesized
      expressions mixing `||` with arithmetic may change meaning ([!3463](https://git.picodata.io/core/picodata/-/merge_requests/3463)).
    - `||` now accepts any scalar operand next to `text` (`int`, `numeric`,
      `double`, `bool`, `datetime`, `uuid`). Each argument unconditionally
      is converted with `CAST(... AS string)`, so its rendering follows
      Tarantool (e.g. `TRUE`, ISO 8601 datetimes) rather than PostgreSQL.
    - Parameter types for `$1` used in `||` expressions are now reported
      correctly over pgproto: an implicit cast no longer overwrites the
      inferred parameter type.
    
    - Executing `SELECT` queries with `ARRAY` columns no longer produces decoding
      errors on cluster with many replicasets.
    
    - Fixed the error `sub-query plan subtree with id XXXX not found`, which
      occurred in some `EXPLAIN` queries containing `DISTINCT`.
    
    - Scalar subqueries in `GROUP BY` expressions now match their twin in the select
      list and `HAVING`, e.g. `SELECT a + (SELECT 1) FROM t GROUP BY a + (SELECT 1)`
      no longer fails with `column "a" is not found in grouping expressions`.
    - A scalar subquery that appears both in `GROUP BY` and in the select list or
      `HAVING` is now planned and executed once instead of once per occurrence.
    
    - A join which pins constants on the sharding keys of both children no longer
      returns an empty result, e.g. `SELECT * FROM t1 JOIN t2 ON a = 1 AND b = 2`
      where `t1` is sharded by `a` and `t2` by `b`.
    
    - Queries with CTEs and window functions that previously returned an error
      `node XXXX is outside of the plan id subtree` now work correctly.
    
    - Executing certain queries with `UNION` and `EXCEPT` no longer returns
      an error `Failed to compile SQL statement: Syntax error at line 1 near '('`,
      e.g. `SELECT 1 UNION SELECT 0 EXCEPT SELECT 1 from t;`.
    
    - Scalar aggregate with empty buckets set now returns `0` instead of `NULL`,
      e.g. query `SELECT count(*) FROM t WHERE a = 1 AND a = 2`.
    
    - Queries using `UNION ALL`/`EXCEPT` that involve a sharded table and a global
      table now return the correct result.
    
    - Executing queries with CTEs that do not include projections no longer results
      in the error `Temporary SQL table _tmp_* not found`.
    
    - Queries containing `UNION`/`UNION ALL`, where one of the parts contains a
      branch with a condition that is always false could return an incorrect (empty)
      result. Now such queries return the correct result, e.g.,
      `SELECT 1 UNION ALL SELECT a FROM t WHERE false`,
      `SELECT 1 UNION SELECT a FROM t WHERE a = 1 AND a = 2`.
    
    replication
    
    - Tiers with `replication_mode = sync` now run Tarantool elections in
      `election_mode = "manual"`, and the election leader is the only instance
      which accepts writes. The governor still designates the master in
      `_pico_replicaset`, but a master which lost the majority is fenced by the
      election itself and can no longer accept writes.
    - Fixed a bug where a lagging replica could be chosen for promotion during
      failover. The elections now provide the "synchronize before promotion"
      guarantee: a candidate only receives a vote from a peer whose vclock is
      not ahead of its own.
    
    backup
    
    - Fixed backup and restore with custom storage directories. SQL `BACKUP` no
      longer crashes when `memtx.dir` or `vinyl.dir` differs from `instance_dir`,
      and `picodata restore` now restores data to the configured `wal_dir`,
      `memtx.dir`, and `vinyl.dir`, including when these directories are nested.
  • 25.5.10

    protected
    9d6966c0 · release: 25.5.10 ·
    [25.5.10] - 2026-07-31
    
    Fixes
    
    - Fixed excessive logging when DdlCommit could not be applied on a replica.
  • 26.3.0

    protected
    [26.3.0] - 2026-07-15
    Feature freeze [26.2]
    Start next minor 26.3.0
  • 26.2.1-rc1

    protected
    19e3661d · release: 26.2.1-rc1 ·
    [26.2.1-rc1] - 2026-07-15
    
    Breaking changes
    
    - Deprecated `plugin_dir` setting is removed following a major release. Use `share_dir` instead.
    
    - Deprecated `advertise_address` setting is removed following a major release. Use `iproto` section instead.
    
    - `--cluster-name` argument for `picodata expel` is removed following a major release as it is no longer needed.
    
    - Deprecated `ServiceWorkerManager` is removed from `picodata_plugin` following a major release.
    
    - `authenticate` function from `picodata_plugin` is now accessible only through `authentication` module.
      Reexport in `internal` module is removed following a major release.
    
    - Deprecated `RegionBuffer::get` is removed following a major release.
    
    - `CancellationTokenHandle::cancel()` now returns `Rc<OnceEvent>` instead of
      `Channel<()>`. Use `finish_event.is_finished()` to check completion or
      `finish_event.wait_timeout(duration)` to wait with a timeout.
    
    api
    
    - Rename fields in `/api/v1/health/status` response: `reasons` to `issues`,
      status level `unhealthy` to `broken`.
    
    cli
    
    - `picodata demo` subcommand is now gated behind the `demo` Cargo feature,
      disabled by default. To build with demo, use `CARGO_FLAGS_EXTRA="--features demo"`.
    
    metrics
    
    - Cache metrics
      `pico_router_cache_{hits,misses,statements_added,statements_evicted}_total`
      and `pico_storage_cache_{statements_added,statements_evicted}_total`
      now carry `tier` and `replicaset` labels (previously unlabelled).
      `pico_storage_cache_{hits,misses}_total`,
      `pico_storage_1st_requests_total`, and `pico_storage_2nd_requests_total`
      gain `tier` and `replicaset` in addition to their existing labels.
      Aggregations across replicasets may need an explicit
      `sum without (tier, replicaset)`.
    
    Features
    
    sql
    
    - Added `ARRAY` literal support ([!3180](https://git.picodata.io/core/picodata/-/merge_requests/3180)).
    - Expanded pgproto support arrays.
    
    - Support `LOGICAL`, `BUCKETS`, and `FORWARD` modes of EXPLAIN for transactions ([!3184](https://git.picodata.io/core/picodata/-/merge_requests/3184)).
    - Add per query bucket estimation to EXPLAIN (RAW) output when BUCKETS mode is
      specified ([!3280](https://git.picodata.io/core/picodata/-/merge_requests/3280)).
    - Provide more accurate info about query execution location in EXPLAIN (RAW)
      output ([!3330](https://git.picodata.io/core/picodata/-/merge_requests/3330)).
    - Reflect the planning caveats for queries with UNION of global and sharded
      tables in EXPLAIN(RAW) ([!3357](https://git.picodata.io/core/picodata/-/merge_requests/3357)).
    
    - Added support for transactional `INSERT ... ON CONFLICT DO UPDATE` statements inside SQL blocks.
    
    - Added an equality-facts analysis pass over the relational plan that derives
      always-true equalities from `WHERE` / `ON` predicates and stores them per
      output slot. Downstream stages (motion planning, bucket determination, JPPD
      transformation) can now answer "is this slot fixed to a constant?" and "do
      these two slots belong to the same equality class?" in O(1) without
      re-parsing predicates. Semantic boundaries (LEFT JOIN nullable side, CTE,
      Motion, set-ops, `LIMIT` / `ORDER BY` / `GROUP BY` / `HAVING`) are respected
      so unrelated scopes never merge, and parameter placeholders are kept
      separate from constants to avoid leaking unsafe bindings into execution-time
      filters.
    
    - Implement the `forward` option for DQL/DML queries that controls how queries
      are routed with respect to bucket ownership:
      - `on`: scatter-gather across replica set leaders;
      - `ro_to_rw`: all buckets on one node, forwarding allowed;
      - `off`: true locality, error if client is not on the correct node.
    
    - [picodata#1596] Added support for `ARRAY` columns in `CREATE TABLE` and
      `ALTER TABLE ADD COLUMN`. Supported syntax: `T[]`, `T[N]`, `T[N][M]`,
      `T[][]`, `T ARRAY`, `T ARRAY[N]`. Declared type and sizes are documentation
      only and do not affect the internal implementation for now.
    
    - Introduce `CONTEXT` facet in `EXPLAIN` statement that shows query execution
      options and remove them from `LOGICAL` facet output.
    
    - Added new `pico_instance_health_status` SQL scalar function to get current
      instance's health status, - SQL wrapper over `/api/v1/health/status`.
    
    - Extended constant folding: AND/OR identities, identity rules for equality with
      true and inequality with false.
    
    - Provide a way to match vdbe opcode or motion row limit error to specific
      storage query in EXPLAIN (RAW).
    
    - [picodata#2764] Transactional blocks now support LET statements.
    
    - [picodata#2765] Transactional blocks now support IF statements.
    
    - `EXPLAIN (FMT)` option is now properly supported for all modes (facets).
      It is now possible to write `explain (fmt)` to get a formatted logical plan
      or `explain (fmt, raw)` to get a formatted raw query plan.
    
    - [picodata#2728] Error generated when `INDEXED BY` is used with non existing index
      now includes the target table name, making it explicit that the index-table
      relationship lookup failed rather than a general index lookup.
    
    - Add new `BUCKETS` facet to `EXPLAIN` statement. Users can now inspect query
      buckets without producing a full execution plan. This facet can be combined
      with `RAW` and `FMT` options. When multiple facets are specified, output
      sections are separated by headers.
    
    - Introduce `LOGICAL` facet in `EXPLAIN` statement. Users can now explicitly
      request the logical query plan. This facet can be combined with `RAW`,
      `BUCKETS`, and `FMT` options. The default `EXPLAIN` with no facets specified
      now emits both `LOGICAL` and `BUCKETS`.
    
    - Support `DELETE` statementes inside transactional `DO` blocks.
    
    - Support `INSERT` statements inside transactional `DO` blocks.
    
    - `EXPLAIN (RAW)` is now more informative and concise due to the new tree-like
      plan representation. The numbers in square brackets can indicate that a group
      of operations is performed on the same relation; in addition, they can be
      used as references to other operations.
    
    - Temporary table names now use the `_tmp_` prefix instead of `TMP_`, aligning them with naming convention for system tables.
    
    config
    
    - Added the `instance.memtx.dir` and `instance.vinyl.dir` configuration parameters, which set the directories where memtx snapshot files and vinyl files are stored respectively.
    
    - Added the `instance.wal_dir` configuration parameter, which sets the directory where WAL files are stored [!3294](https://git.picodata.io/core/picodata/-/merge_requests/3294).
    
    - Added a new parameter `cluster.tier.wal_mode` which controls how the write-ahead log is flushed to disk, letting you trade durability against write performance:
      - `write` (default), the fiber handling a transaction waits for `write(2)` to complete but does not wait for `fsync(2)` before returning control to the user. Data lands in the operating system page cache but is not guaranteed to reach disk, so the most recent records may be lost or corrupted if the power or operating system fails.
      - `fsync`, each `write(2)` is followed by `fsync(2)`, which forces a physical flush to disk and guarantees a consistent database state after a crash. This is the recommended mode when you need reliable recovery from hardware or OS failures. The tradeoff is reduced write performance.
    
    - [picodata#760] New configuration parameter `experimental_sharding_implementation` which
      enables the new behavior on the given tier. The parameter must be specified at
      cluster bootstrap via the configuration file and cannot be changed after that
      (in the future this restriction may be lifted).
    
    LDAP is now configurable through yaml
    
    LDAP authentication can now be configured with `picodata.yaml` configuration file. This also adds ability to use alternative (non-system-wide) trusted root CAs file when connecting to LDAP server via TLS.
    
    For now, previous configuration method through environment variables (`TT_LDAP_URL`, `TT_LDAP_DN_FMT`, `TT_LDAP_ENABLE_TLS`) is still supported, but considered obsolete. A warning will be printed on start.
    
    Here's an example YAML configuration snippet for configuring LDAP:
    
    ```yaml
    instance:
      ldap:
        enabled: true                             # `false` by default. LDAP authentication will fail if set to `false`.
        connect: 127.0.0.1:1337                   # Address of the LDAP server to connect to.
        dn_format: "cn=$USER,dc=example,dc=org"   # Defines conversion of picodata username to an LDAP Distinguished Name (DN).
                                                  # Must have exactly one occurrence of `$USER` in it.
        tls:
          enabled: true                           # `false` by default. If `true`, TLS will be used to connect to the server
          method: start_tls                       # `implicit` by default. Accepted values are `implicit` and `start_tls`.
                                                  # `implicit` means using `ldaps`. `start_tls` means using LDAP over TLS (StartTLS).
          ca_file: /etc/picodata/ldap-root-ca.crt # Path to a file containing alternative trusted root CA certificates, formatted as PEM.
                                                  # System trusted certificate store will be ignored, and those certificates will be used instead.
    ```
    
    Migration from legacy environment variables
    
    You need to convert the
    
    1. The old value of `TT_LDAP_DN_FMT` should be put into `instance.ldap.dn_format`. The format strings are fully compatible.
    
    2. For `TT_LDAP_URL` and `TT_LDAP_ENABLE_TLS`:
    
    | `TT_LDAP_URL`               | `TT_LDAP_ENABLE_TLS` | Action                                                                                                                                                |
    |-----------------------------|----------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------|
    | `ldap://[hostname]:[port]`  | not set              | Set `instance.ldap.connect` to `[hostname]:[port]`.<br/>Leave other options as default values.                                                        |
    | `ldap://[hostname]:[port]`  | `true`               | Set `instance.ldap.connect` to `[hostname]:[port]`.<br/>Set `instance.ldap.tls.enabled` to `true`.<br/>Set `instance.ldap.tls.method` to `start_tls`. |
    | `ldaps://[hostname]:[port]` | not set              | Set `instance.ldap.connect` to `[hostname]:[port]`.<br/>Set `instance.ldap.tls.enabled` to `true`.<br/>Set `instance.ldap.tls.method` to `implicit`.  |
    | `ldaps://[hostname]:[port]` | `true`               | This is an invalid configuration, since it requests use of StartTLS while also using LDAPS (implicit TLS). It is unrepresentable with the new config. |
    
    - [picodata#760] Added validation of cluster.tier config file section against
      the persisted system table state upon instance restart.
    
    - [picodata#2952] Added the `instance.wal_dir` configuration parameter, which
      sets the directory where WAL files are stored.
    
    join
    
    - When joining a cluster without an explicit `replicaset_name`, an instance
      whose name follows the standard naming scheme `<replicaset_name>_<n>`
      (e.g., `default_6_2`) now prefers joining `<replicaset_name>` (`default_6`)
      over whichever replicaset would otherwise be picked automatically. This
      makes it easier to restore a cluster from a backup of just the master
      instances and rejoin replicas with their expected names.
    
    plugin
    
    - Added on_cluster_leader_change callback to plugin API. It is called on two (at max) instances: on the old raft leader and on the new one [!3224](https://git.picodata.io/core/picodata/-/merge_requests/3224).
    - Renamed on_leader_change to on_replicaset_leader_change. Both methods are going to be called before the next major release.
    
    replication
    
    - Added synchronous replication for tiers via the new `replication_mode`
      tier option (`async`/`sync`, default `async`), set with
      `cluster.tier.<name>.replication_mode`. In `sync` mode Picodata enables
      Tarantool synchronous replication for sharded tables: a write is confirmed
      only after a quorum of the replicaset (`ReplicationFactor / 2 + 1`)
      acknowledges it, protecting against data loss and replication conflicts
      on master failover at the cost of write latency. Picodata automatically
      configures the synchro quorum, manages txn limbo ownership across
      master switchovers, and sets the `is_sync` flag on spaces created
      in the tier ([!2962](https://git.picodata.io/core/picodata/-/merge_requests/2962)).
    
      Scope and constraints:
      - Applies only to sharded (user) tables. Global and system tables (`_pico*`)
        are replicated globally via Raft and are unaffected. Tarantool system spaces
        are unaffected too.
      - The mode is fixed at cluster bootstrap and cannot be changed for an
        already-deployed cluster.
      - On quorum loss the replicaset becomes read-only and serves only reads
        (DQL); recovery is manual — the quorum must be restored by hand.
      - Replication factor 2 is not recommended with `sync` mode, since the
        quorum is then also 2 and the replicaset loses write availability on any
        single instance failure.
    
    webui
    
    - Optimize `/api/v1/tiers` and `/api/v1/cluster` endpoints to reduce RPC calls.
      HTTP addresses are now read from `_pico_peer_address` storage instead of RPC,
      and memory info is only fetched from replicaset leaders. This reduces the
      number of RPC calls from O(N×RF) to O(N) where N is the number of replicasets.
      Offline instances now show their HTTP address (from storage) instead of empty string.
    
    - Added new instance filters: `isVoter` and `isRaftLeader`. Both support
      the standard `Is` / `IsOneOf` / `IsNotOneOf` expressions with a Yes/No
      value set.
    
    - Extended the generic `Filter` component to accept boolean-valued tag
      options in addition to strings. The filter visual style is unchanged.
    
    - The replicaset card now renders placeholders for missing instances
      (instances expected by the replicaset configuration but not currently
      reported by the cluster).
    
    - Added `isRaftLeader` and `isVoter` flags to the instance model. Tier
      and replicaset cards now show indicators when they contain the raft
      leader or a voter instance.
    
    - The replicaset cards now display indicators if they have the not ready status.
    
    - The filter now has the option to select a text search tag without first entering text.
    
    - Added an instance details modal, opened by clicking an instance in the list.
      The modal includes the Overview, Storage, and Replication tabs. These tabs
      display the instance's general information, Vinyl and Memtx storage configuration,
      and replication details, including upstream and downstream information for remote
      nodes.
    
    misc
    
    - Improved accuracy of `space:len()` for Vinyl tables.
    
    Bug fixes
    
    - Fixed crash when disabling a plugin with slow background jobs. Previously,
      if a job didn't finish within the shutdown timeout, the plugin library could
      be unloaded while the job fiber was still running.
    
    - Fix cold restart deadlock where all instances in a replicaset would get empty
      replication configs, preventing synchronization. The governor now includes
      only the master in the fallback replication config, preserving conflict
      isolation while allowing the cluster to recover.
    
    - Fixed plugin unnamed background jobs being marked with wrong source location
      (missing `#[track_caller]` attribute).
    
    - Revoking privileges from `admin` user caused a panic. Now, revoking priviliges
      from `admin` user is forbidden, for same reasons as for the `pico_service` user.
    
    - Fixed sentinel panic on long activation wait.
    
    - Fixed an out-of-bounds panic in plugin RPC client when selecting a random
      candidate instance for `RequestTarget::Any`.
    
    - [picodata#2838] Fixed panic on single-node cluster forced expel
      ("removed all voters"), which now returns an explicit error.
    
    - [picodata#2888] Fixed a bug where cluster would fail to bootstrap if there were no voter
      instances in the initial `--peer` set.
    
    - Fixed the `Storage cache hitrate` panels in the bundled Grafana dashboard.
      They previously referenced non-existent metric names
      (`pico_storage_cache_1st_requests_total` / `…_2nd_requests_total`) and the
      formula folded DML traffic into the storage hitrate, silently inflating it.
      The panels now compute `hits / (hits + misses)` from
      `pico_storage_cache_hits_total` / `pico_storage_cache_misses_total` (DQL-only
      by construction), aggregated across `rpc_type` so the iproto path
      (`1st`, `2nd`) and the local fast-path (`local`) are reflected together.
    
    - All cache panels in `monitoring/dashboard/Picodata.json` now respect the
      dashboard's `$tier` and `$replicaset` template variables.
    
    - Fixed CAS conflict detection for globally distributed tables with secondary
      unique indexes. Previously, stale CAS requests could be appended to the raft
      log with different primary keys but the same secondary unique key, causing
      replicas to fail applying the later entry and preventing raft from advancing.
      Such requests are now rejected with a retriable `CasConflictFound` error.
    
    - [picodata#2926] Reduced log verbosity in vshard for routine replicaset events.
    
    - Implement and export `box_session_user_name` function in tarantool-sys ([tarantool!387](https://git.picodata.io/core/tarantool/-/merge_requests/387)).
    - Implement a function `tarantool::session::user_name` and use it in the `on_access_denied` trigger to prevent an implicit multi-statement transaction, which panicked ([!3196](https://git.picodata.io/core/picodata/-/merge_requests/3196)).
    
    config
    
    - Fixed a regression in config parsing. `--iproto-listen`, `--iproto-advertise` and
      `--http-listen` were triggering an error instead of overriding corresponding value
      in yaml config when deprecated listen options were used in the config.
    
    discovery
    
    - Discovery no longer panics on multi-address nodes ([picodata!3312]).
    
    sql
    
    - Queries of the form `(a OR b) AND (c OR d) AND (e OR f)...` could grow
      exponentially after DNF conversion. This led to a stack overflow. A limit of
      512 disjunctions has been added; if this limit is exceeded, the DNF is not
      constructed. You may notice this in the `EXPLAIN` output:
      `Query (WHOLE STORAGE)`. It is recommended to rewrite such queries
      [picodata!3353].
    
    - Fixed a SQL planner panic caused by stale type metadata after clone-based
      rewrites such as `BETWEEN` normalization and `GROUP BY` alias expansion.
    
    - Fixed a bug preventing scalar functions from being used in GROUP BY.
    
    - Fixed a bug with the storage cache that caused an error "Temporary table TMP_ not found".
    
    - Fixed a permission error occured during query planning for non-admin users.
    
    - Fixed the errors `box.cfg.read_only is true` and `Failed to add a storage reference`,
      which occurred when restarting a storage instance and previously required a retry.
    
    - Fixed `ALTER PLUGIN ADD SERVICE TO TIER` accepting nonexistent tier names.
      Now validates that the specified tier exists and returns an error otherwise.
    
    - Fixed the `query for request_id with plan_id not found` error that occurred
      on queries with `UNION` of `CTE` on a cluster consisting of multiple instances.
    
    - Logical `EXPLAIN` (the default mode) now preserves subquery indentation.
    
    - Backup operation will now be automatically aborted if there are offline instances.
      This prevents cluster being locked in a readonly state.
    
    - Fixed the `NO_ROUTE_TO_BUCKET` error that occurred when sending a request to
      the single node of a replicaset during its restart. This error is now retried
      by the router.
    
    - [picodata#2812] Use direct RPC for query metadata on DQL cache miss
      - Replace vshard-based Lua dispatch with ConnectionPool::call_raw for
        the proc_query_metadata callback. This fixes SQL query execution from
        arbiter tier instances (bucket_count=0) where no vshard router exists.
    
    - [picodata#2842] Fixed the `schema version has changed: need to re-compile SQL statement`
      error, which could occur when you execute multiple DQL queries due to
      yield during cache eviction.
    
    - [picodata#2732] Fixed a panic when attempting to inherit privileges via SQL
      (e.g., `GRANT admin TO somebody`). We do not support privilege inheritance
      via `GRANT user1 TO user2`. The system now validates the grantee type and
      returns a proper `NoSuchRole` error instead of panicking.
    
    - Reused CTE bodies are now materialized once per query instead of being
      silently inlined per reference, fixing wrong results for non-deterministic
      CTE bodies and avoiding redundant recomputation.
    
    - Fixed NOT push-down: no longer short-circuits before recursing into operand
      subtrees. The pass now also descends into Cast children to simplify NOTs nested inside.
    
    - [picodata#2775] Dropping the primary index is now rejected with a clear error.
    
    - `_pico_db_config` can no longer be truncated or deleted, as such operations
      may break instances or clusters.
    
  • 26.1.6

    protected
    46530baf · release: 26.1.6 ·
    [25.1.6] - 2026-07-13
    
    Fixes
    
    - Fixed excessive logging when DdlCommit could not be applied on a replica.
    - Queries of the form `(a OR b) AND (c OR d) AND (e OR f)...` could grow
      exponentially after DNF conversion. This led to a stack overflow. A limit of
      512 disjunctions has been added; if this limit is exceeded, the DNF is not
      constructed. You may notice this in the `EXPLAIN` output:
      `Query (STORAGE)`. It is recommended to rewrite such queries [picodata!3353].
  • 26.1.5

    protected
    f8070ddd · release: 26.1.5 ·
    [26.1.5] - 2026-07-01
    
    Features
    
    - [picodata#2952] Added the `instance.wal_dir` configuration parameter, which
      sets the directory where WAL files are stored.
    - Extended constant folding: AND/OR identities, identity rules for equality with
      true and inequality with false.
    
    Fixes
    
    - [picodata#3312] Discovery no longer panics on multi-address nodes.
    
  • 26.1.4

    protected
    368c49a4 · release: 26.1.4 ·
    [26.1.4] - 2026-05-28
    
    Fixes
    
    - [picodata#2926] Reduced log verbosity in vshard for routine replicaset events.
    - Vinyl: fix page index min-key corruption in LCP groups
  • 26.1.3

    protected
    83c615e3 · release: 26.1.3 (retag) ·
    [26.1.3] - 2026-05-21
    
    Breaking changes
    
    - `CancellationTokenHandle::cancel()` now returns `Rc<OnceEvent>` instead of
      `Channel<()>`. Use `finish_event.is_finished()` to check completion or
      `finish_event.wait_timeout(duration)` to wait with a timeout.
    - Rename fields in `/api/v1/health/status` response: `reasons` to `issues`,
      status level `unhealthy` to `broken`.
    - `picodata demo` subcommand is now gated behind the `demo` Cargo feature,
      disabled by default. To build with demo, use `CARGO_FLAGS_EXTRA="--features demo"`.
    
    Features
    
    - Improved accuracy of `space:len()` for Vinyl tables.
    - Support `DELETE` statementes inside transactional `DO` blocks.
    - Support `INSERT` statements inside transactional `DO` blocks.
    - [picodata#1596] Added support for `ARRAY` columns in `CREATE TABLE` and
      `ALTER TABLE ADD COLUMN`. Supported syntax: `T[]`, `T[N]`, `T[N][M]`,
      `T[][]`, `T ARRAY`, `T ARRAY[N]`. Declared type and sizes are documentation
      only and do not affect the internal implementation for now.
    
    Fixes
    
    - Fixed crash when disabling a plugin with slow background jobs. Previously,
      if a job didn't finish within the shutdown timeout, the plugin library could
      be unloaded while the job fiber was still running.
    - Fixed the `NO_ROUTE_TO_BUCKET` error that occurred when sending a request to
      the single node of a replicaset during its restart. This error is now retried
      by the router.
    - [picodata#2842] Fixed the `schema version has changed: need to re-compile SQL statement`
      error, which could occur when you execute multiple DQL queries due to
      yield during cache eviction.
    - Fixed sentinel panic on long activation wait.
    - [picodata#2812] Use direct RPC for query metadata on DQL cache miss
      - Replace vshard-based Lua dispatch with ConnectionPool::call_raw for
        the proc_query_metadata callback. This fixes SQL query execution from
        arbiter tier instances (bucket_count=0) where no vshard router exists.
    - [picodata#2888] Fixed a bug where cluster would fail to bootstrap if there were no voter
      instances in the initial `--peer` set.
    - Revoking privileges from `admin` user caused a panic. Now, revoking priviliges
      from `admin` user is forbidden, for same reasons as for the `pico_service` user.
    - Fixed `ALTER PLUGIN ADD SERVICE TO TIER` accepting nonexistent tier names.
      Now validates that the specified tier exists and returns an error otherwise.
    - Backup operation will now be automatically aborted if there are offline instances.
      This prevents cluster being locked in a readonly state.
    - [picodata#2732] Fixed a panic when attempting to inherit privileges via SQL
      (e.g., `GRANT admin TO somebody`). We do not support privilege inheritance
      via `GRANT user1 TO user2`. The system now validates the grantee type and
      returns a proper `NoSuchRole` error instead of panicking.
  • 26.1.2

    protected
    6db4aba0 · release: 26.1.2 ·
    [26.1.2] - 2026-04-14
    
    Changed
    
    - Optimize `/api/v1/tiers` and `/api/v1/cluster` endpoints to reduce RPC calls.
      HTTP addresses are now read from `_pico_peer_address` storage instead of RPC,
      and memory info is only fetched from replicaset leaders. This reduces the
      number of RPC calls from O(N×RF) to O(N) where N is the number of replicasets.
      Offline instances now show their HTTP address (from storage) instead of empty string.
    
    Fixes
    
    - Fixed a SQL planner panic caused by stale type metadata after clone-based
      rewrites such as `BETWEEN` normalization and `GROUP BY` alias expansion.
    - Fixed a bug with the storage cache that caused an error "Temporary table TMP_ not found".
    - Fixed a regression in config parsing. `--iproto-listen`, `--iproto-advertise` and
      `--http-listen` were triggering an error instead of overriding corresponding value
      in yaml config when deprecated listen options were used in the config.
    - Fixed a permission error occured during query planning for non-admin users.
    - Fix cold restart deadlock where all instances in a replicaset would get empty
      replication configs, preventing synchronization. The governor now includes
      only the master in the fallback replication config, preserving conflict
      isolation while allowing the cluster to recover.
    - Fixed the errors `box.cfg.read_only is true` and `Failed to add a storage reference`,
      which occurred when restarting a storage instance and previously required a retry.
    - Fixed the `query for request_id with plan_id not found` error that occurred
      on queries with `UNION` of `CTE` on a cluster consisting of multiple instances.
    - Fixes an issue when http and plugin addresses were inserted into `_pico_peer_address`
      when an instance joined a mixed-version cluster, causing a panic on older instances.
      It is also now not possible to bootstrap an 26.1.x instance defining a plugin listener
      address into a mixed 25.5.x and 26.1.x cluster - cluster has to be fully updated to do that.
  • 26.2.0

    protected
    [26.2.0] - 2026-03-24
    Feature freeze [26.1]
    Start next minor 26.2.0
  • 26.1.1

    protected
    c6c37afb · release: 26.1.1 ·
    [26.1.1] - 2026-03-24
    
    Features
    
    - Unified socket configuration: introduce new `instance.iproto`, `instance.http`,
      and `instance.pgproto` config sections that consolidate listen/advertise/TLS settings
      per protocol. Old top-level parameters (`instance.iproto_listen`,
      `instance.iproto_advertise`, `instance.http_listen`, `instance.pg`) are deprecated
      but remain functional. HTTP server is now enabled by default on port 5327.
      HTTP and pgproto peer addresses are stored in `_pico_peer_address` system table
      with corresponding connection types (`http`, `pgproto`, `plugin:<name>.<service>`).
    - Rework SQL execution protocol for DML queries to reduce data transfer.
    - Support JSON_EXTRACT_PATH function.
    - Introduce non-blocking SQL execution to prevent fiber starvation.
    - New column `sync_incarnation` is added to `_pico_instance` system table.
    - New ALTER SYSTEM parameter `governor_check_replication_error` (default: true)
      enables the checking if replication is broken on any instance, in which case
      the instance will be automatically made Offline.
    - New ALTER SYSTEM parameter `sql_log` (default: false)
      enables logging of all SQL statements to log file.
    - Add CREATE TABLE syntax "PRIMARY KEY (bucket_id, ...)":
      - When this syntax is used, there is no separate 'bucket_id' index;
      - Instead, 'bucket_id' is included as the first part of the primary key index.
    - New columns `target_state_reason` & `target_state_change_time` in `_pico_instance` system table
    - Added env option PICODATA_UNSAFE_FORCE_RECOVERY.
      - Possible values: true, false.
      - This option is passed to Tarantool as `force_recovery` option.
      - If force_recovery equals true, Tarantool tries to continue
        if there is an error while reading a snapshot file (at server instance start)
        or a write-ahead log file (at server instance start or when applying
        an update at a replica.
    - Introduce `read_preference` option for routing DQL queries to replicas in specific scenarios.
    - Introduce `pico_stmt_invalidation` option for getting errors when binding invalid statements.
    - Introduce `pico_query_metadata` option for getting distribution key metadata.
    - Introduce `sql_preemption_opcode_max` to control the VDBE opcode interval
      between execution time checks when `sql_preemption` is enabled.
    - New ALTER SYSTEM parameter `sql_runtime_concurrency_max` (default: `1`)
      limits the number of simultaneously executing SQL requests per instance.
    - Support cluster update to next major version (26.1.0).
    - Support compatibility between the next major Picodata version and older plugin versions.
    - Add support for `EXPLAIN (RAW)` for queries that fail at local sql execution stage.
    - Add unlogged tables to SQL:
      - Unlogged tables' updates are not writeen into the WAL, so they are not persisted on restarts of
        an instance and are not replicated. On leader change, all unlogged tables are truncated to
        prevent inconsistencies. Creating unlogged tables is possible with the `CREATE UNLOGGED TABLE ...`
        syntax. Unlogged tables are implemented as Tarantool data-temporary spaces, so it is not possible to
        store them using the vinyl engine.
    - \[breaking\] Instead of always being a tier with name `default`, default tier is now the first tier mentioned in the config.
    - Add support for `compression_level` Vinyl option for secondary indices created with `CREATE INDEX`.
    - Add support for Vinyl index options (`bloom_fpr`, `page_size`, `range_size`, `run_count_per_level`,
      `run_size_ratio`, `compression_level`) in `CREATE TABLE ... WITH (...)` syntax for configuring
      implicit primary key and bucket_id indices.
    - Add suppoort for anonymous blocks. An anonymous block is a sequence of statements that execute
      queries transactionally. Blocks are single-bucket, meaning that all the queries within the
      block must be executed on the same bucket (or have distribution any).
    - Add optimization for Limit + Distinct and Limit + OrderBy.
      When certain conditions are met, the Limit node is added to the local stage of SQL query plan.
    
      Supported statements are:
      - QUERY: execute the given query;
      - RETURN QUERY: execute the given query and return its result.
    
    - Add detailed health status endpoint (`/api/v1/health/status`) with instance, Raft, bucket, and cluster information.
    - Add support for Kubernetes startup, liveness and readiness probes.
    - Support `bucket_count=0` for tiers. A tier with `bucket_count=0` has no sharded data
      (only global system tables) and is intended for "arbiter" tiers used in Raft consensus.
      Vshard bootstrap and configuration are skipped for such tiers, and replicaset expel
      proceeds without waiting for bucket transfer. Creating sharded tables on a zero-bucket
      tier is rejected with a clear error.
    - Add support for `EXPLAIN (RAW)` for block queries.
    - Speed up instance restart by actively trying to identify the raft leader instead of waiting for it to send a heartbeat to us.
    - Refactor the plan id calculation for more accurate and faster caching.
    - ACL/ALTER SYSTEM/ALTER INDEX RENAME operations now support WAIT APPLIED GLOBALLY / WAIT APPLIED LOCALLY syntax and
      default to globally, matching DDL behavior.
    - Add bucket estimation for INSERT queries in explain.
    - Support reading from global tables in anonymous blocks; writing is not supported yet.
    - Upgrade Tarantool from 2.11.5 to 2.11.8.
    - Add migration context validation API into plugin SDK.
    - Introduce a local SQL execution path for eligible queries that bypasses
      `iproto` on the current instance; usage is exposed via the
      `pico_sql_local_query_total` and `pico_sql_local_query_duration` metrics.
    - Remove unnecessary `Motion(Full)` for queries that are guaranteed to be routed to a single node due to the sharding key filter.
    
    CLI
    
      - Completely re-architected `picodata demo` subcommand:
        - Fixed improper signal handling (SIGINT, SIGTERM) and process termination.
        - Added graceful shutdown and guaranteed cleanup of child processes.
        - Introduced cluster orchestration model for simplified lifecycle management.
        - Added configurable command-line parameters and cluster information display.
        - Add machine-readable output formats to `picodata admin`
        - Add long version output (-VV) with more info
    
    WebUI
    
    - Webui now displays the value of `cluster_version` instead of current
      instance's version. That way you can easily tell if the cluster has been
      upgraded successfully or not yet.
    - the display of the target state in the instance card has been removed
    - the ability to group by replicas has been removed
    - added a visual indication of the problem status for the offline instance counter
    - virtualization has been applied to the tiers and instance list
    - the cluster information is displayed in the header
    - the filter has been redesigned, now it is constantly displayed in front of the list of shooting ranges or instances. Added the ability to filter by text and by tags, such as dash name, replica set name, instance name, version, status.
    
    Fixes
    
    - Fixed that governor would hang indefinitely if an Offline replicaset had
      target_master_name != current_master_name.
    - Fixed that instance would hang indefinitely when trying to join the cluster if
      the cluster becomes too big.
      NOTE: The fix requires modifying the proc_raft_join RPC response format
      which technically breaks compatibility with previous versions of picodata.
      However picodata explicitly doesn't support heterogeneous joins (when version
      of joining instances mismatches version of cluster), so this shouldn't be a
      problem for anybody. NOTE also that this doesn't affect restarting instances
      which already joined the cluster.
    - Fixed a crash when SQL request arrives before instance is properly initialized
    - Fixed that instances would be made Offline immediately after a raft entry is
      applied if there weren't any entries applied for a long time before that
    - Fixed that instances would randomly fail with ER_READONLY during bootstrap
    - Fixed ER_BOOTSTRAP_CONNECTION_NOT_TO_ALL failure during instance join stage.
    - Fixed that governor would send redundant proc_sharding RPCs which would make
      it impossible to deploy huge clusters. Now RPCs from governor are split into
      batches of configurable size (default 200, ALTER SYSTEM parameter `governor_rpc_batch_size`).
    - Improve upgrade flow for creating Lua stored functions (exported to SQL).
    - Node construction is now deferred until actually needed, avoiding unnecessary
      work for cached queries on any instance execution
    - Fixed a memory leak in SQL API of plugin SDK
    - `picodata status` no longer panics when `stdout`, `stderr`,
      or both are redirected to a broken pipe.
    - Fixed that the whole replicaset would be broken if one instance get's a
      replication conflict. (See also https://git.picodata.io/core/picodata/-/issues/2231).
    - Fixed that governor would sometimes be blocked in read_only on a DDL operation
      mode not being able to apply any subsequent raft operations.
    - Introduce unnamed_join alias for motions with joins under them to distinguish columns with identical names
    - Governor RPC batching is also implemented for proc_apply_schema_change.
    - Governor RPC batching is also implemented for proc_apply_backup.
    - Datetime literals should support `yyyy-mm-dd` format, e.g. `select '2026-01-17'::datetime`.
    - Fix type inference for the `a BETWEEN b AND c` expression; now types of `a`, `b` and `c` should be
      properly unified, meanining that `select '2026-01-13' between '2026-01-01'::datetime and '2026-01-20'`
      will work as expected.
    - Fixed that upgrading between patch versions wouldn't run upgrade scripts.
    - Fixed assertion failure in CAS right after raft leader change followed by
      persisted raft log tail truncation.
    - Fixed instance.vinyl.* options to be applied to primary and bucket_id indices.
    - Fixed a crash in proc_runtime_info when the last applied raft entry contained
      a unicode string where a 100th byte position was not on a character boundary.
    - Fixed that sentinel_loop was broken during upgrade from versions before 25.5.3.
    - Fixed ignoring `NULLS FIRST` and `NULLS LAST` in unnamed window queries with ordering.
    - Fixed metadata loss in queries with LIMIT clause in picodata admin.
    - Fixed invalid volatile flag for rust-implemented builtin functions.
    - Fixed governor's `ConfigureReplication` step was broken during upgrade from before 25.5.3
    - Fixed that instances from tiers with can_vote=false attempting to promote to raft leader.
    - Fixed that `--pg-advertise` CLI argument was erroneously disallowed to be used
      simultaneously with `--iproto-advertise`.
    - Fixed a race condition between DDL (i.e., TRUNCATE) and DQL when the preemption option is enabled.
    - Fixed concurrent access to storage temporary tables by synchronizing their lifecycle
      and execution with a per-plan lock.
    - Fixed a number of vinyl issues by backporting upstream patches
    - Fixed an issue where upgrade operations were inserted incorrectly
      when applying system catalog changes for several catalog versions.
    - Fixed `picodata plugin configure` panic on attempt to update non-existent plugin or a non-existing
      service of an existing plugin.
    - Fixed `proposal dropped` errors sometimes being returned from DDL commands for example when raft is unknown.
    - Fixed an RPC to avoid skipping metrics collection code path on early return in procedure implementation.
    - Make sure that single-tiered clusters upgraded from 25.3.x always have a default tier.
    - Fixed that instances would fail with ER_READONLY while joining a replicaset
      whose master was still bootstrapping. Governor no longer triggers mastership
      failover for a master that is in the initial Offline(0) join state and has
      not yet had a chance to become Online.
    - Fixed local SQL iterators to survive fiber yields during table truncation.
    - Fixed a caching bug affecting `UNION` queries with global and sharded tables in a cluster of several replicasets.
    - Fixed a caching bug that caused some different queries to tables with `bucket_id` in the primary key to have the same plan id.
    - Fixed SUM/AVG type resolution for Double
    - Fixed incorrect filter pushdown into compound queries containing window functions.
    
    Observability
    
    - All duration-based metrics now report in fractional seconds instead of
      milliseconds for consistency with Prometheus and more precision.
    - RPC request durations now use a monotonic high-precision clock instead
      of the event-loop clock to improve timing accuracy.
    - Added SQL temp-table lock metrics:
      `pico_sql_temp_table_leases_total` and
      `pico_sql_temp_table_lock_waits_total`.
    
    Breaking changes
    
    - Remove `tros` and `tarolog` dependencies from `picodata-plugin`. These
      libraries can still be used as direct dependencies when needed.
    - Hashing behavior changed for `DOUBLE` type fields in primary keys
      and distribution keys. Previously, values were always re-encoded as MP_DOUBLE
      (9 bytes) before hashing. Now, integer-representable doubles (e.g., `1.0`)
      are converted to integer encoding before hashing, making them hash identically
      to their integer equivalents (e.g., `1`). This is correct behavior that allows
      lookups like `SELECT * FROM t WHERE double_col = 1` to find rows inserted with
      `double_col = 1.0`. However, existing data sharded on `DOUBLE` keys containing
      integer values may have different bucket assignments after upgrade.
    
  • 25.5.9

    protected
    fed09c14 · release: 25.5.9 ·
    [25.5.9] - 2026-03-20
    
    Fixes
    
    - Support cluster update to next major version (26.1.0).
    - Fixed incorrect filter pushdown into compound queries containing window functions.
  • 26.1.0

    protected
    [26.1.0] - 2026-03-19
    Feature freeze [25.5]
    Start next major 26.1.0
  • 25.5.8

    protected
    8947561f · release: 25.5.8 ·
    [25.5.8] - 2026-02-25
    
    Features
    
    - New ALTER SYSTEM parameter `sql_log` (default: false)
      enables logging of all SQL statements to log file.
    - Introduce `sql_preemption_opcode_max` to control the VDBE opcode interval
      between execution time checks when `sql_preemption` is enabled.
    - Fixed local SQL iterators to survive fiber yields during table truncation.
    
    Fixes
    
    - Fixed that `--pg-advertise` CLI argument was erroneously disallowed to be used
      simultaneously with `--iproto-advertise`.
    - Fixed an issue where upgrade operations were inserted incorrectly
      when applying system catalog changes for several catalog versions.
  • 25.5.7

    protected
    b254d360 · release: 25.5.7 ·
    [25.5.7] - 2026-02-10
    
    Fixes
    
    - Fixed a number of vinyl issues by backporting upstream patches
  • 25.5.6

    protected
    14c64653 · release: 25.5.6 ·
    [25.5.6] - 2026-02-06
    
    WebUI
    - Webui now displays the value of `cluster_version` instead of current
      instance's version. That way you can easily tell if the cluster has been
      upgraded successfully or not yet.
    
    Fixes
    
    - Fixed governor's `ConfigureReplication` step was broken during upgrade from before 25.5.3
    - Fixed that instances from tiers with can_vote=false attempting to promote to raft leader.
    - Fixed a crash in case of any error during TRUNCATE operation.
    - Fixed a race condition between DDL (i.e., TRUNCATE) and DQL when the preemption option is enabled.
  • 25.5.5

    protected
    2851d7f3 · release: 25.5.5 ·
    [25.5.5] - 2026-01-26
    
    Fixes
    
    - Fixed assertion failure in CAS right after raft leader change followed by
      persisted raft log tail truncation.
    - Fixed a crash in proc_runtime_info when the last applied raft entry contained
      a unicode string where a 100th byte position was not on a character boundary.
    - Added env option PICODATA_UNSAFE_FORCE_RECOVERY.
      - Possible values: true, false.
      - This option is passed to Tarantool as `force_recovery` option.
      - If force_recovery equals true, Tarantool tries to continue
        if there is an error while reading a snapshot file (at server instance start)
        or a write-ahead log file (at server instance start or when applying
        an update at a replica.
    - Always open vylog files with O_SYNC.
    - Fixed that sentinel_loop was broken during upgrade from versions before 25.5.3.
  • 25.5.4

    protected
    36fbec30 · release: 25.5.4 ·
    [25.5.4] - 2026-01-21
    
    Fixes
    
    - Introduce unnamed_join alias for motions with joins under them to distinguish columns with identical names
    - Fix erroneous logic of counting rows returned from replicasets which led to undercovered limit exceedance
      errors.
    - Fixed that upgrading between patch versions wouldn't run upgrade scripts.
    - Datetime literals should support `yyyy-mm-dd` format, e.g. `select '2026-01-17'::datetime`.
    - Fix type inference for the `a BETWEEN b AND c` expression; now types of `a`, `b` and `c` should be
      properly unified, meanining that `select '2026-01-13' between '2026-01-01'::datetime and '2026-01-20'`
      will work as expected.