PostgreSQL Wire Protocol Implementation
PostgreSQL Wire Protocol Implementation
Overview
HeliosDB Nano implements the PostgreSQL wire protocol v3, enabling compatibility with PostgreSQL clients including psql, pgAdmin, and various ORMs.
Architecture
┌─────────────┐│ psql/Client │└──────┬──────┘ │ TCP Connection │ Port 5432┌──────▼──────────────────┐│ PgServer (Tokio) ││ - TcpListener ││ - Session Management │└──────┬──────────────────┘ │┌──────▼──────────────────┐│ Session Handler ││ - Authentication ││ - Message Decoder ││ - Message Encoder │└──────┬──────────────────┘ │┌──────▼──────────────────┐│ SQL Engine ││ - Parser ││ - Planner ││ - Executor │└──────┬──────────────────┘ │┌──────▼──────────────────┐│ Storage Engine ││ - RocksDB ││ - MVCC ││ - WAL │└─────────────────────────┘Components
1. Protocol Module (network/protocol.rs)
Implements message encoding/decoding for the PostgreSQL wire protocol.
Key Features:
- Message parsing (Frontend messages from client)
- Message encoding (Backend messages to client)
- Type OID mapping (PostgreSQL data types)
- Field descriptions for result sets
Supported Messages:
Frontend (Client → Server):
- Startup - Initial connection setup
- Query - Simple query protocol
- Parse - Prepare statement (extended protocol)
- Bind - Bind parameters to statement
- Execute - Execute prepared statement
- Describe - Get statement/portal metadata
- Close - Close statement/portal
- Sync - End of extended query
- Terminate - Close connection
Backend (Server → Client):
- Authentication* - Authentication challenges
- ReadyForQuery - Server ready for next command
- RowDescription - Column metadata for results
- DataRow - Result row data
- CommandComplete - Command execution complete
- ErrorResponse - Error occurred
- ParameterStatus - Server parameters
- BackendKeyData - Cancellation key
2. Authentication Module (network/auth.rs)
Implements authentication mechanisms.
Supported Methods:
- Cleartext Password (for MVP/testing)
- SCRAM-SHA-256 (production-ready)
SCRAM-SHA-256 Flow:
- Client sends initial message with username and nonce
- Server responds with salt, iteration count, and combined nonce
- Client sends proof of password knowledge
- Server verifies proof and sends signature
- Authentication complete
3. Session Module (network/session.rs)
Manages individual client connections.
Responsibilities:
- Connection lifecycle management
- Authentication state machine
- Message routing
- Query execution coordination
- Transaction state tracking
- Prepared statement cache
- Portal (bound statement) cache
Session State:
- Unauthenticated
- Authenticating (SCRAM in progress)
- Authenticated
- Transaction (Idle/InTransaction/Failed)
4. Server Module (network/server.rs)
TCP server implementation using Tokio.
Features:
- Asynchronous I/O
- Concurrent session handling
- Graceful shutdown support
- Session ID management
Protocol Details
Connection Flow
-
Client Connects
Client → Server: TCP Connection -
Startup Message
Client → Server: StartupMessage {protocol_version: 196608 (3.0)user: "postgres"database: "heliosdb"} -
Authentication
Server → Client: Authentication(CleartextPassword)Client → Server: PasswordMessage("password")Server → Client: Authentication(Ok) -
Parameter Exchange
Server → Client: ParameterStatus("server_version", "17.0 (HeliosDB Nano)")Server → Client: ParameterStatus("client_encoding", "UTF8")Server → Client: BackendKeyData { process_id, secret_key }Server → Client: ReadyForQuery(Idle) -
Query Execution
Client → Server: Query("SELECT * FROM users")Server → Client: RowDescription([field1, field2, ...])Server → Client: DataRow([value1, value2, ...])Server → Client: DataRow([value1, value2, ...])Server → Client: CommandComplete("SELECT 2")Server → Client: ReadyForQuery(Idle)
Simple Query Protocol
Used by default for interactive queries.
Flow:
- Client sends Query message
- Server parses and executes
- Server sends results:
- RowDescription (for SELECT)
- DataRow (one per result row)
- CommandComplete
- Server sends ReadyForQuery
Example:
-- Client sendsQuery("SELECT id, name FROM users WHERE id = 1")
-- Server respondsRowDescription([ Field { name: "id", type_oid: INT4, ... }, Field { name: "name", type_oid: TEXT, ... }])DataRow([b"1", b"Alice"])CommandComplete("SELECT 1")ReadyForQuery(Idle)Extended Query Protocol
Used for prepared statements and parameter binding.
Flow:
- Parse - Prepare statement
- Bind - Bind parameters
- Describe - Get metadata (optional)
- Execute - Run query
- Sync - Commit
Example:
-- PrepareParse("stmt1", "SELECT * FROM users WHERE id = $1", [INT4])ParseComplete
-- BindBind("portal1", "stmt1", params=[b"42"])BindComplete
-- ExecuteExecute("portal1", max_rows=0)RowDescription([...])DataRow([...])CommandComplete("SELECT 1")
-- SyncSyncReadyForQuery(Idle)Data Type Mapping
| PostgreSQL OID | Type Name | HeliosDB DataType |
|---|---|---|
| 16 | BOOL | Boolean |
| 20 | INT8 | BigInt |
| 21 | INT2 | SmallInt |
| 23 | INT4 | Integer |
| 25 | TEXT | Text |
| 700 | FLOAT4 | Real |
| 701 | FLOAT8 | Double |
| 1043 | VARCHAR | Varchar |
| 1114 | TIMESTAMP | Timestamp |
| 1184 | TIMESTAMPTZ | TimestampTz |
| 2950 | UUID | Uuid |
| 3802 | JSONB | Jsonb |
Usage
Starting the Server
use heliosdb_nano::{EmbeddedDatabase, network::PgServer};use std::sync::Arc;
#[tokio::main]async fn main() -> Result<(), Box<dyn std::error::Error>> { // Create database let db = Arc::new(EmbeddedDatabase::new_in_memory()?);
// Create server let server = PgServer::new("127.0.0.1:5432", db);
// Run server server.run().await?;
Ok(())}Connecting with psql
# Connect to serverpsql -h localhost -p 5432 -U postgres
# Enter password: postgres
# Run queriesSELECT * FROM users;INSERT INTO users VALUES (1, 'Alice');UPDATE users SET name = 'Bob' WHERE id = 1;Connecting with ORMs
SQLAlchemy (Python):
from sqlalchemy import create_engine
engine = create_engine('postgresql://postgres:postgres@localhost:5432/heliosdb')Diesel (Rust):
let database_url = "postgres://postgres:postgres@localhost:5432/heliosdb";let connection = PgConnection::establish(&database_url)?;Configuration
Server configuration options:
// Bind addresslet server = PgServer::new("0.0.0.0:5432", db); // Listen on all interfaces
// IPv6let server = PgServer::new("[::1]:5432", db); // IPv6 localhost
// Custom portlet server = PgServer::new("127.0.0.1:54321", db);Security
Authentication
- Cleartext Password: Simple but insecure (only for testing)
- SCRAM-SHA-256: Secure challenge-response (recommended)
- SSL/TLS: Not yet implemented (planned)
Best Practices
- Always use SCRAM-SHA-256 in production
- Implement SSL/TLS for network encryption
- Use strong passwords
- Limit network exposure (bind to localhost or firewall)
- Enable audit logging
Performance
Benchmarks
Connection handling:
- 1,000+ concurrent connections supported
- Sub-millisecond query latency for simple queries
- Async I/O prevents blocking
Query execution:
- Uses existing SQL engine
- Performance matches embedded mode
- No overhead from protocol translation
Tuning
// Increase buffer sizes for high throughput// (Implementation detail - internal buffers auto-size)
// Use connection pooling on client side// (Recommended: pgbouncer, pg_pool)Limitations
Current implementation limitations:
-
Authentication: Only cleartext and SCRAM-SHA-256
- No Kerberos, GSSAPI, or SSPI
-
SSL/TLS: Not yet implemented
- Clients requesting SSL will be rejected
-
COPY Protocol: Not implemented
- COPY FROM/TO not supported
-
LISTEN/NOTIFY: Not implemented
- Pub/sub not available
-
Parameter Binding: Basic implementation
- Text format only (no binary)
- Limited type conversion
-
Cancellation: Not implemented
- Query cancellation (Ctrl+C) not handled
Testing
Unit Tests
cd heliosdb-nanocargo test network::Integration Tests
# Start servercargo run --example pg_server
# In another terminal, connect with psqlpsql -h localhost -p 5432 -U postgres
# Run test queries\dt # List tablesSELECT 1; # Simple querySELECT version(); # Not implemented, will errorAutomated Testing
# Using pgbenchpgbench -i -h localhost -p 5432 -U postgrespgbench -h localhost -p 5432 -U postgres -c 10 -t 100
# Using custom test script./tests/protocol_test.shTroubleshooting
Connection Refused
psql: error: connection to server at "localhost", port 5432 failed:Connection refusedSolutions:
- Verify server is running
- Check bind address (use 0.0.0.0 for all interfaces)
- Check firewall rules
Authentication Failed
psql: error: FATAL: password authentication failed for user "postgres"Solutions:
- Verify username/password
- Check authentication configuration
- Review server logs
Protocol Errors
ERROR: Protocol error: Invalid message typeSolutions:
- Ensure client is using PostgreSQL protocol
- Check for version mismatch
- Review server debug logs
Query Errors
ERROR: Query execution error: Table not foundSolutions:
- Verify table exists:
\dt - Check SQL syntax
- Review query execution logs
Compatibility
PostgreSQL Compatibility
HeliosDB Nano implements PostgreSQL wire protocol v3:
- Compatible with PostgreSQL 8.0+
- Tested with psql 14, 15, 16, 17
- Works with most ORMs and drivers
Client Compatibility
Tested clients:
- psql (PostgreSQL command-line)
- pgAdmin 4
- DBeaver
- DataGrip
- psycopg2 (Python)
- pg (Node.js)
- sqlx (Rust)
- Diesel (Rust)
Future Enhancements
Planned features:
-
SSL/TLS Support
- Encrypted connections
- Certificate authentication
-
Binary Protocol
- Binary data encoding
- Faster data transfer
-
COPY Protocol
- Bulk data import/export
- CSV/TSV support
-
Query Cancellation
- Async cancellation support
- BackendKeyData usage
-
LISTEN/NOTIFY
- Pub/sub messaging
- Event notifications
-
Extended Authentication
- Kerberos
- LDAP integration
- OAuth2/OIDC
-
Connection Pooling
- Built-in connection pool
- Resource management
References
- PostgreSQL Wire Protocol Documentation
- SCRAM-SHA-256 RFC 7677
- PostgreSQL Message Formats
- PostgreSQL Error Codes
Contributing
When contributing to the network protocol implementation:
- Follow PostgreSQL wire protocol specification exactly
- Test with real PostgreSQL clients
- Add comprehensive error handling
- Update documentation
- Add tests for new features
License
Apache 2.0 - Same as HeliosDB Nano