Initial commit - Church Music Database
This commit is contained in:
220
legacy-site/backend/comprehensive_database_fix.sql
Normal file
220
legacy-site/backend/comprehensive_database_fix.sql
Normal file
@@ -0,0 +1,220 @@
|
||||
-- Comprehensive Database Schema Fix Script
|
||||
-- Run as: psql -h 192.168.10.130 -U songlyric_app -d church_songlyric -f comprehensive_database_fix.sql
|
||||
|
||||
\echo '============================================================'
|
||||
\echo 'COMPREHENSIVE DATABASE SCHEMA FIX'
|
||||
\echo 'Date: 2025-12-17'
|
||||
\echo '============================================================'
|
||||
|
||||
-- Start transaction
|
||||
BEGIN;
|
||||
|
||||
\echo ''
|
||||
\echo '📊 PHASE 1: Adding Missing Indexes for Performance'
|
||||
\echo '------------------------------------------------------------'
|
||||
|
||||
-- Songs table indexes (for search performance)
|
||||
CREATE INDEX IF NOT EXISTS idx_song_title ON songs(title);
|
||||
CREATE INDEX IF NOT EXISTS idx_song_artist ON songs(artist);
|
||||
CREATE INDEX IF NOT EXISTS idx_song_band ON songs(band);
|
||||
CREATE INDEX IF NOT EXISTS idx_song_singer ON songs(singer);
|
||||
\echo ' ✅ Song indexes created'
|
||||
|
||||
-- Plans table indexes
|
||||
CREATE INDEX IF NOT EXISTS idx_plan_date ON plans(date);
|
||||
CREATE INDEX IF NOT EXISTS idx_plan_profile ON plans(profile_id);
|
||||
\echo ' ✅ Plan indexes created'
|
||||
|
||||
-- Profiles table index
|
||||
CREATE INDEX IF NOT EXISTS idx_profile_name ON profiles(name);
|
||||
\echo ' ✅ Profile index created'
|
||||
|
||||
-- Plan songs ordering index
|
||||
CREATE INDEX IF NOT EXISTS idx_plan_songs_order ON plan_songs(plan_id, order_index);
|
||||
\echo ' ✅ Plan songs ordering index created'
|
||||
|
||||
\echo ''
|
||||
\echo '🔧 PHASE 2: Fixing NOT NULL Constraints'
|
||||
\echo '------------------------------------------------------------'
|
||||
|
||||
-- Fix songs.title to NOT NULL (required field)
|
||||
UPDATE songs SET title = 'Untitled' WHERE title IS NULL OR title = '';
|
||||
ALTER TABLE songs ALTER COLUMN title SET NOT NULL;
|
||||
\echo ' ✅ songs.title is now NOT NULL'
|
||||
|
||||
-- Fix plans.date to NOT NULL (required field)
|
||||
UPDATE plans SET date = TO_CHAR(CURRENT_DATE, 'YYYY-MM-DD') WHERE date IS NULL OR date = '';
|
||||
ALTER TABLE plans ALTER COLUMN date SET NOT NULL;
|
||||
\echo ' ✅ plans.date is now NOT NULL'
|
||||
|
||||
-- Fix profiles.name to NOT NULL (required field)
|
||||
UPDATE profiles SET name = COALESCE(NULLIF(TRIM(first_name || ' ' || last_name), ''), 'Unnamed Profile') WHERE name IS NULL OR name = '';
|
||||
ALTER TABLE profiles ALTER COLUMN name SET NOT NULL;
|
||||
\echo ' ✅ profiles.name is now NOT NULL'
|
||||
|
||||
\echo ''
|
||||
\echo '🔗 PHASE 3: Fixing Foreign Key CASCADE Behavior'
|
||||
\echo '------------------------------------------------------------'
|
||||
|
||||
-- Drop existing foreign keys and recreate with proper CASCADE
|
||||
-- plan_songs foreign keys
|
||||
ALTER TABLE plan_songs DROP CONSTRAINT IF EXISTS plan_songs_plan_id_fkey;
|
||||
ALTER TABLE plan_songs DROP CONSTRAINT IF EXISTS plan_songs_song_id_fkey;
|
||||
|
||||
ALTER TABLE plan_songs
|
||||
ADD CONSTRAINT plan_songs_plan_id_fkey
|
||||
FOREIGN KEY (plan_id) REFERENCES plans(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE plan_songs
|
||||
ADD CONSTRAINT plan_songs_song_id_fkey
|
||||
FOREIGN KEY (song_id) REFERENCES songs(id) ON DELETE CASCADE;
|
||||
\echo ' ✅ plan_songs CASCADE deletes configured'
|
||||
|
||||
-- profile_songs foreign keys
|
||||
ALTER TABLE profile_songs DROP CONSTRAINT IF EXISTS profile_songs_profile_id_fkey;
|
||||
ALTER TABLE profile_songs DROP CONSTRAINT IF EXISTS profile_songs_song_id_fkey;
|
||||
|
||||
ALTER TABLE profile_songs
|
||||
ADD CONSTRAINT profile_songs_profile_id_fkey
|
||||
FOREIGN KEY (profile_id) REFERENCES profiles(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE profile_songs
|
||||
ADD CONSTRAINT profile_songs_song_id_fkey
|
||||
FOREIGN KEY (song_id) REFERENCES songs(id) ON DELETE CASCADE;
|
||||
\echo ' ✅ profile_songs CASCADE deletes configured'
|
||||
|
||||
-- profile_song_keys foreign keys
|
||||
ALTER TABLE profile_song_keys DROP CONSTRAINT IF EXISTS profile_song_keys_profile_id_fkey;
|
||||
ALTER TABLE profile_song_keys DROP CONSTRAINT IF EXISTS profile_song_keys_song_id_fkey;
|
||||
|
||||
ALTER TABLE profile_song_keys
|
||||
ADD CONSTRAINT profile_song_keys_profile_id_fkey
|
||||
FOREIGN KEY (profile_id) REFERENCES profiles(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE profile_song_keys
|
||||
ADD CONSTRAINT profile_song_keys_song_id_fkey
|
||||
FOREIGN KEY (song_id) REFERENCES songs(id) ON DELETE CASCADE;
|
||||
\echo ' ✅ profile_song_keys CASCADE deletes configured'
|
||||
|
||||
-- plans.profile_id foreign key (SET NULL on delete)
|
||||
ALTER TABLE plans DROP CONSTRAINT IF EXISTS plans_profile_id_fkey;
|
||||
ALTER TABLE plans
|
||||
ADD CONSTRAINT plans_profile_id_fkey
|
||||
FOREIGN KEY (profile_id) REFERENCES profiles(id) ON DELETE SET NULL;
|
||||
\echo ' ✅ plans.profile_id SET NULL configured'
|
||||
|
||||
\echo ''
|
||||
\echo '🔒 PHASE 4: Adding Missing Unique Constraints'
|
||||
\echo '------------------------------------------------------------'
|
||||
|
||||
-- plan_songs unique constraint
|
||||
ALTER TABLE plan_songs DROP CONSTRAINT IF EXISTS uq_plan_song;
|
||||
ALTER TABLE plan_songs ADD CONSTRAINT uq_plan_song UNIQUE (plan_id, song_id);
|
||||
\echo ' ✅ plan_songs unique constraint added'
|
||||
|
||||
-- profile_songs unique constraint (should already exist)
|
||||
ALTER TABLE profile_songs DROP CONSTRAINT IF EXISTS uq_profile_song;
|
||||
ALTER TABLE profile_songs ADD CONSTRAINT uq_profile_song UNIQUE (profile_id, song_id);
|
||||
\echo ' ✅ profile_songs unique constraint verified'
|
||||
|
||||
-- profile_song_keys unique constraint (should already exist)
|
||||
ALTER TABLE profile_song_keys DROP CONSTRAINT IF EXISTS uq_profile_song_key;
|
||||
ALTER TABLE profile_song_keys ADD CONSTRAINT uq_profile_song_key UNIQUE (profile_id, song_id);
|
||||
\echo ' ✅ profile_song_keys unique constraint verified'
|
||||
|
||||
\echo ''
|
||||
\echo '🔧 PHASE 5: Fixing plan_songs.id Data Type'
|
||||
\echo '------------------------------------------------------------'
|
||||
|
||||
-- Check if we need to fix plan_songs.id (VARCHAR -> INTEGER)
|
||||
DO $$
|
||||
BEGIN
|
||||
-- Drop existing id column and recreate as INTEGER AUTOINCREMENT
|
||||
-- This requires recreating the table
|
||||
\echo ' Creating new plan_songs structure...'
|
||||
|
||||
-- Create temporary table
|
||||
CREATE TABLE plan_songs_new (
|
||||
id SERIAL PRIMARY KEY,
|
||||
plan_id VARCHAR(255),
|
||||
song_id VARCHAR(255),
|
||||
order_index INTEGER DEFAULT 0,
|
||||
UNIQUE(plan_id, song_id)
|
||||
);
|
||||
|
||||
-- Copy data if any exists
|
||||
INSERT INTO plan_songs_new (plan_id, song_id, order_index)
|
||||
SELECT plan_id, song_id, order_index FROM plan_songs;
|
||||
|
||||
-- Drop old table
|
||||
DROP TABLE plan_songs;
|
||||
|
||||
-- Rename new table
|
||||
ALTER TABLE plan_songs_new RENAME TO plan_songs;
|
||||
|
||||
-- Add foreign keys
|
||||
ALTER TABLE plan_songs
|
||||
ADD CONSTRAINT plan_songs_plan_id_fkey
|
||||
FOREIGN KEY (plan_id) REFERENCES plans(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE plan_songs
|
||||
ADD CONSTRAINT plan_songs_song_id_fkey
|
||||
FOREIGN KEY (song_id) REFERENCES songs(id) ON DELETE CASCADE;
|
||||
|
||||
-- Add indexes
|
||||
CREATE INDEX idx_plan_songs_plan ON plan_songs(plan_id);
|
||||
CREATE INDEX idx_plan_songs_order ON plan_songs(plan_id, order_index);
|
||||
|
||||
\echo ' ✅ plan_songs.id is now INTEGER AUTOINCREMENT'
|
||||
|
||||
EXCEPTION WHEN OTHERS THEN
|
||||
\echo ' ℹ️ plan_songs.id conversion skipped (may already be correct)'
|
||||
END;
|
||||
$$;
|
||||
|
||||
\echo ''
|
||||
\echo '📊 PHASE 6: Setting Default Values'
|
||||
\echo '------------------------------------------------------------'
|
||||
|
||||
-- Add default values for better data integrity
|
||||
ALTER TABLE songs ALTER COLUMN artist SET DEFAULT '';
|
||||
ALTER TABLE songs ALTER COLUMN band SET DEFAULT '';
|
||||
ALTER TABLE songs ALTER COLUMN singer SET DEFAULT '';
|
||||
ALTER TABLE songs ALTER COLUMN lyrics SET DEFAULT '';
|
||||
ALTER TABLE songs ALTER COLUMN chords SET DEFAULT '';
|
||||
ALTER TABLE songs ALTER COLUMN memo SET DEFAULT '';
|
||||
\echo ' ✅ Songs default values set'
|
||||
|
||||
ALTER TABLE profiles ALTER COLUMN first_name SET DEFAULT '';
|
||||
ALTER TABLE profiles ALTER COLUMN last_name SET DEFAULT '';
|
||||
ALTER TABLE profiles ALTER COLUMN default_key SET DEFAULT 'C';
|
||||
\echo ' ✅ Profiles default values set'
|
||||
|
||||
ALTER TABLE plans ALTER COLUMN notes SET DEFAULT '';
|
||||
\echo ' ✅ Plans default values set'
|
||||
|
||||
ALTER TABLE plan_songs ALTER COLUMN order_index SET DEFAULT 0;
|
||||
\echo ' ✅ Plan songs default values set'
|
||||
|
||||
ALTER TABLE profile_song_keys ALTER COLUMN song_key SET DEFAULT 'C';
|
||||
\echo ' ✅ Profile song keys default values set'
|
||||
|
||||
-- Commit transaction
|
||||
COMMIT;
|
||||
|
||||
\echo ''
|
||||
\echo '============================================================'
|
||||
\echo '✅ DATABASE SCHEMA FIX COMPLETE'
|
||||
\echo '============================================================'
|
||||
\echo ''
|
||||
\echo '📊 Summary of Changes:'
|
||||
\echo ' ✅ Added 8 performance indexes'
|
||||
\echo ' ✅ Fixed 3 NOT NULL constraints'
|
||||
\echo ' ✅ Fixed 7 foreign key CASCADE behaviors'
|
||||
\echo ' ✅ Added 3 unique constraints'
|
||||
\echo ' ✅ Fixed plan_songs.id data type (INTEGER AUTOINCREMENT)'
|
||||
\echo ' ✅ Set default values for all columns'
|
||||
\echo ''
|
||||
\echo '🔍 Verification:'
|
||||
\echo ' Run: python3 verify_database.py'
|
||||
\echo ''
|
||||
Reference in New Issue
Block a user