T-SQL: Kommentare aus Scripts entfernen
Um eine Datenbank nach Objekten zu durchsuchen die einen vorgegebenen String enthalten muss man nur durch die System-View sys.sql_modules parsen. Hier steht im Feld “Definitions” der Quelltext von Funktionen, Prozeduren oder Views.
| T-SQL | | copy code | | ? |
| 1 | SELECT OBJECT_ID,definition FROM sys.sql_modules WHERE definition like '%[^a-zA-Z0-9_]Contact[^a-zA-Z0-9_]%' |
| 2 |
Allerdings hat dieses einfache Verfahren einen Nachteil. Wenn der Quellcode sehr gut dokumentiert ist bzw. durch andere Vorgaben viele Kommentarbereiche enthalten sind, kann das Ergebnis eine ganze Menge an Treffern anzeigen die man so vielleicht gar nicht haben wollte.
Um also diese Kommentare aus den Quelltexten (weitestgehend) zu entfernen, habe ich eine scalar Funktion geschrieben die dies bei einer Abfrage direkt erledigen kann. Der Rest des Quellcodes kann man dann nach dem gewünschten Begriff durchsuchen und erhält so hoffentlich eine aussagekräftigere Ergebnismenge.
Hier das Script:
| T-SQL | | copy code | | ? |
| 001 | |
| 002 | CREATE FUNCTION dbo.[SVF_StripComments](@Textfeld NVARCHAR(MAX)) |
| 003 | RETURNS NVARCHAR(MAX) |
| 004 | AS |
| 005 | BEGIN |
| 006 | /* -------------------------------------------------------- |
| 007 | Die Funktion entfernt Kommentare aus einem gegebenen String |
| 008 | Es werden Zeilenkommentare als auch Blockkommentare |
| 009 | entfernt. Die Zeilenschaltung bei Zeilenkommentaren bleibt |
| 010 | erhalten. |
| 011 | |
| 012 | Es werden auch Kommentare in Strings ersetzt. Dies bedeutet |
| 013 | bei Zeilenkommentaren, dass hier das Ende mit dem Ende |
| 014 | des Strings erreicht wird. |
| 015 | --------------------------------------------------------- */ |
| 016 | |
| 017 | DECLARE @DefLen INT |
| 018 | DECLARE @InString BIT |
| 019 | DECLARE @I INT |
| 020 | DECLARE @Mask TINYINT |
| 021 | DECLARE @MoveCursor INT |
| 022 | DECLARE @TempSpace NVARCHAR(MAX) |
| 023 | |
| 024 | DECLARE @IsLineCmt BIT |
| 025 | DECLARE @IsBlockCmt TINYINT |
| 026 | |
| 027 | SET @TempSpace = '' |
| 028 | SET @DefLen = LEN(@Textfeld) |
| 029 | SET @I = 1 |
| 030 | SET @Mask = 0 |
| 031 | SET @InString = 0 |
| 032 | SET @IsLineCmt = 0 |
| 033 | SET @IsBlockCmt= 0 |
| 034 | SET @MoveCursor= 1 |
| 035 | |
| 036 | -- Quellstring zeichenweise durchlaufen |
| 037 | |
| 038 | WHILE @I <= @DefLen |
| 039 | BEGIN |
| 040 | |
| 041 | -- Beim Zeilenkommentar innerhalb eines Strings ist |
| 042 | -- das Ende des Kommentars, wenn das Ende des Strings |
| 043 | -- erreicht ist. |
| 044 | -- Wenn noch ein Blockkommentar vorhanden ist, dann |
| 045 | -- noch nicht die @Mask-Variable (Kommentarkennzeichen) |
| 046 | -- zurücksetzen da wir ja noch im Kommentar sind. |
| 047 | |
| 048 | IF @IsLineCmt = 1 and @InString = 1 and SUBSTRING(@Textfeld,@I,1) = '''' |
| 049 | BEGIN |
| 050 | SET @IsLineCmt = 0 |
| 051 | SET @Mask = CASE WHEN @IsBlockCmt > 0 THEN 1 ELSE 0 END |
| 052 | END |
| 053 | |
| 054 | -- Stringtest (befinden wir uns in einem String?) |
| 055 | -- Dies ist nur außerhalb eines Kommentars notwendig .. |
| 056 | |
| 057 | IF @IsLineCmt = 0 and @Mask = 0 and SUBSTRING(@Textfeld,@I,1) = '''' |
| 058 | BEGIN |
| 059 | SET @InString = CASE @InString WHEN 1 THEN 0 ELSE 1 END |
| 060 | END |
| 061 | |
| 062 | -- ---------------------------------------------------------------------------- |
| 063 | -- Beginn der Kommentare testen |
| 064 | -- ---------------------------------------------------------------------------- |
| 065 | |
| 066 | -- Begin eines Block-Kommentars? |
| 067 | |
| 068 | IF SUBSTRING(@Textfeld,@I,2) = '/*' and @IsLineCmt = 0 |
| 069 | BEGIN |
| 070 | SET @Mask = 1 |
| 071 | SET @IsBlockCmt = @IsBlockCmt + 1 |
| 072 | END |
| 073 | |
| 074 | -- Begin eines Zeilenkommentars? |
| 075 | -- Innerhalb eines Kommentars wird nicht geprüft! |
| 076 | |
| 077 | IF @Mask = 0 and SUBSTRING(@Textfeld,@I,2) = '--' |
| 078 | BEGIN |
| 079 | SET @Mask = 1 |
| 080 | SET @IsLineCmt = 1 |
| 081 | END |
| 082 | |
| 083 | -- ---------------------------------------------------------------------------- |
| 084 | -- Auf Ende der Kommentare testen |
| 085 | -- ---------------------------------------------------------------------------- |
| 086 | |
| 087 | -- Ende der Zeile beim Zeilenkommentar? |
| 088 | |
| 089 | IF @IsLineCmt = 1 and SUBSTRING(@Textfeld,@I,2) = CHAR(13)+CHAR(10) |
| 090 | BEGIN |
| 091 | SET @Mask = 0 |
| 092 | END |
| 093 | |
| 094 | -- Ende der Zeile beim Block-Kommentar? |
| 095 | |
| 096 | IF @IsBlockCmt > 0 and SUBSTRING(@Textfeld,@I,2) = '*/' |
| 097 | BEGIN |
| 098 | SET @I = @I + CASE WHEN @IsBlockCmt > 1 THEN 1 ELSE 2 END |
| 099 | |
| 100 | SET @IsBlockCmt = @IsBlockCmt - 1 |
| 101 | |
| 102 | IF @IsBlockCmt <= 0 |
| 103 | BEGIN |
| 104 | SET @IsBlockCmt = 0 |
| 105 | SET @Mask = 0 |
| 106 | SET @MoveCursor = 0 |
| 107 | END |
| 108 | END |
| 109 | |
| 110 | -- ---------------------------------------------------------------------------- |
| 111 | -- Bei CRLF bzw. Block-Ende werden zwei Zeichen ersetzt. |
| 112 | -- Wenn dies der Fall ist, dann darf bei der Mask-Abfrage der "Cursor" im |
| 113 | -- Quellstring nicht mehr weiter gerechnet werden. |
| 114 | -- ---------------------------------------------------------------------------- |
| 115 | |
| 116 | -- Wenn der Zeilenkommentar (mit CRLF) endet ... |
| 117 | |
| 118 | IF @IsLineCmt = 1 and @Mask = 0 |
| 119 | BEGIN |
| 120 | SET @TempSpace = @TempSpace + SUBSTRING(@Textfeld,@I,2) |
| 121 | SET @IsLineCmt = 0 |
| 122 | |
| 123 | SET @I = @I + 2 |
| 124 | SET @MoveCursor = 0 |
| 125 | |
| 126 | -- innerhalb eines Blockkommentars? |
| 127 | SET @Mask = CASE @IsBlockCmt WHEN 1 THEN 1 ELSE 0 END |
| 128 | END |
| 129 | |
| 130 | -- ---------------------------------------------------------------------------- |
| 131 | -- Wenn @Mask gesetzt ist, dann Inhalt der Quelle ignorieren |
| 132 | -- im anderen Fall wird der Inhalt in den Arbeitsbereich kopiert. |
| 133 | -- ---------------------------------------------------------------------------- |
| 134 | |
| 135 | IF @Mask = 1 |
| 136 | BEGIN |
| 137 | SET @I = @I + 1 |
| 138 | END |
| 139 | |
| 140 | -- Wenn @MoveCursor = 0 ist, dann wurde der Spaltenzähler bereits auf das |
| 141 | -- nächste zu verarbeitende Zeichen gesetzt. |
| 142 | -- Es muss dann keine weitere Verarbeitung durchgeführt werden. |
| 143 | |
| 144 | IF @MoveCursor = 0 |
| 145 | BEGIN |
| 146 | SET @MoveCursor = 1 |
| 147 | END |
| 148 | ELSE |
| 149 | BEGIN |
| 150 | IF @Mask = 0 |
| 151 | BEGIN |
| 152 | SET @TempSpace = @TempSpace + SUBSTRING(@Textfeld,@I,1) |
| 153 | SET @I = @I + 1 |
| 154 | END |
| 155 | END |
| 156 | END |
| 157 | |
| 158 | RETURN @TempSpace |
| 159 | END |
| 160 | go |
| 161 | |
| 162 | -- -------------------------------------------------------------- |
| 163 | -- ... und hier die Funktion testen |
| 164 | -- -------------------------------------------------------------- |
| 165 | |
| 166 | DECLARE @Textfeld NVARCHAR(1000); |
| 167 | |
| 168 | SET @Textfeld = ' |
| 169 | -- ----------------------------- |
| 170 | -- Hello World |
| 171 | -- ----------------------------- |
| 172 | // Hello World |
| 173 | Hello ''''''World'''' -- Hier ist ein Kommentar'' + Nachlauf |
| 174 | /* Hello ''''''World'''' -- Hier ist ein Kommentar'' + Nachlauf |
| 175 | Hier gehts weiter mit World */ wie auch immer |
| 176 | -> Achtung: ''und noch eine World.Tabelle'' |
| 177 | -> hier ist endlich Schluss mit World_usw. |
| 178 | |
| 179 | /* |
| 180 | Hier -- ''Kommentar |
| 181 | sein oder nichtsein. |
| 182 | */ |
| 183 | '; |
| 184 | |
| 185 | PRINT '=========================================================' |
| 186 | PRINT dbo.SVF_StripComments(@Textfeld) |
| 187 | PRINT '=========================================================' |
| 188 |
have fun
Facebook
XING
META-SQL