none
ADODB Zugriff auf SQL 2000 benötigt neuerdings (nach mehreren Jahren) die Curserlocation adUseClient RRS feed

  • Frage

  • Hallo,

     

    ich habe mehere VB6 Anwendungen, welche per ADODB auf einen SQL Server 2000 zugreifen. Bisher (die letzten 6 Jahre) liefen die Anwendungen einwandfrei (unter NT4, W2K und XP).

    Merkwürdigerweise erhielten 2 Anwendungen plötzlich nur noch leere Recordsets vom Server bzw. konnten keine Updates ausführen. Erst nachdem ich die Cursorlocation explizit auf adUseClient gesetzt habe, funktionierte der Zugriff auf den SQ 2000 Server wieder. Vorher wurde die Cursorlocation überhaupt nicht gesetzt.

    Hat irgendjemand eine Idee waran das liegen könnte (Updates, Netzwerk, Firewall, etv.) ?

     

    Vielen Dank und Gruß

     

    Gerhard

    Dienstag, 6. Juli 2010 22:10

Antworten

  • Hallo Gerhard,
    Merkwürdigerweise erhielten 2 Anwendungen plötzlich nur noch leere Recordsets vom Server bzw. konnten keine Updates ausführen. Erst nachdem ich die Cursorlocation explizit auf adUseClient gesetzt habe, funktionierte der Zugriff auf den SQ 2000 Server wieder. Vorher wurde die Cursorlocation überhaupt nicht gesetzt.

    Hat irgendjemand eine Idee waran das liegen könnte (Updates, Netzwerk, Firewall, etv.) ?

    Ich kann dir den genauen Grund nicht nennen, ich denke aber, es müsste ein Windows oder SQL Server Update gewesen sein. Ich habe diesen Effekt auf 2 Windows 2003 Servern vor ca. 1 oder 1 1/2 Jahren auch festgestellt und da wurde an den Servern absolut nichts außer halt die Updates für Windows und SQL Server jeweils installiert.

    Der Effekt könnte durch eine Änderung in den ADO Komponenten kommen, so dass anstelle von adUseClient nun adUseServer als Default verwendet wird oder (was ich für wahrscheinlicher halte) dass das Verhalten bei adUseServer geändert wurde.

    Bei mir hat sich das so bemerkbar gemacht, dass SELECT SCOPE_IDENTITY() immer NULL zurück lieferte und über den Profiler konnte man sehen, dass die Statements trotz Verwendung einer einzigen Connection in verschiedenen Verbindungen ausgeführt wurden. (Lief seit ca. 1999 problemlos, nur dann irgendwann letztes Jahr nicht mehr)

     


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community
    Dienstag, 6. Juli 2010 23:33
    Moderator
  • Hallo Gerald,

    die CursorLocation ist im Standard immer adUseServer, das hat sich seit MDAC 1.5 nicht geändert.
    Und MDAC / SQL Server 2000 Aktualisierungen beschränken sich seit längerem nur noch auf kritische Fehler:

    http://www.microsoft.com/germany/technet/sicherheit/bulletins/aktuell/default.mspx?Pane=0&ProductID=30&ServicePackID=0&SeverityID=1&SeverityID=2&SeverityID=3&SeverityID=4&DateRange=0

    wobei die letzte Aktualisierung wie man sieht schon einige Zeit her ist
    (was bei Auslaufprodukten kein Wunder ist).

    Die Frage wäre: Was führst Du konkret an Anweisungen aus?

    Da es eine Rückgabe bei adUseClient gibt, ist ein klassisches Problem
    die Rückgabe von leeren Recordsets, die auch durch andere als SELECT-
    Anweisungen erfolgen, siehe z. B.: http://support.microsoft.com/kb/197528 (uam.)

    Auch die Behandlung von Fehlern hat bei ADO/MDAC immer schon Probleme bereitet:
    PRB: Recordset Does Not Open with A Stored Procedure that Returns a High Severity Error

    Unabhängig von Microsoft:
    Weitere Probleme könnten Virenscanner bereiten, die sich heute teilweise
    tief ins Betriebssytem einnisten.

    Gruß Elmar

     

    Mittwoch, 7. Juli 2010 07:09
    Beantworter
  • Hallo Elmar,

    die CursorLocation ist im Standard immer adUseServer, das hat sich seit MDAC 1.5 nicht geändert.

    mind. beim Wechsel zu 2.0 gab es dennoch andere, erhebliche Änderungen, welche damals doch zu ziemlichen Problemen bei vielen Anwendungen geführt haben. Die eigentliche Ursache war zwar der Code (bspw. erstellen von Recordsets mit Set ... = Server.CreateObject( ... ) in Schleifen, welche mehr als ca. 100 mal ausgeführt wurden), vor MDAC 2.0 lief das aber trotzdem prima.

    Ob da die CursorLocation irgendwann geändert wurde, weiß ich aber nicht.

    Die Frage wäre: Was führst Du konkret an Anweisungen aus?

    Da es eine Rückgabe bei adUseClient gibt, ist ein klassisches Problem
    die Rückgabe von leeren Recordsets, die auch durch andere als SELECT-
    Anweisungen erfolgen, siehe z. B.: http://support.microsoft.com/kb/197528 (uam.)

    Die Problematik lässt sich bei mir auf 3 verschiedenen Servern nachvollziehen. Anwendungen, die jahrelang ohne Probleme liefen, haben dann letztes Jahr irgendwann angefangen, "rumzuspinnen".

    Dim Connection, Recordset, NewId
    Set Connection = Server.CreateObject( "ADODB.Connection" )
      Connection.Open ...
    
      Connection.Execute "INSERT INTO ..."
    
    Set Recordset = Server.CreateObject( "ADODB.Recordset" )
      Recordset.Open "SELECT SCOPE_IDENTITY", Connection, 1, 1 ' oder auch 3, 3 oder was anderes
    
      NewId = Recordset.Fields( 0 )

    ...

    Ist natürlich nur ein Beispiel, nicht vollständig, ... aber hat jahrelang wunderbar funktioniert, dann irgendwann nicht mehr. SCOPE_IDENTITY() lieferte dann NULL zurück und im Profiler konnte man sehen, dass für jede Abfrage eine einzelne Connection vorhanden war. Mit Angabe von Recordset.CursorLocation = adUseClient war es dann wieder so, wie es sein sollte.

     


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community
    Mittwoch, 7. Juli 2010 09:03
    Moderator
  • Hallo Stefan,

    bei mir schwindet ADODB so langsam aus dem Gedächtnis
    und die zum jeweiligen Fehler passende KB sowieso -
    schon bei der Suche für oben habe ich zu viele alte Bekannte gefunden ;-))
    Bekanntlich war die Anzahl der Fehler von MDAC vor 2.5 legendär,
    was sich erst mit 2.6/2.7 (SQL Server 2000) so langsam beruhigte.

    Wenn für jede Aktion eine eigene Verbindung aufgemacht wird, 
    liegt das daran, dass die vorherige noch Ergebnisse zum Verarbeiten hat:
    PRB: Implicit Connections Created by the SQL Server OLE DB Provider (SQLOLEDB) Are Not Pooled

    und adUseClient hat den (hier netten) Nebeneffekt, dass Resultsets verarbeitet werden,
    auch wenn man sie selbst nicht erwarten würde.

    Dein Beispiel funktioniert, wobei ich beim Insert-Execute immer ein adUseNoRecords (= 128/ &H80)
    mitgeben würde  und gleich das Recordset aus dem Execute verwenden -
    weil sonst nur Overhead produziert wird.
    (Und eine Lehre aus anderen Problemen ist, die ich nicht mehr aufwärmen möchte):

    Sub InsertWithScopeIdentity()
      Dim cnnSQLServer As ADODB.Connection
      Dim rstIdentity As ADODB.Recordset
        
      Set cnnSQLServer = New ADODB.Connection
      With cnnSQLServer
        .CursorLocation = adUseServer ' adUseClient
        .CommandTimeout = 5
        .Open "PROVIDER=SQLOLEDB.1;INTEGRATED SECURITY=SSPI;DATA SOURCE=.;INITIAL CATALOG=Northwind"
      End With
      
      cnnSQLServer.Execute "INSERT INTO dbo.Orders (CustomerID) VALUES(N'ALFKI');", Options:=adExecuteNoRecords
      
      Set rstIdentity = cnnSQLServer.Execute("SELECT SCOPE_IDENTITY() AS OrderID")
      Debug.Print rstIdentity(0)
      
      rstIdentity.Close
      cnnSQLServer.Close
    End Sub
    

    (und auch eine längere Schleife übersteht)
    Wobei es wie gesagt unter Access lief - und insofern eher mit dem hier nicht mehr installiertem VB 6 vergleichbar ist -
    und nicht unter ASP/IIS.

    Gruß Elmar


    Mittwoch, 7. Juli 2010 10:22
    Beantworter
  • Hallo Elmar,

    Wenn für jede Aktion eine eigene Verbindung aufgemacht wird, 
    liegt das daran, dass die vorherige noch Ergebnisse zum Verarbeiten hat:
    PRB: Implicit Connections Created by the SQL Server OLE DB Provider (SQLOLEDB) Are Not Pooled

    und adUseClient hat den (hier netten) Nebeneffekt, dass Resultsets verarbeitet werden,
    auch wenn man sie selbst nicht erwarten würde.

    Grundsätzlich gebe ich dir natürlich Recht und man hätte das sicherlich auch optimieren können. Aber - und das sehe ich als schwerwiegender an - gab es anscheinend wohl doch eine Änderung im Verhalten solcher Abfragen/Komponenten. Wie bei Gerhard lief das jahrelang ohne Probleme und außer WindowsUpdate gabs da definitiv nichts.

    Aber seis drum :) Evtl. hilft unser Geschreibsel Gerhard weiter, er kann sich ja ggfs. nochmal dazu äußern.

     


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community
    Mittwoch, 7. Juli 2010 10:36
    Moderator
  • Hallo Gerhard,

    wenn man im Enterprise Manager guckt, ist das leider nicht mit dem Verhalten von
    ADO/OLEDB vergleichbar. Es fängt schon damit an, dass dort ODBC verwendet wird ;-)

    Mit leeren Recordsets (Resultsets) sind die Rückgaben von INSERT, UPDATE, DELETE usw.
    gemeint, wo man im EM nur sieht: (n) Zeilen betroffen.

    Wenn ihr Trigger einsetzt, so können die Nebeneffekte von dort herrühren,
    wenn dort ein SET NOCOUNT ON fehlt.

    Gruß Elmar

     

    Mittwoch, 7. Juli 2010 14:44
    Beantworter

