Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/aurora-dsql-mcp-server/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed

- Update `SELECT FOR UPDATE` guidance for non-key predicates and joined tables, locking-clause-targeted OCC conflict checks, supported lock clauses, targeted-row primary-key accounting toward the 10 MiB transaction-size limit, and whole-transaction SQLSTATE `40001` retries.
- Update DSQL steering for PostgreSQL-compatible explicit `NUMERIC(p,s)` bounds: precision 1–1000 and scale -1000–1000, including negative scales and scales greater than precision. Bare `NUMERIC` defaults to `NUMERIC(18,6)`.
- Bump `dsql-lint` dependency to `>=0.2.1,<0.3` and lock to `0.2.6`. `0.2.6` accepts both `JSON` and `JSONB` as stored column types (earlier 0.2.x versions rewrote `JSONB` → `JSON`).
- Steering, skill, and migration guides updated:
Expand Down
2 changes: 1 addition & 1 deletion src/aurora-dsql-mcp-server/kiro_power/POWER.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ This power includes the following steering files in [steering](./steering)
- **pg-migrations-multi-region**
- Load for multi-region, active-active, or HA questions — architecture, geographic partitioning
- **orm-guides-overview**
- Load when migrating any ORM to DSQL — adapter names and gotchas for Django, Hibernate, Rails, SQLAlchemy
- Load when migrating an ORM or using ORM locking with DSQL — adapter names, locking, and gotchas for Django, Hibernate, Rails, SQLAlchemy
- **data-loading**
- Load when planning or running bulk loads with `aurora-dsql-loader` — fresh-vs-warm partitions, resume/retry, `--on-conflict`, throughput diagnostics
- **query-plan-interpretation**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ Aurora DSQL is designed for massive horizontal scale without latency degradation

### Batch Size Optimization

- **PREFER batches of 500-1,000 rows** - Balance throughput and transaction limits (3,000 rows, 10 MiB, 5 minutes max — verify via `awsknowledge`: `aurora dsql transaction limits`)
- **PREFER batches of 500-1,000 rows** - Balance throughput and transaction limits (3,000 row modifications, 10 MiB, 5 minutes max — verify via `awsknowledge`: `aurora dsql transaction limits`)
- **SHOULD process batches concurrently** - Use multiple connections; consider multiple threads for bulk loading
- **Smaller batches reduce** lock contention, enable better concurrency, fail faster, distribute load evenly
- **Smaller batches reduce** OCC conflict surface, enable better concurrency, fail faster, distribute load evenly

### AVOID Hot Keys

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ For the full Table Recreation Pattern and verify & swap steps, see [overview.md]
## Batch Size Rules

- **PREFER batches of 500-1,000 rows** for optimal performance
- Smaller batches reduce lock contention and enable better concurrency
- Smaller batches reduce OCC conflict surface and enable better concurrency

