Forum Delphi.cz

Databáze => Obecné => Téma založeno: miroB 19-07-2018, 14:50:17

Název: SQLite a TBCD prakticky + Problém
Přispěvatel: miroB 19-07-2018, 14:50:17
Skúšam SQLite + FireDAC + TBCD.
Pôvodne ma vystrašila info z odkazu:
http://docwiki.embarcadero.com/RADStudio/Tokyo/en/Using_SQLite_with_FireDAC#High-Precision_Numbers (http://docwiki.embarcadero.com/RADStudio/Tokyo/en/Using_SQLite_with_FireDAC#High-Precision_Numbers)

Spravil som pokus, viď priložený obrázok.
Tvorba a naplnenie tabuľky v SQL  (qryCreate):
Kód: MySQL [Vybrat]
  1. CREATE TABLE tblBCD ( bcd23 Numeric( 64,23 ), bcd25 Numeric( 64,25 ) );
  2. Insert into tblBCD ( bcd23, bcd25 ) values
  3.  ( '-12345678901234567890,12345678901234567890123456789012345678901',
  4.    '-12345678901234567890,123456789012345678901234567890123456789012' );
  5. select rowid, bcd23, bcd25 from tblBCD
Na výstupe sú však miesto desatinných oddeľovačov znaky "<". Je vidieť aj na obrázku.
Kontrola cez kód:
Kód: Delphi [Vybrat]
  1. uses
  2. Data.FmtBcd
  3. ..
  4. procedure TForm1.FormCreate(Sender: TObject);
  5. var
  6.   x, y, x2, y2 : TBCD;
  7.   s, s2, s3 : String;
  8. begin
  9.   if dbMain.Connected then
  10.     dbMain.Connected   := false;
  11.   dbMain.Connected     := true;
  12.   qryCreate.ExecSQL;
  13.   qryCategories.Active := True;                 // PROBLÉM :
  14.   s   := qryCategories.Fields[ 0 ].AsString; // s : obsahuje kompletný záznam, ale ten znak "<" ..
  15.   s2  := StringReplace( s, '<', ',', [] );   // s2 je už s čiarkou ..
  16.   y   := StrToBcd( s2 );                     // korektné BCD číslo
  17.   s3  := BcdToStr( y - 1 );                  // korektný výsledok
  18.   x2  := qryCategories.Fields[ 0 ].AsBcd;    // toto zdanlivo funguje, ale Precision je poškodená
  19. end;
ešte SQL kód qryCategories:
Kód: MySQL [Vybrat]
  1. select   *,rowid from tblBCD

Naplnenie cez kód sa však správa korektne:
Kód: Delphi [Vybrat]
  1.   s := '-12345678901234567890,12345678901234567890123456789012';
  2.   x2 := StrToBcd( s );                   // BCD číslo
  3.   qryCategories.Edit;                    // vloženie do tabuľky
  4.   qryCategories.Fields[ 0 ].AsBCD := x2; // vloženie do tabuľky
  5.   qryCategories.Post;                    // vloženie do tabuľky
  6.   y2 := qryCategories.Fields[ 0 ].AsBCD; // vloženie do tabuľky
  7.   x := y2 - 1;                           // VYBRATIE z tabuľky + matem operácia
  8.   s3  := BcdToStr( x );                  // koprektný výsledok
  9. //    '-12345678901234567891,12345678901234567890123456789012345678901'
Zdá sa, že SQLite + FireDAC dokážu manažovať BCD
Problém je zatiaľ len s vkladaním pomocou SQL - INSERT INTO
Z kódu Delphi sa BCD čísla vložené a vybrané z tabuľky správajú korektne

Problém je zrejme vo FormatSettings, pretože vo Windows mám decimal separator ako čiarku.

ČIASTKOVÝ ZÁVER: BCD je v SQLite vďaka FireDAC použiteľné bez okľuky cez TEXT, či BLOB.
Funguje typ NUMERIC. Zatiaľ vidím jediný väčší problém: napĺňanie BCD cez INSERT INTO..

Apropos: operácie v databáze sa zrejme prevádzajú na Double, pretože matemat operácie dajú presnosť len v rámci Double.
To by vyzeralo na dodatočné UDF funkcie..


