使用 dblink 复制新数据的函数中出现语法错误
Syntax error in function using dblink to replicate new data
我从来没有在 Postgres 中创建过函数,我按照一些教程制作了这段代码,但我不知道为什么会出错,控制台中的错误是:
"syntax error at or near "SELECT"
LINE 5: SELECT public.dblink_connect('hostaddr=127.0.0.1 port=54...
我在 Ubuntu 上使用 9.3.6 版。
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();
您已将函数标记为 LANGUAGE sql
,这仅适用于包含单个 SQL 语句的函数。这个函数写在LANGUAGE plpgsql
.
它仍然会抱怨 SELECT
,因为 plpgsql
要求您实际对 SELECT
的结果执行某些操作。您需要将 SELECT
替换为 PERFORM
,以明确表示您要丢弃结果。
,但还有更多:
您的 search_path
实际上 做对了 。 pg_catalog
自动包含在 first 除非您明确将其放在其他位置。
- How does the search_path influence identifier resolution and the "current schema"
更重要的是,整个函数的当前形式毫无意义。您打开了一个 dblink 连接,但您没有使用它。看起来你想加入 dblink_exec()
。但是您需要首先将查询字符串与 NEW
形式的值连接起来,因为 NEW
在虫洞的另一边是不可见的。所以你自己就有了一个动态 SQL 的很好的例子。对于初学者来说,这是一个相当陡峭的开始!
最近在 dba.SE:
上的相关回答中详细的代码示例和 dblink 函数的解释
此外,这必须是 trigger function 才能在触发器中使用。
您的函数可以这样工作:
CREATE OR REPLACE FUNCTION fn_replicate_insertof_students()
RETURNS <b>trigger</b> AS
$func$
BEGIN
<b>PERFORM</b> public.dblink_connect('hostaddr=127.0.0.1 port=5433
dbname=Utiles user=postgres password=Mypass');
<b>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, ... ));</b>
<b>PERFORM</b> public.dblink_disconnect();
<b>RETURN NULL;</b> -- only ok for AFTER trigger
END
$func$ LANGUAGE <b>plpgsql</b> VOLATILE SECURITY DEFINER
SET search_path=myschema, pg_temp;
ALTER FUNCTION fn_replicate_insertof_students() OWNER TO postgres; -- guessing
还要确保为 SECURITY DEFINER
function.
设置所有者权限
考虑在目标服务器上使用 FOREIGN SERVER
、USER MAPPING
和密码文件。 above link.
中的详细信息
整个想法是一个相当昂贵的复制特例。对于 table 的一些插入,这没问题,但是有 better solutions for massive load.
我从来没有在 Postgres 中创建过函数,我按照一些教程制作了这段代码,但我不知道为什么会出错,控制台中的错误是:
"syntax error at or near "SELECT" LINE 5: SELECT public.dblink_connect('hostaddr=127.0.0.1 port=54...
我在 Ubuntu 上使用 9.3.6 版。
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();
您已将函数标记为 LANGUAGE sql
,这仅适用于包含单个 SQL 语句的函数。这个函数写在LANGUAGE plpgsql
.
它仍然会抱怨 SELECT
,因为 plpgsql
要求您实际对 SELECT
的结果执行某些操作。您需要将 SELECT
替换为 PERFORM
,以明确表示您要丢弃结果。
您的 search_path
实际上 做对了 。 pg_catalog
自动包含在 first 除非您明确将其放在其他位置。
- How does the search_path influence identifier resolution and the "current schema"
更重要的是,整个函数的当前形式毫无意义。您打开了一个 dblink 连接,但您没有使用它。看起来你想加入 dblink_exec()
。但是您需要首先将查询字符串与 NEW
形式的值连接起来,因为 NEW
在虫洞的另一边是不可见的。所以你自己就有了一个动态 SQL 的很好的例子。对于初学者来说,这是一个相当陡峭的开始!
最近在 dba.SE:
上的相关回答中详细的代码示例和 dblink 函数的解释此外,这必须是 trigger function 才能在触发器中使用。
您的函数可以这样工作:
CREATE OR REPLACE FUNCTION fn_replicate_insertof_students()
RETURNS <b>trigger</b> AS
$func$
BEGIN
<b>PERFORM</b> public.dblink_connect('hostaddr=127.0.0.1 port=5433
dbname=Utiles user=postgres password=Mypass');
<b>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, ... ));</b>
<b>PERFORM</b> public.dblink_disconnect();
<b>RETURN NULL;</b> -- only ok for AFTER trigger
END
$func$ LANGUAGE <b>plpgsql</b> VOLATILE SECURITY DEFINER
SET search_path=myschema, pg_temp;
ALTER FUNCTION fn_replicate_insertof_students() OWNER TO postgres; -- guessing
还要确保为 SECURITY DEFINER
function.
考虑在目标服务器上使用 FOREIGN SERVER
、USER MAPPING
和密码文件。 above link.
整个想法是一个相当昂贵的复制特例。对于 table 的一些插入,这没问题,但是有 better solutions for massive load.