/*
================================================================================
pg_whoisactive - PostgreSQL Session Monitoring Tool
================================================================================
DESCRIPTION:
A comprehensive PostgreSQL inspired by Adam Machanic's sp_whoisactive stored
procedure used on SQL server. This function provides detailed real-time information about active
database sessions, including:
- Current executing queries and their duration
- Session blocking and lock information
- I/O statistics and resource usage
- Connection details and client information
- Transaction status and isolation levels
- Wait states and performance metrics
CAPABILITIES:
✓ Monitor active and idle database sessions
✓ Identify blocking chains and deadlock scenarios
✓ Track query execution times and resource consumption
✓ Display I/O statistics (reads, writes, temp usage)
✓ Show connection information (host, application, user)
✓ Filter sessions by various criteria
✓ Format output for easy analysis
✓ Help system with parameter documentation
PARAMETERS:
show_own_spid (BOOLEAN, default: FALSE)
- Include the current session in results
show_system_spids (BOOLEAN, default: FALSE)
- Include system/background processes
show_sleeping_spids (INTEGER, default: 1)
- 0: Show only active sessions
- 1: Show active + idle sessions with open transactions
- 2: Show all sessions (including completely idle)
get_full_inner_text (BOOLEAN, default: FALSE)
- TRUE: Display complete SQL query text
- FALSE: Truncate long queries to 100 characters
get_plans (BOOLEAN, default: FALSE)
- Reserved for future query plan integration
get_locks (BOOLEAN, default: FALSE)
- Include detailed lock information in wait_info column
get_avg_time (BOOLEAN, default: FALSE)
- Reserved for future average execution time tracking
get_additional_info (BOOLEAN, default: FALSE)
- Reserved for additional session metadata
find_block_leaders (BOOLEAN, default: TRUE)
- Identify and report blocking relationships between sessions
delta_interval (INTEGER, default: 5)
- Reserved for future delta calculations between samples
format_output (INTEGER, default: 1)
- 1: Normal output format
- 2: Reserved for detailed format
destination_table (TEXT, default: NULL)
- Reserved for future table output functionality
help (BOOLEAN, default: FALSE)
- Display help information and parameter descriptions
OUTPUT COLUMNS:
dd_hh_mm_ss - Session duration (DD:HH:MM:SS or HH:MM:SS)
session_id - PostgreSQL process ID (PID)
sql_text - Current SQL statement being executed
sql_command - SQL command type (SELECT, INSERT, UPDATE, etc.)
login_name - Database username
wait_info - Current wait state or blocking information
tran_log_writes - Transaction information and duration
cpu_time - CPU time used (reserved for future use)
tempdb_allocations - Temporary file count
tempdb_current - Current temporary space usage
blocking_session_id - PID of session blocking this one
blocked_session_count - Number of sessions this one is blocking
reads - Read I/O statistics
writes - Write I/O statistics
context_switches - Context switch information (reserved)
physical_io - Physical I/O metrics (reserved)
query_cost - Query execution cost (reserved)
status - Current session status
isolation_level - Transaction isolation level (reserved)
open_tran_count - Number of open transactions
percent_complete - Query completion percentage (reserved)
host_name - Client hostname or IP address
database_name - Current database name
program_name - Client application name
start_time - When the current query started
login_time - When the session was established
request_id - Request identifier (uses PID)
collection_time - Timestamp when data was collected
USAGE EXAMPLES:
-- Basic monitoring (most common use case)
SELECT * FROM pg_whoisactive();
-- Show all sessions including idle ones
SELECT * FROM pg_whoisactive(show_sleeping_spids := 2);
-- Focus on blocking issues
SELECT * FROM pg_whoisactive(find_block_leaders := true, get_locks := true)
WHERE blocking_session_id IS NOT NULL OR blocked_session_count > 0;
-- Detailed analysis of active sessions
SELECT * FROM pg_whoisactive(
show_sleeping_spids := 0,
get_full_inner_text := true,
get_locks := true
);
-- Monitor specific session
SELECT * FROM pg_whoisactive() WHERE session_id = 12345;
-- Get help
SELECT * FROM pg_whoisactive(help := true);
COMPANION FUNCTIONS:
pg_blocking_tree() - Shows hierarchical blocking relationships
COMPATIBILITY:
- PostgreSQL 9.6+
- Requires pg_stat_activity and pg_locks system views
- Works with all PostgreSQL editions
AUTHOR: Database Monitoring Tool
VERSION: 1.0
CREATED: 2024
================================================================================
*/
CREATE OR REPLACE FUNCTION public.pg_whoisactive(
show_own_spid BOOLEAN DEFAULT FALSE, -- Show current session
show_system_spids BOOLEAN DEFAULT FALSE, -- Show system processes
show_sleeping_spids INTEGER DEFAULT 1, -- 0=no idle, 1=sleeping with open trans, 2=all sleeping
get_full_inner_text BOOLEAN DEFAULT FALSE, -- Show full query text
get_plans BOOLEAN DEFAULT FALSE, -- Get query plans (if available)
get_locks BOOLEAN DEFAULT FALSE, -- Show lock information
get_avg_time BOOLEAN DEFAULT FALSE, -- Show average execution times
get_additional_info BOOLEAN DEFAULT FALSE, -- Show additional session info
find_block_leaders BOOLEAN DEFAULT TRUE, -- Identify blocking chain leaders
delta_interval INTEGER DEFAULT 5, -- Seconds between samples for delta calculations
format_output INTEGER DEFAULT 1, -- 1=normal, 2=detailed
destination_table TEXT DEFAULT NULL, -- Future: output to table
help BOOLEAN DEFAULT FALSE -- Show help information
)
RETURNS TABLE (
dd_hh_mm_ss TEXT, -- Session duration
session_id INTEGER, -- Process ID
sql_text TEXT, -- Current SQL statement
sql_command TEXT, -- Command type (SELECT, INSERT, etc.)
login_name TEXT, -- Username
wait_info TEXT, -- What the session is waiting for
tran_log_writes TEXT, -- Transaction info
cpu_time TEXT, -- CPU time (if available)
tempdb_allocations TEXT, -- Temp space usage
tempdb_current TEXT, -- Current temp usage
blocking_session_id INTEGER, -- Session that's blocking this one
blocked_session_count INTEGER, -- How many sessions this one is blocking
reads TEXT, -- Read statistics
writes TEXT, -- Write statistics
context_switches TEXT, -- Context switch info
physical_io TEXT, -- Physical I/O
query_cost TEXT, -- Query cost (if available)
status TEXT, -- Session status
isolation_level TEXT, -- Transaction isolation level
open_tran_count INTEGER, -- Number of open transactions
percent_complete TEXT, -- Progress (if available)
host_name TEXT, -- Client hostname/IP
database_name TEXT, -- Current database
program_name TEXT, -- Application name
start_time TIMESTAMP WITH TIME ZONE, -- When session started
login_time TIMESTAMP WITH TIME ZONE, -- When user logged in
request_id INTEGER, -- Request ID
collection_time TIMESTAMP WITH TIME ZONE -- When this data was collected
)
LANGUAGE plpgsql
AS $function$
-- pg_whoisactive - PostgreSQL equivalent of SQL Server's sp_whoisactive
-- A comprehensive session monitoring tool for PostgreSQL
DECLARE
rec RECORD;
blocking_info RECORD;
blocked_count INTEGER;
lock_info TEXT;
wait_description TEXT;
query_text TEXT;
cmd_type TEXT;
duration_formatted TEXT;
days INTEGER;
hours INTEGER;
minutes INTEGER;
seconds INTEGER;
total_seconds NUMERIC;
reads_value TEXT;
writes_value TEXT;
temp_files_value TEXT;
temp_bytes_value TEXT;
BEGIN
-- Show help if requested
IF help THEN
RETURN QUERY
SELECT
'HELP'::TEXT as dd_hh_mm_ss,
0 as session_id,
'pg_whoisactive - PostgreSQL equivalent of sp_whoisactive'::TEXT as sql_text,
'HELP'::TEXT as sql_command,
'show_own_spid: Include current session (default: false)'::TEXT as login_name,
'show_system_spids: Include system processes (default: false)'::TEXT as wait_info,
'show_sleeping_spids: 0=no idle, 1=idle with trans, 2=all idle (default: 1)'::TEXT as tran_log_writes,
'get_full_inner_text: Show complete SQL text (default: false)'::TEXT as cpu_time,
'get_locks: Include lock information (default: false)'::TEXT as tempdb_allocations,
'find_block_leaders: Identify blocking leaders (default: true)'::TEXT as tempdb_current,
NULL::INTEGER as blocking_session_id,
NULL::INTEGER as blocked_session_count,
'Usage: SELECT * FROM pg_whoisactive();'::TEXT as reads,
'Advanced: SELECT * FROM pg_whoisactive(show_sleeping_spids := 2, get_locks := true);'::TEXT as writes,
NULL::TEXT as context_switches,
NULL::TEXT as physical_io,
NULL::TEXT as query_cost,
NULL::TEXT as status,
NULL::TEXT as isolation_level,
NULL::INTEGER as open_tran_count,
NULL::TEXT as percent_complete,
NULL::TEXT as host_name,
NULL::TEXT as database_name,
NULL::TEXT as program_name,
NULL::TIMESTAMP WITH TIME ZONE as start_time,
NULL::TIMESTAMP WITH TIME ZONE as login_time,
NULL::INTEGER as request_id,
now() as collection_time;
RETURN;
END IF;
-- Main query logic
FOR rec IN
SELECT
a.pid,
a.usename,
a.application_name,
a.client_addr,
a.client_hostname,
a.backend_start,
a.xact_start,
a.query_start,
a.state_change,
a.state,
a.query,
a.datname,
a.backend_type,
-- Get I/O stats if available
COALESCE(s.blks_read, 0) as blks_read,
COALESCE(s.blks_hit, 0) as blks_hit,
COALESCE(s.tup_returned, 0) as tup_returned,
COALESCE(s.tup_fetched, 0) as tup_fetched,
COALESCE(s.tup_inserted, 0) as tup_inserted,
COALESCE(s.tup_updated, 0) as tup_updated,
COALESCE(s.tup_deleted, 0) as tup_deleted,
COALESCE(s.temp_files, 0) as temp_files,
COALESCE(s.temp_bytes, 0) as temp_bytes
FROM pg_stat_activity a
LEFT JOIN pg_stat_database s ON s.datname = a.datname
WHERE
-- Filter current session
(show_own_spid = TRUE OR a.pid <> pg_backend_pid())
-- Filter system processes
AND (show_system_spids = TRUE OR (a.datname IS NOT NULL AND a.backend_type = 'client backend'))
-- Filter idle connections based on show_sleeping_spids parameter
AND (
show_sleeping_spids = 2 OR -- Show all
(show_sleeping_spids = 1 AND (a.state <> 'idle' OR a.xact_start IS NOT NULL)) OR -- Show active or idle in transaction
(show_sleeping_spids = 0 AND a.state = 'active') -- Show only active
)
ORDER BY
CASE WHEN a.state = 'active' THEN 1 ELSE 2 END, -- Active sessions first
a.query_start DESC NULLS LAST
LOOP
-- Calculate and format session duration
total_seconds := EXTRACT(EPOCH FROM (COALESCE(now() - rec.backend_start, INTERVAL '0')));
days := FLOOR(total_seconds / 86400);
hours := FLOOR((total_seconds % 86400) / 3600);
minutes := FLOOR((total_seconds % 3600) / 60);
seconds := FLOOR(total_seconds % 60);
IF days > 0 THEN
duration_formatted := LPAD(days::TEXT, 2, '0') || ':' || LPAD(hours::TEXT, 2, '0') || ':' || LPAD(minutes::TEXT, 2, '0') || ':' || LPAD(seconds::TEXT, 2, '0');
ELSE
duration_formatted := LPAD(hours::TEXT, 2, '0') || ':' || LPAD(minutes::TEXT, 2, '0') || ':' || LPAD(seconds::TEXT, 2, '0');
END IF;
-- Process SQL text
IF get_full_inner_text THEN
query_text := rec.query;
ELSE
query_text := CASE
WHEN rec.query IS NULL THEN NULL
WHEN LENGTH(rec.query) > 100 THEN LEFT(rec.query, 97) || '...'
ELSE rec.query
END;
END IF;
-- Extract command type
IF rec.query IS NOT NULL AND TRIM(rec.query) <> '' THEN
cmd_type := UPPER(SPLIT_PART(TRIM(rec.query), ' ', 1));
IF cmd_type = '' THEN cmd_type := NULL; END IF;
ELSE
cmd_type := NULL;
END IF;
-- Determine wait info and status
wait_description := CASE
WHEN rec.state = 'active' THEN 'RUNNABLE'
WHEN rec.state = 'idle' THEN 'IDLE'
WHEN rec.state = 'idle in transaction' THEN 'IDLE IN TRANSACTION'
WHEN rec.state = 'idle in transaction (aborted)' THEN 'IDLE IN TRANSACTION (ABORTED)'
WHEN rec.state = 'fastpath function call' THEN 'FASTPATH FUNCTION CALL'
WHEN rec.state = 'disabled' THEN 'DISABLED'
ELSE UPPER(rec.state)
END;
-- Find blocking information if requested
IF find_block_leaders THEN
-- Check if this session is blocked
SELECT b.blocking_pid INTO blocking_info
FROM (
SELECT
blocked_locks.pid as blocked_pid,
blocking_locks.pid as blocking_pid
FROM pg_catalog.pg_locks blocked_locks
JOIN pg_catalog.pg_locks blocking_locks ON (
blocking_locks.locktype = blocked_locks.locktype
AND blocking_locks.database IS NOT DISTINCT FROM blocked_locks.database
AND blocking_locks.relation IS NOT DISTINCT FROM blocked_locks.relation
AND blocking_locks.page IS NOT DISTINCT FROM blocked_locks.page
AND blocking_locks.tuple IS NOT DISTINCT FROM blocked_locks.tuple
AND blocking_locks.virtualxid IS NOT DISTINCT FROM blocked_locks.virtualxid
AND blocking_locks.transactionid IS NOT DISTINCT FROM blocked_locks.transactionid
AND blocking_locks.classid IS NOT DISTINCT FROM blocked_locks.classid
AND blocking_locks.objid IS NOT DISTINCT FROM blocked_locks.objid
AND blocking_locks.objsubid IS NOT DISTINCT FROM blocked_locks.objsubid
AND blocking_locks.virtualtransaction IS NOT DISTINCT FROM blocked_locks.virtualtransaction
)
WHERE NOT blocked_locks.granted
AND blocking_locks.granted
AND blocked_locks.pid <> blocking_locks.pid
) b
WHERE b.blocked_pid = rec.pid;
-- Count how many sessions this one is blocking
SELECT COUNT(*) INTO blocked_count
FROM (
SELECT
blocked_locks.pid as blocked_pid,
blocking_locks.pid as blocking_pid
FROM pg_catalog.pg_locks blocked_locks
JOIN pg_catalog.pg_locks blocking_locks ON (
blocking_locks.locktype = blocked_locks.locktype
AND blocking_locks.database IS NOT DISTINCT FROM blocked_locks.database
AND blocking_locks.relation IS NOT DISTINCT FROM blocked_locks.relation
AND blocking_locks.page IS NOT DISTINCT FROM blocked_locks.page
AND blocking_locks.tuple IS NOT DISTINCT FROM blocked_locks.tuple
AND blocking_locks.virtualxid IS NOT DISTINCT FROM blocked_locks.virtualxid
AND blocking_locks.transactionid IS NOT DISTINCT FROM blocked_locks.transactionid
AND blocking_locks.classid IS NOT DISTINCT FROM blocked_locks.classid
AND blocking_locks.objid IS NOT DISTINCT FROM blocked_locks.objid
AND blocking_locks.objsubid IS NOT DISTINCT FROM blocked_locks.objsubid
AND blocking_locks.virtualtransaction IS NOT DISTINCT FROM blocked_locks.virtualtransaction
)
WHERE NOT blocked_locks.granted
AND blocking_locks.granted
AND blocked_locks.pid <> blocking_locks.pid
) b
WHERE b.blocking_pid = rec.pid;
ELSE
blocking_info := NULL;
blocked_count := 0;
END IF;
-- Get lock information if requested
IF get_locks THEN
SELECT STRING_AGG(
l.locktype || ':' || l.mode ||
CASE WHEN l.granted THEN ':GRANTED' ELSE ':WAITING' END,
', '
) INTO lock_info
FROM pg_locks l
WHERE l.pid = rec.pid;
ELSE
lock_info := NULL;
END IF;
-- Format read/write statistics
reads_value := CASE
WHEN rec.blks_read > 0 OR rec.blks_hit > 0 THEN
'Logical: ' || (rec.blks_read + rec.blks_hit)::TEXT || ', Physical: ' || rec.blks_read::TEXT
ELSE NULL
END;
writes_value := CASE
WHEN (rec.tup_inserted + rec.tup_updated + rec.tup_deleted) > 0 THEN
'Rows: ' || (rec.tup_inserted + rec.tup_updated + rec.tup_deleted)::TEXT
ELSE NULL
END;
-- Format temp usage
temp_files_value := CASE
WHEN rec.temp_files > 0 THEN rec.temp_files::TEXT || ' files'
ELSE NULL
END;
temp_bytes_value := CASE
WHEN rec.temp_bytes > 0 THEN pg_size_pretty(rec.temp_bytes)
ELSE NULL
END;
-- Return the row
RETURN QUERY
SELECT
duration_formatted, -- dd_hh_mm_ss
rec.pid, -- session_id
query_text, -- sql_text
cmd_type, -- sql_command
rec.usename::TEXT, -- login_name
CASE
WHEN blocking_info.blocking_pid IS NOT NULL THEN
'BLOCKED BY: ' || blocking_info.blocking_pid::TEXT
WHEN get_locks AND lock_info IS NOT NULL THEN lock_info
ELSE wait_description
END, -- wait_info
CASE
WHEN rec.xact_start IS NOT NULL THEN
'Open: ' || EXTRACT(EPOCH FROM (now() - rec.xact_start))::INTEGER::TEXT || 's'
ELSE NULL
END, -- tran_log_writes
NULL::TEXT, -- cpu_time (not available in PostgreSQL)
temp_files_value, -- tempdb_allocations
temp_bytes_value, -- tempdb_current
blocking_info.blocking_pid, -- blocking_session_id
CASE WHEN blocked_count > 0 THEN blocked_count ELSE NULL END, -- blocked_session_count
reads_value, -- reads
writes_value, -- writes
NULL::TEXT, -- context_switches (not available)
NULL::TEXT, -- physical_io
NULL::TEXT, -- query_cost (would need EXPLAIN)
wait_description, -- status
NULL::TEXT, -- isolation_level (would need transaction info)
CASE WHEN rec.xact_start IS NOT NULL THEN 1 ELSE 0 END, -- open_tran_count
NULL::TEXT, -- percent_complete (not available)
COALESCE(rec.client_hostname, rec.client_addr::TEXT, 'local'), -- host_name
rec.datname::TEXT, -- database_name
COALESCE(rec.application_name::TEXT, 'unknown'), -- program_name
rec.query_start, -- start_time
rec.backend_start, -- login_time
rec.pid, -- request_id (using pid)
now(); -- collection_time
END LOOP;
END;
$function$;
-- Create a helper function for quick blocking analysis
CREATE OR REPLACE FUNCTION pg_blocking_tree()
RETURNS TABLE (
level INTEGER,
blocking_pid INTEGER,
blocked_pid INTEGER,
blocked_user TEXT,
blocked_query TEXT,
blocked_duration TEXT
)
LANGUAGE sql
AS $$
/*
================================================================================
pg_blocking_tree - Hierarchical Blocking Chain Analysis
================================================================================
DESCRIPTION:
Displays blocking relationships in a hierarchical tree format, showing
which sessions are blocking others and the chain of dependencies.
RETURNS:
level - Depth in the blocking hierarchy
blocking_pid - Session causing the block
blocked_pid - Session being blocked
blocked_user - Username of blocked session
blocked_query - SQL being blocked
blocked_duration - How long the session has been blocked
USAGE:
SELECT * FROM pg_blocking_tree();
================================================================================
*/
WITH RECURSIVE blocking_tree AS (
-- Find the root blockers (sessions that block others but aren't blocked themselves)
SELECT
1 as level,
blocking_locks.pid as blocking_pid,
blocked_locks.pid as blocked_pid,
blocked_activity.usename as blocked_user,
blocked_activity.query as blocked_query,
EXTRACT(EPOCH FROM (now() - blocked_activity.query_start))::INTEGER::TEXT || 's' as blocked_duration
FROM pg_catalog.pg_locks blocked_locks
JOIN pg_catalog.pg_stat_activity blocked_activity ON blocked_activity.pid = blocked_locks.pid
JOIN pg_catalog.pg_locks blocking_locks ON (
blocking_locks.locktype = blocked_locks.locktype
AND blocking_locks.database IS NOT DISTINCT FROM blocked_locks.database
AND blocking_locks.relation IS NOT DISTINCT FROM blocked_locks.relation
AND blocking_locks.page IS NOT DISTINCT FROM blocked_locks.page
AND blocking_locks.tuple IS NOT DISTINCT FROM blocked_locks.tuple
AND blocking_locks.virtualxid IS NOT DISTINCT FROM blocked_locks.virtualxid
AND blocking_locks.transactionid IS NOT DISTINCT FROM blocked_locks.transactionid
AND blocking_locks.classid IS NOT DISTINCT FROM blocked_locks.classid
AND blocking_locks.objid IS NOT DISTINCT FROM blocked_locks.objid
AND blocking_locks.objsubid IS NOT DISTINCT FROM blocked_locks.objsubid
AND blocking_locks.virtualtransaction IS NOT DISTINCT FROM blocked_locks.virtualtransaction
)
WHERE NOT blocked_locks.granted
AND blocking_locks.granted
AND blocked_locks.pid <> blocking_locks.pid
)
SELECT * FROM blocking_tree
ORDER BY level, blocking_pid, blocked_pid;
$$;
/*
================================================================================
USAGE EXAMPLES AND REFERENCE
================================================================================
-- BASIC MONITORING
--------------------------------------------------------------------------------
-- View all active sessions (most common usage)
SELECT * FROM pg_whoisactive();
-- Show only currently executing queries
SELECT * FROM pg_whoisactive(show_sleeping_spids := 0);
-- Include all sessions (even completely idle ones)
SELECT * FROM pg_whoisactive(show_sleeping_spids := 2);
-- BLOCKING ANALYSIS
--------------------------------------------------------------------------------
-- Quick check for blocking issues
SELECT * FROM pg_whoisactive(find_block_leaders := true)
WHERE blocking_session_id IS NOT NULL OR blocked_session_count > 0;
-- Detailed blocking analysis with lock information
SELECT session_id, login_name, sql_text, wait_info, blocking_session_id, blocked_session_count
FROM pg_whoisactive(get_locks := true, find_block_leaders := true)
WHERE blocking_session_id IS NOT NULL OR blocked_session_count > 0;
-- Show complete blocking hierarchy
SELECT * FROM pg_blocking_tree();
-- DETAILED SESSION ANALYSIS
--------------------------------------------------------------------------------
-- Full query text and detailed information
SELECT * FROM pg_whoisactive(
get_full_inner_text := true,
get_locks := true,
find_block_leaders := true
);
-- Monitor specific session by PID
SELECT * FROM pg_whoisactive() WHERE session_id = 12345;
-- Long-running transactions
SELECT session_id, login_name, sql_command, tran_log_writes, dd_hh_mm_ss
FROM pg_whoisactive()
WHERE tran_log_writes IS NOT NULL
ORDER BY dd_hh_mm_ss DESC;
-- PERFORMANCE MONITORING
--------------------------------------------------------------------------------
-- Sessions with high I/O activity
SELECT session_id, login_name, sql_command, reads, writes, tempdb_current
FROM pg_whoisactive()
WHERE reads IS NOT NULL OR writes IS NOT NULL OR tempdb_current IS NOT NULL;
-- Currently active sessions sorted by duration
SELECT session_id, dd_hh_mm_ss, login_name, sql_text, status
FROM pg_whoisactive(show_sleeping_spids := 0)
ORDER BY dd_hh_mm_ss DESC;
-- TROUBLESHOOTING QUERIES
--------------------------------------------------------------------------------
-- Find sessions from specific application
SELECT * FROM pg_whoisactive() WHERE program_name LIKE '%myapp%';
-- Find sessions from specific user
SELECT * FROM pg_whoisactive() WHERE login_name = 'problem_user';
-- Find sessions connected from specific host
SELECT * FROM pg_whoisactive() WHERE host_name LIKE '%problemhost%';
-- Sessions in specific database
SELECT * FROM pg_whoisactive() WHERE database_name = 'production_db';
-- ADMINISTRATIVE TASKS
--------------------------------------------------------------------------------
-- Help and parameter reference
SELECT * FROM pg_whoisactive(help := true);
-- Include system processes for maintenance operations
SELECT * FROM pg_whoisactive(show_system_spids := true);
-- Monitor your own session activity
SELECT * FROM pg_whoisactive(show_own_spid := true) WHERE session_id = pg_backend_pid();
================================================================================
*/
Category: Uncategorized
ChatGPT prompt to create How-To Guide Builder
This prompt assists in creating a complete how-to guide for any topic, specifically tailored to the target audience’s skill level (beginner, intermediate, or advanced) and the desired content format (blog post, video script, infographic, etc.).
<System>
You are an expert technical writer, educator, and SEO strategist. Your job is to generate a full, structured, and professional how-to guide based on user inputs: TOPIC, SKILLLEVEL, and FORMAT. Tailor your output to match the intended audience and content style.
</System>
<Context>
The user wants to create an informative how-to guide that provides step-by-step instructions, insights, FAQs, and more for a specific topic. The guide should be educational, comprehensive, and approachable for the target skill level and content format.
</Context>
<Instructions>
1. Begin by identifying the TOPIC, SKILLLEVEL, and FORMAT provided.
2. Research and list the 5-10 most common pain points, questions, or challenges learners face related to TOPIC.
3. Create a 5-7 section outline breaking down the how-to process of TOPIC. Match complexity to SKILLLEVEL.
4. Write an engaging introduction:
- Explain why TOPIC is important or beneficial.
- Clarify what the reader will achieve or understand by the end.
5. For each main section:
- Explain what needs to be done.
- Mention any warnings or prep steps.
- Share 2-3 best practices or helpful tips.
- Recommend tools or resources if relevant.
6. Add a troubleshooting section with common mistakes and how to fix them.
7. Include a “Frequently Asked Questions” section with concise answers.
8. Add a “Next Steps” or “Advanced Techniques” section for progressing beyond basics.
9. If technical terms exist, include a glossary with beginner-friendly definitions.
10. Based on FORMAT, suggest visuals (e.g. screenshots, diagrams, timestamps) to support content delivery.
11. End with a conclusion summarizing the key points and motivating the reader to act.
12. Format the final piece according to FORMAT (blog post, video script, infographic layout, etc.), and include a table of contents if length exceeds 1,000 words.
</Instructions>
<Constrains>
- Stay within the bounds of the SKILLLEVEL.
- Maintain a tone and structure appropriate to FORMAT.
- Be practical, user-friendly, and professional.
- Avoid jargon unless explained in glossary.
</Constrains>
<Output Format>
Deliver the how-to guide as a completed piece matching FORMAT, with all structural sections in place.
</Output Format>
<Reasoning>
Apply Theory of Mind to analyze the user's request, considering both logical intent and emotional undertones. Use Strategic Chain-of-Thought and System 2 Thinking to provide evidence-based, nuanced responses that balance depth with clarity.
</Reasoning>
<User Input>
Reply with: "Please enter your {prompt subject} request and I will start the process," then wait for the user to provide their specific {prompt subject} process request.
</User Input>
Prompt Use Case:
A database engineer wants to create a runbook to troubleshoot MySQL replication issues.
Generate User creation script for Redshift
"""
This script generates a user creation script and a list of ALTER GROUP scripts to add the user to the corresponding groups.
Sample Execution:
python Generate_user_creation_script.py
Enter the username for the new user: test_user
Enter the schema names (comma-separated, e.g., 'etl,hr,public'): "etl","hr","public"
Output:
CREATE USER "test_user" PASSWORD 'Hidden1!';
ALTER GROUP etl_ro ADD USER "test_user";
ALTER GROUP hr_ro ADD USER "test_user";
ALTER GROUP public_ro ADD USER "test_user";
"""
def strip_and_parse_schemas(schemas_string):
"""
Strips the double quotes and commas from a given string of schema names and returns a list of schema names.
:param schemas_string: String of schema names, e.g. '"etl","hr","public"'
:return: List of schema names ['etl', 'hr', 'public']
"""
schemas_list = schemas_string.replace('"', '').split(',')
return schemas_list
def generate_create_user_script(username, password):
"""
Generates SQL script to create a new user with a given username and password.
:param username: The username of the new user
:param password: The password for the new user
:return: SQL statement for user creation
"""
create_user_script = f'CREATE USER "{username}" PASSWORD \'{password}\';'
return create_user_script
def generate_alter_group_scripts(schemas, username):
"""
Generates SQL statements to add the user to the pre-existing groups for each schema.
:param schemas: List of schema names
:param username: The username to be added to the groups
:return: List of ALTER GROUP SQL statements
"""
alter_group_scripts = []
for schema in schemas:
group_name = f"{schema}_ro" # Dynamically generate the group name (e.g., "etl_ro")
alter_group_script = f'ALTER GROUP {group_name} ADD USER "{username}";'
alter_group_scripts.append(alter_group_script)
return alter_group_scripts
def print_scripts(schemas, username, password):
"""
Prints the user creation script and the ALTER GROUP scripts to add the user to the corresponding groups.
:param schemas: List of schema names
:param username: The username of the new user
:param password: The password for the new user
"""
print(generate_create_user_script(username, password))
alter_group_scripts = generate_alter_group_scripts(schemas, username)
for script in alter_group_scripts:
print(script)
def main():
# Prompt for username input
username = input("Enter the username for the new user: ")
# Prompt for schema array input (comma-separated string)
schemas_string = input("Enter the schema names (comma-separated, e.g., 'etl,hr,public'): ")
# Strip and parse the schema names
schemas = strip_and_parse_schemas(schemas_string)
# Set the password (or prompt for it if you'd like)
password = "Hidden1!" # You can customize this if needed
# Generate and print the scripts
print_scripts(schemas, username, password)
if __name__ == "__main__":
main()
Unstage the last local commit on git
This can be done using the git reset command to move the HEAD pointer back one commit while keeping the changes in your working directory.
git reset HEAD~1
The command has successfully unstaged your last commit. The changes from that commit are now back in your working directory, but they are not staged or committed. You can now:
- Review the changes
- Make additional modifications if needed
- Stage and commit the changes again when you’re ready
Revert the last local changes
This will discard all uncommitted changes in your working directory and staging area. Since this is a destructive operation, I’ll use git reset –hard to revert to the last commit.
git reset --hard HEAD
What Happens
- All uncommitted changes are discarded
- Working directory returns to the state of the last commit
- Staging area is cleared
- ⚠️ Warning: This operation cannot be undone
Export and Import MongoDB
-- Download selected collections from prod cluster
mongoexport --uri="mongodb+srv://user_name@prodcluster.zfzcx.mongodb.net/proddb" --collection=groups --out=groups.json
mongoexport --uri="mongodb+srv://user_name@prodcluster.zfzcx.mongodb.net/proddb" --collection=members --out=members.json
--Import json into another cluster
mongoimport --uri "mongodb+srv://user_name@prodcluster_2.3i2z0.mongodb.net/proddb" --collection groups --file groups.json
mongoimport --uri "mongodb+srv://user_name@prodcluster_2.3i2z0.mongodb.net/proddb" --collection members --file members.json
-- Mongodump to download the entire DB
mongodump --uri="mongodb+srv://user_name@prodcluster.zfzcx.mongodb.net/proddb" --out=c:/path/mongodump
-- Mongorestore to restore the entire DB
mongorestore --uri="mongodb+srv://user_name@prodcluster.zfzcx.mongodb.net/proddb" c:/path/mongodump