Jak wywołać funkcję bazodanową z parametrem typu array

Jak wywołać funkcję bazodanową z parametrem typu array
woolfik
  • Rejestracja:ponad 17 lat
  • Ostatnio:34 minuty
  • Postów:1597
0

Witajcie,

Wielokrotnie używałem parametrów tablicowych w postgresie ale pierwszy raz przyszło mi przekazać je przez FireDAC w delphi.

Przykład funkcji w postgresql 9.6:

Kopiuj
CREATE OR REPLACE FUNCTION test.farrtest (
  aid integer,
  aarrtest integer []
)
RETURNS void AS
$body$
declare
  vEnums integer;
begin
    foreach vEnums in ARRAY aarrtest loop
  		insert into test.ttest(id) values (vEnums);
    end loop;  
END;
$body$
LANGUAGE 'plpgsql'
VOLATILE
CALLED ON NULL INPUT
SECURITY INVOKER
PARALLEL UNSAFE
COST 100;

delphi:

Kopiuj
ADS.Params[0].DataType := vrecord.id.DataType;
ADS.Params[0].Value :=  vrecord.id.value;

ADS.Params[1].DataType := ?;
for i := 0 to sl.count - 1 do
  ADS.Params[1].Values[i].Value := i;

Próbowałem również z arraytype, arraysize i nic ... ktoś wie jak to poprawnie ustawić?

edytowany 1x, ostatnio: flowCRANE
PD
  • Rejestracja:ponad 22 lata
  • Ostatnio:minuta
1

może coś w tym stylu:

Kopiuj
sl.Delimiter := ',';
ADS.Params[1].Value := '{' + sl.DelimitedText + '}';

przy założeniu, że sl to TStringList z wartościami tablicy
edit: lub jeżeli w delphi masz również tablicę intów to np.:

Kopiuj
function IntArrayToParam(arr: array of Integer): String;
var
  i: Integer;
begin
  Result := '';
  for i := Low(arr) to High(arr) do
    if i < High(arr) then
      Result := Result + IntToStr(arr[i]) + ','
    else
      Result := Result + IntToStr(arr[i]);
  Result := '{' + Result + '}';
end;           

...
ADS.Params[1].Value := IntArrayToParam(tablica);

pozdrawiam
paweld
edytowany 3x, ostatnio: Paweł Dmitruk
woolfik
  • Rejestracja:ponad 17 lat
  • Ostatnio:34 minuty
  • Postów:1597
0

Tak też już próbowałem:

Kopiuj
('[FireDAC][Stan]-19. Data type conversion is not supported', 0, nil, nil, False)
Kopiuj
    ADS.Params[0].DataType := ftInteger;
    ADS.Params[0].Value := 1;
    ADS.Params[1].DataType := ftArray;
    ADS.Params[1].Value := '{1,2,3}';
    ADS.Open;

edit:
W przypadku:

Kopiuj
    ADS.Params[0].DataType := ftInteger;
    ADS.Params[0].Value := 1;
    ADS.Params[1].DataType := ftUnknown;
    ADS.Params[1].Value := '{1,2,3}';
    ADS.Open;
Kopiuj
('[FireDAC][Phys][PG][libpq] BŁĄD: funkcja test.farrtest(integer, character varying) nie istnieje.'#$D#$A'Brak funkcji pasującej do podanej nazwy i typów argumentów. Być może należy dodać jawne rzutowanie typów.', 0, nil, nil, False)

Problem w tym, że firedac nie widzi tego parametru int [] ... a przynajmniej ja nie umiem tych komponentów wysterować aby je widział poprawnie i konwertuje na varchar ... a tu z kolei baza rzuca błąd, że nie ma takiej funkcji

edytowany 2x, ostatnio: woolfik
PD
  • Rejestracja:ponad 22 lata
  • Ostatnio:minuta
0

a jeżeli nie ustawisz typu danych dla parametru to też nie puszcza?


pozdrawiam
paweld
woolfik
Dokładnie taki sam komunikat jak w przypadku ftUnknown
PD
Twoją edycję zobaczyłem dopiero po napisaniu postu
PD
  • Rejestracja:ponad 22 lata
  • Ostatnio:minuta
1

a próbowałeś skorzystać z makra, a nie parametru

Kopiuj
ADS.SQL.Test := 'select farrtest (:id, &arr)';
ADS.Params[0].AsInteger := 1;
ADS.Macros[0].AsRaw := '{1,2,3}';
ADS.Open;

pozdrawiam
paweld
edytowany 1x, ostatnio: Paweł Dmitruk
woolfik
Przyznam szczerze, że z makra nigdy nie korzystałem ale dostaję teraz coś takiego: ('[FireDAC][Phys]-321. Character [(] is missed', 0, nil, nil, False)
WL
No to już blisko jesteś; makro AsRaw przekazuje do serwera dokładnie to co wpiszesz. Trzeba uważać, bo to podatne na SQLInjection, ale da się zrobić przy pomocy tego to, czego nie da się np. za pomocą parametrów (jak chociażby przekazanie tablicy wartości do where fo in (!MacroValues))
PD
  • Rejestracja:ponad 22 lata
  • Ostatnio:minuta
4

https://github.com/Embarcadero/RADStudio10.3Demos/tree/master/Object%20Pascal/Database/FireDAC/Samples/DBMS%20Specific/PostgreSQL/Arrays

Kopiuj
ADS.Params[0].AsInteger := 1;
ADS.Params[1].ArrayType := atTable;
ADS.Params[1].ArraySize := 3;
ADS.Params[1].AsIntegers[0] := 1;
ADS.Params[1].AsIntegers[1] := 2;
ADS.Params[1].AsIntegers[2] := 3;

pozdrawiam
paweld
woolfik
hmmm ... sprawdzę na nowym delphi ale na XE5 nie ma nawet takiego typu jak atTable natomiast inne powodują różne exceptiony tak czy inaczej dzięki

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.