import { safeSql } from '@supabase/pg-meta/src/pg-format' import { LOCAL_STORAGE_KEYS, useParams } from 'common' import { RefreshCw, RotateCcw, X } from 'lucide-react' import { parseAsString, useQueryStates } from 'nuqs' import { useEffect, useMemo, useState } from 'react' import { toast } from 'sonner' import { Button, cn, LoadingLine } from 'ui' import { Admonition } from 'ui-patterns' import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal' import { Markdown } from '../../Markdown' import { captureQueryPerformanceError } from '../QueryPerformance.utils' import { QueryPerformanceFilterBar } from '../QueryPerformanceFilterBar' import { QueryPerformanceGrid } from '../QueryPerformanceGrid' import { QueryPerformanceMetrics } from '../QueryPerformanceMetrics' import { QueryPerformanceInfiniteHook } from '../useQueryPerformanceQuery' import { transformStatementDataToRows } from './WithStatements.utils' import { PresetHookResult } from '@/components/interfaces/Reports/Reports.utils' import { DownloadResultsButton } from '@/components/ui/DownloadResultsButton' import { ShortcutTooltip } from '@/components/ui/ShortcutTooltip' import { useReadReplicasQuery } from '@/data/read-replicas/replicas-query' import { formatDatabaseID } from '@/data/read-replicas/replicas.utils' import { executeSql } from '@/data/sql/execute-sql-query' import { useInfiniteScroll } from '@/hooks/misc/useInfiniteScroll' import { useLocalStorageQuery } from '@/hooks/misc/useLocalStorage' import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject' import { DOCS_URL, IS_PLATFORM } from '@/lib/constants' import { getErrorMessage } from '@/lib/get-error-message' import { useDatabaseSelectorStateSnapshot } from '@/state/database-selector' import { SHORTCUT_IDS } from '@/state/shortcuts/registry' import { useShortcut } from '@/state/shortcuts/useShortcut' interface WithStatementsProps { queryHitRate: PresetHookResult queryPerformanceQuery: QueryPerformanceInfiniteHook queryMetrics: PresetHookResult } export const WithStatements = ({ queryHitRate, queryPerformanceQuery, queryMetrics, }: WithStatementsProps) => { const { ref } = useParams() const { data: project } = useSelectedProjectQuery() const state = useDatabaseSelectorStateSnapshot() const { data, isLoading, isRefetching, isFetchingNextPage, hasNextPage, error: queryError, fetchNextPage, refetch: runQuery, } = queryPerformanceQuery const isPrimaryDatabase = state.selectedDatabaseId === ref const formattedDatabaseId = formatDatabaseID(state.selectedDatabaseId ?? '') const hitRateError = 'error' in queryHitRate ? queryHitRate.error : null const metricsError = 'error' in queryMetrics ? queryMetrics.error : null const mainQueryError = queryError || null const [showResetgPgStatStatements, setShowResetgPgStatStatements] = useState(false) const [showBottomSection, setShowBottomSection] = useLocalStorageQuery( LOCAL_STORAGE_KEYS.QUERY_PERF_SHOW_BOTTOM_SECTION, true ) const [{ indexAdvisor }] = useQueryStates({ indexAdvisor: parseAsString.withDefault('false'), }) const handleRefresh = () => { runQuery() queryHitRate.runQuery() queryMetrics.runQuery() } useShortcut(SHORTCUT_IDS.OBSERVABILITY_REFRESH, handleRefresh, { enabled: !isRefetching, }) useShortcut(SHORTCUT_IDS.OBSERVABILITY_RESET_REPORT, () => { setShowResetgPgStatStatements(true) }) const processedData = useMemo(() => { return transformStatementDataToRows(data || [], indexAdvisor === 'true') }, [data, indexAdvisor]) const { data: databases } = useReadReplicasQuery({ projectRef: ref }) const handleScroll = useInfiniteScroll({ isLoading, isFetchingNextPage, hasNextPage, fetchNextPage, }) useEffect(() => { state.setSelectedDatabaseId(ref) // eslint-disable-next-line react-hooks/exhaustive-deps }, [ref]) useEffect(() => { if (mainQueryError) { const errorMessage = getErrorMessage(mainQueryError) const isNotInstalled = typeof errorMessage === 'string' && errorMessage.includes('pg_stat_statements') && errorMessage.includes('does not exist') if (!isNotInstalled) { captureQueryPerformanceError(mainQueryError, { projectRef: ref, databaseIdentifier: state.selectedDatabaseId, queryPreset: 'unified', queryType: 'mainQuery', postgresVersion: project?.dbVersion, databaseType: isPrimaryDatabase ? 'primary' : 'read-replica', sql: queryPerformanceQuery.resolvedSql, errorMessage: errorMessage || undefined, }) } } }, [ mainQueryError, ref, state.selectedDatabaseId, project?.dbVersion, isPrimaryDatabase, queryPerformanceQuery.resolvedSql, ]) useEffect(() => { if (hitRateError) { const errorMessage = getErrorMessage(hitRateError) captureQueryPerformanceError(hitRateError, { projectRef: ref, databaseIdentifier: state.selectedDatabaseId, queryPreset: 'queryHitRate', queryType: 'hitRate', postgresVersion: project?.dbVersion, databaseType: isPrimaryDatabase ? 'primary' : 'read-replica', errorMessage: errorMessage || undefined, }) } }, [hitRateError, ref, state.selectedDatabaseId, project?.dbVersion, isPrimaryDatabase]) useEffect(() => { if (metricsError) { const errorMessage = getErrorMessage(metricsError) captureQueryPerformanceError(metricsError, { projectRef: ref, databaseIdentifier: state.selectedDatabaseId, queryPreset: 'queryMetrics', queryType: 'metrics', postgresVersion: project?.dbVersion, databaseType: isPrimaryDatabase ? 'primary' : 'read-replica', errorMessage: errorMessage || undefined, }) } }, [metricsError, ref, state.selectedDatabaseId, project?.dbVersion, isPrimaryDatabase]) const hasError = mainQueryError || hitRateError || metricsError const errorMessage = mainQueryError ? getErrorMessage(mainQueryError) || 'Failed to load query performance data' : hitRateError ? getErrorMessage(hitRateError) || 'Failed to load cache hit rate data' : metricsError ? getErrorMessage(metricsError) || 'Failed to load query metrics' : null const isPgStatStatementsNotInstalled = typeof errorMessage === 'string' && errorMessage.includes('pg_stat_statements') && errorMessage.includes('does not exist') return ( <> {hasError && (
Reset report
Consider resetting the analysis after optimizing any queries
How is this report generated?
Inspect your database for potential issues
This will reset the pg_stat_statements table in the extensions schema on your{' '} {isPrimaryDatabase ? 'primary database' : `read replica (ID: ${formattedDatabaseId})`} , which is used to calculate query performance. This data will repopulate immediately after.