Sztuczka z PREPARE
nie działa, ponieważ nie przyjmuje * ciągu tekstowego* (wartości), jak CREATE FUNCTION
tak, ale prawidłowe oświadczenie (kod).
Aby przekonwertować dane w wykonywalny kod musisz użyć dynamicznego SQL, czyli EXECUTE
w funkcji plpgsql lub DO
oświadczenie. Działa to bez problemu, o ile zwracany typ nie zależy od wyniku pierwszej funkcji myresult()
. W przeciwnym razie wróciłeś, aby złapać 22, jak opisano w mojej poprzedniej odpowiedzi:
- Jak wykonać łańcuchowy wynik procedury składowanej w postgresie
Kluczową częścią jest zadeklarowanie typu zwrotu (w tym przypadku typ wiersza) jakoś. Możesz utworzyć TABLE
, TEMP TABLE
lub TYPE
w celu. Możesz też użyć przygotowanego oświadczenia lub refcursora.
Rozwiązanie z przygotowanym oświadczeniem
Byłeś bardzo blisko. Brakującym elementem układanki jest przygotowanie wygenerowanego zapytania za pomocą dynamicznego SQL .
Funkcja dynamicznego przygotowywania zestawień
Utwórz tę funkcję raz . To zoptymalizowana i bezpieczna wersja Twojej funkcji myresult()
:
CREATE OR REPLACE FUNCTION f_prep_query (_tbl regclass, _prefix text)
RETURNS void AS
$func$
BEGIN
IF EXISTS (SELECT 1 FROM pg_prepared_statements WHERE name = 'stmt_dyn') THEN
DEALLOCATE stmt_dyn;
END IF; -- you my or may not need this safety check
EXECUTE (
SELECT 'PREPARE stmt_dyn AS SELECT '
|| string_agg(quote_ident(attname), ',' ORDER BY attname)
|| ' FROM ' || _tbl
FROM pg_catalog.pg_attribute
WHERE attrelid = _tbl
AND attname LIKE _prefix || '%'
AND attnum > 0
AND NOT attisdropped
);
END
$func$ LANGUAGE plpgsql;
Używam regclass
dla parametru nazwy tabeli _tbl
aby był jednoznaczny i bezpieczny przed SQLi. Szczegóły:
- Nazwa tabeli jako parametr funkcji PostgreSQL
Schemat informacyjny nie zawiera kolumny oid katalogów systemowych, więc przełączyłem się na pg_catalog.pg_attribute
zamiast information_schema.columns
. To też jest szybsze. Są w tym wady i zalety:
- Jak sprawdzić, czy tabela istnieje w danym schemacie
Jeśli przygotowana instrukcja o nazwie stmt_dyn
już istnieje, PREPARE
zgłosi wyjątek. Jeśli jest to akceptowalne, usuń zaznaczenie w widoku systemowym pg_prepared_statements
i następujące DEALLOCATE
.
Bardziej wyrafinowane algorytmy umożliwiają zarządzanie wieloma przygotowanymi instrukcjami na sesję lub przyjęcie nazwy przygotowanej instrukcji jako dodatkowego parametru, a nawet użycie skrótu MD5 ciągu zapytania jako nazwy, ale to wykracza poza ramy zakres tego pytania.
Pamiętaj, że PREPARE
działa poza zakresem transakcji , raz PREPARE
się powiedzie, przygotowane oświadczenie istnieje przez cały czas trwania sesji. Jeśli transakcja pakowania zostanie przerwana, PREPARE
nie ma to wpływu. ROLLBACK
nie można usuń przygotowane wyciągi.
Dynamiczne wykonywanie zapytań
Dwa zapytania, ale tylko jedno zadzwoń do serwera. I bardzo wydajny.
SELECT f_prep_query('tbl'::regclass, 'pre'::text);
EXECUTE stmt_dyn;
Prostsze i znacznie bardziej wydajne w większości prostych przypadków użycia niż tworzenie tabeli tymczasowej lub kursora i wybieranie / pobieranie z tego (co byłoby innymi opcjami).
Skrzypce SQL.