Toon posts:

[delphi TDataset/TQuery] SQL logging

Pagina: 1
Acties:

Verwijderd

Topicstarter
Ik wil graag mijn query's gaan loggen. Ik heb het in principe al werkend, maar zoals ik het nu heb moet ik steeds vlak voor het executen van een query de TQuery.SQL (TStrings) weg laten schrijven. Dit werkt op zich mooi, maar ik zou het liever aan een event van de datasources of query koppelen.

Welke moet ik daar voor hebben? Treedt er uberhaupt een event op vlak voor het executen van een query (doormiddel van een SQL.open of een ExecSQL)

  • P_de_B
  • Registratie: Juli 2003
  • Niet online
Welke database gebruik je? MS SQL heeft bijvoorbeeld zelf een profiler die goed kan loggen, misschien is dat een idee?

Oops! Google Chrome could not find www.rijks%20museum.nl


Verwijderd

Topicstarter
P_de_B schreef op donderdag 31 augustus 2006 @ 08:30:
Welke database gebruik je? MS SQL heeft bijvoorbeeld zelf een profiler die goed kan loggen, misschien is dat een idee?
Nee het gaat om MySQL. En het gaat in principe niet om het loggen zelf. Het gaat er om dat ik in mijn apps tijdens een error een debug-scherm naar voren kan roepen waar de laatst gedraaide query's vanuit app staan.

ik schrijf het niet weg in een database verder ofzo.... wordt gewoon weggeschreven naar een memo-component.

  • Pino
  • Registratie: Oktober 2001
  • Laatst online: 13-02 12:38
Wat dacht je van 'BeforeOpen'?

Je kunt ook gewoon in je foutafhandelingsroutine de query teruglezen toch? Die is in de tussentijd niet veranderd als het goed is.

[ Voor 69% gewijzigd door Pino op 31-08-2006 09:02 ]

"If you don't know where you are going, any road will take you there"


Verwijderd

Topicstarter
Pino schreef op donderdag 31 augustus 2006 @ 09:00:
Wat dacht je van 'BeforeOpen'?

Je kunt ook gewoon in je foutafhandelingsroutine de query teruglezen toch? Die is in de tussentijd niet veranderd als het goed is.
BeforeOpen heb ik al geprobeerd te gebruiken, maar dan worden de ExecSQL query's niet in meegenomen. Alleen maar de de query's die "open" of "active" krijgen.

gelijk nog een ander vraagje waar ik niet uit kom, ik heb het volgende stukje code:
Delphi:
1
2
3
4
5
6
7
8
9
procedure TApplicatie.buttonClick(Sender: TObject);
var qry : TStrings;
begin
  qry.Clear;
  qry.Add(' SELECT * from tabel ');
  qry.Add(' WHERE kolom =  1 ');

  QueryExec(data.qry1, qry, false);
end;


uitleg QueryExec:
"data" is een datamodule waar een query genaamd "qry1" op staat.
"qry" is de variable uit de procedure "buttonClick"
en "false" geeft aan dat het een "open" query is en geen "ExecSQL".

de procedure ziet er als volgt uit:
Delphi:
1
2
3
4
5
6
7
8
9
10
11
procedure QueryExec(Q: TQuery; Qry: TStrings; Exec : boolean);
begin
  with Q do
    begin
      SQL.Clear;
      SQL := qry;
      if exec = true then
        ExecSQL
      else open;
    end; //with
end;


ik krijg hier alleen steeds een error op:
---------------------------
Debugger Fault Notification
---------------------------
Project C:\Delphi Projects\app.exe faulted with message: 'access violation at 0x00404b06: write of address 0x0046268b'. Process Stopped. Use Step or Run to continue.
---------------------------
OK
---------------------------

hoe zit dat? iemand enig idee? Ik doe iets raars volgens mij maar ik kom er niet achter wat...

[ Voor 58% gewijzigd door Verwijderd op 01-09-2006 09:09 ]


Verwijderd

Verwijderd schreef op donderdag 31 augustus 2006 @ 12:57:
code:
1
2
3
4
5
6
7
8
9
procedure TApplicatie.buttonClick(Sender: TObject);
var qry : TStrings;
begin
  qry.Clear;
  qry.Add(' SELECT * from tabel ');
  qry.Add(' WHERE kolom =  1 ');

  QueryExec(data.qry1, qry, false);
end;


ik krijg hier alleen steeds een error op:
---------------------------
Debugger Fault Notification
---------------------------
Project C:\Delphi Projects\app.exe faulted with message: 'access violation at 0x00404b06: write of address 0x0046268b'. Process Stopped. Use Step or Run to continue.
---------------------------
OK
---------------------------

hoe zit dat? iemand enig idee? Ik doe iets raars volgens mij maar ik kom er niet achter wat...
Maak hier 's van:
Delphi:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
procedure TApplicatie.buttonClick(Sender: TObject);
var qry : TStringList;
begin
  qry := TStringList.Create;
  try
    qry.Add(' SELECT * from tabel ');
    qry.Add(' WHERE kolom =  1 ');
    // log hier evt. je query string

    QueryExec(data.qry1, qry, false);
  finally
    qry.Free;
  end;
end;

Jij definieert qry als een locale variabele voor je procedure, maar je maakt 'm nergens aan. Zonder 'm expliciet te creeren is 't echter een loze pointer naar een willekeurig stuk geheugen.
TStrings kun je overigens niet direct zelf aanmaken, omdat 't een abstacte base class is waar o.a. TStringList van is afgeleid, maar bv. ook de items van een TreeView. Vandaar dat ik 'm nu maar even als TStringList heb gedefinieerd.

Dat loggen van die query kun je overigens ook in je QueryExec doen, vlak voor ExecSQL of Open wordt aangeroepen. Dan hoeft 't maar op 1 plek.

