home / skills / nevaberry / nevaberry-plugins / postgresql-knowledge-patch
/plugins/postgresql-knowledge-patch/skills/postgresql-knowledge-patch
This skill helps you write PostgreSQL 17+ queries by applying new MERGE, JSON, partitioning, and DDL enhancements across practical examples.
npx playbooks add skill nevaberry/nevaberry-plugins --skill postgresql-knowledge-patchReview the files below or copy the command above to add this skill to your agents.
---
name: postgresql-knowledge-patch
description: This skill should be used when writing PostgreSQL queries, using MERGE, JSON functions, logical replication, partitioning, or any PostgreSQL features from 17+ (2024-2026).
license: MIT
metadata:
author: Nevaberry
version: "18.1"
---
# PostgreSQL 17+ Knowledge Patch
Claude's baseline knowledge covers PostgreSQL through 16. This skill provides features from 17 (Sep 2024) onwards.
**Source**: PostgreSQL release notes at https://www.postgresql.org/docs/release/
## PostgreSQL 17 (Sep 2024)
### SQL/JSON (Major)
| Function | Purpose | Example |
|----------|---------|---------|
| `JSON_TABLE()` | JSON → table rows | `FROM JSON_TABLE(data, '$.items[*]' COLUMNS (id int PATH '$.id'))` |
| `JSON()` | Cast text → json | `JSON('{"a":1}')` |
| `JSON_SCALAR()` | Scalar → JSON | `JSON_SCALAR(42)` |
| `JSON_SERIALIZE()` | JSON → text | `JSON_SERIALIZE(jsonb_col)` |
| `JSON_EXISTS()` | Path exists? boolean | `JSON_EXISTS(data, '$.key')` |
| `JSON_VALUE()` | Extract scalar as SQL type | `JSON_VALUE(data, '$.key' RETURNING int)` |
| `JSON_QUERY()` | Extract JSON fragment | `JSON_QUERY(data, '$.arr')` |
jsonpath type methods: `.bigint()`, `.boolean()`, `.date()`, `.decimal()`, `.integer()`, `.number()`, `.string()`, `.time()`, `.time_tz()`, `.timestamp()`, `.timestamp_tz()`
### MERGE Enhancements
- `WHEN NOT MATCHED BY SOURCE THEN DELETE/UPDATE` — act on unmatched target rows
- `RETURNING merge_action(), *` — returns 'INSERT'/'UPDATE'/'DELETE' per row
- Works on updatable views
### New SQL Syntax
| Feature | Syntax |
|---------|--------|
| COPY error skip | `COPY t FROM file WITH (ON_ERROR ignore)` |
| Change generated expr | `ALTER TABLE t ALTER COLUMN c SET EXPRESSION AS (expr)` |
| Random in range | `random(1, 100)` — works for int, bigint, numeric |
| Interval infinity | `'infinity'::interval`, `'-infinity'::interval` |
| Session timezone | `timestamp_col AT LOCAL` |
| Optimizer memory | `EXPLAIN (MEMORY)` |
| Serialization cost | `EXPLAIN (SERIALIZE)` |
### New Functions
`to_bin(int)`, `to_oct(int)`, `uuid_extract_version(uuid)`, `uuid_extract_timestamp(uuid)`
### DDL Changes
- Identity columns on partitioned tables (previously unsupported)
- Exclusion constraints on partitioned tables (partition key must use equality)
- `MAINTAIN` privilege for VACUUM/ANALYZE/REINDEX/REFRESH/CLUSTER/LOCK
- `transaction_timeout` GUC — limits total transaction duration
For detailed examples and code samples, consult **`references/postgresql-17.md`**.
## PostgreSQL 18 (Sep 2025)
### Virtual Generated Columns (Major)
Generated columns are now **virtual by default** (computed at read time, no disk storage). Use `STORED` for write-time storage.
```sql
CREATE TABLE t (a int, b int, total int GENERATED ALWAYS AS (a + b)); -- virtual (PG18 default)
CREATE TABLE t (a int, b int, total int GENERATED ALWAYS AS (a + b) STORED); -- stored (PG16-17 behavior)
```
### OLD/NEW in RETURNING (Major)
```sql
UPDATE t SET val = val + 1 RETURNING old.val AS before, new.val AS after;
DELETE FROM t WHERE id = 1 RETURNING old.*;
MERGE INTO t USING s ON t.id = s.id ... RETURNING merge_action(), old.*, new.*;
```
### Temporal Constraints (WITHOUT OVERLAPS)
| Feature | Syntax |
|---------|--------|
| Temporal PK | `PRIMARY KEY (id, range_col WITHOUT OVERLAPS)` |
| Temporal UNIQUE | `UNIQUE (id, range_col WITHOUT OVERLAPS)` |
| Temporal FK | `FOREIGN KEY (id, PERIOD range_col) REFERENCES parent (id, PERIOD range_col)` |
Requires `btree_gist` extension.
### NOT ENFORCED Constraints
```sql
ALTER TABLE t ADD CHECK (val > 0) NOT ENFORCED;
ALTER TABLE t ADD FOREIGN KEY (x) REFERENCES r NOT ENFORCED;
```
### New Functions
| Function | Purpose | Example |
|----------|---------|---------|
| `uuidv7()` | Timestamp-ordered UUID | `SELECT uuidv7()` |
| `casefold(text)` | Unicode case folding | `casefold('Straße') = casefold('STRASSE')` |
| `array_sort(anyarray)` | Sort array | `array_sort(ARRAY[3,1,2])` → `{1,2,3}` |
| `array_reverse(anyarray)` | Reverse array | `array_reverse(ARRAY[1,2,3])` → `{3,2,1}` |
| `crc32(bytea)` | CRC32 checksum | `crc32('hello'::bytea)` |
| `crc32c(bytea)` | CRC32C checksum | `crc32c('hello'::bytea)` |
### Data Type Changes
- **jsonb null casting**: `('null'::jsonb)::int` → `NULL` (was error pre-18)
- **Integer ↔ bytea casting**: `255::int2::bytea` → `\x00ff`, `'\x00ff'::bytea::int2` → `255`
- `json{b}_strip_nulls(json, strip_in_arrays)` — optional array null stripping
### New SQL Syntax
| Feature | Syntax |
|---------|--------|
| COPY reject limit | `COPY t FROM file WITH (ON_ERROR ignore, REJECT_LIMIT 100)` |
| VACUUM only parent | `VACUUM (ONLY) partitioned_table` |
| ANALYZE only parent | `ANALYZE (ONLY) partitioned_table` |
### Breaking Changes
- `EXPLAIN ANALYZE` now auto-includes `BUFFERS` output
- `initdb` enables data checksums by default (`--no-data-checksums` to disable)
- `COPY FROM` CSV no longer treats `\.` as EOF marker
- Generated columns default to virtual (not stored)
- NOT NULL constraints now in `pg_constraint`, can have names
For detailed examples and code samples, consult **`references/postgresql-18.md`**.
## Reference Files
For extended documentation with full code examples:
- **`references/postgresql-17.md`** — JSON_TABLE, SQL/JSON functions, MERGE, COPY ON_ERROR, and more with detailed usage examples
- **`references/postgresql-18.md`** — Virtual generated columns, OLD/NEW in RETURNING, temporal constraints, NOT ENFORCED constraints, and more with detailed usage examples
This skill provides an up-to-date reference for PostgreSQL features introduced in versions 17 and 18 (2024–2025). It focuses on new SQL/JSON features, MERGE enhancements, DDL/DDL-level changes, virtual generated columns, temporal and NOT ENFORCED constraints, and new utility functions. Use it to write accurate queries and DDL that rely on post-16 behavior changes and new syntax.
The skill summarizes the practical behavior, syntax, and examples of new PostgreSQL functions and language changes. It highlights JSON_TABLE and the expanded SQL/JSON function set, MERGE return values and new match actions, virtual generated columns, OLD/NEW in RETURNING, temporal constraints, and useful helper functions like uuidv7() and casefold(). It calls out breaking changes and new configuration options so you can adapt queries and migrations.
Will generated columns created before PG18 become virtual after upgrade?
No. Columns already created with STORED semantics remain stored. New default is virtual for columns created after PG18 unless STORED is specified.
How do I detect which rows MERGE inserted vs updated vs deleted?
Use RETURNING merge_action(), * which returns 'INSERT', 'UPDATE', or 'DELETE' per row along with row data.