Skip to main content

Module 13: PostgreSQL Source Code

This module prepares you to read, understand, and contribute to the PostgreSQL codebase. You’ll learn the code structure, key patterns, and how to set up a development environment. Practical context: The PostgreSQL codebase is approximately 1.3 million lines of C, developed over 35+ years by hundreds of contributors. It is widely regarded as one of the best-structured large C codebases in existence. The code is heavily commented, follows consistent conventions, and uses patterns that were battle-tested long before “clean code” was a popular concept. If you can read PostgreSQL source, you can read virtually any C codebase.
Estimated Time: 14-16 hours
Difficulty: Expert
Prerequisite: Complete Modules 7-9 (internals)
Outcome: Ready for first contribution

13.1 Repository Structure

Key Directories Deep Dive

SQL Parsing

13.2 Development Environment Setup

Building from Source

Build Options Explained

Practical tip: Never use -O0 for performance testing — the optimizer makes a dramatic difference in PostgreSQL’s performance (often 2-3x). Use -O0 -g3 for debugging with GDB/LLDB where you need accurate variable inspection, and -O2 -g for realistic performance profiling. Assertions (--enable-cassert) add about 10-15% overhead, so disable them for benchmarks but always enable them during development — they catch subtle bugs that would otherwise manifest as data corruption in production.

IDE Setup


13.3 Code Conventions

Naming Conventions

Common Patterns


13.4 Key Data Structures

Understanding these three structures is like learning the nouns of the PostgreSQL language. Nearly every function you will read in the codebase accepts, returns, or manipulates a Relation, a HeapTuple, or a Buffer. Master these and the rest of the code becomes dramatically more readable.

Relation (Table)

HeapTuple

Practical tip: A HeapTuple is a pointer to tuple data, not a copy of it. If the buffer containing the tuple is released, the HeapTuple becomes a dangling pointer. When you need a tuple to survive beyond the current buffer lock, use heap_copytuple() to create an independent copy in the current memory context.

Buffer


13.5 Tracing Code Flow

Example: SELECT Query Path

Using GDB

Practical tip: Do not attach GDB to the postmaster process. Instead, connect with psql first, then attach GDB to the specific backend process serving your session. Run SELECT pg_backend_pid(); in psql to find your PID, then gdb -p <pid>. This avoids accidentally freezing the postmaster (which would block all new connections) and lets you debug a single session in isolation.

13.6 Adding a Simple Feature

The best way to learn a codebase is to make a small change to it. These two examples — adding a configuration parameter and adding a SQL function — are the PostgreSQL equivalents of “Hello, World.” They touch just enough of the infrastructure to teach you the patterns without requiring deep domain expertise.

Example: Add New GUC Parameter

Example: Add New SQL Function


13.7 Running Tests

Practical tip: Always run make check before submitting a patch. The PostgreSQL community takes regressions very seriously — a patch that introduces even one test failure will be rejected immediately. Run make check-world for the most thorough validation, but be aware it can take 10-30 minutes depending on your hardware. For iterative development, make check TESTS="your_test" gives fast feedback on just the tests relevant to your change.

Writing Tests


13.8 Key Source Files to Study

Practical tip: Start with tcop/postgres.c and exec_simple_query(). This is the “main loop” of query processing — every SELECT, INSERT, UPDATE, and DELETE flows through here. Once you understand this function, you can follow any query from entry point to result. Read it with the call trace from Section 13.5 open in a second window. After postgres.c, costsize.c is the next most rewarding file to study because it reveals exactly how the planner assigns costs — knowledge that directly improves your ability to tune queries in production.

13.9 Practice Exercise

Goal: Add “Planning Time: X ms” output to regular EXPLAIN (not just ANALYZE)Steps:
  1. Find where EXPLAIN output is generated (commands/explain.c)
  2. Study ExplainOnePlan() function
  3. Add timing capture before/after planning in ExplainOneQuery()
  4. Output the timing in ExplainPrintPlan()
  5. Write regression tests
  6. Submit patch to pgsql-hackers
Files to modify:
  • src/backend/commands/explain.c
  • src/test/regress/sql/explain.sql
  • src/test/regress/expected/explain.out

Next Module

Module 14: Contributing to PostgreSQL

Submit your first patch to PostgreSQL