Název: Re:SQLite a TBCD prakticky + Problém
Přispěvatel: vandrovnik 20-07-2018, 10:52:09
A nemá se v tom INSERT použít desetinná tečka?
Název: Re:SQLite a TBCD prakticky + Problém
Přispěvatel: vandrovnik 20-07-2018, 11:51:12
Jinak hlodá ve mně zvědavost, z jakého měření padají tak přesná čísla, protože i double by uměl uložit vzdálenost ze Země k Alfa Centauri s přesností na 1 cm 10 m :-)
Název: Re:SQLite a TBCD prakticky + Problém
Přispěvatel: miroB 20-07-2018, 15:17:10
A nemá se v tom INSERT použít desetinná tečka?
S bodkou to nefungovalo vôbec. S čiarkou tak, ako som napísal.
Celkom verím, že sa vo vnútri procesov bije čiarka s bodkou.
Zrejme ak by som mal Win-y nastavene na US, prebehlo by všetko OK. Preskúmam neskôr.
Pri pokuse s čiarkou dáva Delphi túto hlášku:
'-12345678901234567890.12345678901234567890123456789012 is not a valid BCD value'.
Ak zamením bodku za čiarku, je to OK.
Niekde som tu videl tému, kde sa rieši nastavenie FormatSettings, aby Delphi bralo od štartu generálne bodku ako oddelovač. Alebo použiť funkciu
TryStrToBcd(AValue, Result, FormatSettings)

Pôvodne ma vystrašila info z odkazu:
http://docwiki.embarcadero.com/RADStudio/Tokyo/en/Using_SQLite_with_FireDAC#High-Precision_Numbers (http://docwiki.embarcadero.com/RADStudio/Tokyo/en/Using_SQLite_with_FireDAC#High-Precision_Numbers)

Duvod je na miste. Manual rika, ze pro takto precizni hodnoty mas pouzit datovy typ TEXT a mapovani datovych typu FireDAC. SQLite tak precizni hodnotu do datoveho typu REAL neulozi.
Vtip je v tom, že ten Numeric funguje. Je pravdepodobné, že FireDAC interne prehodí typ na blob, alebo text. Funguje nad tým napríklad aj agregačná funkcia SUM. Ibaže zobrazí double. Zatiaľ mi vkladanie funguje len cez Delphi kód. Nie cez SQL. Napríklad pre Numeric( 26,16 ), sa zdá, že pracuje ako s Float/Double.
Ale Numeric( 64,23 ), založí zrejme pole typu Char(34), aspon taky je datasize. Hlási ho však ako ftFMTBcd.

Jinak hlodá ve mně zvědavost, z jakého měření padají tak přesná čísla, protože i double by uměl uložit vzdálenost ze Země k Alfa Centauri s přesností na 1 cm 10 m :-)
Teraz je to ako hobby. Ale plánujem to rozbehnúť. Už viackrát som narazil na problém s nepresnosťou pri sčítaní veľkého množstva údajov. V rámci rôznych štatistík.
Najmä ak ide o rôzne postupy, tak sa výsledky nezhodovali presne.
V bankách furt mali problém s presnosťou. To som však zažil (ako pozorovateľ), pred rokmi, teraz nie:)
PS: Ak by riadne fungoval Extended aj pod 64 bit kódom, ani by ma nenapadlo riešiť nejaké BCD.
Tie obrovské čísla, čo som prezentoval, išli už len pre zaujímavosť až na hranicu toho, čo zvláda BCD.



Název: Re:SQLite a TBCD prakticky + Problém
Přispěvatel: miroB 20-07-2018, 23:22:50
Vecer mrknu na to co se uvnitr deje..
Rád sa dozviem niečo praktické na túto tému. Alebo zo zákulisia..
Název: Re:SQLite a TBCD prakticky + Problém
Přispěvatel: miroB 21-07-2018, 21:31:57
Super toto funguje:
Mohl by sis vsak vytvorit vlastni datovy typ, jenz bude mit affinity TEXT, treba FLOATTEXT a pro nej vytvorit mapovani (kdybys pouzil mapovani primo na TEXT, mohlo by dojit ke kolizi hodnot jenz mely byt ulozeny jako text). Pak muzes pouzit desetinnou tecku, protoze se SQLite nebude snazit o konverzi do SQLITE_FLOAT a FireDAC se stavajicim kodem dokaze prevest SQLITE_TEXT s desetinnou teckou. Tedy napr.:

