Newsgroup: it.comp.lang.delphi
Titolo: Query parametriche e testo SQL completo

All'interno di un'applicazione faccio uso di query parametriche, per 
intenderci: "INSERT INTO TABLE_1 (IDPK, Nome, Cognome) VALUES (:IDPK, 
:Nome, :Cognome)".
Vorrei implementare la funzionalitï¿œ di loggare eventuali errori generati 
dal database (tipo il tentativo di duplicare una chiave primaria o un 
indice unique) su un apposito file di log, ma quello che mi manca ï¿œ come 
tirare fuori il testo SQL completato con i valori che sostituiscono i 
parametri, cioï¿œ nel caso precedente qualcosa del tipo "INSERT INTO 
TABLE_1 (IDPK, Nome, Cognome) VALUES ('5', 'Pippo', 'PierPippo')".
C'ï¿œ un'automazione nei componenti che ereditano da TQuery o TDataset che 
faccia questo? Ho guardato sul manuale e ho googlato in giro ma non ho 
trovato nulla.
Chiaramente potrei farlo a "manazza", cioï¿œ prelevando tutti i parametri 
dalla proprietï¿œ Params e sostituendoli sulla stringa SQL, ma ï¿œ possibile 
che non ci sia niente del genere nel componente?

 i valori che sostituiscono i parametri
Quando credi una PS la stringa SQL con i placeholder viene inviata al
driver del tuo DB. Questo poi ne fa un po' quel che vuole per
ottimizzare le performance.
Ti faccio un esempio di quello che alcuni driver/DB fanno:
1. Inviano al DB la PS che la compila o addirittura la compila
direttamente il driver e poi la invia compilata al DB.
2. Il DB poi la esegue crearendo, per esempio, una VIEW dinamica
corredata da indici dinamici.
A questo punto la stringa SQL iniziale non esiste più!
Quando poi tu popoli (credi di popolare) la tua stringa SQL avviene
questo:
3. il driver riceve solo i tuoi params e li manda al DB
4. Il DB li trasforrma in puntatori agli indici della view dinamica
sopra
5. Il DB restituisce i valori della riga puntata.
Cioè il DB, saltando tutto il processo di parsing e compilazione della
stringa SQL con i valori ricevuti al momento, ti restituisce i dati
molto più velocemente
Come vedi, allora, quando popoli la tua PS, essa in realtà non esiste
più per il DB, ma esistono solo dei puntatori a uno o più dei suoi
indici. Se poi ci sono errori di qualsiasi tipo diventa difficile
restituirti la stringa "preparata" perché in realtà non esiste proprio
una stringa preparata, a meno che il driver (o tu) non la scriva in
forma di stringa appositamente per te nella sua gestione dell'errore.
Ultima nota: il meccanismo spiegato sopra mostra anche come molti
usano le PS in modo sbagliato: in java, per esempio, molti creano un
oggetto PreparedStatement al volo solo quando serve  e contestualmente
lo popolano con i parametri, costringendo il DB ad eseguire i passi 1
e 2 ad ogni esecuzione.
Ciao,
Gp

Molto interessante quanto hai scritto.
Io pensavo che fossero i componenti di accesso al db a fare il parsing 
della stringa, e invece fa tutto il db.
Vabb�, vuol dire che nel file di log riporter� la stringa sql con i 
parametri e di fianco l'elenco dei valori assegnati ai parametri.

 parametri e di fianco l'elenco dei valori assegnati ai parametri.
Non vorrei fare la cosa piu' facile di quello che potrebbe essere, ma 
avendo la stringa SQL di partenza, i parametri, che sono delle liste, 
con un ciclo e 1 replacestring riesci a ricavare il tutto ....
qualche cosa del tipo:
   sCmd := <Query>Comando;
   for j := 0 to <Query>Parameters.Count -1 do;
   begin
     sPar := <Query>Parameters[j].Value;
     sCmd := StringReplace(sCmd,':'+<Query>Parameters[j].Name,
                               sPar,[rfIgnoreCase]);
   end;
NB: Queste 4 righe non sono testate, ma buttate giu' solo come schema, 
in quanto non distinguo i tipi di parametro, non testo se il parametro 
esiste e altre cose, ma potrebbe essere uno spunto da cui partire.
^_Goblin_^
-- 
Ibis et redibis non morieris in bello
http://goblinland.myminicity.com/

 esiste e altre cose, ma potrebbe essere uno spunto da cui partire.
Una soluzione di quel genere l'avevo pensata anch'io, ma in realt� 
dovrei tener conto  del tipo di dato e anche del motore db che ho sotto, 
per esempio se uso mysql e il parametro � una data dovr� trasformarlo 
nel formato "yyyy-mm-dd", invece se il db � access il formato � 
"#mm-dd-yyyy#" (o qualcosa del genere, non ricordo pi� come lavora access).
Comunque per ottenere una stringa SQL eseguibile diventa un lavoraccio.
Ed in effetti a me interessa solo sapere quali dati hanno causato il 
problema e la struttura della query  eseguita.

 trovato nulla.
TSQLMonitor potrebbe fare al caso tuo.
http://docs.codegear.com/products/rad_studio/radstudio2007/RS2007_helpupdate
s/HUpdate4/EN/html/devwin32/unidebuggingdbexpressapplications_xml.html
PS: � sempre meglio specificare la versione di Delphi che si usa, il DB,
la 
tecnologia di accesso, il sistema operativo, ecc... quando si chiede la 
soluzione a qualche dubbio/problema.
ACSH
-- 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it

 e la struttura della query  eseguita.
L'approccio corretto ï¿œ di agire sul sistema di logging/tracing del 
database.
Come giï¿œ spiegato da altri, ï¿œ il driver che gestisce l'sql da invocare, 
e non ï¿œ detto che sia come tu lo hai scritto. Ado per esempio genera 
dei micro sql di update, scomponendo la query se ï¿œ molto grossa in 
piccole query atomiche.
Per lavori di questo genere nel mio logging subsystem ho solo bisogno 
di loggare i parametri, perchï¿œ la query giï¿œ la conosco visto che ï¿œ 
annegata nei componenti e, di conseguenza, nei sorgenti.
ciao
-- 
Morde

 soluzione a qualche dubbio/problema.
Infatti esiste anche un sistema di logging delle query passate alla dll 
ADO (msado....dll) , ma come dicevo pocanzi la sola cosa da conoscere 
*runtime* ï¿œ il valore del parametro, tutto il resto ï¿œ giï¿œ conosciuto.
ciao
-- 
Morde