Синтаксическая ошибка в функции с использованием dblink для репликации новых данных
Я никогда не создавал функцию в Postgres, я следовал некоторым учебникам и сделал этот код, но я не знаю, почему это неправильно, ошибка в консоли:
"syntax error at or near "SELECT" LINE 5: SELECT public.dblink_connect('hostaddr=127.0.0.1 port=54...
Я использую версию 9.3.6 на Ubuntu.
CREATE OR REPLACE FUNCTION fn_replicate_insertof_students()
RETURNS text AS
$BODY$
BEGIN
SELECT public.dblink_connect('hostaddr=127.0.0.1 port=5433 dbname=Utiles user=postgres password=Mypass');
INSERT INTO res_partner (company_id,name,lang,comment,street,supplier,city,zip,country_id,email,phone,date,customer,mobile,ref,state_id,opt_out,city_id,l10n_mx_city2,l10n_mx_street3,l10n_mx_street4,notification_email_send,type,street2,active)
VALUES (1,NEW.name,'es_MX',NEW.comment,NEW.street,false,NEW.city,NEW.zip,NEW.country_id,NEW.email,NEW.phone,NEW.date,true,NEW.mobile,NEW.ref,NEW.state_id,false,NEW.city_id,NEW.l10n_mx_city2,NEW.l10n_mx_street3,NEW.l10n_mx_street4,NEW.notification_email_send,NEW.type,NEW.street2,NEW.active));
SELECT public.dblink_disconnect();
END;
$BODY$ LANGUAGE sql VOLATILE SECURITY DEFINER
SET search_path=myschema, pg_temp;
CREATE TRIGGER tr_replicate_insertof_students
AFTER INSERT
ON res_partner
FOR EACH ROW
EXECUTE PROCEDURE fn_replicate_insertof_students();
2 ответа
@ Ник поднял несколько хороших моментов, но есть еще:
Ваш search_path
на самом деле сделано правильно. pg_catalog
сначала включается автоматически, если вы явно не поместите его туда в другой позиции.
Что еще более важно, вся функция является бессмысленной в ее нынешнем виде. Вы открываете соединение dblink, но не используете его. Похоже, вы хотите добавить dblink_exec()
, Но вам нужно объединить строку запроса с формой значений NEW
во-первых, так как NEW
не видно на другой стороне червоточины. Итак, у вас есть хороший пример динамического SQL. Довольно крутой старт для начинающего!
Подробный пример кода и объяснение функции с dblink в этом недавнем связанном ответе на dba.SE:
Кроме того, это должна быть функция триггера, которая будет использоваться в триггере.
Ваша функция может работать так:
CREATE OR REPLACE FUNCTION fn_replicate_insertof_students()
RETURNS trigger AS
$func$
BEGIN
PERFORM public.dblink_connect('hostaddr=127.0.0.1 port=5433
dbname=Utiles user=postgres password=Mypass');
PERFORM public.dblink_exec(format(
$f$INSERT INTO res_partner (company_id, name, lang, comment, ... )
VALUES (1, %L, 'es_MX', %L, ... )$f$
, NEW.name, NEW.comment, ... ));
PERFORM public.dblink_disconnect();
RETURN NULL; -- only ok for AFTER trigger
END
$func$ LANGUAGE plpgsql VOLATILE SECURITY DEFINER
SET search_path=myschema, pg_temp;
ALTER FUNCTION fn_replicate_insertof_students() OWNER TO postgres; -- guessing
Также не забудьте установить право владельца на SECURITY DEFINER
функция
Рассмотрите возможность использования FOREIGN SERVER
, USER MAPPING
и файл паролей на целевом сервере. Подробности в ссылке выше.
Вся идея - довольно дорогой частный случай репликации. Для некоторых вставок в таблицу это нормально, но есть более эффективные решения для большой нагрузки.
Вы пометили функцию как LANGUAGE sql
, который предназначен только для функций, содержащих отдельные операторы SQL. Эта функция написана на LANGUAGE plpgsql
,
Он все еще будет жаловаться на SELECT
, так как plpgsql
требует, чтобы вы на самом деле что-то сделали с результатом SELECT
, Вам нужно будет заменить SELECT
с PERFORM
, чтобы сделать явным, что вы отбрасываете результат.