Databáze > Ostatní DB
SQLite: TFDSQLiteFunction využitie parametra Aggregated
miroB:
Zrejme neviem korektne použiť OnFinalize event.
V rámci OnFinalize síce vypočítam, čo potrebujem, ale neviem to dať ako Output (výsledok). Taký parameter tam nie je.
Na rozdiel od OnCalculate, kde Output k dispozícii je.
Je možné, že zle chápem funkcie s Aggregated=True;
Tu je kód. Výpočet sRslt prebehne správne, ale celkovo funkcia nefunguje.
Cieľ je náhrada SQLite : Group_Concat. Ale len s výpisom jedinečných argumentov
PS: hodne som googlil, ale márne
--- Kód: Delphi ---.. T_Group_concat_distinct = class( TObject ) // AUserData dict : TDictionary<String, Integer>; chSeparator : Char; sRslt : String; public Constructor CREATE; // dict := TDictionary<String, Integer>.Create; end;.. procedure Tdm.fnConcatDistinctFinalize( AFunc: TSQLiteFunctionInstance; var AUserData: TObject);var s : String;begin with T_ConcatDistinct( AUserData ) do if dict <> nil then begin sRslt := ''; for s in dict.Keys do if sRslt = '' then sRslt := s else sRslt := sRslt + chSeparator + s;// Sem teoreticky Output.AsWideString =sRslt, Ale to nejde dict.Free; dict := nil; end;end;Tu je on Calculate event:
--- Kód: Delphi ---procedure Tdm.fnConcatDistinctCalculate( AFunc: TSQLiteFunctionInstance; var AUserData: TObject);var iVal: Integer;begin if AUserData = nil then // Prvý priechod funkciou begin AUserData := T_Group_concat_distinct.CREATE; if AInputs[ 1 ].IsNull then T_Group_concat_distinct( AUserData ).chSeparator := ',' else T_Group_concat_distinct( AUserData ).chSeparator := AInputs[ 1 ].AsWideString[ 1 ]; end; with T_Group_concat_distinct( AUserData ) do if dict = nil then AOutput.AsWideString := sRslt else if ( AInputs[ 0 ].IsNull = false ) and ( dict.ContainsKey( AInputs[ 0 ].AsWideString ) = False ) then dict.Add( AInputs[ 0 ].AsWideString, 0 );end;
99525:
--- Kód: Delphi ---procedure Tdm.fnConcatDistinctFinalize(AFunc: TSQLiteFunctionInstance; var AUserData: TObject);begin ... AFunc.Output.AsWideString := sRslt; ...end;
A z OnCalculate odstran predavani vysledku. Ten se u agregacnich funkci predava az v OnFinalize.
miroB:
Upravil som, ako si napísal. Odobral som aj kód priradovania v OnCalculate, Teraz je OnFinalize takto:
--- Kód: Delphi ---.. with T_Group_concat_distinct( AUserData ) do begin if dict <> nil then begin sRslt := ''; for s in dict.Keys do if sRslt = '' then sRslt := s else sRslt := sRslt + chSeparator + s;// AFunc.Output.AsWideString := sRslt; dict.Free; dict := nil; exit; end; AFunc.Output.AsWideString := sRslt; // REM varianta 2. end;..Výsledok je prázdny. Prázdny je, aj keď sa vymenia tie zaremovania.
Inak cez to priradenie prechádza v tomto tvare raz. A sRslt tam má správny zoznam hodnôt. Lenže vo výpise výsledku funkcie nie je nič. Zrejme NULL.
Aktuálne v OnCalculate:
--- Kód: Delphi ---.. with T_Group_concat_distinct( AUserData ) do if dict <> nil then if ( AInputs[ 0 ].IsNull = false ) and ( dict.ContainsKey( AInputs[ 0 ].AsWideString ) = False ) then dict.Add( AInputs[ 0 ].AsWideString, 0 );
miroB:
Vytvorenie tabulky a kontrolný SELECT:
--- Kód: MySQL ---Create table ignorujZastavky ( Passport Int32, Názov Text( 24 ), Číslo Int16 );INSERT INTO ignorujZastavky ( Passport, Názov, Číslo ) VALUES -- 18,631,910,911,912,913( NULL, 'Voz Trnávka',18 ),( NULL, 'Voz Petržalka',631 ), ( 91002, 'Krasňany',910 ),( 91101, 'Petržalka', 911 ),( 91201, 'Trnávka1', 912 ),( 91202, 'Trnávka2', 912 ),( 91301, 'Hroboňova', 913 );select group_concat_distinct( Číslo , ',' ) AS [zoznam::Text(120) ] from ignorujZastavky;
99528:
Hm. Zvlastni. SQLite vola ten finalizacni callback s jinym kontextem (sqlite3_context). Tohle je nicmene chyba FireDAC. Ve zkratce, parametr context je v nasledujicich metodach pro agregacni funkce ruzny, no a protoze FireDAC ignoruje jeho predani, nemuzes tak vratit pri finalizaci hodnotu:
--- Kód: Delphi ---procedure TSQLiteFunctionInstance.DoCalculate(context: psqlite3_context; nargs: Integer; args: ppsqlite3_value);begin ...end; procedure TSQLiteFunctionInstance.DoFinalize(context: psqlite3_context);begin Func.DoFinalize(Self); // o kontext se s timto kodem prijdeend;
Rychla oprava by mohla byt napr. (modul FireDAC.Phys.SQLiteWrapper):
--- Kód: Delphi ---procedure TSQLiteFunctionInstance.DoFinalize(context: psqlite3_context);begin FOutput.Handle := context; // je treba uchovat kontext, jinak nebude mozne vratit hodnotu Func.DoFinalize(Self);end;
Zkousel jsem predani agregacniho kontextu (uzivatelska data alokovana SQLite pomoci funkce sqlite3_aggregate_context) a predani probehne spravne, cili ty ruzne kontexty mezi kalkulaci a finalizaci jsou ze strany SQLite umyslem. Jen se na to nemyslelo ve FireDAC (nejspis nikdo netestoval).
Jinak to ze se ma hodnota predavat pri finalizaci vim z kodu SQLite. Podivej se napr. na funkci SUM, konkretne jeji finalizacni callback sumFinalize:
--- Kód: C++ ---static void sumFinalize(sqlite3_context *context){ SumCtx *p; p = sqlite3_aggregate_context(context, 0); if( p && p->cnt>0 ){ if( p->overflow ){ sqlite3_result_error(context,"integer overflow",-1); /* <- signalizace chyby */ }else if( p->approx ){ sqlite3_result_double(context, p->rSum); /* <- predani vysledku */ }else{ sqlite3_result_int64(context, p->iSum); /* <- predani vysledku */ } }}
Navigace
[0] Seznam témat
[#] Další strana
Přejít na plnou verzi