Skip to content

Known Limitations

This page lists behaviour that differs from PostgreSQL (or from what the rest of these docs might lead you to expect) in the current release, plus what the latest release fixed. Every open item links to its public issue on HeliosDatabase/HeliosDB-Nano, which is where status updates land first.


Recently fixed

If you worked around any of these on an earlier release, the workaround is no longer needed on the current release:

  • Read-your-own-writes in UPDATE / DELETE. Inside BEGIN … COMMIT, an UPDATE or DELETE now sees rows INSERTed earlier in the same transaction (the create-then-patch pattern ORMs emit). Previously it reported 0 rows affected and the change was lost. (#41) Transactions on a database branch still do not see their own branch writes from UPDATE/DELETE.
  • CALL inside a transaction. A procedure body invoked with CALL inside BEGIN now runs in that transaction and is undone by ROLLBACK; previously its writes committed immediately.
  • Savepoints. A savepoint belongs to the transaction that created it, is cleared at COMMIT/ROLLBACK, and SAVEPOINT / RELEASE / ROLLBACK TO SAVEPOINT work over the extended query protocol. Naming a savepoint not established in the current transaction raises 3B001.
  • CREATE TEMPORARY TABLE. Temporary tables are now private to the session that creates them and are dropped when it ends. Previously they were created as permanent, globally visible tables.
  • Session-less statements and the embedded transaction. A wire, REST or MCP statement executed without a session can no longer run inside, commit, or roll back a transaction opened by the embedding application; it is refused with No active transaction to commit. POST /v1/branches/:name/execute refuses transaction-control statements.
  • Multiple databases in one process. Advisory locks (pg_advisory_lock), pg_stat_activity, MCP SSE sessions and join_memory_limit_mb are scoped per open database. Within one database, pg_stat_activity masks client_addr, client_port, state, backend_start and state_change for backends owned by another login role, as PostgreSQL does.

Open issues

Concurrency

  • Concurrent UPDATE … SET n = n + 1 on one row can lose increments. Under the default READ COMMITTED, concurrent autocommit read-modify-write updates of the same row can each report success while some increments are lost, and no 40001 is raised. (#50) Until fixed, serialise such updates in the application (for example with pg_advisory_lock around the update, or a single writer) rather than relying on the database to merge them.
  • See Concurrency and Transactions for the embedded-mode transaction model (one transaction slot per process) and the isolation levels actually served.

SQL behaviour

  • NULLS FIRST / NULLS LAST are accepted but ignored. (#43) Workaround: ORDER BY CASE WHEN col IS NULL THEN 1 ELSE 0 END, col.
  • ORDER BY after GROUP BY cannot reference a select-list alias mixed with a grouped column, or repeat an aggregate; the error names internal placeholders such as agg_0 / group_N. (#44) Workaround: order by select-list position (ORDER BY 3 DESC, 2 ASC).
  • setval() returns its argument but does not move the sequence. (#51)
  • A boolean function whose argument is a bound parameter is returned as text ('t'/'f'), e.g. pg_try_advisory_lock($1). (#52)
  • CREATE INDEX on an expression is rejected. (#34)
  • ::vector cast on a bound parameter fails; only inline literals work. (#33)
  • LISTEN / NOTIFY / pg_notify are not implemented; clients must poll. (#40)
  • Trigger bodies do not execute, apart from BEFORE INSERT … FOR EACH ROW functions that only assign NEW.<col> or RETURN NULL. Do not rely on triggers for audit rows or derived data; use a second statement in the same transaction or a procedure invoked with CALL.
  • SQLite-style TEXT DEFAULT CURRENT_TIMESTAMP stores a quoted ISO value that differs from SQLite. (#39)

Driver and ORM compatibility

  • psycopg 3 defaults: a datetime.date bound with %s (binary format) is rejected — use %t; DEALLOCATE ALL is not implemented. (#54)
  • SELECT * FROM current_schema() fails with 42P01, which blocks TypeORM initialisation. (#46)
  • pg_catalog.set_config() is missing, so an unmodified pg_dump script does not restore. (#47)

Databases, roles and security

  • No switch to require TLS. With --tls-cert/--tls-key the PostgreSQL listener offers TLS, but a client that does not request it is still served in plaintext. (#53) To enforce encryption, bind to loopback or a private network and terminate TLS in front of Nano, or require sslmode=require/verify-full on every client.
  • A role created with CREATE ROLE … LOGIN cannot authenticate with SCRAM; the bootstrap postgres user can. (#49)
  • Credentials can only be given on the command line, so --password is visible in the process list. (#38)
  • A CREATE DATABASE registration is lost after restart; the rows remain reachable through the default database. (#48)
  • Offline tools cannot open a data directory encrypted at rest (no key source on that path). (#45)
  • Encryption key rotation is not implemented. AES-256-GCM runs under a single static key with random nonces; very high-volume deployments should track write volume against the 2^32-invocations-per-key bound.
  • The MySQL listener is trust-only: the user name is asserted by the client, not verified. Do not expose --mysql beyond trusted networks.

Realtime

  • Known issue: realtime events are not delivered in the current release; tracked by the Nano team. Subscriptions to /realtime/v1/websocket are accepted, but change events do not arrive. Poll with SQL in the meantime.

Replication, CDC and backup

  • ALTER TABLE … RENAME has no logical-log entry, so replay and CDC consumers can diverge after a rename. (#36)
  • A standby can transiently observe a partially-applied transaction; see Concurrency and Transactions.
  • restore reports Tables: 0, Rows: 0 although the data is restored. (#42)

Planned

These capabilities are described elsewhere in the docs or in older material but are not part of the current release. Each is planned.

  • Row-level security outside the embedded API. In the stock Nano server, row-level security is enforced through the embedded API and the REPL; SQL CREATE POLICY and enforcement for REST and wire clients are planned. The REST API does not apply RLS policies, so enforce per-user access in your service layer. Realtime (WebSocket) subscriptions are not filtered by row-level security; secured realtime is planned.
  • Row-level security for set operations and WITH queries. RLS policies filter table scans, joins, aggregates, sorts and limits; filtering of set operations (UNION/INTERSECT/EXCEPT), WITH queries and table functions is planned.
  • PL/pgSQL control flow and trigger bodies. Nano runs plain-SQL DO blocks and simple SQL/PL/pgSQL functions (SQL statements, SELECT INTO, RETURN); PL/pgSQL control flow (IF, LOOP, WHILE, FOR, RAISE, :=, dynamic EXECUTE) and trigger bodies are planned. See PL/pgSQL for the exact scope.
  • REST filter operators. Nano’s REST filters support eq, neq, gt, gte, lt, lte, like, ilike, is and in, with not. negation; cs, cd, ov, full-text and or/and filters are planned, and the /rest/v1 table routes are a known issue in the current release. Use the PostgreSQL wire protocol for table access in the meantime.
  • Full-text search stemming. tsvector, tsquery, @@, to_tsvector/to_tsquery and ts_rank/ts_rank_cd work, but the text search configuration argument is ignored: language stemming, boolean tsquery operators and phrase/proximity search are planned. Matching today is any-term over lowercase tokens. See Full-text search.
  • Geospatial. Geospatial functions and indexes (ST_DWithin, ST_Distance, geometry types) are planned; they are not in the current release.
  • File storage and edge functions. File storage (buckets and signed URLs) and edge functions are on the HeliosDB roadmap; today Nano serves REST, auth and realtime, and stores data in its data directory.
  • API key authentication for the HTTP API. Keep the HTTP and MySQL listeners on loopback (the default): API-key authentication for the HTTP API is planned, and a smaller listening surface is good practice anyway.
  • Cloud KMS key sources and online key rotation for encryption at rest are planned; keys come from an environment variable or a key file today.
  • MCP, Code-Graph and Graph-RAG in the prebuilt binaries. Code-Graph (hdb_code), Graph-RAG (WITH CONTEXT) and the native MCP server ship in HeliosDB Nano as build-from-source features (--features code-graph,graph-rag,mcp-endpoint); the prebuilt binaries and the container image use the default features and do not include them.

Distribution

  • Prebuilt Linux binaries require glibc 2.39 or newer.
  • A container image is published at ghcr.io/heliosdatabase/heliosdb-nano (one tag per release plus latest, multi-arch amd64/arm64); it contains the default-feature build. Docker Hub is not an official channel.
  • Nano is published on crates.io as heliosdb-nano, with prebuilt binaries for Linux, macOS and Windows on GitHub Releases.
  • The PyPI binding heliosdb-nano-embedded is released separately and can lag the engine release; check PyPI for the published version.
  • The TypeScript client @heliosdb/client is built from the HeliosDB-SDKs source and is not published on npm; Node apps can also use the pg driver over the PostgreSQL wire protocol.

Found something not listed here? Open an issue on GitHub, ask on Discord, or email support@heliosdb.com. Report security issues privately to security@heliosdb.com.