Kód: Delphi [Vybrat]
  1. var
  2.   Value: TBcd;
  3.   MapRule: TFDMapRule;
  4. begin
  5.   FDQuery1.FormatOptions.OwnMapRules := True;
  6.  
  7.   MapRule := FDQuery1.FormatOptions.MapRules.Add;
  8.   MapRule.TypeMask := 'FLOATTEXT';
  9.   MapRule.TargetDataType := dtFmtBCD;
  10.  
  11.   FDQuery1.SQL.Text :=
  12.     'DROP TABLE IF EXISTS MyTable;' +
  13.     'CREATE TABLE MyTable(TheValue FLOATTEXT);' +
  14.     'INSERT INTO MyTable (TheValue) VALUES (''-12345678901234567890.12345678901234567890123456789012345678901'');' +
  15.     'SELECT TheValue FROM MyTable;';
  16.   FDQuery1.Open;
  17.  
  18.   Value := FDQuery1.Fields[0].AsBCD;
  19.   ...
  20. end;
..
Samozrejme potrebujem k tomu vlastné Custom funkcie, pretože so stringami SQLite matiku neovláda.
Tu je príklad riešenia.
Ako vidieť dá desatinná čiarka tam furt otravuje. Ale funkcia funguje:
Kód: Delphi [Vybrat]
  1. // Inicializácia funkcie:
  2. FDSQLiteFunction1.DriverLink := FDPhysSQLiteDriverLink1;
  3. FDSQLiteFunction1.FunctionName := 'Rozdiel';
  4. FDSQLiteFunction1.ArgumentsCount := 2;
  5. FDSQLiteFunction1.OnCalculate := FDSQLiteFunction1Calculate;
  6. FDSQLiteFunction1.Active := True;
  7.  
  8. // Event:
  9. procedure TForm1.FDSQLiteFunction1Calculate(AFunc: TSQLiteFunctionInstance;  AInputs: TSQLiteInputs; AOutput: TSQLiteOutput; var AUserData: TObject);
  10.  
  11.   function custStrToBcd( const s: String ): TBCD;
  12.     var
  13.       p: PChar;
  14.     begin
  15.     p        := StrScan( PChar( s ), '.' );
  16.     if p <> nil then
  17.       begin
  18.       p^     := ',';
  19.       result := StrToBcd( s );
  20.       p^     := '.';
  21.       end
  22.     else
  23.       result := StrToBcd( s );
  24.     end;
  25. begin
  26.   AOutput.AsString := BCDToStr( custStrToBcd( AInputs[ 0 ].AsString ) - custStrToBcd( AInputs[ 1 ].AsString ) );
  27. end;
  28.  
Príslušný SQL:
Kód: MySQL [Vybrat]
  1. DROP TABLE IF EXISTS MyTable;
  2. CREATE TABLE MyTable(TheValue FLOATTEXT);
  3. INSERT INTO MyTable (TheValue) VALUES ( '-12345678901234567890.12345678901234567890123456789012345678901' );
  4. SELECT TheValue, Rozdiel( TheValue, '1' ) AS [Odčítané::Text(64)] FROM MyTable;
Výsledok je korektný. Nula pred desatinnou bodkou sa zamení za jedničku. ( prvý vstup je záporné číslo, druhý kladný, preto odčítanie, aby jednička pribudla)
Název: Re:SQLite a TBCD prakticky + Problém
Přispěvatel: miroB 21-07-2018, 21:46:23
AsNumber z toho spraví double a .. som v háji:)
Bolo by to celé zbytočné. Alebo som niečo prehliadol?
Bohužiaľ Custom funkcie nepodporujú cast AsBCD.

