From 29a03d43748e61b2541d072bde529e8a3732874e Mon Sep 17 00:00:00 2001 From: Marko Budiselic Date: Thu, 13 Aug 2026 20:33:02 +0200 Subject: [PATCH 1/2] Add use_case_001 docs --- pages/memgraph-zero/memgql/changelog.mdx | 49 ++++++- .../memgraph-zero/memgql/connect/postgres.mdx | 67 ++++++++++ .../memgraph-zero/memgql/multiple-graphs.mdx | 72 +++++++++- pages/memgraph-zero/memgql/reference.mdx | 27 ++++ pages/memgraph-zero/memgql/schema-file.mdx | 125 +++++++++++++++++- 5 files changed, 334 insertions(+), 6 deletions(-) diff --git a/pages/memgraph-zero/memgql/changelog.mdx b/pages/memgraph-zero/memgql/changelog.mdx index 9a5e80b13..06544150b 100644 --- a/pages/memgraph-zero/memgql/changelog.mdx +++ b/pages/memgraph-zero/memgql/changelog.mdx @@ -5,7 +5,54 @@ description: MemGQL release notes # MemGQL Changelog -## MemGQL v0.1.0 - TODO +## MemGQL v0.10.0 - TODO + +### 🍃 New features & Improvements + +- **Cross-connector edges.** A graph can now declare an edge whose two endpoints + live in *different* backends, with `mappedJoinSource { "fromKey": …, "toKey": … }` + — no backing table on either side; the relationship *is* equality between one + property on each endpoint. A single pattern then traverses the boundary: + `MATCH (c:Component)-[:MANUFACTURED_BY]->(m:Manufacturer)` reads components + from PostgreSQL and manufacturers from Memgraph. This is the only edge form + that works when one endpoint is a native-graph backend, which has no joinable + edge table to point at. `RETURN c, r, m` packs real nodes and a relationship, + so graph clients can draw and expand the result. Under the hood the pattern is + rewritten into the cross-backend join that already ran, so piping, per-part + caching and the local join apply unchanged. See + [Cross-connector edges](/memgraph-zero/memgql/schema-file#cross-connector-edges). +- **JSON / JSONB columns are queryable.** Document columns (PostgreSQL `JSONB`, + MySQL `JSON`, …) map two composable ways. A **declared path** pins a value + inside the document to its own typed property + (`{ "name": "voltage", "column": "props", "path": "electrical.voltage", "type": "Double" }`), + so `WHERE c.voltage > 240` pushes down as an extraction cast to that type — the + cast is what keeps the comparison numeric instead of text, where `'90' > '240'`. + **Passthrough** (`{ "name": "props", "type": "Json" }`) keeps the column a + document: it returns as a map and *undeclared* keys stay reachable as + `c.props.rohs`, each pushed down as an extraction, for heterogeneous blobs that + can't be declared up front. Supported on PostgreSQL, MySQL, DuckDB, SQL Server, + Microsoft Fabric and Snowflake; a mapping declaring a `path` against any other + connector fails to load rather than failing every query. Writing *through* a + path is refused rather than clobbering the surrounding document. See + [JSON / JSONB columns](/memgraph-zero/memgql/schema-file#json--jsonb-columns). +- **TLS for PostgreSQL connections.** The mode stays in the connection URI + (`sslmode=`, libpq semantics), and the connector declares what a URI cannot + express: `sslRootCert` (a PEM bundle to trust instead of the system roots) and + `trustServerCertificate` (encrypt without verifying the server — an escape + hatch for managed instances behind a mismatched certificate, warned about on + every use). Implemented with rustls, so there's no OpenSSL to install. + Declaring TLS settings alongside `sslmode=disable` is refused rather than + silently connecting in plaintext, and the two trust options are mutually + exclusive. Both survive an `EXPORT SCHEMA` round-trip. See + [TLS connections](/memgraph-zero/memgql/connect/postgres#tls-connections). +- **`SHOW STATS` reports query load per source.** One row per connector with + `queries`, `rows`, `errors`, `avg_latency_ms` and `max_latency_ms` — what the + *source* saw, so the load a federated query puts on a production backend can be + estimated before rollout. Latency covers the statement *and* the fetch of its + rows, in fractional milliseconds. `RESET STATS` zeroes the counters, so a single + query can be measured in isolation. Cache efficacy stays in `SHOW GRAPH CACHES`, + which is keyed by graph rather than connector. See + [Load per source](/memgraph-zero/memgql/multiple-graphs#load-per-source). ## MemGQL v0.9.0 - August 9th, 2026 diff --git a/pages/memgraph-zero/memgql/connect/postgres.mdx b/pages/memgraph-zero/memgql/connect/postgres.mdx index bc6b8e4dc..9d98c7032 100644 --- a/pages/memgraph-zero/memgql/connect/postgres.mdx +++ b/pages/memgraph-zero/memgql/connect/postgres.mdx @@ -90,6 +90,73 @@ MATCH (a:Person)-[:KNOWS]->(b:Person) RETURN a.name, b.name; For environment variables, see [Reference](../reference.mdx#postgresql-postgres). +## TLS connections + +For a cloud-hosted PostgreSQL, the connection **mode** goes in the connection +string as libpq's `sslmode=`, and the connector declares what a URI cannot +express — which certificates to trust: + +```json +{ + "name": "pg", + "type": "postgres", + "connection": { + "uri": "postgresql://user:pass@db.example.com:5432/app?sslmode=require", + "sslRootCert": "/etc/ssl/certs/customer-ca.pem", + "trustServerCertificate": false + } +} +``` + +| Field | Description | +|-------|-------------| +| `sslmode=` (in `uri`) | libpq semantics, including the default: `disable` never attempts TLS, `prefer` uses it when it works, `require` makes it mandatory. | +| `sslRootCert` | Path to a PEM bundle of CA certificates to trust **instead of** the system roots. Omit it to use the system trust store. | +| `trustServerCertificate` | Encrypt without verifying the server's identity. | + +TLS is implemented with [rustls](https://github.com/rustls/rustls), so there is +no OpenSSL or other C library to install. + +`trustServerCertificate` protects against passive eavesdropping but **not** +against an active man-in-the-middle, and it logs a warning on every use. It +exists because managed instances are routinely fronted by a certificate that +doesn't match the hostname you dial; prefer `sslRootCert` where you can. The two +are mutually exclusive — a CA bundle plus "trust anything" is a contradiction +and is rejected. + +Two more guardrails: + +- Declaring TLS settings alongside `sslmode=disable` is **refused** rather than + silently connecting in plaintext. +- Under `sslmode=prefer`, a failed handshake retries in plaintext and warns — so + enabling TLS support doesn't strand a connector pointed at a server whose + certificate you have no reason to trust. A connector that *declared* + `sslRootCert` or `trustServerCertificate` never falls back; it named a trust + anchor, so the failure is an error. Under `require` it is always an error. + +These fields round-trip through `EXPORT SCHEMA`, so a dumped and reloaded +catalog reconnects with the same trust settings. + +## JSONB columns + +A `JSONB` column can be mapped as typed properties at fixed paths, or passed +through as a document whose undeclared keys stay queryable: + +```json +"attributes": [ + { "name": "voltage", "column": "props", "path": "electrical.voltage", "type": "Double" }, + { "name": "props", "type": "Json" } +] +``` + +```gql +MATCH (c:Component) WHERE c.voltage > 100 RETURN c.sku, c.props.rohs; +``` + +Both forms push the extraction down to PostgreSQL, and a declared `type` makes +the comparison numeric instead of lexicographic. See +[Schema File → JSON / JSONB columns](/memgraph-zero/memgql/schema-file#json--jsonb-columns). + ## Supported GQL features | Feature | Postgres | diff --git a/pages/memgraph-zero/memgql/multiple-graphs.mdx b/pages/memgraph-zero/memgql/multiple-graphs.mdx index 56d929878..df6a81299 100644 --- a/pages/memgraph-zero/memgql/multiple-graphs.mdx +++ b/pages/memgraph-zero/memgql/multiple-graphs.mdx @@ -140,8 +140,10 @@ follow-up read routes without needing a `REFRESH SCHEMA`. - A graph bound to a **non-default remote database** (Memgraph multi-tenancy) is fenced to explicit `USE`; per-tenant introspection isn't wired up yet. - A **single `MATCH` pattern that spans two backends** errors with guidance to - split it into one `MATCH` clause per graph; auto-splitting one pattern is out - of scope. + split it into one `MATCH` clause per graph — unless the link between them is + declared as a + [cross-connector edge](#traversing-across-backends-with-an-edge), which is + split automatically. - A label-less `MATCH (n)` against a SQL backend still surfaces a raw backend error (there's nothing to route or translate by). @@ -255,6 +257,46 @@ or without it. It engages for backends registered as catalog graphs locally. If the selective side matches nothing, the other backend is never queried. +### Traversing across backends with an edge + +The joins above are written as predicates over two query parts. A graph can +instead declare the link as a **cross-connector edge**, so the same join is +traversed as one pattern: + +```json +{ + "label": "MANUFACTURED_BY", + "from": "Component", + "to": "Manufacturer", + "mappedJoinSource": { "fromKey": "manufacturer_code", "toKey": "code" } +} +``` + +With `Component` mapped to PostgreSQL and `Manufacturer` to Memgraph, one +`MATCH` now spans both: + +```gql +-- Instead of: USE pg_graph MATCH (c:Component) USE mg_graph MATCH (m:Manufacturer) +-- WHERE c.manufacturer_code = m.code +MATCH (c:Component)-[:MANUFACTURED_BY]->(m:Manufacturer) +WHERE c.voltage > 100 +RETURN c.sku, m.name; +``` + +MemGQL rewrites the pattern into the federated join described above — one part +per connector plus the join equality — so piping, per-part caching and the local +join all apply unchanged. Returning whole elements works too, which is what a +graph client needs to draw and expand the result: + +```gql +MATCH (c:Component)-[r:MANUFACTURED_BY]->(m:Manufacturer) RETURN c, r, m; +``` + +The edge must be traversed in a direction, matched by a single `MATCH` with one +path pattern, and carries no properties of its own. See +[Schema File → Cross-connector edges](/memgraph-zero/memgql/schema-file#cross-connector-edges) +for the full rules. + ## Composite Queries Across Graphs The GQL standard defines composite expressions combining query branches with `UNION`, `INTERSECT`, and `EXCEPT`. Each branch can target a different graph. @@ -367,6 +409,32 @@ SHOW GRAPH social; mode). To see what each one actually *defines* (the labels, relationship types, and properties used for routing), use [`SHOW SCHEMA`](#schema-discovery). +### Load per source + +Federated queries fan out to several backends, so it helps to know how much each +one is actually being asked to do. `SHOW STATS` reports that per connector: + +```gql +RESET STATS; +MATCH (c:Component)-[:MANUFACTURED_BY]->(m:Manufacturer) RETURN c.sku, m.name; +SHOW STATS; +``` + +``` ++--------+---------+------+--------+----------------+----------------+ +| source | queries | rows | errors | avg_latency_ms | max_latency_ms | ++--------+---------+------+--------+----------------+----------------+ +| mg | 1 | 2 | 0 | 6.42 | 6.42 | +| pg | 1 | 4 | 0 | 9.18 | 9.18 | ++--------+---------+------+--------+----------------+----------------+ +``` + +Counts are what each **source** saw: statements dispatched to it and rows it +returned. `RESET STATS` zeroes the counters, so one query's cost on a production +backend can be measured in isolation. Cache hits and misses are keyed by graph +rather than connector and live in +[`SHOW GRAPH CACHES`](#caching-a-graph-in-memgraph). + ## Graph Lifecycle Management ### Creating graphs diff --git a/pages/memgraph-zero/memgql/reference.mdx b/pages/memgraph-zero/memgql/reference.mdx index b73db1c90..9c4fd5b00 100644 --- a/pages/memgraph-zero/memgql/reference.mdx +++ b/pages/memgraph-zero/memgql/reference.mdx @@ -174,7 +174,34 @@ SHOW MAPPINGS; -- per-graph mappings SHOW SCHEMA [FOR ]; -- unified routing index: labels, rel-types, properties EXPORT SCHEMA [TO '']; -- merged catalog as canonical schema JSON (round-trippable) REFRESH SCHEMA; -- re-introspect live Cypher connections (Memgraph/Neo4j) + +-- Query load per source +SHOW STATS; -- source, queries, rows, errors, avg_latency_ms, max_latency_ms +RESET STATS; -- zero the counters +``` + +`SHOW STATS` reports what each **source** saw — statements MemGQL dispatched to +it and rows it returned — so the load federation puts on a production backend +can be measured before rollout: + ``` ++--------+---------+------+--------+----------------+----------------+ +| source | queries | rows | errors | avg_latency_ms | max_latency_ms | ++--------+---------+------+--------+----------------+----------------+ +| mg | 3 | 6 | 0 | 6.42 | 11.03 | +| pg | 3 | 12 | 0 | 9.18 | 18.55 | ++--------+---------+------+--------+----------------+----------------+ +``` + +Latency covers a whole query — the statement *and* the fetch of its rows — and +is reported in fractional milliseconds, since a healthy local source answers in +hundreds of microseconds. `max_latency_ms` sits next to the average because an +average hides the tail that shows up as a load problem. `RESET STATS` zeroes the +counters, so a single query's cost can be measured in isolation. + +Counters are keyed by connector. **Cache** efficacy is keyed by graph and lives +in [`SHOW GRAPH CACHES`](/memgraph-zero/memgql/multiple-graphs#caching-a-graph-in-memgraph) +(hits, misses, resident fragments). ``` -- Single graph diff --git a/pages/memgraph-zero/memgql/schema-file.mdx b/pages/memgraph-zero/memgql/schema-file.mdx index 011413d97..948c5eb4b 100644 --- a/pages/memgraph-zero/memgql/schema-file.mdx +++ b/pages/memgraph-zero/memgql/schema-file.mdx @@ -139,10 +139,17 @@ Every `connection` field is optional; supply what a given backend needs: | `schema` | Middle namespace (PostgreSQL schema, MySQL / ClickHouse database, Iceberg schema). | | `catalog` | Native root for three-level backends (Iceberg catalog, SQL Server database, Fabric warehouse/lakehouse item). | | `path` | File-backed backends (DuckDB). | +| `sslRootCert` | PEM bundle of CA certificates to trust instead of the system roots (PostgreSQL). | +| `trustServerCertificate` | Encrypt without verifying the server's certificate (PostgreSQL). Mutually exclusive with `sslRootCert`. | **Supported `type` values:** `memgraph`, `neo4j`, `postgres` (`postgresql`), `mysql`, `sqlserver`, `oracle`, `duckdb`, `iceberg`, `iceberg-direct`, -`clickhouse`, `pinot`, `fabric`. +`clickhouse`, `pinot`, `snowflake`, `mongodb`, `fabric`. + +For PostgreSQL, the TLS **mode** stays in the URI (`sslmode=`), where libpq +users expect it; `sslRootCert` / `trustServerCertificate` declare what a URI +cannot express. See +[TLS connections](/memgraph-zero/memgql/connect/postgres#tls-connections). ## `graphs` @@ -231,7 +238,9 @@ A vertex maps a **label** to a backend source. Exactly one source kind is set: An edge maps a **relationship type** between two labels. Relational edges name the foreign-key columns via `metaFields.from` / `metaFields.to`; native-graph -edges pass through. +edges pass through; and a `mappedJoinSource` edge links two labels that live in +**different connectors** (see [Cross-connector edges](#cross-connector-edges)). +Exactly one source kind is set. ```json { @@ -280,6 +289,68 @@ A relational edge adds two more `metaFields` on top of `id`: missing. Native-graph edges (`mappedGraphSource`) need only `from` / `to` labels; the traversal is resolved by the backend. +#### Cross-connector edges + +A third source kind, `mappedJoinSource`, declares an edge whose two endpoints +live in **different connectors**. It has no backing table anywhere: the +relationship *is* equality between one property on each endpoint. + +```json +{ + "label": "MANUFACTURED_BY", + "from": "Component", + "to": "Manufacturer", + "mappedJoinSource": { + "fromKey": "manufacturer_code", + "toKey": "code" + } +} +``` + +With `Component` mapped to a PostgreSQL table and `Manufacturer` to a Memgraph +connector, one pattern now traverses the boundary: + +```gql +MATCH (c:Component)-[:MANUFACTURED_BY]->(m:Manufacturer) RETURN c.sku, m.name; +``` + +| `mappedJoinSource` key | Description | +|------------------------|-------------| +| `fromKey` | Property on the `from` vertex. A **GQL property name**, not a raw column; it resolves through that vertex's own mapping. | +| `toKey` | Property on the `to` vertex, resolved the same way. | + +This is the only edge form that works when one endpoint is a native-graph +backend, which has no joinable edge table to point at. Under the hood the +traversal is rewritten into the +[cross-backend join](/memgraph-zero/memgql/multiple-graphs#focused-multi-graph-queries) +that already runs — one part per connector plus the join equality — so piping, +per-part caching and the local join all apply unchanged. + +`RETURN c, r, m` packs real nodes and a relationship, so graph clients such as +Memgraph Lab can draw and expand the result. Element ids are synthesized from +the connector, label and key, so two backends that both number rows from `1` +don't collide. + +**Rules and limits** (each is refused with a message saying what to write +instead): + +- Both endpoints must live in different connectors — within one connector use + `mappedTableSource` with `metaFields.from` / `to`. +- Each key must be a declared `attribute` of its endpoint vertex (native-graph + vertices are exempt, since the query passes through). +- The edge must be traversed **in a direction**: `-[:R]->` or `<-[:R]-`, not + `-[:R]-`. +- No variable-length traversal, no `OPTIONAL MATCH`, and one `MATCH` with one + path pattern per query. +- The edge carries no properties, so it cannot be filtered — filter the + endpoints instead. +- Every node in the pattern needs a label, so each side can be routed. +- Aggregating *across* the join (for example `count()` over both sides) is not + supported yet; return the rows and count client-side. + +A **table-backed** edge whose endpoints sit in different connectors is still +skipped at load time with a warning pointing at `mappedJoinSource`. + ### Attributes `attributes` declare the properties a label exposes. @@ -289,9 +360,57 @@ labels; the traversal is resolved by the backend. | `name` | yes | The GQL property name. | | `column` | no | The backing column (defaults to `name`), e.g. property `name` ← column `full_name`. | | `type` | no | Recorded, not enforced at query time (default `String`). | +| `path` | no | Location inside a JSON document column (see below). | Allowed `type` values: `Boolean`, `Byte`, `Short`, `Int`, `Long`, `HugeInt`, -`Float`, `Double`, `Decimal`, `String`, `Date`, `DateTime`. +`Float`, `Double`, `Decimal`, `String`, `Date`, `DateTime`, `Json`. + +#### JSON / JSONB columns + +A document column (PostgreSQL `JSONB`, MySQL `JSON`, …) can be mapped two ways, +and they compose — use both on the same column. + +**Declared path.** Pin a value inside the document to its own typed property. +`column` names the document column, `path` the location inside it, and `type` +the type of the value found there: + +```json +{ + "name": "voltage", + "column": "props", + "path": "electrical.voltage", + "type": "Double" +} +``` + +```gql +MATCH (c:Component) WHERE c.voltage > 240 RETURN c.voltage; +``` + +pushes down to the source as an extraction cast to the declared type. The cast +is what makes the comparison numeric — without it the database compares text, +where `'90' > '240'`. `path` is a dotted string; for keys that themselves +contain a dot, write an explicit segment list: `"path": ["spec.v2", "voltage"]`. + +**Passthrough.** Mark the column `Json` and it stays a document: `RETURN +c.props` returns a map, and **undeclared** keys are reachable with ordinary +property syntax — `c.props.rohs`, `c.props.electrical.voltage` — each pushed +down as an extraction on the source. This is the option for heterogeneous blobs +where declaring every key up front isn't possible. An undeclared key carries no +declared type, so the comparison supplies one: compared against a number it is +cast like a declared numeric path, compared against a string it stays text. A +key the document doesn't have reads as `null` rather than failing the query. + +```json +{ "name": "props", "type": "Json" } +``` + +**Limits.** `path` attributes are read-only — an `INSERT` through a JSON path is +rejected rather than clobbering the surrounding document. JSON path support is +per backend: PostgreSQL, MySQL, DuckDB, SQL Server, Microsoft Fabric and +Snowflake. A mapping that declares a `path` against any other connector fails to +load, so the mismatch surfaces at boot / `CREATE GRAPH` rather than on every +query. `attributes` are optional and need not be exhaustive: a property you don't list still resolves to a same-named column at query time (`p.sku` → column `sku`). From ee4bed55f8ed0f2babafc36c3e9f676a008262f3 Mon Sep 17 00:00:00 2001 From: Marko Budiselic Date: Thu, 13 Aug 2026 20:35:27 +0200 Subject: [PATCH 2/2] Adjust the changelog --- pages/memgraph-zero/memgql/changelog.mdx | 63 +++++++++--------------- 1 file changed, 23 insertions(+), 40 deletions(-) diff --git a/pages/memgraph-zero/memgql/changelog.mdx b/pages/memgraph-zero/memgql/changelog.mdx index 06544150b..a5abc6d78 100644 --- a/pages/memgraph-zero/memgql/changelog.mdx +++ b/pages/memgraph-zero/memgql/changelog.mdx @@ -9,49 +9,32 @@ description: MemGQL release notes ### 🍃 New features & Improvements -- **Cross-connector edges.** A graph can now declare an edge whose two endpoints - live in *different* backends, with `mappedJoinSource { "fromKey": …, "toKey": … }` - — no backing table on either side; the relationship *is* equality between one - property on each endpoint. A single pattern then traverses the boundary: - `MATCH (c:Component)-[:MANUFACTURED_BY]->(m:Manufacturer)` reads components - from PostgreSQL and manufacturers from Memgraph. This is the only edge form - that works when one endpoint is a native-graph backend, which has no joinable - edge table to point at. `RETURN c, r, m` packs real nodes and a relationship, - so graph clients can draw and expand the result. Under the hood the pattern is - rewritten into the cross-backend join that already ran, so piping, per-part - caching and the local join apply unchanged. See +- **Cross-connector edges.** An edge declared with + `mappedJoinSource { "fromKey": …, "toKey": … }` links two labels in *different* + backends, so one pattern traverses the boundary: + `MATCH (c:Component)-[:MANUFACTURED_BY]->(m:Manufacturer)` reads components from + PostgreSQL and manufacturers from Memgraph. `RETURN c, r, m` packs real nodes and + a relationship, so graph clients can draw and expand the result. See [Cross-connector edges](/memgraph-zero/memgql/schema-file#cross-connector-edges). -- **JSON / JSONB columns are queryable.** Document columns (PostgreSQL `JSONB`, - MySQL `JSON`, …) map two composable ways. A **declared path** pins a value - inside the document to its own typed property - (`{ "name": "voltage", "column": "props", "path": "electrical.voltage", "type": "Double" }`), - so `WHERE c.voltage > 240` pushes down as an extraction cast to that type — the - cast is what keeps the comparison numeric instead of text, where `'90' > '240'`. - **Passthrough** (`{ "name": "props", "type": "Json" }`) keeps the column a - document: it returns as a map and *undeclared* keys stay reachable as - `c.props.rohs`, each pushed down as an extraction, for heterogeneous blobs that - can't be declared up front. Supported on PostgreSQL, MySQL, DuckDB, SQL Server, - Microsoft Fabric and Snowflake; a mapping declaring a `path` against any other - connector fails to load rather than failing every query. Writing *through* a - path is refused rather than clobbering the surrounding document. See +- **JSON / JSONB columns are queryable.** An attribute can declare a `path` into a + document column (`"column": "props", "path": "electrical.voltage", "type": "Double"`), + giving it its own typed property; or type the column `Json`, which returns it as a + map and keeps *undeclared* keys reachable as `c.props.rohs`. Both push the + extraction down to the source, and a declared type keeps comparisons numeric + rather than lexicographic. PostgreSQL, MySQL, DuckDB, SQL Server, Microsoft + Fabric and Snowflake. See [JSON / JSONB columns](/memgraph-zero/memgql/schema-file#json--jsonb-columns). -- **TLS for PostgreSQL connections.** The mode stays in the connection URI - (`sslmode=`, libpq semantics), and the connector declares what a URI cannot - express: `sslRootCert` (a PEM bundle to trust instead of the system roots) and - `trustServerCertificate` (encrypt without verifying the server — an escape - hatch for managed instances behind a mismatched certificate, warned about on - every use). Implemented with rustls, so there's no OpenSSL to install. - Declaring TLS settings alongside `sslmode=disable` is refused rather than - silently connecting in plaintext, and the two trust options are mutually - exclusive. Both survive an `EXPORT SCHEMA` round-trip. See +- **TLS for PostgreSQL connections.** The mode stays in the URI (`sslmode=`, libpq + semantics); the connector adds `sslRootCert` (PEM bundle to trust instead of the + system roots) and `trustServerCertificate` (encrypt without verifying the server). + Built on rustls, so there's no OpenSSL to install. Declaring TLS settings + alongside `sslmode=disable` is refused rather than silently connecting in + plaintext. See [TLS connections](/memgraph-zero/memgql/connect/postgres#tls-connections). -- **`SHOW STATS` reports query load per source.** One row per connector with - `queries`, `rows`, `errors`, `avg_latency_ms` and `max_latency_ms` — what the - *source* saw, so the load a federated query puts on a production backend can be - estimated before rollout. Latency covers the statement *and* the fetch of its - rows, in fractional milliseconds. `RESET STATS` zeroes the counters, so a single - query can be measured in isolation. Cache efficacy stays in `SHOW GRAPH CACHES`, - which is keyed by graph rather than connector. See +- **`SHOW STATS` reports query load per source.** One row per connector — + `queries`, `rows`, `errors`, `avg_latency_ms`, `max_latency_ms` — counting what + the source itself saw, so federation's impact on a production backend can be + measured. `RESET STATS` zeroes the counters. See [Load per source](/memgraph-zero/memgql/multiple-graphs#load-per-source). ## MemGQL v0.9.0 - August 9th, 2026