Einzelnen Beitrag anzeigen

mmoeller1

Registriert seit: 5. Mai 2009
4 Beiträge
 
#1

Probleme mit Native Client 10 und Transactions

  Alt 5. Mai 2009, 10:18
Datenbank: Microsoft SQL Server • Version: 2008 • Zugriff über: ADO
Hi,

ich arbeite grade an der Kompatibilität meiner Software zu SQL Server 2008.
Leider habe ich damit massive Probleme....

Ich vermute stark, dass das Problem mit dem Native Client 10 zusammen hängt.


Hier mein Problem:

Ich rufe in einer Transaktion eine StoredProcedure (über TADOStoredProc) auf.
Danach ändere ich in meiner StoredProcedure Komponente den 'ProcedureName' und Refreshe die Parameter.
Beim nächsten ausführen über "ExecProc" in einer Transaktion bekomme ich folgenden Fehler:

Falsche Syntax in der Nähe des 'set'-Schlüsselworts.


Weitere Fakten:

Dieser Fehler taucht teilweise auch bei Insert Anweisungen auf.
Ohne Transaktionen gibt es kein Problem.
Mit dem Native Client 9 funktioniert es mit oder ohne Transaktionen.


Hier der SQL Code der auf dem SQL Server ankommt:

SQL Log - native client 10 - mit Transaktion
SQL-Code:
exec [master].[sys].sp_procedure_params_100_rowset N'test',1,NULL,NULL
go
exec [test]
go
exec [master].[sys].sp_procedure_params_100_rowset N'test',1,NULL,NULL
go
SET NO_BROWSETABLE ON
go
 set fmtonly on EXEC set fmtonly off                                    -- Exception in Delphi here
go
 set fmtonly off
go



Und jetzt was ohne Transaction oder mit/ohne Transaktion bei Native Client 9 ankommt:


SQL-Code:
exec [master].[sys].sp_procedure_params_100_rowset N'test',1,NULL,NULL
go
exec [test]
go
exec [master].[sys].sp_procedure_params_100_rowset N'test',1,NULL,NULL
go
SET NO_BROWSETABLE ON
go
 set fmtonly on EXEC set fmtonly off
go
 set fmtonly off
go
SET NO_BROWSETABLE OFF
go
exec [test]
go


Die Stelle mit dem Problem ist set fmtonly on EXEC set fmtonly off

Ich vermute dass der Native client 10 in der Transaktion aus versehen eine Exception auslöst. Bei allen anderen varianten ist der abgesendete Code der gleiche (also genau so falsch), löst aber keinen Fehler aus.


Ich habe schon alle möglichen Property-Kombinationen der AdoConnection und AdoStoredProcedure Komponente getestet. Leider ohne Erfolg.

Ein Workaround war KEIN Parameters.Refresh zu machen, sondern die Parameter zu clearen und dann manuell anzulegen.
Leider gab es dann bei diversen anderen stellen Problemen mit Insert anweisungen.



Hier eine Demo:

Um das Problem reproduzieren zu können, benötigt Ihr den Native Client 10: http://go.microsoft.com/fwlink/?LinkId=110393




Project1.dpr

Delphi-Quellcode:
program Project1;

uses
  Forms,
  Unit1 in 'Unit1.pas{Form1};

{$R *.res}

begin
  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.



Unit1.dfm


Delphi-Quellcode:
object Form1: TForm1
  Left = 424
  Top = 528
  Width = 483
  Height = 187
  Caption = 'Form1'
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  OldCreateOrder = False
  Position = poScreenCenter
  OnDestroy = FormDestroy
  DesignSize = (
    475
    153)
  PixelsPerInch = 96
  TextHeight = 13
  object Button1: TButton
    Left = 8
    Top = 56
    Width = 233
    Height = 25
    Caption = 'connect to DB and create StoredProc'
    TabOrder = 0
    OnClick = Button1Click
  end
  object Button2: TButton
    Left = 8
    Top = 120
    Width = 201
    Height = 25
    Caption = 'Execute StoredProc'
    TabOrder = 1
    OnClick = Button2Click
  end
  object CheckBox1: TCheckBox
    Left = 8
    Top = 104
    Width = 193
    Height = 17
    Caption = 'use transactions'
    Checked = True
    State = cbChecked
    TabOrder = 2
  end
  object LabeledEdit1: TLabeledEdit
    Left = 8
    Top = 24
    Width = 378
    Height = 21
    Anchors = [akLeft, akTop, akRight]
    EditLabel.Width = 81
    EditLabel.Height = 13
    EditLabel.Caption = 'ConnectionString'
    TabOrder = 3
    Text = 'Provider=SQLNCLI10.1'
  end
  object Button3: TButton
    Left = 393
    Top = 22
    Width = 75
    Height = 25
    Anchors = [akTop, akRight]
    Caption = 'build'
    TabOrder = 4
    OnClick = Button3Click
  end
  object Button4: TButton
    Left = 393
    Top = 119
    Width = 75
    Height = 25
    Anchors = [akRight, akBottom]
    Caption = 'Close'
    TabOrder = 5
    OnClick = Button4Click
  end
  object ADOConnection1: TADOConnection
    ConnectionString = 'Provider=SQLNCLI10.1'
    LoginPrompt = False
    Provider = 'SQLNCLI10.1'
    Left = 104
    Top = 48
  end
  object ADOStoredProc1: TADOStoredProc
    Connection = ADOConnection1
    Parameters = <>
    Left = 200
    Top = 48
  end
  object ADOCommand1: TADOCommand
    Connection = ADOConnection1
    Parameters = <>
    Left = 280
    Top = 56
  end