Inak, pozitívne je, že Custom funkcie SQLite databázu extra nespomaľujú.
Naopak ak funkcia dokáže nahradiť zložitejšiu SQL konštrukciu, tak výpočet sa až násobne zrýchli.
Zopár takých funkcií už mám.
Název: Re:SQLite a TBCD prakticky + Problém
Přispěvatel: miroB 21-07-2018, 21:59:20
Hneď idem vyskúšať..
Vyskúšané !
Funkcia ako taká zbehne. Aj výsledok je matematicky správny, lenže..
Pri vyťahovaní výsledku ( x2 := FDQuery1.Fields[ 1 ].AsBcd; )  príde ku chybovej hláške:

'-12345678901234567891.12345678901234567890123456789012345678901 is not a valid BCD value'
Tá nešťastná bodka - čiarka ako decimal separator stále straší.
Nie je lepšie zabezpečiť pre program, aby sa systém rovno tváril ako US a nie SK/CZ ?
Název: Re:SQLite a TBCD prakticky + Problém
Přispěvatel: miroB 21-07-2018, 22:08:31
Inak toto funguje OK:
Kód: Delphi [Vybrat]
  1. AOutput.AsString := BcdToStr( AInputs[ 0 ].AsNumber - AInputs[ 1 ].AsNumber );
Nie je to ideál, ale myslím, že k nejak výraznému spomaleniu nepríde.
Název: Re:SQLite a TBCD prakticky + Problém
Přispěvatel: miroB 21-07-2018, 22:43:15
Žiadny pozitívny efekt proti predošlému textu. Ale to riešenie, čo som upravil posledne, je nanajvýš uspokojivé.
Název: Re:SQLite a TBCD prakticky + Problém
Přispěvatel: miroB 21-07-2018, 23:10:07
Už sa teším na budúce aggregate bcdSUM, bcdCOUNT, bcdAVG a aj MIN MAX :)
Ono sa to na prvý pohľad nezdá, ale v double po pár matematických operáciách a zaokrúhleniach sa stráca presnosť.
Nevraviac už o tom, že double ako také nie je možné vzájomne porovnávať.
Ten typ numeric, v rozsahu aspoň 20 číslic by pomohol. Ako presné číslo. Nie ako nejak neurčito zaokrúhlený float. A tá zbytočnosť exponentu u float. Tragédia.
Komu treba 45 000 000 000 000 000 000 000. Ten sprostý exponent je tak akurát dobrý na podobnú somarinu..
Leda tak hypoteticky na IBAN. Lenže tam nejde zase CZ/SK, lebo to už je TEXT
Dobre nech si nechajú aj číslo s exponentom, ale nech k nemu dajú ekvivalent na normálne číslo, čo nemusí byť primitívne zaokrúhlené. To je pre databázy pomerne tragédia..
Preto by mal existovať riadny Numeric / Decimal, ktorý by mal 10-12 bytov a bolo by to prevždy vyriešené. Myslím že to mala už prastará dbf-ka. To zase prišiel na svet medzitým nejaký vedecký mudrlant..
Tu nejde o to, že by SQLite nepodporovala taký rozumný formát.
Odklonili sa od neho aj programovacie jazyky. Aspoň do tej miery, že ak ho majú, tak len ako nejakú neplnohodnotnú a neefektívnu exotiku.
Currerncy by bol kandidát. Ale niekedy je treba viac miest za desatinnou bodkou, než má Currency.
Preto Decimal, napríklad aj taký nenáročný ako Decimal(5, 2). Ale presný.


Název: Re:SQLite a TBCD prakticky + Problém
Přispěvatel: Stanislav Hruška 22-07-2018, 09:05:28
A rozdeliť to desatinné číslo na dve celé čísla? Neviem, ani len netuším, čo by to znamenalo v praxi pri matematických operáciach
Název: Re:SQLite a TBCD prakticky + Problém
Přispěvatel: miroB 22-07-2018, 11:51:36
Uvažoval som o tom. 2 x 8 bytov (celkom 16), by nádherne stačilo. Keby to bolo napríklad niečo ako Currency, s presnosťou nie na 4, ale aspoň 10 číslic. Aj keď Currency tuším interne počíta so 6 desatinnými miestami, výsledok, zaokrúhľuje na 4. Tá pevná desatinná časť je smola.
Pre dve čísla v databáze by museli byť dve polia a s tým robiť SQL-y.. To by bolo divné.
Preto by to chcelo odkladať ako record do blobu.
Tiež by to chcelo narobiť špeciálne funkcie. Prvé pole by nieslo info o celých číslach. No a desatinná časť by bolo double.
Mimo databázy ( v Delphi ) by sa ten record uložil do BCD. Základné výpočty BCD zvláda.
Lenže to by bolo treba prekopať FireDAC.

