\x89PNG\r\n\x1a\n\x00\x00\x00\x0DIHDR\x00\x00\x00\x01\x00 \x00\x00\x01\x08\x06\x00\x00\x00\x1F\x15\xC4\x89\x00\x00\x00 \x0AIDATx\x9Ccb\x00\x00\x00\x06\x00\x03\x1A\x05\x9D\x00\x00 \x00\x00IEND\xAE\x42\x60\x82 csarite.com
KUJUNTI.ID MINISH3LL
Path : /var/www/html/yedekledb24/DatabaseBackupMasterv7/
(S)h3ll Cr3at0r :
F!le Upl0ad :

B-Con CMD Config cPanel C-Rdp D-Log Info Jump Mass Ransom Symlink vHost Zone-H

Current File : /var/www/html/yedekledb24/DatabaseBackupMasterv7/database_performance.py


#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
PostgreSQL veritabanı performans metrikleri için yardımcı fonksiyonlar.
Bu modül, pg_stat_statements kullanarak sunucularda çalışan sorguların performans verilerini alır.
"""

import os
import logging
from datetime import datetime, timedelta
import psycopg2
from psycopg2 import sql

# Log konfigürasyonu
logging.basicConfig(level=logging.INFO, 
                   format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def pg_stat_statements_enabled(connection):
    """
    PostgreSQL sunucusunda pg_stat_statements'ın etkin olup olmadığını kontrol eder.
    
    Args:
        connection: PostgreSQL bağlantı nesnesi
        
    Returns:
        bool: Modül yüklüyse True, değilse False
    """
    try:
        cursor = connection.cursor()
        
        # Önce extension yüklenmiş mi onu kontrol et
        cursor.execute("SELECT 1 FROM pg_extension WHERE extname = 'pg_stat_statements'")
        extension_exists = cursor.fetchone() is not None
        
        if not extension_exists:
            return False
            
        # Extension yüklüyse, fonksiyonlarının var olup olmadığını kontrol et
        # (Bu yetkisiz kullanıcılar için de çalışır ve modülün aktif olup olmadığını gösterir)
        cursor.execute("""
            SELECT COUNT(*) > 0 
            FROM pg_proc p 
            JOIN pg_namespace n ON p.pronamespace = n.oid 
            WHERE n.nspname = 'public' AND p.proname LIKE 'pg_stat_statements%'
        """)
        
        has_functions = cursor.fetchone()[0]
        
        # Eğer shared_preload_libraries kontrolü yapmak için yetki varsa daha kesin bir kontrol yap
        try:
            cursor.execute("SHOW shared_preload_libraries")
            libraries = cursor.fetchone()[0]
            if libraries and 'pg_stat_statements' in libraries:
                return True
        except psycopg2.errors.InsufficientPrivilege:
            # Yetki yoksa, fonksiyonların varlığına bakarak karar ver
            return has_functions
        
        # Diğer durumlar için, modülün tüm parçalarının kontrolünü birleştiriyoruz
        return extension_exists and has_functions
        
    except Exception as e:
        error_msg = "pg_stat_statements kontrol edilirken hata: {}".format(str(e))
        logger.error(error_msg)
        # Özel hata mesajları yayınlayalım (hata ayıklama için)
        return False

def enable_pg_stat_statements(connection):
    """
    PostgreSQL sunucusunda pg_stat_statements'ı etkinleştirir.
    
    Args:
        connection: PostgreSQL bağlantı nesnesi
        
    Returns:
        dict: İşlem sonucu (success, message)
    """
    try:
        cursor = connection.cursor()
        
        # Önce extension'ın zaten var olup olmadığını kontrol et
        cursor.execute("SELECT 1 FROM pg_extension WHERE extname = 'pg_stat_statements'")
        if cursor.fetchone() is None:
            # Extension'ı kur
            cursor.execute("CREATE EXTENSION IF NOT EXISTS pg_stat_statements")
            connection.commit()
            return {"success": True, "message": "pg_stat_statements eklentisi kuruldu. Sunucuyu yeniden başlatmanız gerekebilir."}
        
        return {"success": True, "message": "pg_stat_statements eklentisi zaten kurulu."}
    except Exception as e:
        error_msg = "pg_stat_statements etkinleştirilirken hata: {}".format(str(e))
        message_text = "Hata: {}".format(str(e))
        logger.error(error_msg)
        return {"success": False, "message": message_text}

def get_top_queries(db_conn, limit=20, order_by='total_time', interval=None):
    """
    PostgreSQL sunucusunda en çok kaynak tüketen sorguları alır.
    
    Args:
        db_conn: PostgreSQL bağlantı bilgileri (dict)
        limit (int): Alınacak sorgu sayısı
        order_by (str): Sıralama kriteri ('total_time', 'calls', 'rows')
        interval (str): Zaman aralığı ('hour', 'day', 'week', 'all')
        
    Returns:
        dict: Sorgu istatistikleri ile birlikte başarı durumu
    """
    # limit parametresini tamsayı olarak zorla
    try:
        limit = int(limit)
    except (ValueError, TypeError):
        limit = 20  # Hata durumunda varsayılan değer
    # PostgreSQL sürüm değişkenlerini başlangıç değerleriyle tanımla
    pg_version = "Unknown"
    pg_version_major = 0
    
    # Zaman sütunu ve sıralama sütununu başlangıçta tanımla
    # Bu değişkenler, format dizesinde kullanılacağı için önceden tanımlanmalı
    time_column = "total_exec_time"
    order_column = "total_exec_time DESC"
    
    # Sonuç verilerini tutacak değişkenler
    data = []
    summary_data = {
        "total_calls": 0,
        "total_rows": 0,
        "total_exec_time": "0.00 ms",
        "query_count": 0,
        "pg_version": "Unknown"
    }
    
    # Bağlantı bilgilerini hazırla
    conn_str = None
    try:
        conn_str = "host={} port={} user={} password={} dbname={}".format(
            db_conn['host'], db_conn['port'], db_conn['username'], db_conn['password'], db_conn['database']
        )
    except Exception as e:
        error_msg = "Bağlantı bilgileri hazırlanırken hata: {}".format(str(e))
        logger.error(error_msg)
        return {"success": False, "message": error_msg, "data": []}
    
    # 1. PostgreSQL sürümünü al (ilk bağlantı)
    try:
        connection = psycopg2.connect(conn_str)
        connection.autocommit = True  # Her sorgu otomatik commit olacak
        
        cursor = connection.cursor()
        cursor.execute("SHOW server_version")
        pg_version_result = cursor.fetchone()
        
        if pg_version_result and pg_version_result[0]:
            pg_version = pg_version_result[0]
            version_parts = pg_version.split('.')
            if version_parts and version_parts[0].isdigit():
                pg_version_major = int(version_parts[0])
            summary_data["pg_version"] = pg_version
        else:
            logger.warning("PostgreSQL sürümü alınamadı")
        
        cursor.close()
        connection.close()
    except Exception as e:
        error_msg = "PostgreSQL sürüm bilgisi alınırken hata: {}".format(str(e))
        conn_error_msg = "Veritabanına bağlanırken hata: {}".format(str(e))
        logger.error(error_msg)
        return {"success": False, "message": conn_error_msg, "data": []}
    
    # pg_stat_statements modülü kontrolünü atlıyoruz - doğrudan sorgulayacağız
    # Zaten pg_extension tablosunda mevcut olduğunu biliyoruz
    
    # 3. Reset isteği varsa istatistikleri sıfırla (üçüncü bağlantı)
    if interval and interval == 'reset':
        try:
            connection = psycopg2.connect(conn_str)
            connection.autocommit = True
            
            cursor = connection.cursor()
            cursor.execute("SELECT pg_stat_statements_reset()")
            
            cursor.close()
            connection.close()
            
            return {"success": True, "message": "Sorgu istatistikleri sıfırlandı.", "data": []}
        except Exception as e:
            error_msg = "İstatistikleri sıfırlarken hata: {}".format(str(e))
            message_text = "İstatistikleri sıfırlarken hata: {}".format(str(e))
            logger.error(error_msg)
            return {"success": False, "message": message_text, "data": []}
    
    # 4. Ana sorguyu çalıştır (dördüncü bağlantı)
    try:
        connection = psycopg2.connect(conn_str)
        connection.autocommit = True
        
        cursor = connection.cursor()
        
        # PG13 ve üzeri için total_time yerine total_exec_time kullanılır
        time_column = "total_exec_time" if pg_version_major >= 13 else "total_time"
        
        # Sıralama kriteri
        if order_by == 'total_time':
            order_column = time_column + " DESC"
        elif order_by == 'calls':
            order_column = "calls DESC"
        elif order_by == 'rows':
            order_column = "rows DESC" 
        else:
            order_column = time_column + " DESC"
        
        # PG13 ve üzeri farklı bir query yapısına sahip
        if pg_version_major >= 13:
            query = f"""
            SELECT 
                query,
                calls,
                rows,
                {time_column} as total_time,
                CASE WHEN calls > 0 THEN {time_column}/calls ELSE 0 END as avg_time,
                min_exec_time as min_time,
                max_exec_time as max_time,
                mean_exec_time as mean_time,
                stddev_exec_time as stddev_time,
                CASE 
                    WHEN SUM({time_column}) OVER() > 0 
                    THEN 100.0 * {time_column} / SUM({time_column}) OVER() 
                    ELSE 0 
                END AS percentage_cpu
            FROM pg_stat_statements
            WHERE calls > 0 AND dbid = (SELECT oid FROM pg_database WHERE datname = current_database())
            ORDER BY {order_column}
            LIMIT %s
            """
        else:
            # PG12 ve altı için
            query = f"""
            SELECT 
                query,
                calls,
                rows,
                {time_column} as total_time,
                CASE WHEN calls > 0 THEN {time_column}/calls ELSE 0 END as avg_time,
                min_time,
                max_time,
                mean_time,
                stddev_time,
                CASE 
                    WHEN SUM({time_column}) OVER() > 0 
                    THEN 100.0 * {time_column} / SUM({time_column}) OVER() 
                    ELSE 0 
                END AS percentage_cpu
            FROM pg_stat_statements
            WHERE calls > 0 AND dbid = (SELECT oid FROM pg_database WHERE datname = current_database())
            ORDER BY {order_column}
            LIMIT %s
            """
        
        cursor.execute(query, (limit,))
        results = cursor.fetchall()
        
        # Sütunları al
        columns = []
        if cursor.description:
            columns = [desc[0] for desc in cursor.description]
        
        # Sonuçları işle
        for row in results:
            if not row:
                continue  # Boş satırları atla
                
            data_row = {}
            for i, value in enumerate(row):
                if i >= len(columns):  # Sütun sayısını aşma
                    continue
                    
                column_name = columns[i]
                
                # Sorguyu işle
                if column_name == 'query':
                    if value and isinstance(value, str) and len(value) > 500:
                        value = value[:500] + '...'
                    data_row[column_name] = value
                    
                # Süre değerlerini formatla
                elif column_name in ['total_time', 'avg_time', 'min_time', 'max_time', 'mean_time', 'stddev_time']:
                    if value is not None and isinstance(value, (int, float)):
                        data_row[column_name] = "{:.2f} ms".format(value)
                    else:
                        data_row[column_name] = "N/A"
                        
                # Yüzde değerini formatla
                elif column_name == 'percentage_cpu':
                    if value is not None and isinstance(value, (int, float)):
                        data_row[column_name] = "{:.2f}%".format(value)
                    else:
                        data_row[column_name] = "N/A"
                        
                # Diğer değerleri olduğu gibi aktar
                else:
                    data_row[column_name] = value
                    
            # Tam bir satır oluşturulduğunda listeye ekle
            data.append(data_row)
            
        cursor.close()
        connection.close()
        
    except Exception as e:
        error_msg = "Sorgu performans verileri alınırken hata: {}".format(str(e))
        logger.error(error_msg)
        return {"success": False, "message": error_msg, "data": []}
    
    # 5. Özet verileri getir (beşinci bağlantı)
    # Önce varsayılan özet veri yapısını oluştur
    summary_data = {
        "total_calls": 0,
        "total_rows": 0,
        "total_exec_time": "0.00 ms",
        "query_count": len(data),
        "pg_version": pg_version
    }
    
    try:
        connection = psycopg2.connect(conn_str)
        connection.autocommit = True
        
        cursor = connection.cursor()
        
        summary_query = f"""
        SELECT 
            COALESCE(sum(calls), 0) as total_calls,
            COALESCE(sum(rows), 0) as total_rows,
            COALESCE(sum({time_column}), 0) as total_exec_time,
            count(*) as query_count
        FROM pg_stat_statements
        WHERE calls > 0 AND dbid = (SELECT oid FROM pg_database WHERE datname = current_database())
        """
        cursor.execute(summary_query)
        summary = cursor.fetchone()
        
        if summary and len(summary) >= 4:  # En az 4 sütunlu sonuç bekliyoruz
            total_calls = summary[0] if summary[0] is not None else 0
            total_rows = summary[1] if summary[1] is not None else 0
            total_exec_time = summary[2] if summary[2] is not None else 0
            query_count = summary[3] if summary[3] is not None else 0
            
            # Özet verileri güncelle - Decimal tiplerini önce float'a çeviriyoruz
            # Decimal tipindeki değerleri float'a çevirerek format sorununu önlüyoruz
            total_calls_float = float(total_calls) if total_calls is not None else 0
            total_rows_float = float(total_rows) if total_rows is not None else 0
            total_exec_time_float = float(total_exec_time) if total_exec_time is not None else 0
            
            # total_exec_time değerini önceden formatla
            formatted_exec_time = "{:.2f} ms".format(total_exec_time_float)
            
            summary_data = {
                "total_calls": int(total_calls_float),  # Int'e çevir
                "total_rows": int(total_rows_float),    # Int'e çevir
                "total_exec_time": formatted_exec_time,  # Önceden formatlanmış değeri kullan
                "query_count": query_count,
                "pg_version": pg_version
            }
            
        cursor.close()
        connection.close()
        
    except Exception as e:
        error_msg = "Özet veriler alınırken hata: {}".format(str(e))
        logger.error(error_msg)
        # Özet veri alınamasa bile ana veriler var, varsayılan değerleri kullan
    
    # 6. Sonuçları döndür
    return {
        "success": True,
        "message": "Veriler başarıyla alındı",
        "data": data,
        "summary": summary_data,
        "pg_version": pg_version
    }

def get_database_stats(db_conn):
    """
    PostgreSQL veritabanı hakkında genel istatistikleri getirir.
    
    Args:
        db_conn: PostgreSQL bağlantı bilgileri (dict)
        
    Returns:
        dict: Veritabanı istatistikleri
    """
    # Varsayılan değerler hazırla
    data = {
        "db_size": "N/A",
        "table_count": 0,
        "index_count": 0,
        "active_connections": 0,
        "largest_tables": [],
        "most_accessed_tables": [],
        "least_used_indexes": []
    }
    
    # Bağlantı bilgilerini hazırla
    conn_str = "host={} port={} user={} password={} dbname={}".format(
        db_conn['host'], db_conn['port'], db_conn['username'], db_conn['password'], db_conn['database']
    )
    
    # 1. Veritabanı boyutu
    try:
        connection = psycopg2.connect(conn_str)
        connection.autocommit = True
        
        cursor = connection.cursor()
        cursor.execute("SELECT pg_size_pretty(pg_database_size(current_database()))")
        result = cursor.fetchone()
        
        if result and result[0]:
            data["db_size"] = result[0]
        
        cursor.close()
        connection.close()
    except Exception as e:
        logger.error("Veritabanı boyutu alınırken hata: {}".format(str(e)))
    
    # 2. Tablo ve indeks sayısı
    try:
        connection = psycopg2.connect(conn_str)
        connection.autocommit = True
        
        cursor = connection.cursor()
        cursor.execute("SELECT count(*) FROM information_schema.tables WHERE table_schema NOT IN ('pg_catalog', 'information_schema')")
        result = cursor.fetchone()
        
        if result and result[0] is not None:
            data["table_count"] = result[0]
        
        # İndeks sayısı
        cursor.execute("SELECT count(*) FROM pg_indexes WHERE schemaname NOT IN ('pg_catalog', 'information_schema')")
        result = cursor.fetchone()
        
        if result and result[0] is not None:
            data["index_count"] = result[0]
        
        cursor.close()
        connection.close()
    except Exception as e:
        logger.error("Tablo ve indeks sayısı alınırken hata: {}".format(str(e)))
    
    # 3. Aktif bağlantı sayısı
    try:
        connection = psycopg2.connect(conn_str)
        connection.autocommit = True
        
        cursor = connection.cursor()
        cursor.execute("SELECT count(*) FROM pg_stat_activity WHERE state = 'active'")
        result = cursor.fetchone()
        
        if result and result[0] is not None:
            data["active_connections"] = result[0]
        
        cursor.close()
        connection.close()
    except Exception as e:
        logger.error("Aktif bağlantı sayısı alınırken hata: {}".format(str(e)))
    
    # 4. En büyük tablolar
    try:
        connection = psycopg2.connect(conn_str)
        connection.autocommit = True
        
        cursor = connection.cursor()
        cursor.execute("""
        SELECT 
            relname as table_name, 
            pg_size_pretty(pg_total_relation_size(relid)) as total_size
        FROM pg_catalog.pg_statio_user_tables
        ORDER BY pg_total_relation_size(relid) DESC
        LIMIT 5
        """)
        results = cursor.fetchall()
        
        if results:
            data["largest_tables"] = [
                {"table_name": row[0], "size": row[1]} for row in results
            ]
        
        cursor.close()
        connection.close()
    except Exception as e:
        logger.error("En büyük tablolar alınırken hata: {}".format(str(e)))
    
    # 5. En sık kullanılan tablolar
    try:
        connection = psycopg2.connect(conn_str)
        connection.autocommit = True
        
        cursor = connection.cursor()
        cursor.execute("""
        SELECT 
            relname as table_name, 
            seq_scan + idx_scan as total_scans
        FROM pg_stat_user_tables
        ORDER BY total_scans DESC
        LIMIT 5
        """)
        results = cursor.fetchall()
        
        if results:
            data["most_accessed_tables"] = [
                {"table_name": row[0], "scans": row[1]} for row in results
            ]
        
        cursor.close()
        connection.close()
    except Exception as e:
        logger.error("En sık kullanılan tablolar alınırken hata: {}".format(str(e)))
    
    # 6. En az kullanılan indeksler
    try:
        connection = psycopg2.connect(conn_str)
        connection.autocommit = True
        
        cursor = connection.cursor()
        cursor.execute("""
        SELECT
            indexrelname as index_name,
            relname as table_name,
            idx_scan as scans
        FROM pg_stat_user_indexes
        ORDER BY idx_scan ASC
        LIMIT 5
        """)
        results = cursor.fetchall()
        
        if results:
            data["least_used_indexes"] = [
                {"index_name": row[0], "table_name": row[1], "scans": row[2]} for row in results
            ]
        
        cursor.close()
        connection.close()
    except Exception as e:
        logger.error("En az kullanılan indeksler alınırken hata: {}".format(str(e)))
    
    # 7. Tüm verileri döndür
    return {
        "success": True,
        "message": "Veritabanı istatistikleri başarıyla alındı",
        "data": data
    }

def get_table_stats(db_conn, table_name):
    """
    Belirli bir tablo hakkında detaylı istatistikleri getirir.
    
    Args:
        db_conn: PostgreSQL bağlantı bilgileri (dict)
        table_name (str): Tablo adı
        
    Returns:
        dict: Tablo istatistikleri
    """
    # Varsayılan veri yapısı
    data = {
        "table_name": table_name,
        "table_size": "N/A",
        "row_count": 0,
        "seq_scan": 0,
        "seq_tup_read": 0,
        "idx_scan": 0,
        "idx_tup_fetch": 0,
        "n_tup_ins": 0,
        "n_tup_upd": 0,
        "n_tup_del": 0,
        "n_live_tup": 0,
        "n_dead_tup": 0,
        "last_vacuum": None,
        "last_autovacuum": None,
        "last_analyze": None,
        "last_autoanalyze": None,
        "indexes": [],
        "columns": []
    }
    
    # Bağlantı bilgisi
    conn_str = "host={} port={} user={} password={} dbname={}".format(
        db_conn['host'], db_conn['port'], db_conn['username'], db_conn['password'], db_conn['database']
    )
    
    # 1. Tablo mevcut mu kontrol et
    try:
        connection = psycopg2.connect(conn_str)
        connection.autocommit = True
        
        cursor = connection.cursor()
        table_query = "SELECT * FROM pg_stat_user_tables WHERE relname = %s"
        cursor.execute(table_query, (table_name,))
        stats = cursor.fetchone()
        
        if not stats:
            cursor.close()
            connection.close()
            return {"success": False, "message": "Tablo bulunamadı: {}".format(table_name), "data": {}}
        
        # Temel tablo istatistiklerini kaydet
        if stats:
            data["seq_scan"] = stats[4] if stats[4] is not None else 0
            data["seq_tup_read"] = stats[5] if stats[5] is not None else 0
            data["idx_scan"] = stats[6] if stats[6] is not None else 0
            data["idx_tup_fetch"] = stats[7] if stats[7] is not None else 0
            data["n_tup_ins"] = stats[8] if stats[8] is not None else 0
            data["n_tup_upd"] = stats[9] if stats[9] is not None else 0
            data["n_tup_del"] = stats[10] if stats[10] is not None else 0
            data["n_live_tup"] = stats[12] if stats[12] is not None else 0
            data["n_dead_tup"] = stats[13] if stats[13] is not None else 0
            data["last_vacuum"] = stats[14]
            data["last_autovacuum"] = stats[15]
            data["last_analyze"] = stats[16]
            data["last_autoanalyze"] = stats[17]
        
        cursor.close()
        connection.close()
    except Exception as e:
        logger.error("Tablo istatistikleri alınırken hata: {}".format(str(e)))
        # Hata olsa bile diğer sorgulara devam et
    
    # 2. Tablo boyutu
    try:
        connection = psycopg2.connect(conn_str)
        connection.autocommit = True
        
        cursor = connection.cursor()
        size_query = "SELECT pg_size_pretty(pg_total_relation_size(%s))"
        cursor.execute(size_query, (table_name,))
        result = cursor.fetchone()
        
        if result and result[0]:
            data["table_size"] = result[0]
        
        cursor.close()
        connection.close()
    except Exception as e:
        logger.error("Tablo boyutu alınırken hata: {}".format(str(e)))
    
    # 3. Satır sayısı (yaklaşık)
    try:
        connection = psycopg2.connect(conn_str)
        connection.autocommit = True
        
        cursor = connection.cursor()
        count_query = "SELECT reltuples::bigint FROM pg_class WHERE relname = %s"
        cursor.execute(count_query, (table_name,))
        result = cursor.fetchone()
        
        if result and result[0] is not None:
            data["row_count"] = result[0]
        
        cursor.close()
        connection.close()
    except Exception as e:
        logger.error("Satır sayısı alınırken hata: {}".format(str(e)))
    
    # 4. İndeks bilgileri
    try:
        connection = psycopg2.connect(conn_str)
        connection.autocommit = True
        
        cursor = connection.cursor()
        index_query = """
        SELECT
            indexrelname as index_name,
            idx_scan as scans,
            pg_size_pretty(pg_relation_size(indexrelid)) as index_size
        FROM pg_stat_user_indexes
        WHERE relname = %s
        ORDER BY idx_scan DESC
        """
        cursor.execute(index_query, (table_name,))
        results = cursor.fetchall()
        
        indexes = []
        for row in results:
            indexes.append({
                "index_name": row[0] if row[0] is not None else "",
                "scans": row[1] if row[1] is not None else 0,
                "index_size": row[2] if row[2] is not None else "N/A"
            })
        
        data["indexes"] = indexes
        
        cursor.close()
        connection.close()
    except Exception as e:
        logger.error("İndeks bilgileri alınırken hata: {}".format(str(e)))
    
    # 5. Sütun bilgileri
    try:
        connection = psycopg2.connect(conn_str)
        connection.autocommit = True
        
        cursor = connection.cursor()
        column_query = """
        SELECT
            column_name,
            data_type,
            character_maximum_length
        FROM information_schema.columns
        WHERE table_name = %s
        ORDER BY ordinal_position
        """
        cursor.execute(column_query, (table_name,))
        results = cursor.fetchall()
        
        columns = []
        for row in results:
            columns.append({
                "column_name": row[0] if row[0] is not None else "",
                "data_type": row[1] if row[1] is not None else "",
                "max_length": row[2]  # max_length NULL olabilir
            })
        
        data["columns"] = columns
        
        cursor.close()
        connection.close()
    except Exception as e:
        logger.error("Sütun bilgileri alınırken hata: {}".format(str(e)))
    
    # 6. Tüm verileri döndür
    return {
        "success": True,
        "message": "{} tablosu istatistikleri başarıyla alındı".format(table_name),
        "data": data
    }

© KUJUNTI.ID