Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   UnpreparedExecute führt SQL doppelt aus (https://www.delphipraxis.net/181347-unpreparedexecute-fuehrt-sql-doppelt-aus.html)

himitsu 7. Aug 2014 18:41

Datenbank: postgres • Version: 9.0 • Zugriff über: PgDAC

UnpreparedExecute führt SQL doppelt aus
 
Moin,

weiß zufällig jemand, warum PgDAC das SQL doppelt ausführt, wenn UnpreparedExecute aktiviert ist?

Beispiele: Ein
Delphi-Quellcode:
SELECT pg_sleep(15)
dauert 30 Sekunden
und ein
Delphi-Quellcode:
DROP FRUNCTION Test();
knall mit "existiert nicht", da das beim zweiten Durchlauf natürlich nicht mehr existiert.

jobo 8. Aug 2014 07:47

AW: UnpreparedExecute führt SQL doppelt aus
 
3 abstruse Ideen:
1. der Treiber ist fehlerhaft.
2. Du hast versehentlich eine doppelte Ausführung programmiert (event, ..)
3. Es gibt in sqlplus (oracle) ein Zeichen, das Statement auszuführen bzw. das letzte abgesetzte Select wiederholt(!) aufzurufen.
Weiß nicht, ob sowas bei pg bzw. dem Treiber evtl auch unterstützt wird.
Hast Du mglw versehentlich solche Zeichen ";", "/" ... am Ende des Statements?

Die Idee zu 3 hatte ich durch den Hilfetext
Zitat:

Remarks

If the UnpreparedExecute propery is set to True, the simple execute is used for SQL statement. Statement is not prepared before execute. It allows to add multiple statements separated by semicolon to the SQL property.
Insbesonderes das "..mehrere Statements getrennt durch Semicolon.." hat mich überrascht und auf die Idee gebracht.

himitsu 8. Aug 2014 13:39

AW: UnpreparedExecute führt SQL doppelt aus
 
In dem Sleep-Beispiel ist kein ; am Ende, aber das ist natürlich möglich, denn das UnpreparedExecute erlaubt ja grade mehrere Befehle, welche via ; getrennt sind.
SQL-Code:
DROP FRUNCTION Test(VARCHAR);
CREATE FUNCTION Test(INTEGER)
...;
UnpreparedExecute=False und es funktioniert meistens, erlaubt dann aber keine SQL-Scripte mehr.
Und jenachdem, ob es einen Fehler gibt (Fehlermeldung im/vom DB-Server), wird das auch manchmal doppelt ausgeführt.


Hatte mal versucht das zu debuggen, aber fand die Stelle nicht.
Ich entdeckte zwar eine Stelle, wo es heißt "wenn der und der Fehler, dann mach nochmal", aber die war es doch nicht, vorallem da es auch passiert, wenn es keine Fehler gab.


[add]
Lauf SQLMonitor an der Connection wird es nur einmal ausgeführt.


[add2]
Und das Schlimme ist ja, daß es nicht immer passiert.
Ein
Delphi-Quellcode:
SELECT pg_sleep(5)
dauert 10 Sekunden, aber ein
Delphi-Quellcode:
SELECT pg_sleep(5), 1
nur 5.
Vermutlich hängt das mit der Art und Anzahl der Datensätze im Result zusammen.

Ein Execute mit DROP FUNCTION wird nur einmal ausgeführt und ein Open ist doppelt (vermutlich da kein Result).

jobo 8. Aug 2014 16:12

AW: UnpreparedExecute führt SQL doppelt aus
 
schau mal hier unter 1.10.0.6 27-May-09:
http://www.devart.com/pgdac/revision_history.html

sieht nach Idee 1 aus.
Allerdings ist das schon recht alter Kram. Ist Dein Treiber so alt? Oder haben sie den Bug redeployed?

himitsu 8. Aug 2014 17:33

AW: UnpreparedExecute führt SQL doppelt aus
 
Ist eine 4.3.7, meinte grade der Einstellungsdialog an der PgConnection. :angle:

Zitat:

Zitat von jobo (Beitrag 1268047)
sieht nach Idee 1 aus.
Allerdings ist das schon recht alter Kram. Ist Dein Treiber so alt? Oder haben sie den Bug redeployed?

Sieht danach aus, vielleicht hatten die den auch zweimal drin und nur das erste Vorkommen behoben, oder doch für mich wieder eingebaut. :stupid:

Zitat:

4.1.3 18-Sep-13
Bug when UnpreparedExecute option is set to True is fixed
Wobei Dieses eigentlich auch nicht schlecht klingt, aber sollte ebenfalls schon drin sein.



Zitat:

Zitat von jobo (Beitrag 1268047)
schau mal hier unter 1.10.0.6 27-May-09:
http://www.devart.com/pgdac/revision_history.html

Schön ist auch der Fehler darüber.
Zitat:

Fixed bug with string fields longer than 65535
DevExpress dreht gern voll durch, wenn VARCHAR-Felder, ohne Längenangabe, rüberkommen, denn PgDAC behauptet dann das Feld sei 16 KB groß (8192 Chars), aber da VARCHAR dennoch mehr enthalten kann, rauchen dann die DBGrids ab und nehmen das Programm mit wenn doch mal mehr als 8191 Zeichen in soeinem Feld drin stecken. :wall:



Hab mich nochmal bissl durchgekämpft.

bei
Delphi-Quellcode:
SELECT pg_sleep(15), 1
:
Code:
dac150.MemData.TData.Open ===> einmal Ausführen
dac150.MemDS.TMemDataSet.InternalOpen
dac150.DBAccess.TCustomDADataSet.InternalOpen
:5071fd43 TDataSet.DoInternalOpen + $1F
dac150.DBAccess.TCustomDADataSet.OpenCursor(False)
:5071fcb7 TDataSet.SetActive + $5B
dac150.DBAccess.TCustomDADataSet.SetActive(???)
:5071fafe TDataSet.Open + $A
...
bei
Delphi-Quellcode:
SELECT pg_sleep(15)
:
Code:
dac150.MemData.TData.Open ===> nochmal Ausführen
:02074a05 TPgSQLCommand.ReadOutParams + $335
:02074627 TPgSQLCommand.DescribeParams + $5B
:02073918 TPgSQLCommand.SetProp + $30
dac150.CRAccess.TCRRecordSet.ExecCommand
:020752d1 TPgSQLRecordSet.InternalCreateComplexField + $C9
dac150.CRAccess.TCRRecordSet.ExecFetch(???)
dac150.CRAccess.TCRRecordSet.InternalOpen(False)
:02076b79 ReadBlobs + $15
dac150.MemData.TData.Open ===> einmal Ausführen
dac150.MemDS.TMemDataSet.InternalOpen
dac150.DBAccess.TCustomDADataSet.InternalOpen
:5071fd43 TDataSet.DoInternalOpen + $1F
dac150.DBAccess.TCustomDADataSet.OpenCursor(False)
:5071fcb7 TDataSet.SetActive + $5B
dac150.DBAccess.TCustomDADataSet.SetActive(???)
:5071fafe TDataSet.Open + $A
...
30 sec mit Unpepared=True
SQL-Code:
SELECT pg_sleep(15)
15 sec mit Unpepared=False
SQL-Code:
SELECT pg_sleep(15)
15 sec
SQL-Code:
SELECT pg_sleep(15), 1
Liefert ein "Unexpected server response" und danach ist die ganze Connection futsch.
SQL-Code:
SELECT COALESCE(pg_sleep(15), '')

-- oder
SELECT pg_sleep(15);
SELECT 1;
Doppelt mit Unpepared=True => liefert den "function does not exists"-Fehler (wurde ja schon im ersten Durchlauf gelöscht)
SQL-Code:
DROP FUNCTION Test()
Einfach mit Unpepared=False
SQL-Code:
DROP FUNCTION Test()

Dejan Vu 8. Aug 2014 20:18

AW: UnpreparedExecute führt SQL doppelt aus
 
Die 'COALESCE' Funktion führt Funktionen in einigen RDBMS doppelt aus, denn sie ist implementiert als
Code:
function Coalesce (a,b,...)
  if invoke(a) != null then return invoke(a)
  else if ...
Nur so als Hinweis. Ich kann mir auch vorstellen, das bei einem "SELECT Foo" zuerst das Format abgefragt wird: 'Wat is dat denn für eine Datentyp'?. Normale SELECT werden natürlich nicht ausgeführt, aber vielleicht so eine Funktion. Das wäre die Erklärung, weshalb das 'unprepared' doppelt ausgeführt wird: 1x zum Ermitteln des Datentyps und 1x bei der Ausführung.

Vielleicht kannst Du das mit einem 'SELECT 0 union SELECT pg_Sleep(15)' umgehen, denn dann wird vielleicht nur das 1.Select bei der Datentypermittlung ausgewertet.

himitsu 8. Aug 2014 20:38

AW: UnpreparedExecute führt SQL doppelt aus
 
Am Besten wäre es, wenn das garnicht erst doppelt ausführt.
Und das mit dem "nach Typ sehen" ... dann sollte doch
Delphi-Quellcode:
SELECT pg_sleep(15)
genauso wie
Delphi-Quellcode:
SELECT pg_sleep(15), 1
ausgeführt werden, was es aber nicht tut. :gruebel:

Das COALESCE war einfach mal ein Versuch, in dem einen praxsisfernen TestSQL auszuprovieren, was passiert, wenn man die Funktion in einer Anderen versteckt, mit dem Ergebnis, daß es noch schlimmer wurde.

Schlimm ist ja, daß man oft garnicht erkennen kann, ob es doppelt ausgeführt wird. Womit man jetzt noch garnicht weiß, ob und wieviele sonstige Abfragen eigentlich doppelt so schnell wären.
Mir ist es eben schon bei Funktionen ala
Delphi-Quellcode:
DROP irgendwas
oder
Delphi-Quellcode:
CREATE irgendwas
aufgefallen, wo es dann so schön knallt.


Im PgAdmin kann man ein SQL ausführen, indem man einfach auf Play drückt und fertig.

Im Code tut man zwar oft entscheigen, ob man nur ein Execute macht, oder ein Open mit auslesen des Results,
aber an vielen Stellen wird einfach irgendein SQL ausgeführt, ohne daß man jetzt schon weiß wie das mal aussieht
und es gibt im Programm auch eine Edit-Oberfläche, wo es jetzt mehrere Buttons gibt (für Open, Execute und Sonderformen), wo es eigentlich recht praktisch wäre, wenn es da auch mal weniger Buttons gibt, für die man sich entscheiden muß.

Dejan Vu 9. Aug 2014 10:27

AW: UnpreparedExecute führt SQL doppelt aus
 
Alter Schwede, verzwickt. Ich passe.

himitsu 9. Aug 2014 10:45

AW: UnpreparedExecute führt SQL doppelt aus
 
Zum Glück scheint es so, daß an den wichtigen Stellen nicht doppelt gerechnet (addiert) wird, zumindestens nicht so, daß es aufeinander aufbaut, sonst wären (hoffentlich) schon irgendwo Probleme mit den Ergebnissen aufgefallen.

Aber ich hatte schonmal einen Fall, wo ein
Delphi-Quellcode:
SELECT SpeichereVaiable('abc', LeseVariable('abc') + 1)
die Variable doppelt hochgezählt hat. (eine 'ne Tabelle mit Name- und Wert-Spalte)


Alle Zeitangaben in WEZ +1. Es ist jetzt 19:21 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz