Jeśli to możliwe, nie rób tego.
Oto odpowiedź - to anty-wzór. Jeśli klient zna tabelę, z której chce uzyskać dane, to SELECT FROM ThatTable
. Jeśli baza danych jest zaprojektowana w taki sposób, że jest to wymagane, wydaje się, że została zaprojektowana w sposób nieoptymalny. Jeśli warstwa dostępu do danych musi wiedzieć, czy wartość istnieje w tabeli, łatwo jest utworzyć kod SQL w tym kodzie, a umieszczenie tego kodu w bazie danych nie jest dobre.
Wydaje mi się, że jest to instalowanie urządzenia wewnątrz windy, w którym można wpisać numer pożądanego piętra. Po naciśnięciu przycisku Go przesuwa mechaniczną dłoń do odpowiedniego przycisku dla żądanego piętra i naciska go. To wprowadza wiele potencjalnych problemów.
Uwaga: tutaj nie ma zamiaru kpić. Mój głupi przykład z windą był * najlepszym urządzeniem, jakie mogłem sobie wyobrazić * do zwięzłego wskazywania problemów z tą techniką. Dodaje bezużyteczną warstwę pośredniej, przenosząc wybór nazwy tabeli z przestrzeni wywołującej (przy użyciu solidnego i dobrze zrozumiałego DSL, SQL) do hybrydy, używając niejasnego / dziwacznego kodu SQL po stronie serwera.
Taki podział odpowiedzialności poprzez przeniesienie logiki konstrukcji zapytań do dynamicznego SQL sprawia, że kod jest trudniejszy do zrozumienia. Narusza standardową i niezawodną konwencję (jak zapytanie SQL wybiera, co wybrać) w nazwie niestandardowego kodu obarczonego potencjałem błędu.
Oto szczegółowe punkty dotyczące niektórych potencjalnych problemów związanych z tym podejściem:
Dynamiczny SQL oferuje możliwość iniekcji SQL, która jest trudna do rozpoznania w kodzie frontonu lub w samym kodzie zaplecza (aby to zobaczyć, trzeba je razem sprawdzić).
Procedury i funkcje składowane mogą uzyskiwać dostęp do zasobów, do których właściciel SP / funkcji ma prawa, ale wywołujący nie. O ile rozumiem, bez szczególnej ostrożności, to domyślnie, gdy używasz kodu, który tworzy dynamiczny SQL i uruchamia go, baza danych wykonuje dynamiczny SQL na prawach wywołującego. Oznacza to, że albo w ogóle nie będziesz mógł korzystać z uprzywilejowanych obiektów, albo będziesz musiał otworzyć je dla wszystkich klientów, zwiększając powierzchnię potencjalnego ataku na dane uprzywilejowane. Ustawienie SP / funkcji w czasie tworzenia, aby zawsze działała jako określony użytkownik (w SQL Server EXECUTE AS
) może rozwiązać ten problem, ale komplikuje sprawę. Zwiększa to ryzyko wstrzyknięcia SQL, o którym mowa w poprzednim punkcie, czyniąc dynamiczny SQL bardzo kuszącym wektorem ataku.
Kiedy programista musi zrozumieć, co robi kod aplikacji, aby go zmodyfikować lub naprawić błąd, bardzo trudno mu będzie uzyskać dokładne zapytanie SQL, które jest wykonywane. Można użyć profilera SQL, ale wymaga to specjalnych uprawnień i może mieć negatywny wpływ na wydajność systemów produkcyjnych. Wykonane zapytanie może zostać zarejestrowane przez SP, ale zwiększa to złożoność i przynosi wątpliwe korzyści (wymaga dostosowania nowych tabel, usunięcia starych danych itp.) I jest dość nieoczywiste. W rzeczywistości niektóre aplikacje są zaprojektowane w taki sposób, że programista nie ma poświadczeń bazy danych, więc zobaczenie przesłanego zapytania jest dla niego prawie niemożliwe.
Gdy wystąpi błąd, na przykład podczas próby wybrania tabeli, która nie istnieje, otrzymasz z bazy danych komunikat zawierający informację o „nieprawidłowej nazwie obiektu”. Stanie się to dokładnie tak samo, niezależnie od tego, czy tworzysz kod SQL na zapleczu, czy w bazie danych, ale różnica polega na tym, że jakiś biedny programista, który próbuje rozwiązać problem z systemem, musi przejść o jeden poziom głębiej do kolejnej jaskini poniżej tej, w której istnieje problem, aby zagłębić się w cudowną procedurę, która robi wszystko, aby spróbować ustalić, na czym polega problem. Dzienniki nie pokażą „Błąd w GetWidget”, pokaże „Błąd w OneProcedureToRuleThemAllRunner”. Ta abstrakcja ogólnie pogorszy system .
Przykład w pseudo-C # przełączania nazw tabel na podstawie parametru:
string sql = $"SELECT * FROM {EscapeSqlIdentifier(tableName)};"
results = connection.Execute(sql);
Chociaż nie eliminuje to każdego możliwego problemu, jaki można sobie wyobrazić, wady, które nakreśliłem w innej technice, są nieobecne w tym przykładzie.