Úplnou lahôdkou pre prácu s číslami je knižnica MPArith 1.37.12 https://sslsites.de/wolfgang-ehrhardt.de/ (https://sslsites.de/wolfgang-ehrhardt.de/)
Používa niečo ako veľké celé číslo a k tomu má info o :  1. exponente a 2. bitprecision.
Knižnica pri voliteľnom rozsahu presnosti, umožní nielen základné matem operácie, ale aj mnohé matematické funkcie.
Pri voľbe presnosti 80 bitov spočíta výsledok s presnosťou 24 čísel.
Presnosť sa dá nastaviť napríklad na 512 bitov.
Max presnosť je však až 120000 bitov !!!
Smola je, že každé číslo tam pozostáva z cca 5 Bigint + reťazec číslic podľa presnosti.
Je to veľká "spotreba" najmä kvôli variabilite tej knižnice.

Z toho nejak odkukať, ako využiť 10 bajtov (fixne, bez možnej zmeny rozsahu ), z toho 9 bajtov pre presnosť 21 číslic   + 1 bajt na mantisu.
Resp poskytovať presnosť 19 číslic a posledné dve zaokrúhliť, ako to robí Currency.
10 bajtov by som v databáze na danú tému vďačne obetoval.

Je to určite menej než berie BCD v kombinácii s textom. Tam je to 34 bajtov. Ak taký text uložím ako UTF16, bude to 68 bajtov.


Název: Re:SQLite a TBCD prakticky + Problém
Přispěvatel: pf1957 22-07-2018, 11:52:05
To je pre databázy pomerne tragédia..
Preto by mal existovať riadny Numeric / Decimal, ktorý by mal 10-12 bytov a bolo by to prevždy vyriešené. Myslím že to mala už prastará dbf-ka. To zase prišiel na svet medzitým nejaký vedecký mudrlant..
Tu nejde o to, že by SQLite nepodporovala taký rozumný formát.
"Normalni" RDBMS samozrejme radnou podporu nejakeho BigDecimal typu maji. Ale kdyz si zkusis na foru SQLite vyhledat podobne pozadavky jako mas, tak odpovedi je, ze SQLite je LITE...
Název: Re:SQLite a TBCD prakticky + Problém
Přispěvatel: miroB 22-07-2018, 12:28:23
..
"Normalni" RDBMS samozrejme radnou podporu nejakeho BigDecimal typu maji. Ale kdyz si zkusis na foru SQLite vyhledat podobne pozadavky jako mas, tak odpovedi je, ze SQLite je LITE...
To beriem.
Lenže ani Delphi k tomu neposkytuje moc podpory, nielen databáza/SQLite.

