By Eric Jones, plus some hacking by me.
self.load_table_state(dst_curs)
self.sync_tables(dst_db)
+ self.restore_fkeys(dst_db)
+
# now the actual event processing happens.
# they must be done all in one tx in dst side
# and the transaction must be kept open so that
"Copy thread sync logic."
#
- # decide what to do - order is imortant
+ # decide what to do - order is important
#
if cnt.do_sync:
# main thread is waiting, catch up, then handle over
if src_enc != dst_enc:
dst_curs.execute("set client_encoding = %s", [src_enc])
+ def restore_fkeys(self, dst_db):
+ dst_curs = dst_db.cursor()
+ # restore fkeys -- one at a time
+ q = "select * from londiste.subscriber_get_queue_valid_pending_fkeys(%s)"
+ dst_curs.execute(q, [self.pgq_queue_name])
+ list = dst_curs.dictfetchall()
+ for row in list:
+ self.log.info('Creating fkey: %(fkey_name)s (%(from_table)s --> %(to_table)s)' % row)
+ q2 = "select londiste.subscriber_restore_table_fkey(%(from_table)s, %(fkey_name)s)"
+ dst_curs.execute(q2, row)
+ dst_db.commit()
+
if __name__ == '__main__':
script = Replicator(sys.argv[1:])
script.start()
elif cmd == "check":
self.check_tables(self.get_provider_table_list())
elif cmd == "fkeys":
- self.collect_fkeys(self.get_provider_table_list())
+ self.collect_fkeys(self.get_provider_table_list(), self.args[3:])
elif cmd == "seqs":
self.subscriber_list_seqs()
elif cmd == "add-seq":
self.log.error('bad subcommand: ' + cmd)
sys.exit(1)
- def collect_fkeys(self, table_list):
+ def collect_fkeys(self, table_list, args):
+ if args == []:
+ args = ['pending', 'active']
+
dst_db = self.get_database('subscriber_db')
dst_curs = dst_db.cursor()
+
+ subscriber_tables = self.get_subscriber_table_list()
- oid_list = []
- for tbl in table_list:
- try:
- oid = skytools.get_table_oid(dst_curs, tbl)
- if oid:
- oid_list.append(str(oid))
- except:
- pass
- if len(oid_list) == 0:
- print "No tables"
- return
- oid_str = ",".join(oid_list)
-
- q = "SELECT n.nspname || '.' || t.relname as tbl, c.conname as con,"\
- " pg_get_constraintdef(c.oid) as def"\
- " FROM pg_constraint c, pg_class t, pg_namespace n"\
- " WHERE c.contype = 'f' and (c.conrelid in (%s) or c.confrelid in (%s))"\
- " AND t.oid = c.conrelid AND n.oid = t.relnamespace" % (oid_str, oid_str)
- dst_curs.execute(q)
- res = dst_curs.dictfetchall()
- dst_db.commit()
-
- print "-- dropping"
- for row in res:
- q = "ALTER TABLE ONLY %(tbl)s DROP CONSTRAINT %(con)s;"
- print q % row
- print "-- creating"
- for row in res:
- q = "ALTER TABLE ONLY %(tbl)s ADD CONSTRAINT %(con)s %(def)s;"
- print q % row
+ fkeys = {'active_fkeys': [], 'pending_fkeys': []}
+ for type in args:
+ q = "select * from londiste.subscriber_get_table_%s_fkeys(%%s);" % type
+ for tbl in table_list:
+ if tbl not in subscriber_tables:
+ continue
+ dst_curs.execute(q, [tbl])
+ fkeys['%s_fkeys' % type].extend(dst_curs.dictfetchall())
+ dst_db.commit()
+
+ for type in args:
+ widths = [15,15,15]
+ for row in fkeys['%s_fkeys' % type]:
+ widths[0] = widths[0] > len(row[0]) and widths[0] or len(row[0])
+ widths[1] = widths[1] > len(row[1]) and widths[1] or len(row[1])
+ widths[2] = widths[2] > len(row[2]) and widths[2] or len(row[2])
+ widths[0] += 2; widths[1] += 2; widths[2] += 2
+
+ fmt = '%%-%ds%%-%ds%%-%ds%%s' % tuple(widths)
+ print '%s fkeys:' % type
+ print fmt % ('from_table', 'to_table', 'fkey_name', 'fkey_def')
+ print fmt % ('----------', '--------', '---------', '--------')
+
+ for row in fkeys['%s_fkeys' % type]:
+ print fmt % row.values()
+ print '\n'
def check_tables(self, table_list):
src_db = self.get_database('provider_db')
if not oid:
self.log.error('Table %s not found' % tbl)
return 1
- q = "select count(1) from pg_trigger where tgrelid = %s"
+ q = "select count(1) from pg_trigger where tgrelid = %s and tgisconstraint is not true"
dst_curs.execute(q, [oid])
got = dst_curs.fetchone()[0]
if got:
for c in src_struct.get_column_list():
if c not in dlist:
raise Exception('Column %s does not exist on dest side' % c)
+
+ # drop all foreign keys to and from this table
+ # they need to be dropped one at a time to avoid deadlocks with user code
+ q = "select * from londiste.find_table_fkeys(%s)"
+ dst_curs.execute(q, [dst_struct.table_name])
+ list = dst_curs.dictfetchall()
+ for row in list:
+ self.log.info('Dropping fkey: %s' % row['fkey_name'])
+ q2 = "select londiste.subscriber_drop_table_fkey(%(from_table)s, %(fkey_name)s)"
+ dst_curs.execute(q2, row)
+ dst_db.commit()
# drop unnecessary stuff
objs = T_CONSTRAINT | T_INDEX | T_TRIGGER | T_RULE
# create previously dropped objects
dst_struct.create(dst_curs, objs, log = self.log)
+ dst_db.commit()
# set state
- tbl_stat.change_snapshot(snapshot)
if self.copy_thread:
tbl_stat.change_state(TABLE_CATCHING_UP)
else:
tbl_stat.change_state(TABLE_OK)
+ tbl_stat.change_snapshot(snapshot)
self.save_table_state(dst_curs)
dst_db.commit()
type = T_CONSTRAINT
SQL = """
SELECT conname as name, pg_get_constraintdef(oid) as def, contype
- FROM pg_constraint WHERE conrelid = %(oid)s
+ FROM pg_constraint WHERE conrelid = %(oid)s AND contype != 'f'
"""
def __init__(self, table_name, row):
self.table_name = table_name
FUNCS = $(wildcard functions/*.sql)
SRCS = structure/tables.sql structure/grants.sql structure/types.sql $(FUNCS)
-REGRESS = londiste_install londiste_provider londiste_subscriber
+REGRESS = londiste_install londiste_provider londiste_subscriber londiste_fkeys
# londiste_denytrigger
REGRESS_OPTS = --load-language=plpythonu --load-language=plpgsql
--- /dev/null
+create table ref_1 (
+ id int4 primary key,
+ val text
+);
+NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "ref_1_pkey" for table "ref_1"
+create table ref_2 (
+ id int4 primary key,
+ ref int4 not null references ref_1,
+ val text
+);
+NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "ref_2_pkey" for table "ref_2"
+create table ref_3 (
+ id int4 primary key,
+ ref2 int4 not null references ref_2,
+ val text
+);
+NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "ref_3_pkey" for table "ref_3"
+select * from londiste.subscriber_add_table('refqueue', 'public.ref_1');
+ subscriber_add_table
+----------------------
+ 0
+(1 row)
+
+select * from londiste.subscriber_add_table('refqueue', 'public.ref_2');
+ subscriber_add_table
+----------------------
+ 0
+(1 row)
+
+select * from londiste.subscriber_add_table('refqueue', 'public.ref_3');
+ subscriber_add_table
+----------------------
+ 0
+(1 row)
+
+select * from londiste.find_table_fkeys('public.ref_1');
+ from_table | to_table | fkey_name | fkey_def
+--------------+--------------+----------------+----------------------------------------
+ public.ref_2 | public.ref_1 | ref_2_ref_fkey | FOREIGN KEY (ref) REFERENCES ref_1(id)
+(1 row)
+
+select * from londiste.find_table_fkeys('public.ref_2');
+ from_table | to_table | fkey_name | fkey_def
+--------------+--------------+-----------------+-----------------------------------------
+ public.ref_2 | public.ref_1 | ref_2_ref_fkey | FOREIGN KEY (ref) REFERENCES ref_1(id)
+ public.ref_3 | public.ref_2 | ref_3_ref2_fkey | FOREIGN KEY (ref2) REFERENCES ref_2(id)
+(2 rows)
+
+select * from londiste.find_table_fkeys('public.ref_3');
+ from_table | to_table | fkey_name | fkey_def
+--------------+--------------+-----------------+-----------------------------------------
+ public.ref_3 | public.ref_2 | ref_3_ref2_fkey | FOREIGN KEY (ref2) REFERENCES ref_2(id)
+(1 row)
+
+select * from londiste.subscriber_get_table_pending_fkeys('public.ref_2');
+ from_table | to_table | fkey_name | fkey_def
+------------+----------+-----------+----------
+(0 rows)
+
+select * from londiste.subscriber_get_queue_valid_pending_fkeys('refqueue');
+ from_table | to_table | fkey_name | fkey_def
+------------+----------+-----------+----------
+(0 rows)
+
+-- drop fkeys
+select * from londiste.subscriber_drop_table_fkey('public.ref_2', 'ref_2_ref_fkey');
+ subscriber_drop_table_fkey
+----------------------------
+ 1
+(1 row)
+
+select * from londiste.find_table_fkeys('public.ref_1');
+ from_table | to_table | fkey_name | fkey_def
+------------+----------+-----------+----------
+(0 rows)
+
+select * from londiste.find_table_fkeys('public.ref_2');
+ from_table | to_table | fkey_name | fkey_def
+--------------+--------------+-----------------+-----------------------------------------
+ public.ref_3 | public.ref_2 | ref_3_ref2_fkey | FOREIGN KEY (ref2) REFERENCES ref_2(id)
+(1 row)
+
+select * from londiste.find_table_fkeys('public.ref_3');
+ from_table | to_table | fkey_name | fkey_def
+--------------+--------------+-----------------+-----------------------------------------
+ public.ref_3 | public.ref_2 | ref_3_ref2_fkey | FOREIGN KEY (ref2) REFERENCES ref_2(id)
+(1 row)
+
+select * from londiste.subscriber_drop_table_fkey('public.ref_3', 'ref_3_ref2_fkey');
+ subscriber_drop_table_fkey
+----------------------------
+ 1
+(1 row)
+
+-- check if dropped
+select * from londiste.find_table_fkeys('public.ref_1');
+ from_table | to_table | fkey_name | fkey_def
+------------+----------+-----------+----------
+(0 rows)
+
+select * from londiste.find_table_fkeys('public.ref_2');
+ from_table | to_table | fkey_name | fkey_def
+------------+----------+-----------+----------
+(0 rows)
+
+select * from londiste.find_table_fkeys('public.ref_3');
+ from_table | to_table | fkey_name | fkey_def
+------------+----------+-----------+----------
+(0 rows)
+
+-- look state
+select * from londiste.subscriber_get_table_pending_fkeys('public.ref_2');
+ from_table | to_table | fkey_name | fkey_def
+--------------+--------------+-----------------+-----------------------------------------
+ public.ref_2 | public.ref_1 | ref_2_ref_fkey | FOREIGN KEY (ref) REFERENCES ref_1(id)
+ public.ref_3 | public.ref_2 | ref_3_ref2_fkey | FOREIGN KEY (ref2) REFERENCES ref_2(id)
+(2 rows)
+
+select * from londiste.subscriber_get_queue_valid_pending_fkeys('refqueue');
+ from_table | to_table | fkey_name | fkey_def
+------------+----------+-----------+----------
+(0 rows)
+
+-- toggle sync
+select * from londiste.subscriber_set_table_state('refqueue', 'public.ref_1', null, 'ok');
+ subscriber_set_table_state
+----------------------------
+ 1
+(1 row)
+
+select * from londiste.subscriber_get_queue_valid_pending_fkeys('refqueue');
+ from_table | to_table | fkey_name | fkey_def
+------------+----------+-----------+----------
+(0 rows)
+
+select * from londiste.subscriber_set_table_state('refqueue', 'public.ref_2', null, 'ok');
+ subscriber_set_table_state
+----------------------------
+ 1
+(1 row)
+
+select * from londiste.subscriber_get_queue_valid_pending_fkeys('refqueue');
+ from_table | to_table | fkey_name | fkey_def
+--------------+--------------+----------------+----------------------------------------
+ public.ref_2 | public.ref_1 | ref_2_ref_fkey | FOREIGN KEY (ref) REFERENCES ref_1(id)
+(1 row)
+
+select * from londiste.subscriber_set_table_state('refqueue', 'public.ref_3', null, 'ok');
+ subscriber_set_table_state
+----------------------------
+ 1
+(1 row)
+
+select * from londiste.subscriber_get_queue_valid_pending_fkeys('refqueue');
+ from_table | to_table | fkey_name | fkey_def
+--------------+--------------+-----------------+-----------------------------------------
+ public.ref_2 | public.ref_1 | ref_2_ref_fkey | FOREIGN KEY (ref) REFERENCES ref_1(id)
+ public.ref_3 | public.ref_2 | ref_3_ref2_fkey | FOREIGN KEY (ref2) REFERENCES ref_2(id)
+(2 rows)
+
+-- restore
+select * from londiste.subscriber_restore_table_fkey('public.ref_2', 'ref_2_ref_fkey');
+ subscriber_restore_table_fkey
+-------------------------------
+ 1
+(1 row)
+
+select * from londiste.subscriber_restore_table_fkey('public.ref_3', 'ref_3_ref2_fkey');
+ subscriber_restore_table_fkey
+-------------------------------
+ 1
+(1 row)
+
+-- look state
+select * from londiste.subscriber_get_table_pending_fkeys('public.ref_2');
+ from_table | to_table | fkey_name | fkey_def
+------------+----------+-----------+----------
+(0 rows)
+
+select * from londiste.subscriber_get_queue_valid_pending_fkeys('refqueue');
+ from_table | to_table | fkey_name | fkey_def
+------------+----------+-----------+----------
+(0 rows)
+
+select * from londiste.find_table_fkeys('public.ref_1');
+ from_table | to_table | fkey_name | fkey_def
+--------------+--------------+----------------+----------------------------------------
+ public.ref_2 | public.ref_1 | ref_2_ref_fkey | FOREIGN KEY (ref) REFERENCES ref_1(id)
+(1 row)
+
+select * from londiste.find_table_fkeys('public.ref_2');
+ from_table | to_table | fkey_name | fkey_def
+--------------+--------------+-----------------+-----------------------------------------
+ public.ref_2 | public.ref_1 | ref_2_ref_fkey | FOREIGN KEY (ref) REFERENCES ref_1(id)
+ public.ref_3 | public.ref_2 | ref_3_ref2_fkey | FOREIGN KEY (ref2) REFERENCES ref_2(id)
+(2 rows)
+
+select * from londiste.find_table_fkeys('public.ref_3');
+ from_table | to_table | fkey_name | fkey_def
+--------------+--------------+-----------------+-----------------------------------------
+ public.ref_3 | public.ref_2 | ref_3_ref2_fkey | FOREIGN KEY (ref2) REFERENCES ref_2(id)
+(1 row)
+
);
select londiste.provider_add_table('pqueue', 'public.testdata_nopk');
ERROR: need key column
-CONTEXT: PL/pgSQL function "provider_add_table" line 2 at return
+CONTEXT: PL/pgSQL function "provider_add_table" line 2 at RETURN
select londiste.provider_add_table('pqueue', 'public.testdata');
ERROR: no such event queue
-CONTEXT: PL/pgSQL function "provider_add_table" line 2 at return
+CONTEXT: PL/pgSQL function "provider_add_table" line 2 at RETURN
select pgq.create_queue('pqueue');
create_queue
--------------
(1 row)
select londiste.provider_add_table('pqueue', 'public.testdata');
-ERROR: duplicate key violates unique constraint "provider_table_pkey"
+ERROR: duplicate key value violates unique constraint "provider_table_pkey"
CONTEXT: SQL statement "INSERT INTO londiste.provider_table (queue_name, table_name, trigger_name) values ( $1 , $2 , $3 )"
PL/pgSQL function "provider_add_table" line 23 at SQL statement
-PL/pgSQL function "provider_add_table" line 2 at return
+PL/pgSQL function "provider_add_table" line 2 at RETURN
select londiste.provider_refresh_trigger('pqueue', 'public.testdata');
provider_refresh_trigger
--------------------------
select londiste.provider_add_seq('pqueue', 'public.no_seq');
ERROR: seq not found
-CONTEXT: PL/pgSQL function "find_seq_oid" line 2 at return
+CONTEXT: PL/pgSQL function "find_seq_oid" line 2 at RETURN
SQL statement "SELECT 1 from pg_class where oid = londiste.find_seq_oid( $1 )"
-PL/pgSQL function "provider_add_seq" line 10 at perform
+PL/pgSQL function "provider_add_seq" line 10 at PERFORM
select londiste.provider_add_seq('pqueue', 'public.testdata_id_seq');
provider_add_seq
------------------
(1 row)
select londiste.provider_add_seq('pqueue', 'public.testdata_id_seq');
-ERROR: duplicate key violates unique constraint "provider_seq_pkey"
+ERROR: duplicate key value violates unique constraint "provider_seq_pkey"
CONTEXT: SQL statement "INSERT INTO londiste.provider_seq (queue_name, seq_name) values ( $1 , $2 )"
PL/pgSQL function "provider_add_seq" line 16 at SQL statement
select * from londiste.provider_get_seq_list('pqueue');
insert into londiste.link (source, dest) values ('mqueue', 'pqueue');
select londiste.provider_add_table('pqueue', 'public.testdata');
ERROR: Linked queue, manipulation not allowed
-CONTEXT: PL/pgSQL function "provider_add_table" line 2 at return
+CONTEXT: PL/pgSQL function "provider_add_table" line 2 at RETURN
select londiste.provider_remove_table('pqueue', 'public.testdata');
ERROR: Linked queue, manipulation not allowed
select londiste.provider_add_seq('pqueue', 'public.testdata_id_seq');
(1 row)
select londiste.subscriber_add_table('pqueue', 'public.testdata');
-ERROR: duplicate key violates unique constraint "subscriber_table_pkey"
+ERROR: duplicate key value violates unique constraint "subscriber_table_pkey"
CONTEXT: SQL statement "INSERT INTO londiste.subscriber_table (queue_name, table_name) values ( $1 , $2 )"
PL/pgSQL function "subscriber_add_table" line 2 at SQL statement
select londiste.subscriber_add_table('pqueue', 'public.testdata');
-ERROR: duplicate key violates unique constraint "subscriber_table_pkey"
+ERROR: duplicate key value violates unique constraint "subscriber_table_pkey"
CONTEXT: SQL statement "INSERT INTO londiste.subscriber_table (queue_name, table_name) values ( $1 , $2 )"
PL/pgSQL function "subscriber_add_table" line 2 at SQL statement
select * from londiste.subscriber_get_table_list('pqueue');
(1 row)
select londiste.subscriber_add_seq('pqueue', 'public.testdata_id_seq');
-ERROR: duplicate key violates unique constraint "subscriber_seq_pkey"
+ERROR: duplicate key value violates unique constraint "subscriber_seq_pkey"
CONTEXT: SQL statement "INSERT INTO londiste.subscriber_seq (queue_name, seq_name) values ( $1 , $2 )"
PL/pgSQL function "subscriber_add_seq" line 4 at SQL statement
select * from londiste.subscriber_get_seq_list('pqueue');
insert into londiste.link (source, dest) values ('mqueue', 'pqueue');
select londiste.subscriber_add_table('pqueue', 'public.testdata');
-ERROR: duplicate key violates unique constraint "subscriber_table_pkey"
+ERROR: duplicate key value violates unique constraint "subscriber_table_pkey"
CONTEXT: SQL statement "INSERT INTO londiste.subscriber_table (queue_name, table_name) values ( $1 , $2 )"
PL/pgSQL function "subscriber_add_table" line 2 at SQL statement
select londiste.subscriber_remove_table('pqueue', 'public.testdata');
return res;
end;
-$$ language plpgsql;
+$$ language plpgsql strict stable;
--- /dev/null
+
+create or replace function londiste.find_table_fkeys(i_table_name text)
+returns setof londiste.subscriber_pending_fkeys as $$
+declare
+ fkey record;
+ tbl_oid oid;
+begin
+ select londiste.find_table_oid(i_table_name) into tbl_oid;
+
+ for fkey in
+ select n1.nspname || '.' || t1.relname as from_table, n2.nspname || '.' || t2.relname as to_table,
+ conname::text as fkey_name, pg_get_constraintdef(c.oid) as fkey_def
+ from pg_constraint c, pg_namespace n1, pg_class t1, pg_namespace n2, pg_class t2
+ where c.contype = 'f' and (c.conrelid = tbl_oid or c.confrelid = tbl_oid)
+ and t1.oid = c.conrelid and n1.oid = t1.relnamespace
+ and t2.oid = c.confrelid and n2.oid = t2.relnamespace
+ order by 1,2,3
+ loop
+ return next fkey;
+ end loop;
+
+ return;
+end;
+$$ language plpgsql strict stable;
+
+
return res;
end;
-$$ language plpgsql;
+$$ language plpgsql strict stable;
create or replace function londiste.find_table_oid(tbl text)
returns oid as $$
begin
return londiste.find_rel_oid(tbl, 'r');
end;
-$$ language plpgsql;
+$$ language plpgsql strict stable;
create or replace function londiste.find_seq_oid(tbl text)
returns oid as $$
begin
return londiste.find_rel_oid(tbl, 'S');
end;
-$$ language plpgsql;
+$$ language plpgsql strict stable;
where consumer_id = i_consumer;
return res;
end;
-$$ language plpgsql security definer;
+$$ language plpgsql security definer strict stable;
--- /dev/null
+
+
+create or replace function londiste.subscriber_get_table_pending_fkeys(i_table_name text)
+returns setof londiste.subscriber_pending_fkeys as $$
+declare
+ fkeys record;
+begin
+ for fkeys in
+ select *
+ from londiste.subscriber_pending_fkeys
+ where from_table=i_table_name or to_table=i_table_name
+ order by 1,2,3
+ loop
+ return next fkeys;
+ end loop;
+
+ return;
+end;
+$$ language plpgsql;
+
+
+create or replace function londiste.subscriber_get_queue_valid_pending_fkeys(i_queue_name text)
+returns setof londiste.subscriber_pending_fkeys as $$
+declare
+ fkeys record;
+begin
+ for fkeys in
+ select pf.*
+ from londiste.subscriber_pending_fkeys pf
+ left join londiste.subscriber_table st_from on (st_from.table_name = pf.from_table)
+ left join londiste.subscriber_table st_to on (st_to.table_name = pf.to_table)
+ where (st_from.table_name is null or (st_from.merge_state = 'ok' and st_from.snapshot is null))
+ and (st_to.table_name is null or (st_to.merge_state = 'ok' and st_to.snapshot is null))
+ and (coalesce(st_from.queue_name = i_queue_name, false)
+ or coalesce(st_to.queue_name = i_queue_name, false))
+ order by 1, 2, 3
+ loop
+ return next fkeys;
+ end loop;
+
+ return;
+end;
+$$ language plpgsql;
+
+
+create or replace function londiste.subscriber_drop_table_fkey(i_from_table text, i_fkey_name text)
+returns integer as $$
+declare
+ fkey record;
+begin
+ select * into fkey
+ from londiste.find_table_fkeys(i_from_table)
+ where fkey_name = i_fkey_name and from_table = i_from_table;
+
+ if not found then
+ return 1;
+ end if;
+
+ insert into londiste.subscriber_pending_fkeys values (fkey.from_table, fkey.to_table, i_fkey_name, fkey.fkey_def);
+
+ execute 'alter table only ' || fkey.from_table || ' drop constraint ' || i_fkey_name || ';';
+
+ return 1;
+end;
+$$ language plpgsql;
+
+
+create or replace function londiste.subscriber_restore_table_fkey(i_from_table text, i_fkey_name text)
+returns integer as $$
+declare
+ fkey record;
+begin
+ select * into fkey
+ from londiste.subscriber_pending_fkeys
+ where fkey_name = i_fkey_name and from_table = i_from_table;
+
+ if not found then
+ return 1;
+ end if;
+
+ delete from londiste.subscriber_pending_fkeys where fkey_name = fkey.fkey_name;
+
+ execute 'alter table only ' || fkey.from_table || ' add constraint '
+ || fkey.fkey_name || ' ' || fkey.fkey_def || ';';
+
+ return 1;
+end;
+$$ language plpgsql;
--- /dev/null
+
+set log_error_verbosity = 'terse';
+
+create table ref_1 (
+ id int4 primary key,
+ val text
+);
+
+create table ref_2 (
+ id int4 primary key,
+ ref int4 not null references ref_1,
+ val text
+);
+
+create table ref_3 (
+ id int4 primary key,
+ ref2 int4 not null references ref_2,
+ val text
+);
+
+select * from londiste.subscriber_add_table('refqueue', 'public.ref_1');
+select * from londiste.subscriber_add_table('refqueue', 'public.ref_2');
+select * from londiste.subscriber_add_table('refqueue', 'public.ref_3');
+
+select * from londiste.find_table_fkeys('public.ref_1');
+select * from londiste.find_table_fkeys('public.ref_2');
+select * from londiste.find_table_fkeys('public.ref_3');
+
+select * from londiste.subscriber_get_table_pending_fkeys('public.ref_2');
+
+select * from londiste.subscriber_get_queue_valid_pending_fkeys('refqueue');
+
+-- drop fkeys
+
+select * from londiste.subscriber_drop_table_fkey('public.ref_2', 'ref_2_ref_fkey');
+
+select * from londiste.find_table_fkeys('public.ref_1');
+select * from londiste.find_table_fkeys('public.ref_2');
+select * from londiste.find_table_fkeys('public.ref_3');
+
+select * from londiste.subscriber_drop_table_fkey('public.ref_3', 'ref_3_ref2_fkey');
+
+-- check if dropped
+
+select * from londiste.find_table_fkeys('public.ref_1');
+select * from londiste.find_table_fkeys('public.ref_2');
+select * from londiste.find_table_fkeys('public.ref_3');
+
+-- look state
+select * from londiste.subscriber_get_table_pending_fkeys('public.ref_2');
+select * from londiste.subscriber_get_queue_valid_pending_fkeys('refqueue');
+
+-- toggle sync
+select * from londiste.subscriber_set_table_state('refqueue', 'public.ref_1', null, 'ok');
+select * from londiste.subscriber_get_queue_valid_pending_fkeys('refqueue');
+select * from londiste.subscriber_set_table_state('refqueue', 'public.ref_2', null, 'ok');
+select * from londiste.subscriber_get_queue_valid_pending_fkeys('refqueue');
+select * from londiste.subscriber_set_table_state('refqueue', 'public.ref_3', null, 'ok');
+select * from londiste.subscriber_get_queue_valid_pending_fkeys('refqueue');
+
+-- restore
+select * from londiste.subscriber_restore_table_fkey('public.ref_2', 'ref_2_ref_fkey');
+select * from londiste.subscriber_restore_table_fkey('public.ref_3', 'ref_3_ref2_fkey');
+
+-- look state
+select * from londiste.subscriber_get_table_pending_fkeys('public.ref_2');
+select * from londiste.subscriber_get_queue_valid_pending_fkeys('refqueue');
+select * from londiste.find_table_fkeys('public.ref_1');
+select * from londiste.find_table_fkeys('public.ref_2');
+select * from londiste.find_table_fkeys('public.ref_3');
+
+
fkey_name text not null,
fkey_def text not null,
- primary key (from_table, to_table, fkey_name),
- unique (to_table, from_table, fkey_name)
+ primary key (from_table, fkey_name)
);
create table data2 (
id serial primary key,
data text,
- -- old_id integer references data1,
+ ref1 integer references data1,
constraint uq_data2 unique (data)
);