Fix packet counter accuracy after TRUNCATE operations
The packet counter uses a PostgreSQL sequence that doesn't get reset when the packets table is truncated, causing inaccurate counts. This migration: - Creates an event trigger that automatically resets the packet counter sequence when the packets table is truncated - Adds a manual reset function reset_packet_counter() that can be called if needed - Improves the get_packet_count() function to properly handle when the sequence is at 0 After applying this migration, the counter will automatically reset to 0 whenever TRUNCATE is used on the packets table. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
2bdad557e9
commit
2629589b7f
1 changed files with 113 additions and 0 deletions
|
|
@ -0,0 +1,113 @@
|
||||||
|
defmodule Aprsme.Repo.Migrations.AddTruncateResetForPacketCounter do
|
||||||
|
use Ecto.Migration
|
||||||
|
|
||||||
|
def up do
|
||||||
|
# Create a function to reset the packet counter sequence
|
||||||
|
execute """
|
||||||
|
CREATE OR REPLACE FUNCTION reset_packet_counter_on_truncate()
|
||||||
|
RETURNS event_trigger AS $$
|
||||||
|
DECLARE
|
||||||
|
cmd RECORD;
|
||||||
|
BEGIN
|
||||||
|
FOR cmd IN SELECT * FROM pg_event_trigger_ddl_commands()
|
||||||
|
LOOP
|
||||||
|
IF cmd.command_tag = 'TRUNCATE TABLE' AND cmd.object_identity = 'public.packets' THEN
|
||||||
|
-- Reset the sequence to 0
|
||||||
|
PERFORM setval('packet_count_seq', 0, false);
|
||||||
|
|
||||||
|
-- Also update the deprecated packet_counters table for backward compatibility
|
||||||
|
UPDATE packet_counters
|
||||||
|
SET count = 0, updated_at = NOW()
|
||||||
|
WHERE counter_type = 'total_packets';
|
||||||
|
END IF;
|
||||||
|
END LOOP;
|
||||||
|
END;
|
||||||
|
$$ LANGUAGE plpgsql;
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Create an event trigger for TRUNCATE operations
|
||||||
|
execute """
|
||||||
|
CREATE EVENT TRIGGER reset_packet_counter_trigger
|
||||||
|
ON ddl_command_end
|
||||||
|
WHEN TAG IN ('TRUNCATE TABLE')
|
||||||
|
EXECUTE FUNCTION reset_packet_counter_on_truncate();
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Also create a manual reset function that can be called if needed
|
||||||
|
execute """
|
||||||
|
CREATE OR REPLACE FUNCTION reset_packet_counter()
|
||||||
|
RETURNS void AS $$
|
||||||
|
BEGIN
|
||||||
|
-- Reset the sequence
|
||||||
|
PERFORM setval('packet_count_seq', 0, false);
|
||||||
|
|
||||||
|
-- Update the deprecated table
|
||||||
|
UPDATE packet_counters
|
||||||
|
SET count = 0, updated_at = NOW()
|
||||||
|
WHERE counter_type = 'total_packets';
|
||||||
|
END;
|
||||||
|
$$ LANGUAGE plpgsql;
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Fix the get_packet_count function to handle the case when sequence is at 0
|
||||||
|
execute """
|
||||||
|
CREATE OR REPLACE FUNCTION get_packet_count()
|
||||||
|
RETURNS BIGINT AS $$
|
||||||
|
DECLARE
|
||||||
|
seq_exists BOOLEAN;
|
||||||
|
current_val BIGINT;
|
||||||
|
BEGIN
|
||||||
|
-- Check if sequence exists
|
||||||
|
SELECT EXISTS (
|
||||||
|
SELECT 1 FROM pg_sequences
|
||||||
|
WHERE schemaname = 'public' AND sequencename = 'packet_count_seq'
|
||||||
|
) INTO seq_exists;
|
||||||
|
|
||||||
|
IF NOT seq_exists THEN
|
||||||
|
-- Fallback to counting if sequence doesn't exist
|
||||||
|
RETURN (SELECT COUNT(*) FROM packets);
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- Try to get current value
|
||||||
|
BEGIN
|
||||||
|
current_val := currval('packet_count_seq');
|
||||||
|
EXCEPTION
|
||||||
|
WHEN object_not_in_prerequisite_state THEN
|
||||||
|
-- If currval hasn't been called yet, get last_value
|
||||||
|
SELECT last_value INTO current_val FROM packet_count_seq;
|
||||||
|
END;
|
||||||
|
|
||||||
|
-- If sequence is at 0 and hasn't been used (is_called = false), return 0
|
||||||
|
IF current_val = 0 THEN
|
||||||
|
RETURN 0;
|
||||||
|
ELSE
|
||||||
|
RETURN current_val;
|
||||||
|
END IF;
|
||||||
|
END;
|
||||||
|
$$ LANGUAGE plpgsql STABLE;
|
||||||
|
"""
|
||||||
|
end
|
||||||
|
|
||||||
|
def down do
|
||||||
|
# Drop the event trigger
|
||||||
|
execute "DROP EVENT TRIGGER IF EXISTS reset_packet_counter_trigger;"
|
||||||
|
|
||||||
|
# Drop the reset functions
|
||||||
|
execute "DROP FUNCTION IF EXISTS reset_packet_counter_on_truncate();"
|
||||||
|
execute "DROP FUNCTION IF EXISTS reset_packet_counter();"
|
||||||
|
|
||||||
|
# Restore the original get_packet_count function
|
||||||
|
execute """
|
||||||
|
CREATE OR REPLACE FUNCTION get_packet_count()
|
||||||
|
RETURNS BIGINT AS $$
|
||||||
|
BEGIN
|
||||||
|
RETURN currval('packet_count_seq');
|
||||||
|
EXCEPTION
|
||||||
|
WHEN object_not_in_prerequisite_state THEN
|
||||||
|
-- If currval hasn't been called yet in this session, get the last value
|
||||||
|
RETURN last_value FROM packet_count_seq;
|
||||||
|
END;
|
||||||
|
$$ LANGUAGE plpgsql STABLE;
|
||||||
|
"""
|
||||||
|
end
|
||||||
|
end
|
||||||
Loading…
Add table
Reference in a new issue