This is a conversion of the original Python dblinter to a PostgreSQL extension written in Rust using pgrx.
In recent years, DBAs were more involved with the database engine itself—creating instances, configuring backups, and monitoring systems—while also overseeing developers' activities. Today, in the DBRE world where databases are cloud-managed, developers and operations teams often work independently, without a dedicated DBA. So databases objects lives their own life, created by persons that do their best. It can be usefull to be able to detect some wrong design creation (for example foreign keys created accross differents schemas...). That's what pglinter was created for.
pglinter is a PostgreSQL linter that analyzes your database for potential issues, performance problems, and best practice violations. This Rust implementation provides:
- Better Performance: Native Rust performance vs Python
- Deep Integration: Runs directly inside PostgreSQL using pgrx
- SARIF Output: Industry-standard Static Analysis Results Interchange Format
- Extensible Rules: Easy to add new rules using Rust traits
This extension is built with pgrx 0.16.1 and supports:
- PostgreSQL 13
- PostgreSQL 14
- PostgreSQL 15
- PostgreSQL 16
- PostgreSQL 17
- PostgreSQL 18beta2 ✨ (latest with pgrx 0.16.1)
- B (Base/Database): Database-wide checks including tables, indexes, constraints, and general database analysis
- C (Cluster): PostgreSQL cluster configuration checks
- S (Schema): Schema-level checks
- Rule Engine (
rule_engine.rs): Core engine that executes rules - Rule Trait: Common interface for all rules
- SARIF Generator: Creates standardized output format
- Configuration: Database-stored rule configurations
- Rust 1.88.0+ (required for pgrx 0.16.1)
- PostgreSQL 13-18 development packages
- cargo-pgrx 0.16.1
Debian/Ubuntu Systems:
PGVER=17
PGLINTER=1.0.0
wget https://github.com/pmpetit/pglinter/releases/download/${PGVER}/postgresql_pglinter_${PGVER}_${PGLINTER}_amd64.deb
sudo dpkg -i postgresql_pglinter_${PGVER}_${PGLINTER}_amd64.debRHEL/CentOS/Fedora Systems:
PGVER=17
PGLINTER=1.0.0
wget https://github.com/pmpetit/pglinter/releases/download/${PGVER}/postgresql_pglinter_${PGVER}-${PGLINTER}-1.x86_64.rpm
sudo rpm -i postgresql_pglinter_${PGVER}-${PGLINTER}-1.x86_64.rpm
# or
sudo yum localinstall postgresql_pglinter_${PGVER}-${PGLINTER}-1.x86_64.rpm# Install cargo-pgrx if not already installed
cargo install --locked cargo-pgrx
# Initialize pgrx (one time setup)
cargo pgrx init
# Build the extension for your PostgreSQL version
cargo pgrx package
# Install using the Makefile (handles both system and pgrx-managed PostgreSQL)
sudo make install
# Or install manually for a specific PostgreSQL version
sudo PGVER=pg16 make install
# Load in your database
psql -d your_database -c "CREATE EXTENSION pglinter;"on kubernetes, prerequisite are
- pg18
- k8s >= 1.33
- K8s feature ImageVolume enable
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: cluster-pglinter
spec:
instances: 1
storage:
size: 1Gi
postgresql:
extensions:
- name: pglinter
image:
reference: ghcr.io/pmpetit/pglinter:1.0.0-18-bookworm
apiVersion: postgresql.cnpg.io/v1
kind: Database
metadata:
name: cluster-pglinter-app
spec:
name: app
owner: app
cluster:
name: cluster-pglinter
extensions:
- name: pglinterAfter the cluster is running, connect and enable the extension:
-- Connect to your database
\c app
-- Create the extension
CREATE EXTENSION pglinter;
-- Verify installation
SELECT pglinter.check();You can also use CloudNative-PG's declarative database management:
apiVersion: postgresql.cnpg.io/v1
kind: Database
metadata:
name: cluster-pglinter-app
spec:
name: app
owner: app
cluster:
name: cluster-pglinter
extensions:
- name: pglinterthen
postgres=# \dx
List of installed extensions
Name | Version | Default version | Schema | Description
---------+---------+-----------------+------------+------------------------------
plpgsql | 1.0 | 1.0 | pg_catalog | PL/pgSQL procedural language
(1 row)
postgres=# \l
List of databases
Name | Owner | Encoding | Locale Provider | Collate | Ctype | Locale | ICU Rules | Access privileges
-----------+----------+----------+-----------------+---------+-------+--------+-----------+-----------------------
app | app | UTF8 | libc | C | C | | |
postgres | postgres | UTF8 | libc | C | C | | |
template0 | postgres | UTF8 | libc | C | C | | | =c/postgres +
| | | | | | | | postgres=CTc/postgres
template1 | postgres | UTF8 | libc | C | C | | | =c/postgres +
| | | | | | | | postgres=CTc/postgres
(4 rows)
postgres=# \c app
You are now connected to database "app" as user "postgres".
app=# \dx
List of installed extensions
Name | Version | Default version | Schema | Description
----------+---------+-----------------+------------+--------------------------------------------------------------
pglinter | 1.0.0 | 1.0.0 | public | pglinter: PostgreSQL Database Linting and Analysis Extension
plpgsql | 1.0 | 1.0 | pg_catalog | PL/pgSQL procedural language
(2 rows)
app=#
pglinter extension is installed.
The extension provides comprehensive database analysis functions:
-- Run all enabled rules (output to client)
SELECT pglinter.check();
-- Run a specific rule only
SELECT pglinter.check_rule('B001'); -- Check tables without primary keys
SELECT pglinter.check_rule('b002'); -- Case-insensitive rule codes
-- Generate SARIF reports to file
SELECT pglinter.check('/path/to/results.sarif');
SELECT pglinter.check_rule('B001', '/path/to/b001_results.sarif');
-- Rule management
SELECT pglinter.show_rules(); -- Show all rules and status
SELECT pglinter.explain_rule('B001'); -- Get rule details and fixes
SELECT pglinter.enable_rule('B001'); -- Enable specific rule
SELECT pglinter.disable_rule('B001'); -- Disable specific rule
SELECT pglinter.is_rule_enabled('B001'); -- Check rule status
SELECT pglinter.enable_all_rules(); -- Enable all rules
SELECT pglinter.disable_all_rules(); -- Disable all rules
-- Rule configuration
SELECT pglinter.update_rule_levels('B001', 30, 70); -- Set warning/error thresholds
SELECT pglinter.get_rule_levels('B001'); -- Get current thresholds
-- YAML import/export
SELECT pglinter.export_rules_to_yaml(); -- Export rules to YAML
SELECT pglinter.import_rules_from_yaml('yaml...'); -- Import rules from YAML- B001: Tables without primary keys
- B002: Redundant indexes
- B003: Tables without indexes on foreign keys
- B004: Unused indexes
- B005: Tables with uppercase names/columns
- B006: Tables not selected (unused tables)
- B007: Foreign keys outside schema boundaries
- B008: Foreign key type mismatches
- B009: Tables sharing trigger functions
- B010: Reserved keywords in object names
- B011: Multiple table owners in same schema
- C002: Insecure pg_hba.conf entries
- C003: MD5 password encryption (deprecated/insecure)
- S001: Schemas without default role grants
- S002: Schemas with environment prefixes/suffixes
- S003: Unsecured public schema
- S004: Schema owned by internal/system roles
- S005: Multiple table owners in same schema
Adding a new rule is straightforward. For a comprehensive step-by-step guide, see the How to Create Rules Tutorial in the documentation.
Results are generated in SARIF 2.1.0 format:
{
"version": "2.1.0",
"runs": [{
"tool": {
"driver": {
"name": "pglinter",
"version": "1.0.0"
}
},
"results": [{
"ruleId": "B001",
"level": "warning",
"message": {
"text": "5 tables without primary key exceed threshold: 10%"
},
"locations": [{
"physicalLocation": {
"artifactLocation": {
"uri": "database"
}
}
}]
}]
}]
}This Rust implementation maintains compatibility with the original Python pglinter while offering:
- Performance: 10-100x faster execution
- Memory Safety: Rust's memory management
- Integration: No external dependencies or connections needed
- Deployment: Single extension installation
- Rule Logic: Direct translation of Python rule logic to Rust
- Configuration: Database-stored instead of YAML files
- Output Format: Same SARIF 2.1.0 format
- API: PostgreSQL functions instead of CLI interface
# Run tests
cargo pgrx test
# Development build
cargo pgrx run
# Package for distribution
cargo pgrx packageDocumentation https://pglinter.readthedocs.io/en/latest/
- Fork the repository
- Create a feature branch
- Add new rules following the established pattern
- Add tests for your rules
- Update documentation
- Submit a pull request
Same as original pglinter project.