A tool to add or move columns to specific positions in PostgreSQL tables
Project description
PostgreSQL Column Position Tool (pgcolpos)
A command-line tool to add or move columns to specific positions in PostgreSQL tables while preserving all constraints, indexes, and permissions.
Problem
PostgreSQL doesn't support the AFTER clause for column positioning like MySQL does. With standard PostgreSQL, new columns are always added at the end of a table, and there's no direct way to reposition existing columns.
Solution
pgcolpos solves this by providing multiple approaches for tables of any size:
- Standard Approach: Full table recreation (best for small tables)
- Batched Approach: Processes data in batches (best for medium tables)
- View Approach: Creates a view with the desired column order (instantaneous, presentation only)
- pg_repack Approach: Uses pg_repack extension (best for very large tables)
Installation
pip install pgcolpos
Usage
Analyzing Tables First (Recommended)
Before performing operations on large tables, analyze them to get recommendations:
pgcolpos analyze users --db="postgresql://user:pass@localhost/mydb"
This will provide size information and recommend the best approach:
Table Analysis Results:
=======================
Table: users
Total Size: 1.2 GB
Table Size: 850 MB
Index Size: 350 MB
Row Count: 5,000,000
Estimated Operation Times:
Standard Approach: 8 minutes
Batched Approach: 5 minutes
View Approach: less than 1 second
pg_repack Approach: 4 minutes
Recommended Approach: batched_approach
Adding a New Column After a Specific Position
# Auto-select the best method based on table size
pgcolpos add users email varchar(255) after username --method=auto --db="postgresql://user:pass@localhost/mydb"
# Standard approach (complete table recreation)
pgcolpos add users email varchar(255) after username --method=standard --db="postgresql://user:pass@localhost/mydb"
# Batched approach for large tables
pgcolpos add users email varchar(255) after username --method=batched --batch-size=50000 --db="postgresql://user:pass@localhost/mydb"
# View approach (fastest but only affects presentation)
pgcolpos add users email varchar(255) after username --method=view --db="postgresql://user:pass@localhost/mydb"
# pg_repack approach (requires pg_repack extension)
pgcolpos add users email varchar(255) after username --method=pg_repack --db="postgresql://user:pass@localhost/mydb"
Moving an Existing Column After a Specific Position
# Auto-select the best method
pgcolpos move products description after name --method=auto --db="postgresql://user:pass@localhost/mydb"
# Batched approach for large tables
pgcolpos move products description after name --method=batched --batch-size=50000 --db="postgresql://user:pass@localhost/mydb"
Help
pgcolpos --help
API Usage
The tool can also be used programmatically in your Python code:
from pgcolpos import add_column, move_column, add_column_batched, add_column_view, estimate_migration_time
import psycopg2
# Establish connection
conn = psycopg2.connect("postgresql://user:pass@localhost/mydb")
# Analyze table to determine best approach
analysis = estimate_migration_time(conn, "users")
print(f"Recommended approach: {analysis['recommended_approach']}")
# Standard approach (small tables)
add_column(conn, "users", "email", "varchar(255)", "username")
# Batched approach (medium-large tables)
add_column_batched(conn, "users", "email", "varchar(255)", "username", batch_size=50000)
# View approach (instant, presentation only)
add_column_view(conn, "users", "email", "varchar(255)", "username")
# Close connection
conn.close()
Performance Comparison
| Method | Best For | Performance | Physical Change? | Downtime | Notes |
|---|---|---|---|---|---|
| Standard | Small tables (<100K rows) | Slow | Yes | High | Simple but locks table |
| Batched | Medium-large tables | Medium | Yes | Medium | Splits work into batches |
| View | Any size table | Instantaneous | No | None | Presentation only |
| pg_repack | Large tables (>1M rows) | Fast | Yes | Low | Requires extension |
Integration with Other Languages/Frameworks
Node.js
const { exec } = require('child_process');
function addColumnAfter(table, newColumn, dataType, afterColumn, connectionString, method = 'auto') {
return new Promise((resolve, reject) => {
exec(`pgcolpos add ${table} ${newColumn} "${dataType}" after ${afterColumn} --method=${method} --db="${connectionString}"`,
(error, stdout, stderr) => {
if (error) {
reject(error);
return;
}
resolve(stdout);
});
});
}
// Usage
addColumnAfter('users', 'email', 'varchar(255)', 'username', 'postgresql://user:pass@localhost/mydb', 'batched')
.then(console.log)
.catch(console.error);
PHP
<?php
function addColumnAfter($table, $newColumn, $dataType, $afterColumn, $connectionString, $method = 'auto') {
$command = "pgcolpos add {$table} {$newColumn} \"{$dataType}\" after {$afterColumn} --method={$method} --db=\"{$connectionString}\"";
$output = shell_exec($command);
return $output;
}
// Usage
$result = addColumnAfter('users', 'email', 'varchar(255)', 'username', 'postgresql://user:pass@localhost/mydb', 'batched');
echo $result;
?>
Java
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class PostgresColumnTool {
public static String addColumnAfter(String table, String newColumn, String dataType,
String afterColumn, String connectionString, String method) throws Exception {
ProcessBuilder processBuilder = new ProcessBuilder(
"pgcolpos", "add", table, newColumn, dataType, "after", afterColumn,
"--method=" + method, "--db=" + connectionString);
Process process = processBuilder.start();
BufferedReader reader =
new BufferedReader(new InputStreamReader(process.getInputStream()));
StringBuilder output = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
output.append(line).append("\n");
}
int exitCode = process.waitFor();
if (exitCode != 0) {
throw new Exception("Command failed with exit code: " + exitCode);
}
return output.toString();
}
// Usage
public static void main(String[] args) {
try {
String result = addColumnAfter("users", "email", "varchar(255)", "username",
"postgresql://user:pass@localhost/mydb", "batched");
System.out.println(result);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Ruby on Rails
In a migration file:
def change
# Using the command-line tool from a Rails migration
connection_string = "postgresql://#{ENV['DB_USER']}:#{ENV['DB_PASS']}@#{ENV['DB_HOST']}/#{ENV['DB_NAME']}"
# First analyze the table
system("pgcolpos analyze users --db=\"#{connection_string}\"")
# Add column after specific position using a batched approach for large tables
system("pgcolpos add users email varchar(255) after username --method=batched --db=\"#{connection_string}\"")
end
Recommendations for Large Tables
- Always analyze first: Run
pgcolpos analyzebefore performing operations on large tables - For truly massive tables: Consider using the view approach initially, followed by a scheduled physical change during off-hours
- Batch size tuning: Adjust batch size based on your server's memory capacity (larger values = faster but more memory intensive)
- Test in staging: Always test on a staging environment before running on production
- Backups: Always create a backup before running operations on important tables
Permissions
Required Permissions
The database user needs either:
- Ownership of the table being modified (recommended), or
- Superuser privileges
For detailed information about permissions, see PERMISSIONS.md.
Warning
This tool modifies your table structure. It's recommended to:
- Run this during low-traffic periods
- Take a backup before using the tool
- Test in a development environment first
License
MIT
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pgcolpos-1.0.0.tar.gz.
File metadata
- Download URL: pgcolpos-1.0.0.tar.gz
- Upload date:
- Size: 21.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7f5da1122c30719fe98d06e4d1186eae96f28c956b1235699d04073070091cea
|
|
| MD5 |
8918f9b996610af15028ba8b565585b9
|
|
| BLAKE2b-256 |
13ae9546df9645823a4fa2ece9e1fb9c8d93fad47973a1a9f38d0a8445b1892c
|
File details
Details for the file pgcolpos-1.0.0-py3-none-any.whl.
File metadata
- Download URL: pgcolpos-1.0.0-py3-none-any.whl
- Upload date:
- Size: 18.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
96815f84d1985133aef6e3c1021c88c5ed369a42925f79cc53470fd4d5f31f82
|
|
| MD5 |
3b96a55afc2c2b689d5a2c6765b38dbe
|
|
| BLAKE2b-256 |
68f3f936af0a899a22cd14832da540a6c5622e5e48e958bb0ccd293ce6e1107a
|