Newsgroup: it.comp.lang.delphi
Titolo: [D5] Query su tabelle paradox

Ciao tutti.
Data una query:
qryFormCom.SQL SELECT * FROM form_com WHERE codice = :cod
con il parametro cod e cod.DataType = ftString
Questo pezzo di codice:
      with dmDosaggio do begin
        qryFormCom.ParamByName('Cod').AsString :=
Dati.PIANOPRO.FieldByName('Formula').AsString;
        qryFormCom.Active := True;
      end;
che viene eseguito circa ogni 500 ms, per un valore del campo Formula =
'10000' (che è composto da tutte cifre ma comunque una stringa) circa una
volta ogni tre ora solleva una EDBEngineError
e nello stack degli errori ho il solo messaggio 'Invalid Parameter'.
La stessa applicazione, eseguita in ambiente di debug un numero sufficiente
di ore per sollevare l'eccezione non da alcun problema.
Ora, immaginando che sia un problema di conversione di tipi, ho provato a
modificare il codice come segue:
var
    codFormula: string;
begin
    ...
    codFormula := Dati.PIANOPRO.FieldByName('Formula').AsString;
      with dmDosaggio do begin
        qryFormCom.ParamByName('Cod').AsString := codFormula;
        qryFormCom.Active := True;
      end;
e nel pomeriggio potrò dire se va bene....
Ma a questo punto qualunque idea, esperienza di vita simile, consiglio su
come riscrivere il tutto o anche sostegno morale è bene accetta  :-)
Gianluca.

 e nel pomeriggio potrò dire se va bene....
