fix(db-tools): resolve REINDEX transaction error by executing directly via pg client, and dynamically support all database tables in integrity dashboard

This commit is contained in:
DanielS
2026-07-03 14:01:27 +02:00
parent 38651037bc
commit 90ec351d96
3 changed files with 79 additions and 12 deletions

View File

@@ -20,12 +20,7 @@ interface TableStatus {
}
interface IntegrityData {
tables: {
profiles: TableStatus;
end_customers: TableStatus;
pos_modules: TableStatus;
licenses: TableStatus;
};
tables: Record<string, TableStatus>;
errors: {
foreign_keys: number;
};

View File

@@ -2,6 +2,7 @@
import { createClient } from '@/lib/supabase/server'
import { verifyAdmin } from '@/lib/actions/auth'
import { Client } from 'pg'
export async function getDatabaseIntegrity() {
try {
@@ -36,12 +37,20 @@ export async function repairDatabaseSchema() {
export async function optimizeDatabaseIndices() {
try {
await verifyAdmin()
const supabase = await createClient()
const { data, error } = await supabase.rpc('optimize_database_indices')
if (error) {
return { success: false, error: error.message }
}
return { success: true, data }
// REINDEX cannot be run inside a transaction block (such as inside a PL/pgSQL function).
// Therefore, we connect directly using pg client and execute raw query.
const connectionString = process.env.DATABASE_URL || 'postgresql://postgres:postgres@localhost:54322/postgres';
const client = new Client({
connectionString,
connectionTimeoutMillis: 10000,
});
await client.connect();
await client.query('REINDEX SCHEMA public;');
await client.end();
return { success: true }
} catch (err: any) {
console.error("Error in optimizeDatabaseIndices:", err)
return { success: false, error: err.message || "Unerwarteter Fehler bei der Indexoptimierung." }

View File

@@ -0,0 +1,63 @@
-- Update check_database_integrity to check all tables
CREATE OR REPLACE FUNCTION public.check_database_integrity()
RETURNS jsonb
SECURITY DEFINER
AS $$
DECLARE
tables_to_check text[] := ARRAY[
'users',
'settings',
'companies',
'categories',
'products',
'product_modules',
'orders',
'profiles',
'end_customers',
'licenses',
'pos_modules'
];
t text;
t_exists boolean;
t_count bigint;
tables_result jsonb := jsonb_build_object();
fk_errors_count bigint := 0;
result jsonb;
BEGIN
FOREACH t IN ARRAY tables_to_check LOOP
SELECT EXISTS (
SELECT 1 FROM pg_tables WHERE schemaname = 'public' AND tablename = t
) INTO t_exists;
t_count := 0;
IF t_exists THEN
EXECUTE format('SELECT count(*) FROM public.%I', t) INTO t_count;
END IF;
tables_result := tables_result || jsonb_build_object(t, jsonb_build_object('exists', t_exists, 'count', t_count));
END LOOP;
-- Count foreign key errors (orphaned licenses)
SELECT EXISTS (SELECT 1 FROM pg_tables WHERE schemaname = 'public' AND tablename = 'licenses') INTO t_exists;
IF t_exists THEN
SELECT EXISTS (SELECT 1 FROM pg_tables WHERE schemaname = 'public' AND tablename = 'end_customers') INTO t_exists;
IF t_exists THEN
EXECUTE '
SELECT count(*)
FROM public.licenses l
LEFT JOIN public.end_customers c ON l.end_customer_id = c.id
WHERE c.id IS NULL AND l.end_customer_id IS NOT NULL
' INTO fk_errors_count;
END IF;
END IF;
result := jsonb_build_object(
'tables', tables_result,
'errors', jsonb_build_object(
'foreign_keys', fk_errors_count
)
);
RETURN result;
END;
$$ LANGUAGE plpgsql;