end


Unit1.pas

Delphi-Quellcode:
unit Unit1;

interface

uses
    Windows,
    Messages,
    SysUtils,
    Variants,
    Classes,
    Graphics,
    Controls,
    Forms,
    Dialogs,
    DB,
    ADODB,
    StdCtrls,
    ExtCtrls;

type
    TForm1 = class(TForm)
        ADOConnection1: TADOConnection;
        ADOStoredProc1: TADOStoredProc;
        Button1: TButton;
        Button2: TButton;
        CheckBox1: TCheckBox;
        LabeledEdit1: TLabeledEdit;
        Button3: TButton;
        Button4: TButton;
        ADOCommand1: TADOCommand;
        procedure Button1Click(Sender: TObject);
        procedure FormDestroy(Sender: TObject);
        procedure Button2Click(Sender: TObject);
        procedure Button3Click(Sender: TObject);
        procedure Button4Click(Sender: TObject);
    private
    { Private-Deklarationen }
    public
    { Public-Deklarationen }
    end;

var
    Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
    ADOConnection1.connected := false;
    ADOConnection1.ConnectionString := LabeledEdit1.Text;
    ADOConnection1.connected := true;

    try
        ADOCommand1.CommandText := 'CREATE PROCEDURE [test] AS';
        ADOCommand1.Execute;
    except
    end;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
    if ADOConnection1.Connected then
    begin

        ADOCommand1.CommandText := 'IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N''[test]'') AND type in (N''P'', N''PC'')) DROP PROCEDURE [test]';
        ADOCommand1.Execute;

        ADOConnection1.connected := false;

    end;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
    if CheckBox1.Checked then ADOConnection1.BeginTrans;
    try
        ADOStoredProc1.ProcedureName := '[test]';
        ADOStoredProc1.parameters.Refresh;
        ADOStoredProc1.ExecProc;

        if CheckBox1.Checked then ADOConnection1.CommitTrans;
    except
        on E: Exception do
        begin
            if CheckBox1.Checked and ADOConnection1.InTransaction then
                ADOConnection1.RollbackTrans;

            ShowException(E, e);
        end;
    end;
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
    LabeledEdit1.Text := PromptDataSource(Handle, LabeledEdit1.Text);
end;

procedure TForm1.Button4Click(Sender: TObject);
begin
    close;
end;

end.


Nach starten der Applikation müsst Ihr den Connectionstring angeben. Klick auf 'build'


ACHTUNG: Der Native Client 10 hat wohl noch ein paar Probleme bei der SQL Authentifizierung (User/Pass Anmeldung). Entweder folgende Anleitung verwenden oder folgenden ConnectionString manuell anpassen und in das Eingabefeld einfügen

1. Provider auswählen -> weiter.
2. Bei "1." die IP oder den Servernamen angeben.
3. Bei "2." "Use an specific user name an password" auswählen.
4. "User name:" angeben (meist 'sa').
5. Bei "Blank password" den Haken entfernen.
6. Bei "Allow saving password" den Haken setzen.
7. "Password:" angeben.
8. Bei "3." Die Datenbank auswählen.
9. Verbindung Testen, dann weiter auf Tab "Alle"
10. Doppelklick auf Eintrag "Integrated Security". Dann ohne Änderung auf "OK".
11. Doppelklick auf Eintrag "Persist Security Info". Eigenschaftswert auf "True" ändern.
12. Dialog mit "OK" verlassen.





Beispiel ConnectionString:


Provider=SQLNCLI10.1;Password=<PASSWORT>;Persist Security Info=True;User ID=sa;Initial Catalog=<DATENBANK>;Data Source=<SERVERADRESSE>;Initial File Name="";Server SPN=""


Es wird automatisch eine StoredProcedure angelegt und beim Beenden wieder entfernt.



Für eure Hilfe wäre ich sehr dankbar!
  Mit Zitat antworten Zitat