Autor Téma: SQLite a TBCD prakticky + Problém  (Přečteno 6709 krát)

Offline pf1957

  • Padawan
  • ******
  • Příspěvků: 2625
  • Karma: 133
    • Verze Delphi: D2007, XE3, DX10
Re:SQLite a TBCD prakticky + Problém
« Odpověď #15 kdy: 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

Online miroB

  • Guru
  • *****
  • Příspěvků: 539
  • Karma: 17
    • Verze Delphi: D1,2,3,4,7,2005,2009, XE8,S,B,T10.2.2 Pro
Re:SQLite a TBCD prakticky + Problém
« Odpověď #16 kdy: 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

Offline pf1957

  • Padawan
  • ******
  • Příspěvků: 2625
  • Karma: 133
    • Verze Delphi: D2007, XE3, DX10
Re:SQLite a TBCD prakticky + Problém
« Odpověď #17 kdy: 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

Online miroB

  • Guru
  • *****
  • Příspěvků: 539
  • Karma: 17
    • Verze Delphi: D1,2,3,4,7,2005,2009, XE8,S,B,T10.2.2 Pro
Re:SQLite a TBCD prakticky + Problém
« Odpověď #18 kdy: 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.

« Poslední změna: 22-07-2018, 17:13:43 od Miroslav Baláž »

Online miroB

  • Guru
  • *****
  • Příspěvků: 539
  • Karma: 17
    • Verze Delphi: D1,2,3,4,7,2005,2009, XE8,S,B,T10.2.2 Pro
Re:SQLite a TBCD prakticky + Problém
« Odpověď #19 kdy: 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.

Online miroB

  • Guru
  • *****
  • Příspěvků: 539
  • Karma: 17
    • Verze Delphi: D1,2,3,4,7,2005,2009, XE8,S,B,T10.2.2 Pro
Re:SQLite a TBCD prakticky + Problém
« Odpověď #20 kdy: 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;

Online miroB

  • Guru
  • *****
  • Příspěvků: 539
  • Karma: 17
    • Verze Delphi: D1,2,3,4,7,2005,2009, XE8,S,B,T10.2.2 Pro
Re:SQLite a TBCD prakticky + Problém
« Odpověď #21 kdy: 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
« Poslední změna: 23-07-2018, 13:16:48 od Miroslav Baláž »

Online miroB

  • Guru
  • *****
  • Příspěvků: 539
  • Karma: 17
    • Verze Delphi: D1,2,3,4,7,2005,2009, XE8,S,B,T10.2.2 Pro
Re:SQLite a TBCD prakticky + Problém
« Odpověď #22 kdy: 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
« Poslední změna: 23-07-2018, 13:47:45 od Miroslav Baláž »

Online miroB

  • Guru
  • *****
  • Příspěvků: 539
  • Karma: 17
    • Verze Delphi: D1,2,3,4,7,2005,2009, XE8,S,B,T10.2.2 Pro
Re:SQLite a TBCD prakticky + Problém
« Odpověď #23 kdy: 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.  

Online miroB

  • Guru
  • *****
  • Příspěvků: 539
  • Karma: 17
    • Verze Delphi: D1,2,3,4,7,2005,2009, XE8,S,B,T10.2.2 Pro
Re:SQLite a TBCD prakticky + Problém
« Odpověď #24 kdy: 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é.

Online miroB

  • Guru
  • *****
  • Příspěvků: 539
  • Karma: 17
    • Verze Delphi: D1,2,3,4,7,2005,2009, XE8,S,B,T10.2.2 Pro
Re:SQLite a TBCD prakticky + Problém
« Odpověď #25 kdy: 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.