带有 dblink 的 postgresql 触发器没有 return 任何东西
postgresql trigger with dblink doesn't return anything
我创建了一个触发器,用于将数据库 1 中 table 'mytable_db1' 的插入复制到数据库 2 中的相同 table 'mytable_db2'。两个数据库都在同一台服务器上。
CREATE OR REPLACE FUNCTION trigger_osm_test_insert()
RETURNS trigger AS
$BODY$
BEGIN
PERFORM dblink_connect('db2', 'dbname=xxx port=5432 user=myusr password=xxx');
PERFORM dblink_exec('db2',
'insert into test.mytable_db2 (osm_id, name, name_eng, name_int, type, z_order, population, last_update, country, iso3, shape)
values ('||new.osm_id||', '''||new.name||''', '''||new.name_eng||''', '''||new.name_int||''', '''||new.type||''', '||new.z_order||',
'||new.population||', '''||new.last_update||''', '''||new.country||''', '''||new.iso3||''',
st_geometry((st_AsText('''||new.shape::text||'''))))');
PERFORM dblink_disconnect('db2');
RETURN new;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
ALTER FUNCTION trigger_osm_test_insert()
OWNER TO myusr;
CREATE TRIGGER osm_insert_test
AFTER INSERT
ON mytable_db1
FOR EACH ROW
EXECUTE PROCEDURE trigger_osm_test_insert();
但是,当我进行如下测试插入时:
insert into test.mytable_db1 (name, shape) values ('test', '0101000020E6100000E0979950035F4A40404B2751B0861CC0');
插入的行已插入 mytable_db1,但触发器似乎无法正常工作,因为我在 mytable_db2 中没有任何内容。插入没有给我任何来自触发器的错误消息。
我正在使用 postgresql 9.2.2。两个数据库都安装了 dblink 1.0 以及 postgis 2.0.6。
有人对我做错了什么有建议吗?
谢谢!
问题是您在执行 INSERT 时没有传递所有列。因此,NEW 中的某些列为空,并且由于您使用字符串连接,所以整个 INSERT INTO...
字符串为空。
例如,这个查询 returns NULL:
select NULL || 'some text';
您应该检查每一列是否为空,例如:
CREATE OR REPLACE FUNCTION trigger_osm_test_insert()
RETURNS trigger AS
$BODY$
DECLARE insert_statement TEXT;
BEGIN
IF NOT ARRAY['db2'] <@ dblink_get_connections() OR dblink_get_connections() IS NULL THEN
PERFORM dblink_connect('db2', 'dbname=xxx port=5432 user=xxx password=xxx');
END IF;
insert_statement = format('insert into mytable_db2 (
osm_id, name, name_eng, name_int, type, z_order,
population, last_update, country, iso3, shape
)
values (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)',
coalesce(new.osm_id::text,'NULL'),
coalesce(quote_literal(new.name), 'NULL'),
coalesce(quote_literal(new.name_eng), 'NULL'),
coalesce(new.name_int::text, 'NULL'),
coalesce(quote_literal(new.type),'NULL'),
coalesce(new.z_order::text,'NULL'),
coalesce(new.population::text,'NULL'),
coalesce(quote_literal(new.last_update::text),'NULL'),
coalesce(quote_literal(new.country),'NULL'),
coalesce(quote_literal(new.iso3::text), 'NULL'),
coalesce(quote_literal(new.shape::text),'NULL')
);
PERFORM dblink_exec('db2', insert_statement);
PERFORM dblink_disconnect('db2');
RETURN new;
END;
$BODY$
LANGUAGE plpgsql VOLATILE;
我不确定列的类型,所以检查一下。插入可以为 NULL 的值有点棘手......请使用这个:
coalesce(new.osm_id::text,'NULL'),
对于插入整数值和这个:
coalesce(quote_literal(new.name), 'NULL'),
用于插入文本、时间戳和几何值。在插入语句中始终使用 %s
.
除此之外,我对函数做了以下修改:
- 检查连接是否已经存在
- 不需要函数
st_geometry((st_AsText())
,因为您已经插入了 WKB 格式的几何图形
- 我使用函数
format()
而不是连接运算符 ||
有更好的解决方案
再举个例子
-- Function: flux_tresorerie_historique_backup_row()
-- DROP FUNCTION flux_tresorerie_historique_backup_row();
CREATE OR REPLACE FUNCTION flux_tresorerie_historique_backup_row()
RETURNS trigger AS
$BODY$
BEGIN
perform dblink_connect('dbname=gtr_bd_archive user=postgres password=postgres');
perform dblink_exec('insert into flux_tresorerie_historique values('||
concat_ws(', ', quote_nullable(OLD.id_flux_historique),
quote_nullable(OLD.date_operation_flux),
quote_nullable(OLD.date_valeur_flux),
quote_nullable(OLD.date_rapprochement_flux),
quote_nullable(OLD.libelle_flux),
quote_nullable(OLD.montant_flux),
quote_nullable(OLD.contre_valeur_dzd),
quote_nullable(OLD.rib_compte_bancaire),
quote_nullable(OLD.frais_flux),
quote_nullable(OLD.sens_flux),
quote_nullable(OLD.statut_flux),
quote_nullable(OLD.code_devise),
quote_nullable(OLD.code_mode_paiement),
quote_nullable(OLD.code_agence),
quote_nullable(OLD.code_compte),
quote_nullable(OLD.code_banque),
quote_nullable(OLD.date_maj_flux),
quote_nullable(OLD.statut_frais),
quote_nullable(OLD.reference_flux),
quote_nullable(OLD.code_commission),
quote_nullable(OLD.id_flux)
)||');');
perform dblink_disconnect();
RETURN NULL;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
ALTER FUNCTION flux_tresorerie_historique_backup_row()
OWNER TO postgres;
如果您的表格相同,您可以像这样使用 "format"
CREATE OR REPLACE FUNCTION flux_tresorerie_historique_backup_row()
RETURNS trigger AS
$func$
BEGIN
PERFORM dblink_connect('myserver'); -- name of foreign server
PERFORM dblink_exec( format(
$$
INSERT INTO flux_tresorerie_historique
SELECT (%L::flux_tresorerie_historique).*
$$
, OLD::text));
PERFORM dblink_disconnect();
RETURN NULL; -- only for AFTER trigger
END
$func$ LANGUAGE plpgsql;
我创建了一个触发器,用于将数据库 1 中 table 'mytable_db1' 的插入复制到数据库 2 中的相同 table 'mytable_db2'。两个数据库都在同一台服务器上。
CREATE OR REPLACE FUNCTION trigger_osm_test_insert()
RETURNS trigger AS
$BODY$
BEGIN
PERFORM dblink_connect('db2', 'dbname=xxx port=5432 user=myusr password=xxx');
PERFORM dblink_exec('db2',
'insert into test.mytable_db2 (osm_id, name, name_eng, name_int, type, z_order, population, last_update, country, iso3, shape)
values ('||new.osm_id||', '''||new.name||''', '''||new.name_eng||''', '''||new.name_int||''', '''||new.type||''', '||new.z_order||',
'||new.population||', '''||new.last_update||''', '''||new.country||''', '''||new.iso3||''',
st_geometry((st_AsText('''||new.shape::text||'''))))');
PERFORM dblink_disconnect('db2');
RETURN new;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
ALTER FUNCTION trigger_osm_test_insert()
OWNER TO myusr;
CREATE TRIGGER osm_insert_test
AFTER INSERT
ON mytable_db1
FOR EACH ROW
EXECUTE PROCEDURE trigger_osm_test_insert();
但是,当我进行如下测试插入时:
insert into test.mytable_db1 (name, shape) values ('test', '0101000020E6100000E0979950035F4A40404B2751B0861CC0');
插入的行已插入 mytable_db1,但触发器似乎无法正常工作,因为我在 mytable_db2 中没有任何内容。插入没有给我任何来自触发器的错误消息。
我正在使用 postgresql 9.2.2。两个数据库都安装了 dblink 1.0 以及 postgis 2.0.6。
有人对我做错了什么有建议吗?
谢谢!
问题是您在执行 INSERT 时没有传递所有列。因此,NEW 中的某些列为空,并且由于您使用字符串连接,所以整个 INSERT INTO...
字符串为空。
例如,这个查询 returns NULL:
select NULL || 'some text';
您应该检查每一列是否为空,例如:
CREATE OR REPLACE FUNCTION trigger_osm_test_insert()
RETURNS trigger AS
$BODY$
DECLARE insert_statement TEXT;
BEGIN
IF NOT ARRAY['db2'] <@ dblink_get_connections() OR dblink_get_connections() IS NULL THEN
PERFORM dblink_connect('db2', 'dbname=xxx port=5432 user=xxx password=xxx');
END IF;
insert_statement = format('insert into mytable_db2 (
osm_id, name, name_eng, name_int, type, z_order,
population, last_update, country, iso3, shape
)
values (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)',
coalesce(new.osm_id::text,'NULL'),
coalesce(quote_literal(new.name), 'NULL'),
coalesce(quote_literal(new.name_eng), 'NULL'),
coalesce(new.name_int::text, 'NULL'),
coalesce(quote_literal(new.type),'NULL'),
coalesce(new.z_order::text,'NULL'),
coalesce(new.population::text,'NULL'),
coalesce(quote_literal(new.last_update::text),'NULL'),
coalesce(quote_literal(new.country),'NULL'),
coalesce(quote_literal(new.iso3::text), 'NULL'),
coalesce(quote_literal(new.shape::text),'NULL')
);
PERFORM dblink_exec('db2', insert_statement);
PERFORM dblink_disconnect('db2');
RETURN new;
END;
$BODY$
LANGUAGE plpgsql VOLATILE;
我不确定列的类型,所以检查一下。插入可以为 NULL 的值有点棘手......请使用这个:
coalesce(new.osm_id::text,'NULL'),
对于插入整数值和这个:
coalesce(quote_literal(new.name), 'NULL'),
用于插入文本、时间戳和几何值。在插入语句中始终使用 %s
.
除此之外,我对函数做了以下修改:
- 检查连接是否已经存在
- 不需要函数
st_geometry((st_AsText())
,因为您已经插入了 WKB 格式的几何图形 - 我使用函数
format()
而不是连接运算符||
有更好的解决方案
再举个例子
-- Function: flux_tresorerie_historique_backup_row()
-- DROP FUNCTION flux_tresorerie_historique_backup_row();
CREATE OR REPLACE FUNCTION flux_tresorerie_historique_backup_row()
RETURNS trigger AS
$BODY$
BEGIN
perform dblink_connect('dbname=gtr_bd_archive user=postgres password=postgres');
perform dblink_exec('insert into flux_tresorerie_historique values('||
concat_ws(', ', quote_nullable(OLD.id_flux_historique),
quote_nullable(OLD.date_operation_flux),
quote_nullable(OLD.date_valeur_flux),
quote_nullable(OLD.date_rapprochement_flux),
quote_nullable(OLD.libelle_flux),
quote_nullable(OLD.montant_flux),
quote_nullable(OLD.contre_valeur_dzd),
quote_nullable(OLD.rib_compte_bancaire),
quote_nullable(OLD.frais_flux),
quote_nullable(OLD.sens_flux),
quote_nullable(OLD.statut_flux),
quote_nullable(OLD.code_devise),
quote_nullable(OLD.code_mode_paiement),
quote_nullable(OLD.code_agence),
quote_nullable(OLD.code_compte),
quote_nullable(OLD.code_banque),
quote_nullable(OLD.date_maj_flux),
quote_nullable(OLD.statut_frais),
quote_nullable(OLD.reference_flux),
quote_nullable(OLD.code_commission),
quote_nullable(OLD.id_flux)
)||');');
perform dblink_disconnect();
RETURN NULL;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
ALTER FUNCTION flux_tresorerie_historique_backup_row()
OWNER TO postgres;
如果您的表格相同,您可以像这样使用 "format"
CREATE OR REPLACE FUNCTION flux_tresorerie_historique_backup_row()
RETURNS trigger AS
$func$
BEGIN
PERFORM dblink_connect('myserver'); -- name of foreign server
PERFORM dblink_exec( format(
$$
INSERT INTO flux_tresorerie_historique
SELECT (%L::flux_tresorerie_historique).*
$$
, OLD::text));
PERFORM dblink_disconnect();
RETURN NULL; -- only for AFTER trigger
END
$func$ LANGUAGE plpgsql;