---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ PRIMARY KEY, UNIQUE, FOREIGN KEY, NOT NULL, CHECK, DEFAULT (CREATE TABLE or dire
Verify current limits via `awsknowledge`: `aurora dsql transaction limits`

```
Rows: 3,000 max
Row modifications: 3,000 max
Size: 10 MiB max
Duration: 5 minutes max
Isolation: Repeatable Read (fixed)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ DELETE FROM owner WHERE city = 'Portland';

**Transaction Limits** (verify current limits via `awsknowledge`: `aurora dsql transaction limits`)**:**

- Maximum 3,000 rows per transaction
- Maximum 3,000 row modifications per transaction
- Maximum 10 MiB data size per transaction
- Maximum 5 minutes per transaction

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,32 @@ Django and Rails; EF Core, Hibernate, and SQLAlchemy provide composite relations
| Rails | Standard `pg` gem + `aws-sdk-dsql` | `gem 'pg'` + `gem 'aws-sdk-dsql'` |
| SQLAlchemy | `aurora_dsql_sqlalchemy` | `pip install aurora-dsql-sqlalchemy boto3` |

## SELECT FOR UPDATE

Aurora DSQL does not require equality predicates on every primary-key column for
`SELECT ... FOR UPDATE`; non-key predicates and queries that join multiple tables are supported.
It does not take blocking row locks. Instead, rows targeted by the locking clause participate in
optimistic commit-time conflict checks. If a concurrent transaction changes a targeted row, the
transaction that loses the commit race fails with SQLSTATE `40001`; retry the whole transaction
with backoff. Keep external side effects outside the retried callback or make them idempotent.

The primary key of each row targeted by the locking clause counts toward the 10 MiB
transaction-size limit.

`FOR UPDATE` and `FOR KEY SHARE` are supported. `FOR NO KEY UPDATE` and `FOR SHARE` are not supported.

## Key Gotchas Per Framework

### Django

| Issue | Fix |
| ----------------- | ------------------------------------------------------------------------------- |
| ENGINE | `'aurora_dsql_django'` (not `django.db.backends.postgresql`) |
| CONN_MAX_AGE | ≤ 1800 (DSQL timeout is 1 hour) |
| Migrations | Each DDL in its own migration; `RunSQL("CREATE INDEX ASYNC ...")` |
| SELECT FOR UPDATE | Use when a write depends on rows read; retain whole-transaction OCC retry |
| AutoField | Replace with `UUIDField(primary_key=True, default=uuid.uuid4)` |
| ForeignKey | Keep `ForeignKey`; the DSQL backend creates database constraints for new tables |
| Issue | Fix |
| ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| ENGINE | `'aurora_dsql_django'` (not `django.db.backends.postgresql`) |
| CONN_MAX_AGE | ≤ 1800 (DSQL timeout is 1 hour) |
| Migrations | Each DDL in its own migration; `RunSQL("CREATE INDEX ASYNC ...")` |
| SELECT FOR UPDATE | `select_for_update()` supports non-key filters and joined querysets that use inner joins; retry the whole transaction on SQLSTATE `40001` |
| AutoField | Replace with `UUIDField(primary_key=True, default=uuid.uuid4)` |
| ForeignKey | Keep `ForeignKey`; the DSQL backend creates database constraints for new tables |

### EF Core (.NET)

Expand All @@ -60,19 +74,20 @@ Requires .NET 8.0+, EF Core 9.0.7+, and `Amazon.AuroraDsql.Npgsql` 1.1.0+.
| Dialect | Provided by `aurora-dsql-hibernate-dialect` (auto-registered) |
| ID generation | `@GeneratedValue(strategy = GenerationType.UUID)` |
| OCC retry | Prefer the [aurora-dsql-jdbc-connector](https://github.com/awslabs/aurora-dsql-connectors/tree/main/java/jdbc) — built-in retry for SQLSTATE 40001. For manual `@Retryable`, match on `SQLException` and check `getSQLState() == "40001"` (Hibernate's class-40 mapping varies by version). |
| Locking | `PESSIMISTIC_WRITE` supports non-key predicates and inner-joined queries; it adds commit-time OCC checks rather than blocking row locks |
| FK constraints | Keep normal relationship mappings; the DSQL dialect exports foreign key constraints |
| DDL generation | `hibernate.hbm2ddl.auto = none` — manage DDL manually |

### Rails

| Issue | Fix |
| ---------- | ------------------------------------------------------------------------------------------------------------------- |
| adapter | `postgresql` (standard pg gem) |
| Auth | Custom connection handler generating IAM tokens via `aws-sdk-dsql` |
| Migrations | `disable_ddl_transaction!` in each migration |
| PKs | `id: :uuid` in `create_table` |
| FKs | Use `add_foreign_key ..., validate: false`, then run `ALTER TABLE ASYNC ... VALIDATE CONSTRAINT` and verify the job |
| Locking | Use `lock!` / `with_lock` when a decision depends on rows read; retain OCC retry in `ApplicationRecord` |
| Issue | Fix |
| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| adapter | `postgresql` (standard pg gem) |
| Auth | Custom connection handler generating IAM tokens via `aws-sdk-dsql` |
| Migrations | `disable_ddl_transaction!` in each migration |
| PKs | `id: :uuid` in `create_table` |
| FKs | Use `add_foreign_key ..., validate: false`, then run `ALTER TABLE ASYNC ... VALIDATE CONSTRAINT` and verify the job |
| Locking | Use `Relation#lock` for non-key filters and joins inside a transaction; use `lock!` or `with_lock` for individual persisted records; retry the whole transaction on SQLSTATE `40001` |

### SQLAlchemy

Expand Down
Loading