Fehlercode: 800a0e78 Fehlermeldung: The operation requested by the application is not allowed if the object is closed. ADODB.Recordset Fehler "800a0e78' - Der Vorgang ist für ein geschlossenes Objekt nicht zugelassen.Ursache: sql = "Insert into #Tabelle [..]" & vbcrlf & _ "Select * from #Tabelle" db.execute(sql) |
Das Problem ist das hier zwei Statements nacheinandere abgearbeitet werden womit ADODB leider nicht so klar kommt wie man es erwarten würde. Genauer betrachtet macht ADODB genau das was es soll. Es liefert 2 Recordsets zurück. Das erste behandelt den das erste Statement was nach seiner Ausfühung ohne Rückgabe gleich wieder geschlossen wurde. Lösung: Ansatz 1: Man führt einfach beide Anweisungen sperat aus. Ansatz 2: Ein "SET NOCOUNT ON" als erste Anweisung behebt ebenfalls das Problem.
Ein Freund von mir bat mich für ihn eine Klasse zu schrieben mit der man MD5-Hash von Files erzeugen kann. Da er noch nicht viel Erfahrung mit .Net hat willigte ich ein. Dabei stellte ich jedoch fest das es viele verschiedene Ansätze gibt die jeweils unterschiedliche Resultate erzeugten. Also erzeugte ich mit dem Tool MD5sum.exe ein paar Referenzwerte um meine Ergebnisse zu vergleichen.
1 Imports System.Security.Cryptography
2 Imports System.Text
3 Imports System.IO
4
5 Public Class MD5FileHash
6 Public Function getMD5HashForFile(ByVal strFileName As String) As String
7 If (New FileInfo(strFileName).Exists) Then
8 Dim objSB As New StringBuilder
9 Dim objMD5 As New MD5CryptoServiceProvider
10 Dim objFS As New FileStream(strFileName, FileMode.Open)
11 Dim bHash() As Byte = objMD5.ComputeHash(objFS)
12 objFS.Close()
13 For Each bHex As Byte In bHash
14 objSB.Append(bHex.ToString("x2"))
15 Next
16 Return objSB.ToString
17 Else
18 Throw New FileNotFoundException("File " & strFileName & " not Found.")
19 Return Nothing
20 End If
21 End Function
22 End Class
|
Wichtig ist das die Referenz auf System.Security bestehen muss. Diese Funktion erzeugt MD5-Hash-Werte von Dateien die unter anderem zu den Hash-Werten von MD5sum.exe, digestIT und der MD Hash Tool extension for Firefox kompatibel sind.
Und zugleich erfolgt der zweite Blogeintrag für Heute. Diesmal befasse ich mich mit dem Problem die Version des Acrobat's respektive Acrobat Reader's im Internetexplorer auszulesen. Das kniflige dabei ist das ich nicht VBScript zurückgreifen möchte. Das hat eine einfachen Grund. Die viele Benutzer haben VBScript deaktiviert oder auf "Eingabeaufforderung" gestellt was zu einem nervigen PopUp führen würde.
1 function getAcrobatVersionsNr(style){ //Parameters Accept: short (Return X.X) | long (Return X.X.X) || Returns is none Acrobat detectet NULL
2 document.write('<object id="pdfObj" classid="clsid:CA8A9780-280D-11CF-A24D-444553540000" width="0" height="0" style="display:none"></object>');
3 try{
4 AcrobatVersion = pdfObj.GetVersions();
5 if(AcrobatVersion == '')
6 return null;
7 else{
8 var indice = AcrobatVersion.indexOf("AcroForm");
9 if (indice>-1) {
10 indice = indice + 9;
11 var AcrobatVersionNrLang = AcrobatVersion.substring(indice, indice + 5)
12 indice=AcrobatVersionNrLang.lastIndexOf(".")
13 AcrobatVersionNrKurz = AcrobatVersionNrLang.substring(0,indice);
14 if (style=='short')
15 return AcrobatVersionNrKurz;
16 else if (style=='long')
17 return AcrobatVersionNrLang;
18 }
19 else
20 return null
21
22 }
23 }
24 catch(ex){return null}
25 }
|
Die Funktion getAcrobatVersionsNr erstellt ein neues Objekt der angegebenen classid welches das AcrobatBowserHelper-Objekt representatiert. Anschließend wird geprüft ob sich dieses Objekt instanzieren ließe und wenn ja wird die Funktion GetVersions aufgerufen welche einen String mit allen installierten AcrobatPlugins und deren Versionen auflistet. Das wichtigste Plugin in diesem Zusammenhang ist AcroForm. Nun wird die Versionsinformation dieses Plugins rausgeparst. Die Funktion verfügt über einen Parameter der angibt in welchem Format die Rückgabe erfolgen soll. Zur Auswahl stehen hier "short" und "long". Weitere Informationen entnehmen Sie bitte dem Kommentar. Sollte keine Acrobatversion installiert sein wird NULL zurückgegeben.
Nach einer kurzen Ruhepause möchte ich nun wieder mit meiner Arbeit beginnen. Und gleich bin ich auf das erste Problem gestoßen. Im Namespace System.Web gibt es eine Klasse die sich HttpUtility nennt und die unter anderem die Funktion Urlencode und Urldecode implementiert. Leider hatte ich feststellen müssen das diese Klasse nicht das macht was ich wollte. Mittels des WebClients aus dem System.Net Namespace wollte ich einen Request absätzen der jedoch als Parameter auch umlaute enthielt. Diese wurde jedoch nicht encodiert und auch der WebClient encodiert sie nicht automatisch. Aus diesem Grund habe ich mich drangemacht selber eine entsprechende Implementierung zu schreiben und das Resultat möchte ich euch hier zur Verfügung stellen.
1 Public Function UrlEncode(ByVal strValue As String) As String
2 Dim strTempreturn As String = ""
3 For Each strChar As Char In strValue
4 If InStr(1, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", strChar) = 0 Then
5 strTempreturn += "%" & Hex(Asc(strChar))
6 Else : strTempreturn += strChar
7 End If
8 Next
9 Return strTempreturn
10 End Function
11
12 Public Function UrlDecode(ByVal strValue As String) As String
13 Dim strTempreturn As String = ""
14 Dim arrTempString() As String = strValue.Split("%")
15 For Each strEntry As String In arrTempString
16 If strEntry.Length >= 2 Then
17 If IsHex(strEntry.Substring(0, 2)) Then
18 strTempreturn += Chr("&H" & strEntry.Substring(0, 2))
19 strTempreturn += strEntry.Substring(2)
20 Else : strTempreturn += "%" & strEntry
21 End If
22 Else : strTempreturn += strEntry
23 End If
24 Next
25 Return strTempreturn
26 End Function
27
28 Public Function IsHex(ByVal strValue As String) As Boolean
29 Dim bolTempreturn As Boolean = True
30 If strValue.Length = 1 Or strValue.Length = 2 Then
31 For Each strChar As Char In strValue
32 If InStr(1, "0123456789ABCDEF", strChar) = 0 Then
33 bolTempreturn = False
34 End If
35 Next
36 Else : bolTempreturn = False
37 End If
38 Return bolTempreturn
39 End Function
|
Beide Funktionen erwartet einen String als Parameter und liefern ebenfalls einen String zurück. Kurz zu den Funktionsweisen: UrlEncode:
Diese Funktion prüft ob die im ubergebenen String enthaltenen Zeichen in der Zeichsatz (0-9a-zA-Z) passen (wobei ä,ü,ö,.. ignoriert werden). Sollte dem nicht so sein, wird der Hex-Wert des ASCII-Code dieses Zeichens ermittelt. UrlDecode:Diese Funktion teilt den übergebenen String anhand des %-Zeichens und prüft ob anschließend die nächsten zwei Zeichen einen Hex-Wert darstellen. Wenn ja wird dieser wieder in ein Char convertiert. IsHex:Diese Funktion überprüft lediglich ob die übergebene Zeichenfolge aus einem bzw. zwei Zeichen besteht und im Zeichsatz für Hex-Werte enthalten ist.
Die Fehlermeldung "Response Buffer Limit Exceeded" wird vom IIS geworfen sobald der Puffer einer Webseite eine Größe von 4 MB - 4194304 Byte - überschreitet. Dies trifft auch auf alle eingebetteten Objecte wie Bilder, PDFs und äühnliches zu die direkt ins ASP eingebunden sind. Für dieses Problem gibt es verschiedene Lösungen. Lösung 1 - Verwendung von Response.Flush: Bei einer reinen HTML-Generrierung ist es möglich die Eigenschaft Response.Buffer zu setzten. Diese bewirkt das erstmal garnix besonderes. Erst im Zusammenhang mit mit Response.Flush() wird es interessant. Sobald Response.Buffer auf True gesetzt wurde wird der generierte Seiteninhalt bis zum nächsten Auftreten von Response.Flush() oder dem Ende der Seite gechacht. Hier ein kleines Beispiel
Response.Buffer = True For i=0 to Ubound(arr) set RS = db.execute("Select from table where y=" & arr(i)) Do While not rs.eof and rs.recordcount>1 ..... Loop Response.Flush() Next |
Lösung 2 - Anhebung des ASPBufferLimits: Die zweite Lösung ist dann zu bevorzugen wenn es sich nicht um eine HTML-Generierung handelt. Als Beispiel kann ich hier zum Beispiel aufführen das eine PDF geladen werden soll die größer als 4MB ist - diesen Fall hatte ich heut selber gehabt. Im AdminScripts-Verzeichnis des IIS (Inetpubs) findet sich das Script adsutil.vbs welches man wie folgt aufrufen muss.| cscript.exe adsutil.vbs SET w3svc/aspbufferinglimit LimitSize |
LimitSize stellt die Puffer-Limit-Größe in Byte dar.
Beispielsweise wird mit der Nummer 67108864 die Puffer-Limit-Größe zu
64 MB festgelegt. Nach einem Neustart der IIS-Webinstanz wird die Einstellung übernommen und das Problem sollte nicht mehr auftreten. Floyd
Häufig stößt man in diversen Foren auf die Frage wie man in ASP NULL-Werte in eine Datenbank binden kann. Leider liefert ASP und ADODB keine Möglichkeit von Haus aus mit dies zu machen. Hierzu muss man sich einem kleinen Trick behelfen.
1 dbNull = db.execute("select null").fields(0) |
Natürlich kann man auch den weg gehen das man "NULL" direkt ins Statment schreib, doch dieser Weg ist weder besonders schön noch besonders empfehlenswert da dies zumeist doppelte Code-Pflege mit sich bringt.
Floyd
Im Artikel SQL-Injektion oder Wie binde ich richtig für Anfänger hatte ich vor einiger Zeit mal eine Funktionsblock gepostet um NULL in eine Datenbank zu binden. Da ich die Funktion jetzt mal wieder brauchte wollt ich sie natürlich gleich verbessern. Die neue Version ist um einiges schlanker und hat auch keinen begrenzten Typenumfang mehr.
1 Function ReturnDBNull(ByVal value As Object) As Object
2 If IsNothing(value) Or value = vbEmpty Or value = vbNull Then
3 Return DBNull.Value
4 Else
5 Return value
6 End If
7 End Function |
Floyd
Über dieses Blog
Diese Blog habe ich im April 2006 aus ein wenig Langeweile und auf der Suche nach etwas neuem auf die Beine gestellt mit dem Ziel es als eine Art privates Quellcodearchiv zu verwenden. Der Schwerpunkt dieses Blogs liegt dabei auf .NET-Technologie von Microsoft wobei ich mich nicht auf diese beschränke. Vorallem die Sprachen und Technologien die ich beruflich und privat einsetze - wie zum Beispiel Active Server Pages ASP, MSSQL (T-SQL) - möchte in in diesem Blog ebenfalls behandeln. Hin und wieder kommt auch mal ein privater Post hinzu.
Über mich
Zu mir gibt es eigendlich nicht viel zu sagen. Ich wurde im August 1984 in Leipzig geboren und lebe seither in einem kleinen Dorf etwa 25km von Leipzig entfernt. Im Dezember 1996 bekamm ich meinen ersten eigenen Computer den ich mir durch viel Hausarbeit schwer erarbeiten musste. ^^ Internet war damals noch nicht und so musste ich mich mit einigen wenigen Zeitschriften und den WSH- und VBS-Scripten begügen. So begann ich meine ersten Begegnungen mit der Programmierei eher mit einigen spielereien an HTML, VBS und QBasic.Irgendwann viel mir dann in der Bücherrei ein Buch über Visual Basic in die Hand. Nachdem ich dieses Buch innerhalb von 2 Wochen begierig verschlugen hatte war wieder einmal Hausarbeit fällig :D denn das Visual Studio 6 musste her. Als Schüler-Version war diese auch relativ erschwinglich. Somit begann ich meine ersten Progrämmchen zu schreiben. Wärend die anderen in meiner Klasse noch überlegten was Sie werden wollten stand es für mich schon relativ zeitig Fest: Programmierer. Also beworb ich mich als Fachinformatiker für Anwendungsentwicklung und fand eine Ausbildung bei der Stadt Leipzig. Nachdem ich diese erfolgreich abschließen konnte musste ich eine weile Warten bis ich dann endlich eine Firma fand die mich einstellen wollte. Doch diese Zeit hab ich intensiv genutzt. .Net war grade frisch rausgekommen und wollte erobert werden. Zwischenzeitlich verdiente ich mich hin und wieder durch kleiner Projekte ein paar Euro dazu. Das größte war ein Verschlüsselungssystem für PDF-Dokumente für eine Schweitzer Bank. Damals gab es noch eine sehr aktive Community im programmierer-borad.de und Zusammen mit ein paar anderen Mitgliedern gründete ich damals das Projekt "Programmers-United" und leitetet dieses Projekt über ein paar Jahre lang bis es Aufgrund von Teilnahmemangel (begündet durch Abitur, Bund, etc. der aktivste Mitglieder) versiegte. Eine neue Aufgabe in der Community musste her. Ich stieß auf it-acamdey und bewarb mich als Mitglied der Artikeladministration. Mitlerweile bin ich Nun dort zum Bereichsleiter aufgestiegen.
Erfahungungen
- VB.Net, ASP.Net (seit Version 1.0), Visual Basic 6, ASP, VBS, JavaScript, CSS, HTML, XML, SQL (T-SQL) und Grundlagen in: Java, C, C++, PHP, C#
- MSSQL-Server (2000 und 2005), Firebird, Access, SQLite, MySQL
- Windows 95 bis Vista, Windows 2000 Server bis 2003 und Grundlagen in: Linux (seit Suse Linux 7.0), Apple Mac OS X
- Visual Studio .Net 2003 bis 2005, #Develop, CVS, Subversion
- Microsoft Office, OpenOffice, Lotus Notes
- ...
Ich denke das sollte es erstmal übermich gewesen sein. Wer noch Fragen hat kann sich gerne bei mir per eMail melden.
Heute bin ich wiedermal in einem Forum auf die Frage gestoßen wie den Inhalt einer Variable in die Zwischenablage kopieren, jedoch soll der Inhalt der Zwischenablage auch nach Beendigung des Programms erhalten bleiben und somit anderen Programmen zur Verfügung stehen.
Die Lösung ist dabei Recht einfach. Die Funktion SetDataObject des Clipboard kopiert bekanntlicherweise den Inhalt einer Variable in die Zwischenablage. Einen zweite Parameter kann man jedoch optional noch angeben. Setzt man diesen auf "true" so sorgt er dafür, dass der Inhalt nicht nach Beendigung des Programms wieder gelöscht wird. Dies wird dann als "persistenz des Clipboard-Inhaltes" bezeichnet.
Dim strDaten As String = "TestString"
Clipboard.SetDataObject(strDaten, True) |
Floyd
Hab soeben auf DasBlog 1.9.6264.0 upgedatet. Hab die Grundkonfiguration erstmal wieder hergestellt. Morgen schau ich mir dann mal die Details an.
Gruß Floyd
Für die Zukunft möchte ich persönlich folgende Datenbanksysteme integriert haben: dienstgesteuerte DBSe:
- MySQL - MS SQL Server - PostgreSQL - Firebird - Interbase - Ingres Datei-basierende DBSe:
- SQLite - MSAccess - Firebird k00ni ps.: Welche Version und welche nicht, ist erstmal uninteressant. Aber ich lege das Augenmerk nicht nur auf "New-Stuff", sondern auch auf "ältere" Systeme.
Ich habe mir lange Gedanken darüber gemacht. Und ich denke, wir sollten am Anfang 2-gleisig fahren. Einseits sollten wir die Open-Source-Datenbanksysteme unterstützten. Andererseits auch die komerziellen, speziell aber die, die auch von den "kleinen Leuten" genutzt werden.
Deshalb würde ich MySQL und MS Access angehen. MySQL deshalb, weil ich damit schon seit fast 3 - 4 Jahren mehr oder weniger gearbeitet habe, meist in Verbindung mit PHP. Ich kenne mich dort so aus, das ich schnell und effektiv administrative Aufgaben lösen kann. MS Access wegen der starken Verwendung in privaten Haushalten und in sehr kleinen Firmen.
Später würde ich dann auf MS SQL Server und SQLite gehen, je nachdem, was der Floyd dazu sagt.
Dieser Post ist nur ein Vorschlag und noch nicht endgültig, es darf also diskutiert werden.
Noch eine Anmerkung: Wir sollten versuchen jetzt am Anfang viele "verschiedene" Datenbanksysteme zu integrieren. Liegt daran, dass wir dann später Muster haben, wo wir bei gleichartigen System ansätzen können. Mit dieser Formulierung meine ich Datenbanksysteme, die einerseits per Dienst betrieben werden (MySQL, PostgreSQL, MSSQL Server). Oder als reines "Ein-Datei"-System, wie beispielsweise SQLite.
k00ni
Zu meiner AbwesenheitEs ist schon eine Weile her, dass ich hier etwas gebloggt habe. Das lag daran, dass ich bei der Bundeswehr meine AGA (Allgemeine Grundausbildung) absolviert habe. Nächste Woche Donnerstag wechsele ich dann den Standort von Bremen (Schwanewede) nach Leipzig (Delitzsch). Während dieser Zeit ist mir kaum möglich gewesen etwas am Quellcode zu basteln. Einerseits hatte ich die ersten Wochen so gut wie keine Zeit. Andererseits war ich so geschafft, dass mir in freien Minuten, die selten waren, einfach die Kraft fehlte, etwas zu programmieren. Da habe ich mich lieber mal ein paar Stunden aufs Ohr gehauen. Wie dem auch sei, die AGA ist vorbei und nun beginnt das "normale" Soldatenleben. Wie es da mit meiner Zeit aussieht weiß ich nicht. Aber die letzten 2 Wochen habe ich langsam wieder angefangen und am equal-Projekt weitergearbeitet. Ich hoffe, dass ich dass den Rest meiner Wehrdienstzeit auch kann. Zur Entwicklung des Projektes
In dieser Richtung hat sich einiges getan. Schon vor 3 Monaten konnte man sich aus einer ausgwählten Datenbank alle Tabellen anzeigen lassen, sowie den Inhalt einer bestimmten dazu. Nun arbeite ich daran, dass man neue Tabellen anlegen kann. Dazu habe ich die Bibliothek equal.Objects überarbeitet und neue Objekte hinzugefügt bzw. bestehende modifiziert oder gelöscht. 2 Punkte sind sehr markant bis jetzt: Einerseits habe ich das Verhalten des Providers geändert. Es sind nun nicht mehr alle Funktionen in einer Klasse zu finden, sondern sind auf 3 aufgeteilt wurden: ConnectionFunctions, TableFunctions und DatabaseFunctions. Damit wird die ganze Sache ressourcenschonender, da bei der Arbeit mit Tabellen nicht unbedingt auch Funktionen für Datenbanken oder Verbindungen braucht. Diese würden nämlich sonst zusätzlich mitgeladen werden. Andererseits habe ich mich dazu entschlossen, den Kern des Projektes komplett in C# zu schreiben. Dazu gehört der Namespace equal, als auch equal.Objects. Letzteres war erst in Visual Basic verfasst wurden, um dem Floyd etwas entgegen zukommen. Wenn man aber bei der Entwicklung ständig zwischen den Sprachen springen muss, dass bremst dass unnötig. Zusätzlich dazu schreibe ich auch den MySQL 5.0 Povider in C#. Bei der Portierung des Quellcodes sind mir viele kleine Fehler aufgefallen (inkonsistente Variablennamen, aufgeblähte Klassen etc.), welche ich gleich behoben habe. Ich denke mit diesem Schritt fahre ich bei der Entwicklung besser. Ich hoffe, dass der Floyd es versteht :) Ein Blick in die GlaskugelIch werde die nächsten Stunden damit verbringen, das Anlegen, Modifizieren und Löschen von MySQL 5.0 Tabellen zu implementieren. Als nächster Punkt ist das Anlegen und Löschen von Datenbanken dran. Ist das komplett geschafft, so werde ich dies in Visual Basic .NET für den MS SQL Server portieren. Der Floyd drängte schon am Anfang, dass wir den MS SQL Server mit reinnehmen. Ich werde aber erstmal den 2000er nehmen, da ich denke, dass die 2005er Version noch nicht sehr verbreitet ist. Vom Projektmäßigen her wars das erstmal von meiner Seite. Ich schätze in ein bis 2 Wochen wird das erledigt sein, je nachdem wie es der Bund zulässt. Stehen die Grundfunktionen des Frameworks, dann wird es auch endlich mal einen Download dazu geben. Aber dazu später mehr, denn im jetzigen Zustand zerballert ihr euch eure Datenbanksysteme nur damit, statt was vernünftiges damit anzustellen. k00ni PostSkriptum: Ich spiele mit dem Gedanken, ein Add-In für das VS.NET 2005 zu schreiben, welches das Entwickeln von Anwendungen für das equal-Framework erlaubt.
Mit nem nun folgenden Script kann man überprüfen ob beim Internetexplorer der PopUp-Blocker aktiviert ist. Sollte der PopUp-Blocker aktiviert sein oder innerhalb des PopUps darf kein JavaScript ausgeführt werden gibt die Funktion "CheckPopUp" "false" zurück, ansonsten "true". Das Script basiert auf 2 Seiten. Und zwar Seite eins, die aufrufende Seite versucht ein PopUp zu öffnen. Dieses PopUp versucht - insofern es geladen wurde - ein Cookie zu setzten welches die aufrufende Seite wieder auswertet. Hier erstmal der Code der Seite 1:
1 <script language=javascript>
2 function setCookie(name, wert){
3 document.cookie = unescape(name)+"="+unescape(wert);
4 }
5 function getCookie(name){
6 var i=0; //Suchposition im Cookie
7 var suche = name+"=";
8 while (i<document.cookie.length){
9 if (document.cookie.substring(i, i+suche.length)==suche){
10 var ende = document.cookie.indexOf(";", i+suche.length);
11 ende = (ende>-1) ? ende : document.cookie.length;
12 var cook = document.cookie.substring(i+suche.length, ende);
13 return unescape(cook);
14 }
15 i++;
16 }
17 return null;
18 }
19 function CheckPopUp(){
20 setCookie("popupblocker", "enabled");
21 var F1 = window.open("checkpopup.html","frmPopUpCheck","width=1,height=1,left=0,top=0");
22 sleep(100);
23 F1.close();
24 return (getCookie('popupblocker')=='enabled');
25 }
26 function doCheckPopUp(){
27 return getCookie('popupblocker');
28 }
29 function sleep(numberMillis){
30 var exitTime = (new Date()).getTime() + numberMillis;
31 while (true)
32 {
33 if ((new Date()).getTime() > exitTime){return;}
34 }
35 }
36 alert(CheckPopUp());
37 </script>
|
Und anschließend den Code der Seite 2 mit dem Name "checkpopup.html":
1 <script>
2 function setCookie(name, wert){
3 document.cookie = unescape(name)+"="+unescape(wert);
4 }
5 setCookie("popupblocker", "disabled");
6 </script>
|
Ich werde versuchen dieses Funktion auch für den Firefox abzubilden was mir leider bisher noch nicht gelang.
So wie versprochen geht es jetzt darum wie man einem Resultset eine fortlaufende Nummer zuweist. Leider geht dies mit MSSQL boardmitteln nicht wodurch ich gezwungen war eine wenig zu improvisieren. Im Artikel Temporäre Tabellen anlegen und löschen habe ich bereits beschrieben wie man temporäre Tabellen anlegen kann. Dieses Prinzip mach ich mir jetzt zu nutze. Hier jetzt erstmal das komplette Statement: /*Prüfen ob die Tabelle "#tblTemp" schon exsistiert - wenn ja löschen IF not OBJECT_ID('tempdb..#tblTemp') IS NULL begin drop table [#tblTemp] end
/*Temporäre Tabelle "#tblTemp" anlegen create table #tblTemp( [a_id] [int] IDENTITY (1, 1) NOT NULL , [a_Spalte1] [int], [a_Spalte2] [varchar]) go
/*Temporäre Tabelle "#tblTemp" mit Werten füllen*/ insert into #tblTemp (a_spalte1,a_Spalte2) select a_spalte1,a_Spalte2 from tblQuelle --Das Selectstatement das mit einer fortlaufenden Nummer angezeigt werden soll
/*Temporäre Tabelle "#tblTemp" auslesen select * from #tblTemp |
So was passiert hier: Im ersen Schritt wird geprüft ob die Tabelle #tblTemp schon exsistiert. Wenn ja wird diese wieder gelöscht (ist nur zur Sicherheit). Der zweite Schritt legt die Tabelle #tblTemp an und fügt die benötigten Spalten hinzu. Hierbei bitte ich um besonderes augenmerk auf die Spalte a_id. Diese wird anschließend unsere fortlaufende Nummer enthalten. Im Schitt 3 wird die Tabelle nun gefüllt wobei als Quelle das eigendliche Statement ausgeführt wird. Und im Schritt 4 wird #tblTemp wieder ausgelesen. Das Resultset könnte dann so aussehen: a_id a_Spalte1 a_Spalte2 ---- ------------ ------------ 1 11111 Leipzig 2 22222 Berlin 3 33333 München Zwar ist dieser weg sehr umständlich aber der einzig mir bekannte Weg. Eine Möglichkeit um möglichst viele Spalten zu Select jedoch nicht alle Spalten in der virtuellen Tabelle aufnehmen zu müssen wäre die, das man nur die Zählerspalte (a_id) und eine ReferenzID-Spalte anleget und anschließend die Quelltabelle mit der temporären Tabelle anhand der ReferenzID-Spalte join't.
Wer sich intensiver mit SQL beschäftigen muss der wird hin und wieder das Problem habe das er Daten innerhalb eine Stored Procedure Daten zwischenspeichen muss. Hierfür bieten sich temporäre Tabellen an. Temporöre Tabellen sind Tabellen die nur im Speicher des SQL-Servers verfügbar sind. Sie werden nicht langfristig auf dem SQL-Server angelegt. Es gilt dabei zwei verschiedene Arten von temporöre Tabellen zu unterscheiden. Zum einen wären das die Sessionbeasierenden temporäre Tabellen. Diese sind nur innerhalb einer Sitzung verfügbar bzw. können nur innerhalb der Stored Procedure verwendet werden die sie erstellt hat. Wobei hierbei zu beachten ist das wenn eine Stored Procedure eine anderen aufruft die aufgerufene Stored Procedure innerhalb der Session der aufrufenden läuft und somit alle Sessionbeasierenden temporäre Tabellen übernimmt. Eine Sessionbeasierenden temporöre Tabellen legt man an in dem man ein # vor den Namen der Tabelle setzt. Die zweite Art von temporäre Tabellen sind die globalen temporöre Tabellen. Diese stehen allen Statements für eine gewissen Zeitraum zur Verfügung und sind nicht abhängig von einer Session. Eine globale temporäre Tabellen legt man an in dem man zwei ## vor den Namen der Tabelle setzt. In diesem Beispiel verwende ich Sessionbeasierenden temporöre Tabellen. Hier ein Beispiel wie man eine solche Tabelle anlegt: /*Temporäre Tabelle "#tblTemp" anlegen create table #tblTemp( [a_id] [int] IDENTITY (1, 1) NOT NULL , [a_Spalte1] [int], [a_Spalte2] [varchar]) go |
Löschen funktioniert eben so einfach: /*Prüfen ob die Tabelle "#tblTemp" schon exsistiert - wenn ja löschen IF not OBJECT_ID('tempdb..#tblTemp') IS NULL begin drop table [#tblTemp] end |
Im nächsten Artikel werde ich diese temporären Tabellen verwenden um einem Resultset eines Select-Stament eine Vortlaufenden Nummer zuzuweisen.
Hallo, ich brauch mal eure Hilfe!! Und zwar hab ich ein sehr interesantes Problem. Ich weiß nicht ob ihn ankhsvn kennt. Das ist ein Visual Studio Addin für SVN. Die haben das Contextmenü des SolutionExplorers um einen Eintrag erweitert - siehe hier:  Die interessante Frage ist, wie haben die es gemacht?! Ich brauch das für ein eigenes Addin was ich grade schreiben will. Aus dem Source-Code werd ich nicht wirklich schlau. Hat wer ne Idee wo ich suchen könnte bzw. wonach? Gruß Floyd



 | |
Am vergangenen Wochenende war ich wiedermal im Kino. Erstmal vorweg: "Euer Spaß" Ca. 20€ für zwei Karten ist schon happig aber oky. Dazu kommen 6€ fürs Parken im Parkhaus (freie Plätze waren leider keine mehr), 10€ für Spritt (von mir bis zum Kino sind es über 30 km und das ganze 2 mal (Hin- und Rückweg)). So aber man möchte ja auch ne kleinigkeit essen und was trinken bei der wärem. Das ganze kostete mich also nochmal 20€. Macht in Summe 56€. Aber oky, wollen wir mal schauen ob der Film es auch wert war ^^ Im zweiten Teil von Fluch der Karibik muss Captain Jack Sparrow gegen Davey Jones antreten, bei dem er in lebenslanger Blutschuld steht. Davey Jones ist Kapitän des Fliegenden Holländers und Herrscher über die Tiefen des Ozeans. Des weiteren kontroliert Davey Jones einen riesigen Kraken der alle Schiffe in die Tiefe reißen kann. Die gefangenen stellt er anschließend vor die Wahl ob Sie bei ihm anheuern und 100 Jahre lang auf seinem Schiff, seine Diener sein werden, oder den Tot. Doch all dem nicht genug muss Captain Jack Sparrow noch die Truhe und den Schlüssel finden mit dem er sich von der Knechtschaft in den Hallen von Davey Jones befreien kann. Wie könnte es auch anderes sein gerät Will Turner - nicht ganz ohne Zutun von Jack Sparrow - in die Hände von Davey Jones, Elizabeth Swann wird verhaftet und ihr Varer erpresst. Es beginnt eine Spande suche nach dem Schlüssel und der Truhe. Doch vorsicht, Jack Sparrow ist nicht der einzigste der nach ihr sucht.
Viele bekannte Gesichter erwartet einen Bei diesem Abenteuer. Auch alten bekannten aus dem ersten Teil werden vollig neue Rollen zugespielt. Cutler Beckett zum Beispiel mutiert zum Priaten. Wie es dazu kommt und die Auflösung der geschichte.... schaut euch den Film doch selber an 
Ich finde das der Film wieder einmal sehr gelungen ist. Wer den ersten Teil gesehen hat sollte sich den zweiten auch reinziehen (In sofern das nötige Kleingeld vorhanden ist ^^).
Eine sache schon vorweg. Wie es aussieht wird es einen dritten Teil geben (müssen). |
Floyd
Alexander Zeitler hatte von ein paar Monaten in seinem Blog Ales on ASP.Net ein Tool veröffentlicht mit welchem man auf einfache und schnelle Art eine GUID-Erzeugen kann ( "Haste mal 'ne Guid?"). Unter Visual Studio 2003 konnte man noch unter dem Menüpunkt "Tools" -> "Generate GUID" sich schnell mal eine GUID erzeugen lassen. Leider wurde diese Funktion im Visual Studio 2005 entfernt (oder ich bin blind ^^). Aus diesem Grund hab ich ein kleines Makro geschrieben das diese Funktion wieder nachrüßtet. Imports System Imports EnvDTE Imports EnvDTE80 Imports System.Diagnostics
Public Module FFSS_Utilities Sub InsertGUID() Dim textSelection As EnvDTE.TextSelection textSelection = CType(DTE.ActiveDocument.Selection(), EnvDTE.TextSelection) textSelection.Text = "{" & System.Guid.NewGuid().ToString & "}" End Sub End Module |
Nicht sonderlich trivial ich weiß ^^ aber manchmal ganz nützlich. Gruß Floyd FFSS_Utilities_InsertGUID.vb (,72 KB)
Hier stell ich mal eine Klasse zur Verfügung mit der man ausgehend von einer Basis-Farbe verschiedenen Abstufungen der Farbe in Form von Prozenten machen kann. Die Angabe der Basis-Farbe kann als System.Drawing.Color-Objekt oder al String im HTML-Format (#RRGGBB) oder VB-Format (&HRRGGBB) gemacht werden. Hier erstmal 2 Beispiele: Beispiel Nr. 1 - Basis-Farbe ("#FF00FF") und 6 Abstufen in 10% Schritten  Beispiel Nr. 2 - Basis-Farbe ("#FF00FF") und 6 Abstufen in 0,2% Schritten (Die schlechte Qualität des Bildes ist der GIF-Kompression zuzschreiben )
 Hier jetzt der Quellcode wie man die Klasse verwendet: Dim a As New Freakfabrik.Drawing.Color.ColorGradation("#ff00ff") If a.BaseColorIsSet = True Then Panel0.BackColor = a.Gradation(1) Panel1.BackColor = a.Gradation(0.9) Panel2.BackColor = a.Gradation(0.8) Panel3.BackColor = a.Gradation(0.7) Panel4.BackColor = a.Gradation(0.6) Panel5.BackColor = a.Gradation(0.5) Panel6.BackColor = a.Gradation(0.4) Panel7.BackColor = a.Gradation(0.3) End If |
Bitte beachtet auch dieses mal wieder die Nutzungsbedinungen die ihr mit dem Download akzeptiert: Nutzungsbedingungen Gruß Floyd Freakfabrik.Drawing.Color.ColorGradation.rar (6,99 KB)
Mein Chef fragte mich heute: "Was geht schneller, ein Tiff horizontal oder vertikal spiegeln?" "Uff.. vermutlich horizontal" bekam er von mir als Antwort. "Ich mäße aber mal lieber nach". Gesagt getan, das notwenige Programm war innerhalb von sekunden aus dem boden gestampft (ich glaub der Loader von VS.Net 2005 hat fast solange gebraucht wie ich um den 5 zeiler zu schreiben  Oky also gehts los mit ein paar Testläufen auf verschiedenen Rechnern. Das Resultat war: "Ja horizontal spiegeln geht schneller, im vergleich zu vertikal. Die zeitliche Differenz beträgt im Schnitt 9%." Klingt viel. Aber selbst auf der langsamsten Kiste die ich zur verfügung hatte (Celaron 1,5Ghz mit 512MB-Ram und Windows XP) waren das 2,25 Millisekunden unterschied. Auf nem Celaron mit 2,4Ghz und 1GB-Ram lag der unterschied schon nurnoch bei 0,7 - 0,8 Millisekunden (oder anders ausgedrückt bei 700.000 Ticks). Und auf nem P4 mit HT und 3,2Ghz nurnoch 0,1 - 0,2 Millisekunden. Hier die genauen Durchschnittsmessergebnisse für den Celaron 2,4 mit 1GB-Ram. Y: 8905224 X: 8124064 (Achtung!: Alle Werte beziehen sich auf den Debug-Mode - nicht den Release-Mode) Floyd
Viele ist der Begriff SQL-Injektion ein Begriff - doch leider wissen die wenigsten Einsteiger wie man das Problem umgeht. Sie prüfen umständlich jede einzelne Eingabe und Escapen die betroffenen Zeichen. (Für alle die mit dem Begriff SQL-Injektion nichts anzufangen wissen: "SQL-Injektion bezeichnet eine Methode um Datenbankabfrage so zu manipulieren das sie zum Angriff auf ein betroffenes System verwendet werden können") Die Lösung heißt "Binden". Was bedeutet Binden überhaupt? Binden ist ein Vorgang der auf Datenbank-Providerebene direkt ausgeführt wird. Dabei werden alle Daten nicht nativ in das SQL-Statement geprügelt (was das Problem von SQL-Injektion ist), sondern für die Daten werden Platzhalter geschaffen. Diese Daten werden dann von Provieder seperat übertragen und das Problem wir umgangen. Ich verdeutliche das mal an einem Beispiel.
| "Select * from tblUser where Name='" & strName & "'" |
wenn in strName zum Beispiel "Muster" drinn steht klappt das einwandfrei. Das Statement was an den Provider übertragen würde würde so aussehen: | Select * from tblUser where Name='Muster' |
Doch das passiert wenn man "van de' Muster" übergiebt (ist eine französiche Namesgebung). Das Statement würde nun so aussehen: | Select * from tblUser where Name='van de' Muster' |
Ooh! Der SQL-Provider spuckt nun einen Fehler aus: Server: Nachr.-Nr. 170, Schweregrad 15, Status 1, Zeile 1 Zeile 1: Falsche Syntax in der Nähe von 'Muster'. Server: Nachr.-Nr. 105, Schweregrad 15, Status 1, Zeile 1 Öffnendes Anführungszeichen vor der Zeichenfolge ' '. |
Denn man das ganze geschickt macht kann man sogar ein Delete mit einschläusen. Als Inhalt übergibt man dann "*' GO Delete from tblUser GO Select * from tblUser where Name='*" Nun würde unsere Statment so aussehen: | Select * from tblUser where Name='*' GO Delete from tblUser GO Select * from tblUser where Name='*' |
Wie sehen, unsere gesammte tblUser wäre auf einmal gelöscht und genau das ist SQL-Injektion. Und jetzt zeige ich wie man das ganze umgeht. Wir fangen wie mit unserem Grundstatement an doch diesmal mit einer kleinen Änderung: | "Select * from tblUser where Name=@Name" |
"@Name" ist ein Platzhalter und wird in unserem Fall fürs Binden verwendet. Dim objsqlClient As New SqlConnection("Data Source=127.0.0.1;Initial Catalog=bbb;") Dim objSQLDA As SqlDataAdapter Dim objDS As New DataSet Dim objSQLCommand_Select As New SqlCommand("Select * from tblUser where Name=@Name", objsqlClient) objSQLCommand_Select.Parameters.Add("@Name", SqlDbType.nvarchar).Value = strInhalt objDS.Clear() objSQLDA = New SqlDataAdapter(objSQLCommand_Select) objSQLDA.Fill(objDS) |
Das Statement das Vom Provider an den SQL-Server ausgegeben wird sieht nun so aus. | exec sp_executesql N'Select * from tblUser where Name=@Name', N'@Name nvarchar(50)', @Name = N'*'' GO Delete from tblUser GO Select * from tblUser where Name=''*' |
Eine SQL-Injektion hat hier also keine Chance. Doch wie "Binde" ich denn nun Richtig? Der einfachste Weg ist der folgende: | objSQLCommand_Select.Parameters.Add(<Bezeichner des Parameters>, <Type>).Value = <Daten> |
Ein Problem gibt es nur wenn man "NULL" binden will. NULL steht für nix - garnix. In alle Basic-Sprachen würde NULL das selbe wie Nothing bedeuten. Nur Nothing oder unter C# NULL läßt sich nicht binden. Wieso?! Null und Nothing sind datentypen mit denen der Provider nix anfangen kann. Dafür gibt es DBNull.Value. Doch jedes mal ein IF zu schreiben oder ein IIF ist auch umständlich. Hierfür kann man die untenstehenden Funktionen verwenden. | objSQLCommand_Select.Parameters.Add("@Name", SqlDbType.nvarchar).Value = ReturnDBNull(strInhalt) |
Nun ist es auch möglich NULL zu binden. Binden hat auch noch einen weiteren Vorteil. Es sieht einfach übersichtlicher aus. So ich hoffe ich konnte euch das Thema "Binden" näher bringen. Es folgt nun noch die Funktionen ReturnDBNull. Floyd Public Function ReturnDBNull(ByVal Value As String) As Object If IsNothing(Value) Then Return DBNull.Value Else Return Value End If End Function Public Function ReturnDBNull(ByVal Value As Int16) As Object If IsNothing(Value) Then Return DBNull.Value Else Return Value End If End Function Public Function ReturnDBNull(ByVal Value As Int32) As Object If IsNothing(Value) Then Return DBNull.Value Else Return Value End If End Function Public Function ReturnDBNull(ByVal Value As Boolean) As Object If IsNothing(Value) Then Return DBNull.Value Else Return Value End If End Function Public Function ReturnDBNull(ByVal Value As Char) As Object If IsNothing(Value) Then Return DBNull.Value Else Return Value End If End Function Public Function ReturnDBNull(ByVal Value As DateTime) As Object If IsNothing(Value) Then Return DBNull.Value Else Return Value End If End Function Public Function ReturnDBNull(ByVal Value As Byte) As Object If IsNothing(Value) Then Return DBNull.Value Else Return Value End If End Function |
|