In meinem aktuellen Projekt werden binäre Objekte, wie zum Beispiel Bitmap Grafiken im SQL Server unter dem Daten Typ varbinary(MAX) gespeichert. Der Zugriff auf die Objekte findet über deren Hash statt. Einige Objekte sollten bereits bei einer ganz neu erzeugten Datenbank vorhanden sein.
Eine Anforderung ist, dass die komplette Datenbank über SQL Skripte erstellt werden kann. Diese Skripte sind natürlich unter Source Control im Team Foundation Server. Aber wie kriege ich jetzt die binären Daten meiner Objekte in ein Skript? Mit den Bordmittel habe ich das nicht geschafft.
Meine Datenbank Diagramme sichere ich mit Hilfe der Skripte aus diesem sehr guten Artikel auf The Code Project: Script SQL Server 2005 diagrams to a file
Darin enthalten ist eine T-SQL User Defined Function mit dem Namen Tool_VarbinaryToVarcharHex. Das ist der wesentliche Baustein, um binäre Daten in einem Skript automatisiert darstellen zu können.
Wichtig ist noch, um den INSERT und UPDATE Befehl einen Try Block zu haben. Falls das Objekt schon existiert, würde der INSERT Befehl scheitern, aber alle nachfolgenden UPDATE Befehle würden die binären Daten anhängen. Das Objekt wäre dann doppelt so groß.
Das komplette Skript erzeugt alle Befehle, um den momentanen Inhalt der Tabelle anzulegen und die binären Daten häppchenweise hineinzuschreiben:
DECLARE @Hash binary(24)
DECLARE @HashText varchar(60)
DECLARE @ObjectData varbinary(MAX)
DECLARE @Line varchar(MAX)
DECLARE @size INT
DECLARE @index INT
DECLARE @chunk INT
DECLARE blobs CURSOR FOR SELECT Hash,ObjectData FROM BinaryObjects WHERE Complete=1
OPEN blobs
FETCH NEXT FROM blobs INTO @Hash,@ObjectData
WHILE (@@FETCH_STATUS = 0)
BEGIN
SET @HashText = ' 0x' + UPPER(dbo.Tool_VarbinaryToVarcharHex (@Hash))
SET @size = DATALENGTH(@ObjectData)
SET @index = 1
SET @chunk = 32
PRINT ''
PRINT '-- BEGIN BLOB'
PRINT 'BEGIN TRY'
PRINT ' INSERT INTO BinaryObjects (Hash, ObjectData, Complete) VALUES'
PRINT ' (' + @HashText + ', 0x, 0)'
WHILE @index < @size
BEGIN
-- Die Objekt Daten häppchenweise ausgeben
SELECT @line =
' ('
+ '0x' + UPPER(dbo.Tool_VarbinaryToVarcharHex (SUBSTRING (ObjectData, @index, @chunk)))
+ ', null, 0)'
FROM BinaryObjects
WHERE Hash = @Hash
PRINT ' UPDATE BinaryObjects SET ObjectData .Write'
PRINT @line
PRINT ' WHERE Hash = ' + @HashText
SET @index = @index + @chunk
END
PRINT ' UPDATE BinaryObjects SET Complete = 1 '
PRINT ' WHERE Hash =' + @HashText
PRINT 'END TRY'
PRINT 'BEGIN CATCH'
PRINT ' PRINT ''Hash ' + @HashText + ' already exists'''
PRINT 'END CATCH'
PRINT '-- END BLOB'
FETCH NEXT FROM blobs INTO @Hash,@ObjectData
END
CLOSE blobs
DEALLOCATE blobs
Dieses Skript erzeugt beispielsweise folgende Ausgabe:
-- BEGIN BLOB
BEGIN TRY
INSERT INTO BinaryObjects (Hash, ObjectData, Complete) VALUES
( 0xA9199ED44700D84F80BBE5F6F2B2F045767C1E2300000132, 0x, 0)
UPDATE BinaryObjects SET ObjectData .Write
(0xFFD8FFE000104A46494600010200006400640000FFEC00114475636B79000100, null, 0)
WHERE Hash = 0xA9199ED44700D84F80BBE5F6F2B2F045767C1E2300000132
UPDATE BinaryObjects SET ObjectData .Write
(0x04000000000000FFEE000E41646F62650064C000000001FFDB0084001B1A1A29, null, 0)
WHERE Hash = 0xA9199ED44700D84F80BBE5F6F2B2F045767C1E2300000132
UPDATE BinaryObjects SET ObjectData .Write
(0x1D2941262641422F2F2F42473F3E3E3F47474747474747474747474747474747, null, 0)
WHERE Hash = 0xA9199ED44700D84F80BBE5F6F2B2F045767C1E2300000132
UPDATE BinaryObjects SET ObjectData .Write
(0x47474747474747474747474747474747474747474747474747474747011D2929, null, 0)
WHERE Hash = 0xA9199ED44700D84F80BBE5F6F2B2F045767C1E2300000132
UPDATE BinaryObjects SET ObjectData .Write
(0x3426343F28283F473F353F474747474747474747474747474747474747474747, null, 0)
WHERE Hash = 0xA9199ED44700D84F80BBE5F6F2B2F045767C1E2300000132
UPDATE BinaryObjects SET ObjectData .Write
(0x4747474747474747474747474747474747474747474747474747474747FFC000, null, 0)
WHERE Hash = 0xA9199ED44700D84F80BBE5F6F2B2F045767C1E2300000132
UPDATE BinaryObjects SET ObjectData .Write
(0x11080010001003012200021101031101FFC4004C000101000000000000000000, null, 0)
WHERE Hash = 0xA9199ED44700D84F80BBE5F6F2B2F045767C1E2300000132
UPDATE BinaryObjects SET ObjectData .Write
(0x0000000000000401010100000000000000000000000000000406100100000000, null, 0)
WHERE Hash = 0xA9199ED44700D84F80BBE5F6F2B2F045767C1E2300000132
UPDATE BinaryObjects SET ObjectData .Write
(0x000000000000000000000000110100000000000000000000000000000000FFDA, null, 0)
WHERE Hash = 0xA9199ED44700D84F80BBE5F6F2B2F045767C1E2300000132
UPDATE BinaryObjects SET ObjectData .Write
(0x000C03010002110311003F008000D46FFFD9, null, 0)
WHERE Hash = 0xA9199ED44700D84F80BBE5F6F2B2F045767C1E2300000132
UPDATE BinaryObjects SET Complete = 1
WHERE Hash = 0xA9199ED44700D84F80BBE5F6F2B2F045767C1E2300000132
END TRY
BEGIN CATCH
PRINT 'Hash 0xA9199ED44700D84F80BBE5F6F2B2F045767C1E2300000132 already exists'
END CATCH
-- END BLOB
Und was steckt da für ein binäres Objekt in dem Skript? Ganz klar, eine kleines, rotes Quadarat! Gespeichert mit 16x16 Pixel im Jpeg Format.