Ešte tak BCD. Lenže to je doosť veľké a skôr nejaké kostrbaté:
Ako vidíme, FireDAC pre SQLite poskytuje určité možnosti (BCD). Tam sa ale zase výdatne pletie problém desatinná čiarka vs desatinná bodka.
Je to veru nejaké nedotiahnuté.
Název: Re:SQLite a TBCD prakticky + Problém
Přispěvatel: pf1957 22-07-2018, 13:22:04
Ešte tak BCD. Lenže to je doosť veľké a skôr nejaké kostrbaté:
Ako vidíme, FireDAC pre SQLite poskytuje určité možnosti (BCD). Tam sa ale zase výdatne pletie problém desatinná čiarka vs desatinná bodka.
Je to veru nejaké nedotiahnuté.
Tak desetinna tecka/carka a oddelovace tisicu vyzaduji pozornost vzdycky, protoze ruzni useri mohou mit ruzna narodni prostredi a to dokonce v jednom kulturnim prostredi napr. programator serverovych aplikaci vetsinou miva anglicy OS, naopak cizokrajny manager miva svoje materske prostredi atd. Asi jedinym uspokojivym resenim je udelat striktni rozhrani mezi view a modelem, tam se vyfackovat s ruznym formatem a vnitrne uz pouzivat jenom jeden. U SQLite to lze vynutit asi before triggerem - jakmile ti do pole nekdo strci hodnotu v jinem formatu, tak to fuckovat
Název: Re:SQLite a TBCD prakticky + Problém
Přispěvatel: miroB 22-07-2018, 16:05:12
..
Tak desetinna tecka/carka a oddelovace tisicu vyzaduji pozornost vzdycky, protoze ruzni useri mohou mit ruzna narodni prostredi a to dokonce v jednom kulturnim prostredi napr. programator serverovych aplikaci vetsinou miva anglicy OS, naopak cizokrajny manager miva svoje materske prostredi atd. Asi jedinym uspokojivym resenim je udelat striktni rozhrani mezi view a modelem, tam se vyfackovat s ruznym formatem a vnitrne uz pouzivat jenom jeden. U SQLite to lze vynutit asi before triggerem - jakmile ti do pole nekdo strci hodnotu v jinem formatu, tak to fuckovat
Ten trigger, to je dosť zaujímavý nápad. Nad tým sa ešte zamyslím
Název: Re:SQLite a TBCD prakticky + Problém
Přispěvatel: pf1957 22-07-2018, 16:53:16
pouzije konverzi na zaklade nastaveni systemu.
No ale abych to nemusel resit, tak si triggerem zajistim, ze v DB se do pole TEXT nedostane syntaxe, kterou tam nechci videt a pak v te UDF udelam jen konverzi formatu, kterou videt chci za pouziti sveho TFormatSettings
Název: Re:SQLite a TBCD prakticky + Problém
Přispěvatel: miroB 22-07-2018, 17:07:30
..
Do sloupce s affinity TEXT muzes ulozit textovou hodnotu s tim ze se ulozi vzdy tak jak je. Ve FireDAC pak muzes vytvorit mapovani trebas na dtFmtBCD diky cemuz se zacnou tvorit sloupce typu TFMTBCDField kde se s hodnotou v bufferu pracuje spravne (pro textovou hodnotu je vsak treba pouzit desetinnou tecku). Problemem jsou UDF, kde se pro vystup vytvori sloupec typu TStringField do nehoz kdyz sahnes pro hodnotu pres AsBcd accessor, pouzije konverzi na zaklade nastaveni systemu.
O UDF sa postarám. Tam je pri SELECT-e už nutný typecasting.
Aby som však  nemusel večne typecast-ovať, tak by som chcel spraviť takú úpravu FireDAC, že prefix u názvu poľa by znamenal automaticky nejaký typ.
Ono sú s týmto tvarom "FieldName::Integer" trochu obecnejšie problémy.
Mám predstavu asi takto:
"s_"  : String/Text
"n_"  : Numeric( 30,10 ) - to stačí na vytvorenie tfFmtBcd. Numeric(28, 10) ešte nestačí, to by bol len ftBcd a ten prakticky nemá význam, lebo Double.
a tiež "t_", "d_", "dt_" .. atď
Niečo v tom smere sme už preberali. Myslíš, že mám šancu?
Dokonca Float/Double a Text by nemuseli byť v tom zahrnuté, lebo do nich to spravidla padne
samo.

Název: Re:SQLite a TBCD prakticky + Problém
Přispěvatel: miroB 22-07-2018, 21:22:21

Kód: Delphi [Vybrat]
  1. procedure TForm1.FDSQLiteFunction1Calculate(AFunc: TSQLiteFunctionInstance; AInputs: TSQLiteInputs; AOutput: TSQLiteOutput; var AUserData: TObject);
  2. begin
  3.   AOutput.AsNumber := AInputs[0].AsNumber - AInputs[1].AsNumber;
  4. end;

se v metode TSQLiteValue.SetData pro parametr AOutput nastavi datovy typ SQLITE_TEXT a hodnota se prevede na text s desetinnou teckou. Problem nastane pri cteni hodnoty accessorem AsBcd (jenz pouziva systemovy format), nebo neco vic?
..
Tá funkcia/event funguje. Len je treba Castnúť funkciu v rámce SELECT.
Napríklad:
Kód: MySQL [Vybrat]
  1. SELECT Rozdiel(MyField, 5.5) AS [rslt::Numeric(30,0)]
