"use client"; import { useState, useEffect, ChangeEvent } from "react"; import { Button } from "@/components/ui/button"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, } from "@/components/ui/dialog"; import { Textarea } from "@/components/ui/textarea"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { useToast } from "@/hooks/use-toast"; import { ExternalDbConnectionAPI } from "@/lib/api/externalDbConnection"; interface TableColumn { column_name: string; data_type: string; is_nullable: string; column_default: string | null; } interface TableInfo { table_name: string; columns: TableColumn[]; description: string | null; } interface QueryResult { [key: string]: string | number | boolean | null | undefined; } interface TableColumn { column_name: string; data_type: string; is_nullable: string; column_default: string | null; } interface TableInfo { table_name: string; columns: TableColumn[]; description: string | null; } interface SqlQueryModalProps { isOpen: boolean; onClose: () => void; connectionId: number; connectionName: string; } export const SqlQueryModal: React.FC = ({ isOpen, onClose, connectionId, connectionName }) => { const { toast } = useToast(); const [query, setQuery] = useState("SELECT * FROM "); const [results, setResults] = useState([]); const [loading, setLoading] = useState(false); const [tables, setTables] = useState([]); const [selectedTable, setSelectedTable] = useState(""); const [loadingTables, setLoadingTables] = useState(false); const [selectedTableColumns, setSelectedTableColumns] = useState([]); const [loadingColumns, setLoadingColumns] = useState(false); // 테이블 목록 로딩 useEffect(() => { console.log("SqlQueryModal - connectionId:", connectionId); const loadTables = async () => { setLoadingTables(true); try { const result = await ExternalDbConnectionAPI.getTables(connectionId); if (result.success && result.data) { setTables(result.data as unknown as TableInfo[]); } } catch (error) { console.error("테이블 목록 로딩 오류:", error); toast({ title: "오류", description: "테이블 목록을 불러오는데 실패했습니다.", variant: "destructive", }); } finally { setLoadingTables(false); } }; loadTables(); }, []); // 테이블 선택 시 컬럼 정보 로딩 const loadTableColumns = async (tableName: string) => { if (!tableName) { setSelectedTableColumns([]); return; } setLoadingColumns(true); try { const result = await ExternalDbConnectionAPI.getTableColumns(connectionId, tableName); if (result.success && result.data) { setSelectedTableColumns(result.data as TableColumn[]); } } catch (error) { console.error("컬럼 정보 로딩 오류:", error); toast({ title: "오류", description: "컬럼 정보를 불러오는데 실패했습니다.", variant: "destructive", }); } finally { setLoadingColumns(false); } }; const handleExecute = async () => { console.log("실행 버튼 클릭"); if (!query.trim()) { toast({ title: "오류", description: "실행할 쿼리를 입력해주세요.", variant: "destructive", }); return; } // SELECT 쿼리만 허용하는 검증 const trimmedQuery = query.trim().toUpperCase(); if (!trimmedQuery.startsWith("SELECT")) { toast({ title: "보안 오류", description: "외부 데이터베이스에서는 SELECT 쿼리만 실행할 수 있습니다. INSERT, UPDATE, DELETE는 허용되지 않습니다.", variant: "destructive", }); return; } // 위험한 키워드 검사 const dangerousKeywords = ["INSERT", "UPDATE", "DELETE", "DROP", "CREATE", "ALTER", "TRUNCATE", "EXEC", "EXECUTE"]; const hasDangerousKeyword = dangerousKeywords.some((keyword) => trimmedQuery.includes(keyword)); if (hasDangerousKeyword) { toast({ title: "보안 오류", description: "데이터를 변경하거나 삭제하는 쿼리는 허용되지 않습니다. SELECT 쿼리만 사용해주세요.", variant: "destructive", }); return; } console.log("쿼리 실행 시작:", { connectionId, query }); setLoading(true); try { const result = await ExternalDbConnectionAPI.executeQuery(connectionId, query); console.log("쿼리 실행 결과:", result); if (result.success && result.data) { setResults(result.data); toast({ title: "성공", description: "쿼리가 성공적으로 실행되었습니다.", }); } else { toast({ title: "오류", description: result.message || "쿼리 실행 중 오류가 발생했습니다.", variant: "destructive", }); } } catch (error) { console.error("쿼리 실행 오류:", error); toast({ title: "오류", description: error instanceof Error ? error.message : "쿼리 실행 중 오류가 발생했습니다.", variant: "destructive", }); } finally { setLoading(false); } }; return ( {connectionName} - SQL 쿼리 실행 데이터베이스에 대해 SQL SELECT 쿼리를 실행하고 결과를 확인할 수 있습니다. {/* 쿼리 입력 영역 */}
{/* 테이블 선택 */}
{/* 테이블 정보 */}

사용 가능한 테이블

{tables.map((table) => (

{table.table_name}

{table.description && (

{table.description}

)}
))}
{/* 선택된 테이블의 컬럼 정보 */} {selectedTable && (

테이블 컬럼 정보: {selectedTable}

{loadingColumns ? (
컬럼 정보 로딩 중...
) : selectedTableColumns.length > 0 ? (
컬럼명 데이터 타입 NULL 허용 기본값 {selectedTableColumns.map((column) => ( {column.column_name} {column.data_type} {column.is_nullable} {column.column_default || "-"} ))}
) : (
컬럼 정보를 불러올 수 없습니다.
)}
)}
{/* 쿼리 입력 */}