Ini sulit untuk dipecahkan, karena SQL menuntut untuk mengetahui tipe pengembalian pada waktu panggilan .
Selain itu, fungsi plpgsql harus memiliki tipe pengembalian yang didefinisikan dengan baik .
Jika Anda memilih untuk mengembalikan catatan anonim , Anda mendapatkan apa yang Anda tetapkan:catatan anonim. Postgres tidak tahu apa yang ada di dalamnya. Oleh karena itu, daftar definisi kolom diperlukan untuk menguraikan jenisnya.
Ada berbagai solusi, tergantung pada persyaratan yang tepat. Jika Anda memiliki cara untuk mengetahui jenis pengembalian pada waktu panggilan , saya menyarankan tipe polimorfik sebagaimana diuraikan dalam bab terakhir dari jawaban ini ("Berbagai jenis tabel lengkap"):
Memperbaiki fungsi PL/pgSQL untuk mengembalikan output dari berbagai kueri SELECT
Tapi itu tidak mencakup penambahan kolom lain ke tipe kembalian saat runtime di dalam fungsi . Itu tidak mungkin. Saya akan memikirkan kembali seluruh pendekatan .
Adapun pendekatan Anda saat ini, hal terdekat yang dapat saya pikirkan adalah tabel sementara (atau kursor), yang Anda kueri dalam panggilan kedua dalam satu transaksi .
Anda memiliki beberapa masalah lain dalam kode Anda . Lihat catatan di bawah.
Bukti konsep
CREATE OR REPLACE FUNCTION f_tbl_plus_infowindow (_tbl regclass) -- regclass!
RETURNS void AS -- no direct return type
$func$
DECLARE
-- appending _tmp for temp table
_tmp text := quote_ident(_tbl::text || '_tmp');
BEGIN
-- Create temp table only for duration of transaction
EXECUTE format(
'CREATE TEMP TABLE %s ON COMMIT DROP AS TABLE %s LIMIT 0', _tmp, _tbl);
IF EXISTS (
SELECT 1
FROM pg_attribute a
WHERE a.attrelid = _tbl
AND a.attname = 'infowindow'
AND a.attisdropped = FALSE)
THEN
EXECUTE format('INSERT INTO %s SELECT * FROM %s', _tmp, _tbl);
ELSE
-- This is assuming a NOT NULL column named "id"!
EXECUTE format($x$
ALTER TABLE %1$s ADD COLUMN infowindow text;
INSERT INTO %1$s
SELECT *, 'ID: ' || id::text
FROM %2$s $x$
,_tmp, _tbl);
END IF;
END
$func$ LANGUAGE plpgsql;
Panggilan harus dalam satu transaksi. Anda mungkin harus memulai transaksi eksplisit, tergantung pada klien Anda.
BEGIN;
SELECT f_tbl_plus_infowindow ('tbl');
SELECT * FROM tbl_tmp; -- do something with the returned rows
ROLLBACK; -- or COMMIT, does not matter here
SQL Fiddle.
Atau Anda bisa membiarkan tabel sementara hidup selama sesi. Namun, berhati-hatilah dengan penamaan yang bertabrakan dengan panggilan berulang.
Catatan
-
Gunakan nama parameter alih-alih
ALIAS
yang sudah usang perintah. -
Untuk benar-benar "default" ke skema saat ini, gunakan kueri sederhana yang saya tampilkan. Menggunakan
regclass
melakukan trik secara otomatis. Detail:- Nama tabel sebagai parameter fungsi PostgreSQL
Selain itu, ini juga menghindari kesalahan sintaks dan kemungkinan injeksi SQL dari nama tabel non-standar (atau dengan format yang salah) dalam kode asli Anda.
-
Kode di
ELSE
. Anda klausa tidak akan berfungsi sama sekali. -
TABLE tbl;
pada dasarnya adalah kependekan dariSELECT * FROM tbl;
. -
Detail tentang
format()
dalam manual.