Announcement

Collapse
No announcement yet.

Vorzeitiger Abbruch von SQL-Abfragen erwünscht

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Vorzeitiger Abbruch von SQL-Abfragen erwünscht

    Hallo Freaks,
    ich habe folgendes Problem. Ein Anwender kann sich Datensätze aus einer sehr grossen C/S-Datenbank (Informix) suchen. Zur Formulierung seiner Suche stehen ihm Maskenfelder zur Verfügung, aus denen dann eine Query (Join über mehrere Tabellen) formuliert wird.

    Eine ungeschickte Maskeneingabe mit Jokerzeichen führt zu sehr grossen
    Datenmengen und somit zu sehr langen Antwortszeiten.

    Unter diesen Umständen soll dem Anwender eine Möglichkeit zum Abbruch der
    gestarteten Abfrage gegeben werden.

    Um zu vermeiden, dass sich der Haupt-Thread währen der Abfrage tot stellt, habe ich das Öffnen der Query in einen zweiten Thread ausgelagert.

    Ich habe schon folgendes ohne Erfolg versucht:
    - TerminateThread .. Der Thread reagiert erst wenn die Query fertig ist
    - dbiCloseCursor .. ein Cursorhandle wird offenbar erst nach dem prepare erstellt

    Wenn jemand eine Lösung kennt bitte ich dringend um Nachricht

    Dieter

  • #2
    Hallo,

    da die BDE verwendet wird, könnte man versuchen, ob das Ereignis <b>OnServerYield</b> (Result := <b>cbrABORT</b>) die Abfrage abwürgen kann. Offiziell steht diese Funktion nur für SYBASE-Server zur Verfügung - so dass es auf einen Test ankommt, wie es sich bei INFORMIX verhält.
    <pre>
    { ************************************************** **************
    Source File Name : YieldFrm.PAS
    Typ : Formular-unit
    Autor : Andreas Kosch
    Erstellt am : 14.04.96
    Compiler : Delphi 3.0
    Betriebssystem : Windows 95
    Beschreibung : Demonstriert das Auswerten des TQuery-
    Ereignisses »OnServerYield«.
    Revisionen : 07.02.97 Migration Ivory
    07.06.97 Test Delphi 3.0 C/S
    ************************************************** ************** }

    unit YieldFrm;

    interface

    uses
    Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
    StdCtrls, Buttons, Grids, DBGrids, DB, DBTables, ExtCtrls;

    type
    TFormMain = class(TForm)
    QueryTest: TQuery;
    DataSourceTest: TDataSource;
    DBGrid1: TDBGrid;
    BitBtnStart: TBitBtn;
    Bevel1: TBevel;
    LabelYieldCount: TLabel;
    BitBtnAbort: TBitBtn;
    procedure BitBtnStartClick(Sender: TObject);
    procedure QueryTestServerYield(DataSet: TDataSet;
    var AbortQuery: Boolean);
    procedure BitBtnAbortClick(Sender: TObject);
    private
    { Private-Deklarationen }
    iCnt : Integer; // OnServerYield-Ereignisse mitzählen
    bSQLAbort : Boolean; // soll abgebrochen werden ?
    public
    { Public-Deklarationen }
    end;

    var
    FormMain: TFormMain;

    implementation

    {$R *.DFM}

    (* Die TQuery-Instanz startet die folgende, längerdauernde SQL-
    Abrage : SELECT ort, COUNT(ort)
    FROM "callback.dbf"
    GROUP BY ort
    ORDER BY ort
    Durch die GROUP BY und ORDER BY legt die BDE temporäre DBF-
    Tabellen an, daher dauert die Abfrage auch auf einem schnellen
    Rechner etwas länger.
    Zur Kontrolle informiert ein TLabel über die eingetroffenen
    OnServerYield-Ereignisse.
    Klickt der Anwender den Abbruch-Button an, so wird die
    Abfrage gestoppt.
    Normalerweise ist OnServerYield für den SQL-Server der Firma
    Sybase gedacht, es funktioniert aber anscheindend auch mit
    normalen Desktop-Datenbanktabellen. *)

    procedure TFormMain.BitBtnStartClick(Sender: TObject);
    begin
    iCnt := 0;
    bSQLAbort := False;
    QueryTest.Active := False;
    BitBtnStart.Enabled := False;
    try
    try
    QueryTest.Open
    except
    on E:EDBEngineError do
    // Fehler 10756 = Fähigkeit nicht vorhanden
    if E.Errors[0].ErrorCode = 10756
    then MessageBeep(0) // Abort
    else raise // andere Fehler anzeigen
    end
    finally
    BitBtnStart.Enabled := True
    end
    end;

    (* Das Ereignis »OnServerYield« implementiert einen Standard-
    Callback-Aufruf der BDE.

    Auszug aus DBTables.pas :

    function TBDEDataSet.YieldCallBack(CBInfo: Pointer): CBRType;
    var
    AbortQuery: Boolean;
    begin
    AbortQuery := False;
    if Assigned(OnServerYield) and (FCBYieldStep <> cbYieldLast)
    then OnServerYield(Self, AbortQuery);
    if AbortQuery then
    Result := cbrABORT else
    Result := cbrUSEDEF;
    end; *)

    procedure TFormMain.QueryTestServerYield(DataSet: TDataSet;
    var AbortQuery: Boolean);
    begin
    Inc(iCnt);
    // Anzahl der OnServerYield-Ereignisse mitzählen
    LabelYieldCount.Caption := Format(' %d OnServerYield-Ereignisse',
    [iCnt]);
    // Anzeige im Formular aktualisieren
    Update;
    // Auswertung des Abbruch-Buttons ermöglichen
    Application.ProcessMessages;
    // Weitermachen oder nicht weitermachen - das ist hier die Frage
    AbortQuery := bSQLAbort
    end;

    (* Anwender kann langandauernde SQL-Abfrage abbrechen *)

    procedure TFormMain.BitBtnAbortClick(Sender: TObject);
    begin
    bSQLAbort := True
    end;

    end.
    </pre>
    Generell sind die Nebenwirkungen jedoch erheblich, so dass ich a) entweder auf MAXROWS oder b) zu einem vorherigen SELECT COUNT greifen würde. Über die BDE-Verwaltung kann die Treiber-Eigenschaft MAX ROWS für einen Alias fest zugewiesen werden - die BDE liefert damit nur noch die hier vermerkte Anzahl von Datensätzen in einer Abfrage zurück. Der Vorgabewert von -1 schaltet diese Begrenzung ab. Immer dann, wenn damit zu rechnen ist, daß nur eine bestimmte SQL-Abfrage via TQuery sehr große Datenmengen ergeben kann, kann eine Begrenzung der maximal zurückgelieferten Datensätze nur für diese eine Abfrage sinnvoll sein. Über einen geringfügig modifzierten TQuery-Nachfolger kann das Programm zur Laufzeit die Anzahl der maximal zum Client übertragenen Datensätze begrenzen:
    <pre>
    procedure TRestrictedQuery.PrepareCursor;
    begin
    inherited PrepareCursor;
    if FMaxRowCount > 0 then
    begin
    Check(DbiValidateProp(hDBIObj(Handle), curMAXROWS, True));
    Check(DbiSetProp(hDBIObj(Handle), curMAXROWS, FMaxRowCount));
    end;
    end;
    </pre&gt

    Comment

    Working...
    X