PostgreSQL Protocol Quick Start Guide¶
For developers integrating HeliosDB-Lite with PostgreSQL clients
5-Minute Quick Start¶
1. Start the Server¶
2. Connect with psql¶
3. Run Queries¶
-- Simple queries
SELECT * FROM users;
INSERT INTO users VALUES (4, 'David', 'david@example.com');
-- Transactions
BEGIN;
UPDATE users SET email = 'newemail@example.com' WHERE id = 1;
COMMIT;
4. Test Prepared Statements (Python)¶
import psycopg2
conn = psycopg2.connect(host='127.0.0.1', port=5432, user='postgres')
cur = conn.cursor()
# Prepared statement (automatic)
cur.execute("SELECT * FROM users WHERE id = %s", (1,))
print(cur.fetchone()) # (1, 'Alice', 'alice@example.com')
Programmatic Usage¶
Starting a Server¶
use heliosdb_lite::{EmbeddedDatabase, protocol::postgres::PgServerBuilder};
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()?);
// Setup schema
db.execute("CREATE TABLE users (id INT, name TEXT)")?;
db.execute("INSERT INTO users VALUES (1, 'Alice')")?;
// Start PostgreSQL server
let server = PgServerBuilder::new()
.address("127.0.0.1:5432".parse()?)
.build(db);
server.serve().await?;
Ok(())
}
Custom Configuration¶
use heliosdb_lite::protocol::postgres::{PgServerBuilder, AuthMethod};
let server = PgServerBuilder::new()
.address("0.0.0.0:5432".parse()?)
.auth_method(AuthMethod::CleartextPassword) // Or Trust, Md5, ScramSha256
.max_connections(50)
.build(db);
Client Examples¶
Python (psycopg2)¶
import psycopg2
# Connect
conn = psycopg2.connect(
host='127.0.0.1',
port=5432,
user='postgres'
)
# Simple query
cur = conn.cursor()
cur.execute("SELECT * FROM users")
for row in cur.fetchall():
print(row)
# Prepared statement (automatic with placeholders)
cur.execute("SELECT * FROM users WHERE id = %s", (1,))
print(cur.fetchone())
# Transaction
conn.autocommit = False
cur.execute("INSERT INTO users VALUES (%s, %s)", (2, 'Bob'))
conn.commit()
conn.close()
Node.js (pg)¶
const { Client } = require('pg');
const client = new Client({
host: '127.0.0.1',
port: 5432,
user: 'postgres',
});
await client.connect();
// Simple query
const res = await client.query('SELECT * FROM users');
console.log(res.rows);
// Prepared statement
const res2 = await client.query(
'SELECT * FROM users WHERE id = $1',
[1]
);
console.log(res2.rows[0]);
// Transaction
await client.query('BEGIN');
await client.query('INSERT INTO users VALUES ($1, $2)', [2, 'Bob']);
await client.query('COMMIT');
await client.end();
Java (JDBC)¶
import java.sql.*;
Connection conn = DriverManager.getConnection(
"jdbc:postgresql://127.0.0.1:5432/postgres",
"postgres",
""
);
// Simple query
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM users");
while (rs.next()) {
System.out.println(rs.getInt("id") + ": " + rs.getString("name"));
}
// Prepared statement
PreparedStatement pstmt = conn.prepareStatement(
"SELECT * FROM users WHERE id = ?"
);
pstmt.setInt(1, 1);
ResultSet rs2 = pstmt.executeQuery();
while (rs2.next()) {
System.out.println(rs2.getString("name"));
}
// Transaction
conn.setAutoCommit(false);
pstmt = conn.prepareStatement("INSERT INTO users VALUES (?, ?)");
pstmt.setInt(1, 2);
pstmt.setString(2, "Bob");
pstmt.executeUpdate();
conn.commit();
conn.close();
Go (lib/pq)¶
package main
import (
"database/sql"
_ "github.com/lib/pq"
)
func main() {
db, _ := sql.Open("postgres",
"host=127.0.0.1 port=5432 user=postgres sslmode=disable")
defer db.Close()
// Simple query
rows, _ := db.Query("SELECT * FROM users")
defer rows.Close()
for rows.Next() {
var id int
var name string
rows.Scan(&id, &name)
println(id, name)
}
// Prepared statement
stmt, _ := db.Prepare("SELECT * FROM users WHERE id = $1")
defer stmt.Close()
rows2, _ := stmt.Query(1)
defer rows2.Close()
// Transaction
tx, _ := db.Begin()
tx.Exec("INSERT INTO users VALUES ($1, $2)", 2, "Bob")
tx.Commit()
}
Supported Features¶
✅ Fully Supported¶
- Simple query protocol (SELECT, INSERT, UPDATE, DELETE)
- Extended query protocol (prepared statements)
- Transactions (BEGIN, COMMIT, ROLLBACK)
- Parameter binding ($1, $2, etc.)
- All common data types (INT, TEXT, FLOAT, BOOLEAN, JSON, etc.)
- Multiple concurrent connections
- Authentication (Trust, CleartextPassword)
⚠️ Partial Support¶
- MD5 authentication (basic implementation)
- SCRAM-SHA-256 (needs full SASL flow)
- pg_catalog system tables (minimal emulation)
❌ Not Yet Supported¶
- SSL/TLS encryption (coming in v2.1)
- COPY protocol (coming in v2.1)
- Binary result format (coming in v2.2)
- Listen/Notify (coming in v3.0)
- Cursors (coming in v3.0)
Common Use Cases¶
Case 1: Embedded Database with Network Access¶
Scenario: SQLite-style embedded database that also accepts network connections.
// Create embedded database
let db = Arc::new(EmbeddedDatabase::new("./mydata.helio")?);
// Access locally
db.execute("CREATE TABLE logs (message TEXT)")?;
// Also expose via PostgreSQL protocol
tokio::spawn(async move {
let server = PgServerBuilder::new()
.address("127.0.0.1:5432".parse()?)
.build(db.clone());
server.serve().await
});
// Local and remote access to same database
Case 2: Testing PostgreSQL Applications¶
Scenario: Run PostgreSQL-compatible tests without Docker.
#[tokio::test]
async fn test_my_app() {
let db = Arc::new(EmbeddedDatabase::new_in_memory()?);
// Start server in background
let db_clone = db.clone();
tokio::spawn(async move {
let server = PgServerBuilder::new()
.address("127.0.0.1:15432".parse().unwrap())
.build(db_clone);
server.serve().await
});
// Wait for server to start
tokio::time::sleep(Duration::from_millis(100)).await;
// Connect with your application
let conn = postgres::Config::new()
.host("127.0.0.1")
.port(15432)
.user("postgres")
.connect(postgres::NoTls)?;
// Run tests...
}
Case 3: Lightweight PostgreSQL Alternative¶
Scenario: Replace PostgreSQL for small deployments.
// Single binary, no installation
let db = Arc::new(EmbeddedDatabase::new("./data")?);
let server = PgServerBuilder::new()
.address("0.0.0.0:5432".parse()?)
.auth_method(AuthMethod::CleartextPassword)
.max_connections(20)
.build(db);
// Compatible with existing PostgreSQL tools
// psql, pgAdmin, DBeaver, etc.
server.serve().await?;
Troubleshooting¶
Connection Refused¶
Fix: Ensure server is running and listening on correct port.
# Check server logs
RUST_LOG=debug cargo run --example postgres_server_extended
# Verify port
lsof -i :5432
netstat -an | grep 5432
Authentication Failed¶
Fix: Check authentication method.
// For testing, use Trust auth (no password)
.auth_method(AuthMethod::Trust)
// For production, use CleartextPassword or ScramSha256
.auth_method(AuthMethod::CleartextPassword)
Prepared Statement Not Found¶
Fix: Ensure statement is prepared before use.
# Prepare first
cur.execute("PREPARE my_stmt AS SELECT * FROM users WHERE id = $1")
# Then execute
cur.execute("EXECUTE my_stmt(1)")
# Or use parameterized queries (automatic preparation)
cur.execute("SELECT * FROM users WHERE id = %s", (1,))
Type Mismatch¶
Fix: Ensure parameter types match column types.
# Wrong
cur.execute("INSERT INTO users (id) VALUES (%s)", ("1",)) # String
# Correct
cur.execute("INSERT INTO users (id) VALUES (%s)", (1,)) # Integer
Performance Tips¶
1. Use Prepared Statements¶
Slow (re-parses every time):
Fast (prepare once, reuse):
2. Batch Operations¶
Slow (1000 round-trips):
Fast (1 round-trip):
3. Use Transactions¶
Slow (auto-commit each statement):
cur.execute("INSERT INTO users VALUES (1, 'Alice')")
cur.execute("INSERT INTO users VALUES (2, 'Bob')")
cur.execute("INSERT INTO users VALUES (3, 'Charlie')")
Fast (batch in transaction):
conn.autocommit = False
cur.execute("INSERT INTO users VALUES (1, 'Alice')")
cur.execute("INSERT INTO users VALUES (2, 'Bob')")
cur.execute("INSERT INTO users VALUES (3, 'Charlie')")
conn.commit()
4. Connection Pooling¶
Slow (new connection each request):
Fast (reuse connections):
from psycopg2 import pool
db_pool = pool.SimpleConnectionPool(1, 20, host='127.0.0.1', ...)
def handle_request():
conn = db_pool.getconn()
# ... use connection ...
db_pool.putconn(conn)
Security Best Practices¶
1. Use Strong Authentication¶
2. Bind to Localhost Only¶
// Development (accessible from network)
.address("0.0.0.0:5432".parse()?)
// Production (local only)
.address("127.0.0.1:5432".parse()?)
3. Limit Connections¶
4. Use SSH Tunnel for Remote Access¶
# On remote machine
ssh -L 5432:localhost:5432 remote-host
# Then connect to localhost
psql -h 127.0.0.1 -p 5432 -U postgres
5. Always Use Prepared Statements¶
# Vulnerable to SQL injection
cur.execute(f"SELECT * FROM users WHERE name = '{user_input}'")
# Safe (parameter binding)
cur.execute("SELECT * FROM users WHERE name = %s", (user_input,))
Advanced Configuration¶
Custom Authentication¶
use heliosdb_lite::protocol::postgres::{AuthManager, AuthMethod};
// Create custom auth manager
let mut auth = AuthManager::new(AuthMethod::CleartextPassword);
auth.add_user("alice".to_string(), "secret123".to_string());
auth.add_user("bob".to_string(), "password456".to_string());
// Use custom auth
let server = PgServerBuilder::new()
.address("127.0.0.1:5432".parse()?)
.auth_manager(auth)
.build(db);
Statement Cache Tuning¶
The prepared statement cache is per-connection with default limits: - Max statements: 100 - Max portals: 50
These are hardcoded currently but can be made configurable:
// In your connection handler (future enhancement)
let prepared_statements = PreparedStatementManager::with_capacity(1000, 500);
Logging Configuration¶
# Set log level via environment
RUST_LOG=heliosdb_lite=debug cargo run
# Fine-grained control
RUST_LOG=heliosdb_lite::protocol::postgres=trace cargo run
# Production (errors only)
RUST_LOG=error cargo run
Migration from PostgreSQL¶
Step 1: Export Data¶
Step 2: Clean Dump (Remove Unsupported Features)¶
# Remove unsupported PostgreSQL-specific syntax
sed -i '/CREATE EXTENSION/d' dump.sql
sed -i '/GRANT/d' dump.sql # RBAC not yet supported
sed -i '/ALTER DEFAULT/d' dump.sql
Step 3: Import to HeliosDB-Lite¶
# Start HeliosDB-Lite server
cargo run --example postgres_server_extended
# Import dump
psql -h 127.0.0.1 -p 5432 -U postgres -f dump.sql
Compatibility Notes¶
Supported PostgreSQL Features: - CREATE TABLE, DROP TABLE - INSERT, SELECT, UPDATE, DELETE - BEGIN, COMMIT, ROLLBACK - Indexes (limited) - JSON/JSONB - Basic data types
Unsupported (Use Alternatives): - Extensions → Native HeliosDB features - Triggers → Application logic - Views → Materialized views (coming) - SERIAL → Manual ID generation - Foreign keys → Application-level validation
Next Steps¶
- Try the example:
cargo run --example postgres_server_extended - Read the docs:
/docs/implementation/POSTGRES_PROTOCOL_IMPLEMENTATION_SUMMARY.md - Run tests:
cargo test postgres_extended_protocol_tests - Report issues: GitHub Issues
Happy coding! 🚀