Edit: TStrings is zelf niet abstract, maar een paar essentiele methods (Clear, Delete, Insert) zijn dat wel, en moeten dus door de afgeleide geimplementeerd worden.
En nog een dingetje: in je QueryExec gebruik je "SQL := qry;". 't Is netter om dan "SQL.Assign(qry)" te gebruiken. Dan wordt niet botweg de pointer van SQL op qry gezet, maar neemt SQL de data van qry over.

Edit2: Assign() is niet alleen netter, maar "SQL := qry;" is doodgewoon fout.
Als je "SQL := qry;" gebruikt, is je vorige SQL TStrings opeens een loos object waar je nooit meer bijkomt en die je dus ook niet kunt opruimen. Gevolg: een pracht van een memory leak...
Bovendien, wanneer de echte eigenaar van qry besluit om die TStrings(-afgeleide) op te ruimen, krijg je bij de eerstvolgende aanroep van QueryExec weer een mooie exception, omdat "SQL.Clear" een lijst probeert leeg te maken die niet meer bestaat.

Oftewel: laat het SQL object over aan je TQuery, en neem alleen de data over uit die qry parameter.

[ Voor 21% gewijzigd door Verwijderd op 31-08-2006 21:03 ]


Verwijderd

Topicstarter
Verwijderd schreef op donderdag 31 augustus 2006 @ 19:39:
[...]

Maak hier 's van:
Delphi:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
procedure TApplicatie.buttonClick(Sender: TObject);
var qry : TStringList;
begin
  qry := TStringList.Create;
  try
    qry.Add(' SELECT * from tabel ');
    qry.Add(' WHERE kolom =  1 ');
    // log hier evt. je query string

    QueryExec(data.qry1, qry, false);
  finally
    qry.Free;
  end;
end;

Jij definieert qry als een locale variabele voor je procedure, maar je maakt 'm nergens aan. Zonder 'm expliciet te creeren is 't echter een loze pointer naar een willekeurig stuk geheugen.
TStrings kun je overigens niet direct zelf aanmaken, omdat 't een abstacte base class is waar o.a. TStringList van is afgeleid, maar bv. ook de items van een TreeView. Vandaar dat ik 'm nu maar even als TStringList heb gedefinieerd.

Dat loggen van die query kun je overigens ook in je QueryExec doen, vlak voor ExecSQL of Open wordt aangeroepen. Dan hoeft 't maar op 1 plek.

Edit: TStrings is zelf niet abstract, maar een paar essentiele methods (Clear, Delete, Insert) zijn dat wel, en moeten dus door de afgeleide geimplementeerd worden.
En nog een dingetje: in je QueryExec gebruik je "SQL := qry;". 't Is netter om dan "SQL.Assign(qry)" te gebruiken. Dan wordt niet botweg de pointer van SQL op qry gezet, maar neemt SQL de data van qry over.

Edit2: Assign() is niet alleen netter, maar "SQL := qry;" is doodgewoon fout.
Als je "SQL := qry;" gebruikt, is je vorige SQL TStrings opeens een loos object waar je nooit meer bijkomt en die je dus ook niet kunt opruimen. Gevolg: een pracht van een memory leak...
Bovendien, wanneer de echte eigenaar van qry besluit om die TStrings(-afgeleide) op te ruimen, krijg je bij de eerstvolgende aanroep van QueryExec weer een mooie exception, omdat "SQL.Clear" een lijst probeert leeg te maken die niet meer bestaat.

Oftewel: laat het SQL object over aan je TQuery, en neem alleen de data over uit die qry parameter.
Dit werkt perfect.... maar ik kan nog een hoop leren van jou zie ik! Ik werk inmiddels 2 jaar een beetje met Delphi. Wat kleine programmatjes geschreven voor kennissen en voor het bedrijf waar ik werk draaien 4 apps produktie die ik zelf gemaakt heb. (van een labelprint-tooltje tot een uren-registratie systeem) Die mag ik wel eens herzien dan als daar ook van die variabele-fouten inzitten.

Kun je in 1 zin zeggen waarom/wanneer je zo'n .create; uit moet voeren? Ik heb dat nooit gebruikt en nooit last gehad eigenlijk. Komt het hier op neer: zonder .create; wordt er ergens in het geheugen de variabele aangemaakt en kan deze wel prima gebruikt worden binnen de procedure/functie. en met een .create; wordt er zeg maar netjes geregistreerd waar de variabele in het geheugen staat en is de variabele uitwisselbaar naar andere procedure's. klopt dat ongeveer?

met integer en string variabele hoeft het bijvoorbeeld weer niet (en kan het zelfs niet) (was effe wat aan het testen)

  • Ozzy
  • Registratie: April 2000
  • Laatst online: 11-02 21:32

Ozzy

omnia mutantur, nihil interit

Met een .Create wordt niet de variabele gereserveerd, maar het object waar de variable naar gaat wijzen. Voor de .Create is een object nil. Integers en strings zijn in Delphi geen objecten, vandaar dat je die niet hoeft en niet kunt .Createn.

De constructor (en die heet vaak .Create) instancieert een object, geheugenreservering, initialisatie van properties en dergelijke worden daarin gedaan. De .Create heeft verder niets te maken met de scope van het object binnen de applicatie, dat is afhankelijk van waar het object gedeclareerd. Dat kan van binnen een routine tot applicatie-wijd zijn, maar ze zullen altijd gecreate moeten worden.

En om het in één zin te houden. "Als je .Create niet gebruikt, bestaat je object niet."

[ Voor 29% gewijzigd door Ozzy op 01-09-2006 11:38 ]

O dag schoonheid, dag schoonheid, dag schoonheid, dag, dag!

Pagina: 1