Come non detto: stesso identico problema :-(
Ciao.
Gianluca.

 Come non detto: stesso identico problema :-(
Non so se potrą aiutarti, ma io proverei, prima dell'open, ad "appendere" in
un file di testo il valore di codFormula, e anche l'eventuale messaggio di
errore catturato da un try...except, in questo modo puoi evitare di
debuggare ore e ore aspettando che ti dia l'errore :)
--
Jax
Journeying Artificial Xenomorph

 debuggare ore e ore aspettando che ti dia l'errore :)
Già fatto.
Dopo aver debuggato tutti i miei ultimi interventi all'applicazione (pensavo
fosse uno di questi, invece evidentemente il problema è altrove) l'unica
soluzione (essendo tutto quanto all'interno di un timer) che ho trovato è
scrivere in un file di testo tutti i passi che vengono eseguiti ed il valore
di tutte le variabili utilizzate.
In tutto questo c'è di strano:
- ad una presunta *parità di condizioni* la maggior parte delle volte il
problema non si verifica;
- l'applicazione è in produzione da alcuni anni presso una 20ina di clienti
e solo quest'ultima versione ha questo tipo di problema, però in una routine
che nemmeno avevo mai visto e quindi mai modificata da me (come non sopporto
dover manutenere applicazioni scritte dal altri).
Stampando mi dice che codFormula è uguale a '10000', mi chiedo se non sia un
problema legato appunto alla conversione dei dati (ma io uso tutto AsString,
anzi passo proprio tramite un variabile string per evitare problemi legati
ai Variant).
Ciao.
Gianluca.

 sia un problema legato appunto alla conversione dei dati (ma io uso
Dico la stupidata del giorno: non è che il campo è definito come lungo 4?


       end;
Hai la certezza che quella particolare query venga eseguita solo nell'evento
del timer?
Non è che esiste un thread che la usa, ad esempio?
Inoltre hai fatto tutti i test su macchine con stessa versione di sistema
operativo, service pack e bde?
Hai provato a lanciare la applicazione con SqlMonitor attivato?
Hai provato a mettere il database in locale? Se si, hai riscontrato lo
stesso problema?
Bye
A.


Eheheh.. per sicurezza ho controllato... tutto ALPHA(5), anche perchè questo
mi pare sia l'unico cliente che memorizza dati solo numerici (da qui il
dubbio delle conversioni).
Cmq, dalle ultime prove effettuate:
01. codFormula := Dati.PIANOPRO.FieldByName('Formula').AsString;
02. with dmDosaggio do begin
03.  qryFormCom.ParamByName('Cod').AsString := codFormula;
04.  qryFormCom.Active := True;
05. end;
Ho messo delle print di debug sia prima di 03 che prima di 04 e, testando:
- codFormula;
- qryFormCom.ParamByName('Cod').AsString
ottengo comunque lo stesso risultato cioè 10000
l'eccezione viene sollevata quando viene eseguito 04 dopodichè mi finisce
direttamente nel blocco finally dove:
if  dmDosaggio.qryFormCom.Active then
  dmDosaggio.qryFormCom.Active := False;
Altro dilemma inestricabile: l'applicazione è stata strutturata in modo da
fermare le operazioni in corso in caso di eccezione. Però poi permette anche
di riprendere da dove era stata interrotta: a questo punto io mi aspetterei,
se l'eccezione si verifica 'ogni tanto', di poter riprendere. Invece niente:
da quel momento in poi quel codice, sempre a parità di condizioni, mi darà
sempre errore.
Ciao
Gianluca.

e nello stack degli errori ho il solo messaggio 'Invalid Parameter'.
Il messaggio "Invalid Parameter", così come "Parametro non corretto",
nella versione italiana, sono generati da Windows, quando le risorse
si esauriscono.  D'altronde, usare le query con Paradox, significa
spararsi sui piedi (anche perché ignorano del tutto gli indici
presenti sulla tabella), specie se 2 al secondo (!!).  Personalmente,
se proprio devi lavorare con BDE+Paradox, ti consiglio di usare una
TTable, che è ottimizzata per lavorare col BDE, e impostare dei range.
-- 
Andrea Laforgia
"640kb of memory should be enough for anyone." -- Bill Gates.

 stesso problema?
Il db è già in locale.
Ciao.
Gianluca.

 TTable, che è ottimizzata per lavorare col BDE, e impostare dei range.
Le versioni di WinXP Win95 dove gira l'applicazione sono in italiano, eppure
il messaggio in inglese (magari non vuol dire niente perchè poi tanto è il
BDE ad intercettarlo ed a buttare fuori il proprio messaggio).
Stando al tuo consiglio ora provo a definire una TTable sulla mia Form_Com e
fare:
tbFormCom.Filter := 'codice  = "' + codFormula + '"';
tbFormCom.Active := True;
... poi ti saprò dire, intanto ringrazio.
Ciao.
Gianluca.

 Il db è già in locale.
Hai abilitato l'accesso esclusivo?
Bye
A.

tbFormCom.Active := True;
Nel caso del filtro devi usare la proprietą Filtered a True.
Io, perņ, ti consiglio di indicizzare i campi di ricerca e usare un
range, oltre ad essere molto veloce, consente di lavorare solo sugli
indici e di chiedere i dati solo quando servono (questo aumenta le
performance e riduce il numero di risorse impiegate).
Non č detto che con questi accorgimenti tu risolva il problema, perņ
sicuramente č il modo migliore di lavorare con Paradox, per il quale
le query non andrebbero MAI usate.


 le query non andrebbero MAI usate.
Ho già inserito chiave primaria ed indice sui campi su cui devo far ricerca
ed ho già sostituito la query con table e range... ora faccio un pò di
test...
Ciao,
Gianluca

5.000 record.
Fatelo arrestare.  Passi che non ci siano indici secondari (se usava
le query, d'altronde, erano inutili, Paradox non li usa), ma che non
ci sia chiave primaria è inaccettabile.  Perlomeno, aggiungendo gli
indici, le prestazioni dovrebbero aumentare sensibilmente.


 menu database-sqlmonitor
Non lo trovo. Forse perchè di D5 ho la versione Pro e non la Ent?
Ciao,
Gianluca.

 indici, le prestazioni dovrebbero aumentare sensibilmente.
Non farmi dire niente che programmo in Delphi dalla quando č uscita la
versione 2.0 e fino a quando non mi son trovato a manutenere questa
applicazione non sapevo nemmeno la sintassi delle label e se goto si
scrivesse "go to" o "goto".
Tra qualche immagino riuscirņ a distinguere capo e coda di ogni singolo
spaghetto in un piatto di carbonara. :-)
Non vado oltre che poi divento OT ed anche antipatico ;-)
Ad occhio, senza abilitare la comunicazione con la seriale, in effetti
sembra leggermente piu veloce.
Ciao.
Gianluca.

potrebbe.
Sorry!
Bye
A.

applicazione 
Un'altra cosa che si dovrebbe fare e che nessuno rispetta, lavorando
con Paradox e le query, è l'impostazione della proprietà "PrivateDir",
del componente Session.  Qui dentro il BDE crea i file temporanei e
per default è quella da cui l'eseguibile viene lanciato.
Per applicazioni multiutente, il cui eseguibile viene lanciato da un
server centrale, è bene che questa cartella sia impostata sulla
macchina locale, in modo da isolare i file temporanei di ogni client,
l'uno dall'altro.  Pare che questo sia anche un accorgimento utile per
non far crescere troppo il file di lock.
Io seguo una strada del genere, nel sorgente DPR del progetto:
var
  WindowsDirectory: array [0..511] of Char;
  PrivateDirPath: String;
...
GetWindowsDirectory(WindowsDirectory, 
                    SizeOf(WindowsDirectory));
PrivateDirPath :=
   IncludeTrailingBackSlash(ExtractFileDrive(WindowsDirectory)) +
                         'MYAPP_PRIVATE';
if not DirectoryExists(PrivateDirPath) then
  if not CreateDir(PrivateDirPath) then
    raise Exception.Create('Impossibile creare la "private
directory"');
Session.PrivateDir := PrivateDirPath;
Application.Initialize;
...