Alle Antworten

  • Hallo Gerhard,
    Merkwürdigerweise erhielten 2 Anwendungen plötzlich nur noch leere Recordsets vom Server bzw. konnten keine Updates ausführen. Erst nachdem ich die Cursorlocation explizit auf adUseClient gesetzt habe, funktionierte der Zugriff auf den SQ 2000 Server wieder. Vorher wurde die Cursorlocation überhaupt nicht gesetzt.

    Hat irgendjemand eine Idee waran das liegen könnte (Updates, Netzwerk, Firewall, etv.) ?

    Ich kann dir den genauen Grund nicht nennen, ich denke aber, es müsste ein Windows oder SQL Server Update gewesen sein. Ich habe diesen Effekt auf 2 Windows 2003 Servern vor ca. 1 oder 1 1/2 Jahren auch festgestellt und da wurde an den Servern absolut nichts außer halt die Updates für Windows und SQL Server jeweils installiert.

    Der Effekt könnte durch eine Änderung in den ADO Komponenten kommen, so dass anstelle von adUseClient nun adUseServer als Default verwendet wird oder (was ich für wahrscheinlicher halte) dass das Verhalten bei adUseServer geändert wurde.

    Bei mir hat sich das so bemerkbar gemacht, dass SELECT SCOPE_IDENTITY() immer NULL zurück lieferte und über den Profiler konnte man sehen, dass die Statements trotz Verwendung einer einzigen Connection in verschiedenen Verbindungen ausgeführt wurden. (Lief seit ca. 1999 problemlos, nur dann irgendwann letztes Jahr nicht mehr)

     


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community
    Dienstag, 6. Juli 2010 23:33
    Moderator
  • Hallo Gerald,

    die CursorLocation ist im Standard immer adUseServer, das hat sich seit MDAC 1.5 nicht geändert.
    Und MDAC / SQL Server 2000 Aktualisierungen beschränken sich seit längerem nur noch auf kritische Fehler:

    http://www.microsoft.com/germany/technet/sicherheit/bulletins/aktuell/default.mspx?Pane=0&ProductID=30&ServicePackID=0&SeverityID=1&SeverityID=2&SeverityID=3&SeverityID=4&DateRange=0

    wobei die letzte Aktualisierung wie man sieht schon einige Zeit her ist
    (was bei Auslaufprodukten kein Wunder ist).

    Die Frage wäre: Was führst Du konkret an Anweisungen aus?

    Da es eine Rückgabe bei adUseClient gibt, ist ein klassisches Problem
    die Rückgabe von leeren Recordsets, die auch durch andere als SELECT-
    Anweisungen erfolgen, siehe z. B.: http://support.microsoft.com/kb/197528 (uam.)

    Auch die Behandlung von Fehlern hat bei ADO/MDAC immer schon Probleme bereitet:
    PRB: Recordset Does Not Open with A Stored Procedure that Returns a High Severity Error

    Unabhängig von Microsoft:
    Weitere Probleme könnten Virenscanner bereiten, die sich heute teilweise
    tief ins Betriebssytem einnisten.

    Gruß Elmar

     

    Mittwoch, 7. Juli 2010 07:09
    Beantworter
  • Hallo Elmar,

    die CursorLocation ist im Standard immer adUseServer, das hat sich seit MDAC 1.5 nicht geändert.

    mind. beim Wechsel zu 2.0 gab es dennoch andere, erhebliche Änderungen, welche damals doch zu ziemlichen Problemen bei vielen Anwendungen geführt haben. Die eigentliche Ursache war zwar der Code (bspw. erstellen von Recordsets mit Set ... = Server.CreateObject( ... ) in Schleifen, welche mehr als ca. 100 mal ausgeführt wurden), vor MDAC 2.0 lief das aber trotzdem prima.

    Ob da die CursorLocation irgendwann geändert wurde, weiß ich aber nicht.

    Die Frage wäre: Was führst Du konkret an Anweisungen aus?

    Da es eine Rückgabe bei adUseClient gibt, ist ein klassisches Problem
    die Rückgabe von leeren Recordsets, die auch durch andere als SELECT-
    Anweisungen erfolgen, siehe z. B.: http://support.microsoft.com/kb/197528 (uam.)

    Die Problematik lässt sich bei mir auf 3 verschiedenen Servern nachvollziehen. Anwendungen, die jahrelang ohne Probleme liefen, haben dann letztes Jahr irgendwann angefangen, "rumzuspinnen".

    Dim Connection, Recordset, NewId
    Set Connection = Server.CreateObject( "ADODB.Connection" )
      Connection.Open ...
    
      Connection.Execute "INSERT INTO ..."
    
    Set Recordset = Server.CreateObject( "ADODB.Recordset" )
      Recordset.Open "SELECT SCOPE_IDENTITY", Connection, 1, 1 ' oder auch 3, 3 oder was anderes
    
      NewId = Recordset.Fields( 0 )

    ...

    Ist natürlich nur ein Beispiel, nicht vollständig, ... aber hat jahrelang wunderbar funktioniert, dann irgendwann nicht mehr. SCOPE_IDENTITY() lieferte dann NULL zurück und im Profiler konnte man sehen, dass für jede Abfrage eine einzelne Connection vorhanden war. Mit Angabe von Recordset.CursorLocation = adUseClient war es dann wieder so, wie es sein sollte.

     


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community
    Mittwoch, 7. Juli 2010 09:03
    Moderator
  • Hallo Stefan,

    bei mir schwindet ADODB so langsam aus dem Gedächtnis
    und die zum jeweiligen Fehler passende KB sowieso -
    schon bei der Suche für oben habe ich zu viele alte Bekannte gefunden ;-))
    Bekanntlich war die Anzahl der Fehler von MDAC vor 2.5 legendär,
    was sich erst mit 2.6/2.7 (SQL Server 2000) so langsam beruhigte.

    Wenn für jede Aktion eine eigene Verbindung aufgemacht wird, 
    liegt das daran, dass die vorherige noch Ergebnisse zum Verarbeiten hat:
    PRB: Implicit Connections Created by the SQL Server OLE DB Provider (SQLOLEDB) Are Not Pooled

    und adUseClient hat den (hier netten) Nebeneffekt, dass Resultsets verarbeitet werden,
    auch wenn man sie selbst nicht erwarten würde.

    Dein Beispiel funktioniert, wobei ich beim Insert-Execute immer ein adUseNoRecords (= 128/ &H80)
    mitgeben würde  und gleich das Recordset aus dem Execute verwenden -
    weil sonst nur Overhead produziert wird.
    (Und eine Lehre aus anderen Problemen ist, die ich nicht mehr aufwärmen möchte):

    Sub InsertWithScopeIdentity()
      Dim cnnSQLServer As ADODB.Connection
      Dim rstIdentity As ADODB.Recordset
        
      Set cnnSQLServer = New ADODB.Connection
      With cnnSQLServer
        .CursorLocation = adUseServer ' adUseClient
        .CommandTimeout = 5
        .Open "PROVIDER=SQLOLEDB.1;INTEGRATED SECURITY=SSPI;DATA SOURCE=.;INITIAL CATALOG=Northwind"
      End With
      
      cnnSQLServer.Execute "INSERT INTO dbo.Orders (CustomerID) VALUES(N'ALFKI');", Options:=adExecuteNoRecords
      
      Set rstIdentity = cnnSQLServer.Execute("SELECT SCOPE_IDENTITY() AS OrderID")
      Debug.Print rstIdentity(0)
      
      rstIdentity.Close
      cnnSQLServer.Close
    End Sub
    

    (und auch eine längere Schleife übersteht)
    Wobei es wie gesagt unter Access lief - und insofern eher mit dem hier nicht mehr installiertem VB 6 vergleichbar ist -
    und nicht unter ASP/IIS.

    Gruß Elmar


    Mittwoch, 7. Juli 2010 10:22
    Beantworter
  • Hallo Elmar,

    Wenn für jede Aktion eine eigene Verbindung aufgemacht wird, 
    liegt das daran, dass die vorherige noch Ergebnisse zum Verarbeiten hat:
    PRB: Implicit Connections Created by the SQL Server OLE DB Provider (SQLOLEDB) Are Not Pooled

    und adUseClient hat den (hier netten) Nebeneffekt, dass Resultsets verarbeitet werden,
    auch wenn man sie selbst nicht erwarten würde.

    Grundsätzlich gebe ich dir natürlich Recht und man hätte das sicherlich auch optimieren können. Aber - und das sehe ich als schwerwiegender an - gab es anscheinend wohl doch eine Änderung im Verhalten solcher Abfragen/Komponenten. Wie bei Gerhard lief das jahrelang ohne Probleme und außer WindowsUpdate gabs da definitiv nichts.

    Aber seis drum :) Evtl. hilft unser Geschreibsel Gerhard weiter, er kann sich ja ggfs. nochmal dazu äußern.

     


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community
    Mittwoch, 7. Juli 2010 10:36
    Moderator
  • Hallo,

     

    danke für die vielen Antoworten :-)

    Außer

    Set connSQL = New ADODB.Connection

    und

    connSQL.Open "File Name=sqlConn.udl"

    gibt es nichts Besonderes.

    Die DB Abfragen liefern auch keine leeren Recordsets zurück - zumindest, wenn man die Abfragen z.B. MSSMS öffnet.

    Es ist halt blöd, wenn existierende Anwendungen von heute auf morgen nicht mehr das tun, wsa sie jahrelang getan haben.

    Wir haben jetzt die Cursorlocation angepaßt und ein paar neue Views auf der Datenbank angelegt. Clientcursor auf >8 Mio Datensätze frisst doch ein etwas mehr Speicher als ein Serverclient.

     

    Gruß

     

    Gerhard

    Mittwoch, 7. Juli 2010 12:41
  • Hallo Gerhard,

    wenn man im Enterprise Manager guckt, ist das leider nicht mit dem Verhalten von
    ADO/OLEDB vergleichbar. Es fängt schon damit an, dass dort ODBC verwendet wird ;-)

    Mit leeren Recordsets (Resultsets) sind die Rückgaben von INSERT, UPDATE, DELETE usw.
    gemeint, wo man im EM nur sieht: (n) Zeilen betroffen.

    Wenn ihr Trigger einsetzt, so können die Nebeneffekte von dort herrühren,
    wenn dort ein SET NOCOUNT ON fehlt.

    Gruß Elmar

     

    Mittwoch, 7. Juli 2010 14:44
    Beantworter