Potom sa dá čítať Field.AsBcd a aj Field.AsAnsiString.
Ak sa necastne, dá sa čítať len Field.AsAnsiString.
Ten cast s použitím '::' má však iné negatívne dôsledky. To by bolo na dlhšie. Preto by som nahradil CAST :: radšej niečím ako:
"AS n_Result", čím by SQLite získal info, že to má castnúť na Numeric(30,0). Vďaka prefixu "n_". Taký prefix zaručene nebude páchať žiadnu ďalšiu škodu, ako je pácha "::"

OK. Zatiaľ mám dosť informácií a námetov.
Toto vlákno je už dlhé a stráca prehľadnosť.
Priebežne teda vykonám nejaké operácie, ktoré zvládnem. Aj na základe vecí popísaných tuná. Až sa to celé niekam rozumne posunie a budem mať viac info, ozvem sa s prípadnými ďalšími otázkami.
Název: Re:SQLite a TBCD prakticky + Problém
Přispěvatel: miroB 23-07-2018, 11:56:52
Ďakujem. Ten tebou navrhovaný Helper je riešením.
len som ho musel upraviť, aby sa BCD dali aj zapisovať.
Procedúra "getAsBCD_Local" sa zdá byť zbytočná. Ale inak to neviem vyriešiť.
Kód: Delphi [Vybrat]
  1.   TFieldHelper = class helper for TField
  2.     function getAsBCD_Local: TBcd;
  3.     procedure setAsBCD_Local( const Value: TBcd );
  4.   public
  5.     property AsBCD: TBcd read getAsBCD_Local write setAsBCD_Local;
  6.   end;
a funkcie:
Kód: Delphi [Vybrat]
  1. { TFieldHelper }
  2. // ČÍTANIE
  3. function TFieldHelper.getAsBCD_Local: TBcd;
  4. begin
  5.   if Self is TStringField then
  6.     Result := StrToBcd( GetAsString, fmtSettingsDOT )
  7.   else
  8.     Result := GetAsBCD;
  9. end;
  10. // ZÁPIS
  11. procedure TFieldHelper.setAsBCD_Local( const Value: TBcd );
  12. begin
  13. {  if Self is TStringField then
  14.     SetAsString( Data.FmtBcd.BcdToStr( Value, fmtSettingsDOT ) )
  15.   else}
  16.   SetAsBCD( value );
  17. end;
S tou bodkou máš pravdu, študujem:
FireDAC,Phys.SQLiteWrapper :  FDStr2BCD a FDBCD2Str. Obe natvrdo použijú bodku
Kód: Delphi [Vybrat]
  1. function TSQLiteValue.GetData(var AValue: Pointer; var ASize: Integer;
  2.   AByRef: Boolean = False; AExtDataType: TSQLiteExtDataType = etUnknown): Boolean;
  3. ..
  4. case iType of  // etNumber
  5.         SQLITE_TEXT,
  6.         SQLITE_BLOB:
  7.           FDStr2BCD(PChar(pVal), iSize, PBcd(AValue)^, '.'); // Tu je natvrdo bodka
  8. ..
  9. a
  10. procedure TSQLiteValue.SetData(AValue: Pointer; ASize: Integer;
  11.   AExtDataType: TSQLiteExtDataType = etUnknown);
  12. ..
  13. etNumber:
  14.       begin
  15.         pVal := Database.Buffer.Check(C_FD_MaxFixedSize);
  16.         FDBCD2Str(PChar(pVal), iSize, PBcd(AValue)^, '.');  // Tu je natvrdo bodka
  17.         iType := SQLITE_TEXT;
  18.       end;
Název: Re:SQLite a TBCD prakticky + Problém
Přispěvatel: miroB 23-07-2018, 12:48:53
Nie sú to vlastne chyby vo FireDAC? Veď by to malo všetko fungovať..

A.
Ten helper mi však nedovolí zapísať
Kód: Delphi [Vybrat]
  1. Field.AsBcd='-1234567890.0123456789';// Toto hlási chybu konverzie
  2. // Lebo ide hneď v úvode cez funkciu
  3. class operator TBcd.Implicit(const str: string): TBcd;
  4. begin
  5.   if not TryStrToBcd(str, Result) then
  6.     raise EBcdException.Create(SInvalidInput);
  7. end;
  8. //a v nej to zhavaruje
