2016-02-09 4 views
2

Я создал триггер для репликации вставок из таблицы 'mytable_db1' в database1 в ту же таблицу 'mytable_db2' в database2. Обе базы данных находятся на одном сервере.postgresql триггер с dblink ничего не возвращает

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.

У кого-нибудь есть предложения о том, что я делаю неправильно?

Спасибо!

ответ

1

Проблема в том, что вы не передаете все столбцы при выполнении INSERT. Из-за этого некоторые столбцы в NEW имеют значение NULL, и поскольку вы используете конкатенацию строк, ваша целая строка имеет значение NULL.

В примере, этот запрос возвращает NULL:

select NULL || 'some text'; 

Вы должны проверить каждую колонку для nulless, в примере так:

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()) не требуется, так как вы уже вставить геометрию в формате ВКБ
  • Я использую функцию format() вместо оператора конкатенации ||
+0

Большое спасибо Томмазо! Он работает сейчас! Единственное, что я должен был повторно ввести функцию st_geometry (st_AsText()) для геометрии.Это давало мне сообщение об ошибке из-за различного типа геометрии между двумя таблицами. Таблица db1 находится в геометрии PostGIS, а db2 - в геометрии ArcSDE. – Thierry

1

Там является Лучшее решение, чтобы сделать это

Вот еще один пример

-- 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; 

если ваши Таблицы identique вы можете использовать «формат», как этого

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; 
Смежные вопросы