br-pgsql 0.1.18

This is an pgsql
Documentation
# AGENTS.md

**Generated:** 2026-02-08 | **Commit:** 03fe473 | **Branch:** main

## OVERVIEW

Rust library crate implementing PostgreSQL wire protocol v3 with SCRAM-SHA-256/MD5/cleartext auth. Synchronous API, connection pooling via global static `DB_POOL`. Error type: `PgsqlError` enum (not `String`).

## STRUCTURE

```
br-pgsql/
├── src/
│   ├── lib.rs       # API surface: Pgsql struct, connect(), pools()
│   ├── config.rs    # Config struct, defaults, URL assembly, hostport validation
│   ├── connect.rs   # TCP lifecycle, startup/auth, query/execute, read() with retry
│   ├── packet.rs    # Wire protocol pack/unpack (2411 lines, largest)
│   ├── pools.rs     # Pools, ConnectionGuard, lazy pool, retry logic
│   ├── format.rs    # OID→JsonValue type conversion, PG array parsing
│   └── error.rs     # PgsqlError enum: Protocol, Connection, Io, Timeout, Pool, Auth
├── tests/index.rs   # Integration test (requires live PostgreSQL)
├── examples/        # index.rs uses tokio-postgres (NOT this crate!)
├── Cargo.toml
└── INSTALL.md       # Clippy/publish commands
```

## WHERE TO LOOK

| Task | Location | Notes |
|------|----------|-------|
| Add PostgreSQL message type | `src/packet.rs``MessageType::form()` | Match on byte tag |
| Add field type conversion | `src/format.rs``FieldFormat::from_u16()` | Match (code, type_oid) |
| Change auth flow | `src/connect.rs``sasl_initial_response_message()` | SCRAM logic |
| Modify pool behavior | `src/pools.rs``get_connect()`, `release_conn()` | Global `DB_POOL` |
| Change defaults | `src/config.rs``Config::new()` | localhost:5432, postgres/111111 |
| Add error variant | `src/error.rs``PgsqlError` enum | Implement Display + From |
| Modify read retry logic | `src/connect.rs``read()` | MAX_RETRIES, deadline, MAX_MESSAGE_SIZE |

## COMMANDS

```bash
# Build
cargo build
cargo build --release

# Format
cargo fmt
cargo fmt --check

# Lint
cargo clippy --all-targets --all-features -- -D warnings
cargo clippy --all-targets --all-features -- -D warnings -W clippy::pedantic

# Test (unit — no PostgreSQL needed)
cargo test --lib

# Test (full — requires PostgreSQL at localhost:5432)
cargo test

# Coverage
cargo llvm-cov --lib
cargo llvm-cov --lib --show-missing-lines

# Publish
cargo package --list
cargo publish --dry-run
```

## MODULE BOUNDARIES

| Module | Responsibility | DO NOT mix with |
|--------|----------------|-----------------|
| `packet.rs` | Wire protocol only | Network I/O |
| `connect.rs` | Socket lifecycle, read/write | Pool policy |
| `pools.rs` | Pool management, retry | Protocol details |
| `format.rs` | Type conversion | Packet parsing |
| `error.rs` | Error types | Business logic |
| `config.rs` | Configuration | Connection logic |

## CONVENTIONS

- **Error type**: `PgsqlError` enum with variants: Protocol, Connection, Io, Timeout, Pool, Auth
- **Imports**: `crate::...` first, then external, then `std`
- **Logging**: `log` macros only, no `println!` in library code (except `_cleanup_idle_connections`)
- **Numeric widths**: Explicit (`u16`, `u32`, `i32`) for protocol fields
- **JSON**: `json::JsonValue` for config and result rows
- **Tests**: Inline `#[cfg(test)] mod tests` in each source file, mock TCP servers via `TcpListener::bind("127.0.0.1:0")`
- **Test constants**: `#[cfg(test)]` overrides for timeouts/sizes (MAX_RETRIES=3, MAX_MESSAGE_SIZE=128, deadline=200ms, RETRY_SLEEP=1ms)

## ANTI-PATTERNS (THIS PROJECT)

- **DO NOT** expand `unsafe { String::from_utf8_unchecked }` usage — existing tech debt
- **DO NOT** add `.unwrap()` in new parse paths — use fallible conversions
- **DO NOT** introduce async in core crate — sync only, async in examples
- **DO NOT** hold mutex during socket operations — keep lock times short
- **DO NOT** change public API signatures without explicit request
- **DO NOT** suppress type errors with `as any`, `@ts-ignore` equivalents

## KNOWN SHARP EDGES

- `packet.rs` uses `unsafe` UTF-8 conversions extensively — narrow edits only
- `tests/index.rs` requires live PostgreSQL with default creds
- `examples/index.rs` demos `tokio-postgres`, not this crate (misleading)
- Global `DB_POOL` static — all `Pools` instances share same backing store
- Chinese comments throughout — preserve or translate consistently
- `pools.rs` tests use single `pools_all_paths` test to avoid global state races
- `connect.rs` `read()` has `#[cfg(test)]` reduced constants — production values differ

## SECURITY HARDENING (APPLIED)

| Protection | Location | Detail |
|------------|----------|--------|
| Message length validation | `packet.rs:222` | `raw_len < 4` guard |
| Bounds checks on all message types | `packet.rs` | ErrorResponse, Notice, ReadyForQuery, ParameterDescription, DataRow, RowDescription |
| SCRAM nonce prefix validation | `packet.rs:269` | `starts_with(&self.client_nonce)` |
| MAX_MESSAGE_SIZE (256MB) | `connect.rs:129` | Prevents OOM DoS |
| Read deadline (300s) | `connect.rs:133` | Prevents infinite hang |
| Frame completeness check | `connect.rs:170` | `msg.len() > len as usize` |
| Pool retry limit | `pools.rs:87` | 20 attempts max |
| Hostport range validation | `config.rs` | 1-65535, fallback to 5432 |
| Residual payload drain | `packet.rs` | ParseCompletion etc. drain when `len > 0` |

## DEPENDENCIES

| Crate | Purpose |
|-------|---------|
| `json` | Config parsing, result rows |
| `hmac` + `sha2` + `base64` + `rand` | SCRAM-SHA-256 auth |
| `md5` | MD5 auth |
| `log` | Diagnostics |
| `tokio-postgres` (dev) | Reference in examples only |
| `env_logger` (dev) | Test logging |

## TEST COVERAGE

**98.89%** line coverage (154 tests, 1.4s). Remaining 38 uncovered lines are test-only panic branches and helper edge cases.

## QUICK CHECKLIST

Before coding:
1. Identify target module boundary
2. Choose smallest validating test command (`cargo test --lib`)
3. Check if change affects DB connection requirements

Before finishing:
1. `cargo fmt --check`
2. `cargo clippy --all-targets --all-features -- -D warnings`
3. `cargo test --lib` (fast, no DB needed)
4. Verify diff is focused and intentional