Existuje aj funkcia "TryStrToBcd(AValue, Bcd, FormatSettings)"
Dá sa spraviť nejaký helper aj na class operator TBcd.Implicit ?
Mätie ma ten class operator. Viem aký má význam, ale prácu s týmto prvkom ozaj nepoznám.

B.
..
- dej pozor na prekryti puvodni property  ???  čo sa stane ak ju prekryjem? Veď o to mi ide nie?
a na to ze
- pri pouziti puvodni verze zapisu se (u Tebe) pro TStringField ulozi retezec s carkou.
V mojej verzii som schválne vynechal :
Kód: Delphi [Vybrat]
  1. {  if Self is TStringField then
  2.     SetAsString( Data.FmtBcd.BcdToStr( Value, fmtSettingsDOT ) )
  3.   else}
Pretože tade to snáď nikdy nepôjde.
Ak zapisujem AsBCD, tak Firedac si pamätá, že zapisujem do poľa TNumericField a nie do TStringField
Název: Re:SQLite a TBCD prakticky + Problém
Přispěvatel: miroB 23-07-2018, 13:28:59
Jasne, už chápem všetky pripomienky.

Ešte k môjmu bodu A.
TBcd.Implicit: pokúšam sa o record helper for TBcd
Lenže chyba: E2123 PROCEDURE, FUNCTION, PROPERTY, or VAR expected
Teda neviem ako modifikovať class operator Implicit, aby som mu podtsrčil
TryStrToBcd(AValue, Bcd, FormatSettings)
Je to v Data.FmtBcd

Predbežne odhadujem, že to nemá riešenie. Viď SO:
https://stackoverflow.com/questions/30126479/is-there-a-workaround-to-make-class-operators-work-for-built-in-types (https://stackoverflow.com/questions/30126479/is-there-a-workaround-to-make-class-operators-work-for-built-in-types)
Název: Re:SQLite a TBCD prakticky + Problém
Přispěvatel: miroB 23-07-2018, 14:10:52
Pretože Record helper TBCD pre "class operator" nie je možný, tento rébus:
Kód: Delphi [Vybrat]
  1. Field.AsBcd='-1234567890.0123456789';
Som vyriešil funkciou:
Kód: Delphi [Vybrat]
  1. procedure TFieldHelper.setAsLocaleBCD( const Value: String );
  2. begin
  3.   if Self is TStringField then
  4.     SetAsString( Value )
  5.   else
  6.     SetAsBCD( StrToBcd( Value, fmtSettingsDOT ) );
  7. end;
  8. ..// VOLANIE:
  9. Fields.setAsLocaleBCD( '-1234567890.0123456789' );
  10.  
Název: Re:SQLite a TBCD prakticky + Problém
Přispěvatel: miroB 23-07-2018, 14:17:09
Nie sú to vlastne chyby vo FireDAC? Veď by to malo všetko fungovať..

Nerekl bych. Pro tak presne hodnoty potrebujes pro SQLite sloupec s affinity TEXT.
No mne sa zdá, že tu boli prezentované štandardné metódy. Tie fungujú napr. pre US nastavenie určite bez problémov. Lenže programovací nástroj by mal rešpektovať aj národné nastavenia.
Alebo by mal umožniť pomocou prítomných parametrov situáciu vyriešiť.
Ak by aj všetko ostatné fungovalo len pre US, tak ani Unicode nie je treba .. Obrazne povedané.
Název: Re:SQLite a TBCD prakticky + Problém
Přispěvatel: miroB 23-07-2018, 15:23:43
A kto tam strká tú čiarku? Nikto iný než systém. Nie užívateľ. Ani SQLite nie. Neviem prečo si BCD berie niečo zo systému, ak mu to prekáža. BCD je vlastne riešené v Data.FmtBcd, takže nie FireDAC, ale Delphi spôsobuje tieto ťažkosti.
Samozrejme aj pri Double je presne ten istý problém, ale ten sa darí niekde po ceste zakryť, na rozdiel od BCD.