Databáze > Ostatní DB

SQLite: TFDSQLiteFunction využitie parametra Aggregated

(1/5) > >>

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