Sun Dec 17 20:27:55 PST 2006
- Previous message: [Slony1-general] Slony-I Release 1.2.2
- Next message: [Slony1-general] "CREATE OR REPLACE function ..."
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Attached is my first attempt at a patch to allow EXECUTE SCRIPT to take a
user specified list of tables to lock.
The idea is that you can specify something like
EXECUTE SCRIPT(set id=1, filename='new_column.sql',
event node=1, lock tables = ('public.test1','public.address')
);
The ddl_updates_tbl_locks.sql should be added to tests/testddl
The diff file should be applied against CVS HEAD.
Let me know if there are any concerns.
Steve Singer
-------------- next part --------------
ALTER TABLE table5 DROP COLUMN a;
ALTER TABLE table1 ADD COLUMN xy int4;
UPDATE table1 SET xy=1;
-------------- next part --------------
? tests/testddl/ddl_updates_tbl_locks.sql
Index: doc/adminguide/slonik_ref.sgml
===================================================================
RCS file: /usr/local/cvsroot/slony1/slony1-engine/doc/adminguide/slonik_ref.sgml,v
retrieving revision 1.65
diff -c -r1.65 slonik_ref.sgml
*** doc/adminguide/slonik_ref.sgml 31 Oct 2006 22:09:39 -0000 1.65
--- doc/adminguide/slonik_ref.sgml 18 Dec 2006 04:27:50 -0000
***************
*** 2548,2553 ****
--- 2548,2563 ----
subscribed to the set.</para></listitem>
</varlistentry>
+ <varlistentry><term><literal>LOCK TABLES = ('fully.qualified_table1',
+ 'fully.qualified_table2','fully_qualified.table3')
+ </literal</term>
+ <listitem><para>(Optional) This option tells Slony to only obtain locks on the
+ tables specified. It is important that any tables that are referenced in
+ the script being executed be listed here or that this option not be specified
+ which will result in a lock being obtained on all tables.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
<para> See also the warnings in &rddlchanges;.</para>
***************
*** 2556,2573 ****
it can get stuck behind other database activity.</para>
<para> At the start of this event, all replicated tables are
! unlocked via the function
<function>alterTableRestore(tab_id)</function>. After the SQL
script has run, they are returned to <quote>replicating
state</quote> using
<function>alterTableForReplication(tab_id)</function>. This means
! that all of these tables are locked by this &lslon process for the
duration of the SQL script execution.</para>
<para> If a table's columns are modified, it is very important
that the triggers be regenerated, otherwise they may be
inappropriate for the new form of the table schema.</para>
<para> Note that if you need to make reference to the cluster
name, you can use the token <command>@CLUSTERNAME@</command>; if
you need to make reference to the &slony1; namespace, you can use
--- 2566,2590 ----
it can get stuck behind other database activity.</para>
<para> At the start of this event, all replicated tables are
! locked and replication is stopped via the function
<function>alterTableRestore(tab_id)</function>. After the SQL
script has run, they are returned to <quote>replicating
state</quote> using
<function>alterTableForReplication(tab_id)</function>. This means
! that all of these tables are locked by the slonik process(on the event node) or
! by the slon process(for other nodes) for the
duration of the SQL script execution.</para>
<para> If a table's columns are modified, it is very important
that the triggers be regenerated, otherwise they may be
inappropriate for the new form of the table schema.</para>
+ <para> The LOCK TABLES option can be used to tell Slony to only
+ lock the tables and suspend replication on the tables indicated.
+ If this option is not specified all replicated tables will be locked
+ during the execution of the script.
+ </para>
+
<para> Note that if you need to make reference to the cluster
name, you can use the token <command>@CLUSTERNAME@</command>; if
you need to make reference to the &slony1; namespace, you can use
***************
*** 2587,2595 ****
</refsect1>
<refsect1> <title> Locking Behaviour </title>
! <para> Each replicated table receives an exclusive lock, on the
! origin node, in order to remove the replication triggers; after
! the DDL script completes, those locks will be cleared. </para>
<para> After the DDL script has run on the origin node, it will
then run on subscriber nodes, where replicated tables will be
--- 2604,2645 ----
</refsect1>
<refsect1> <title> Locking Behaviour </title>
! <para> If the LOCK TABLES options is not specified then each replicated table
! receives an exclusive lock on the
! origin node in order to remove the replication triggers. Every other replicated
! table will have its application and constraint triggers re-enablled on the slave
! databases for the duration of the EXECUTE SCRIPT. After
! the DDL script completes the locks will be cleared and triggers will be reverted.
! All non-Slony database
! activity on replicated tables should be stopped to prevent the risk of deadlock.</para>
!
! <para> If the LOCK TABLES option is specified then only the the tables
! listed will have the replication triggers removed from them on the origin or other triggers
! enabled on the slave. This will require
! obtaining an exclusive lock on each listed table for the duration of the EXECUTE script.
! After the DDL script completes, those locks will be cleared.
! This allows the DBA to control which tables will be locked during the EXECUTE SCRIPT
! </para>
!
! <para>
! Any tables that are referenced in the DDL script need to be locked. The following guidelines
! are useful:
! </para>
! <itemizedlist>
! <listitem><para>Any tables referenced by an ALTER table must be locked</para></listitem>
! <listitem><para>If adding a foreign key both the table the key is being added to and
! the table the foreign key references must be locked</para></listitem>
! <listitem><para>Any tables that are the target of INSERT or UPDATE statements must be locked
! </para></listitem>
! <listitem><para>Any tables that are being queried must be locked</para></listitem>
! <listitem><para>If a table is being dropped it should be removed from all replication sets
! before the DDL script is run and thus does not need to be locked</para></listitem>
! <listitem><para>If in doubt don't use the LOCK TABLES option and allow Slony to lock everything
! </para></listitem>
!
! </itemizedlist>
!
!
<para> After the DDL script has run on the origin node, it will
then run on subscriber nodes, where replicated tables will be
Index: src/backend/slony1_funcs.sql
===================================================================
RCS file: /usr/local/cvsroot/slony1/slony1-engine/src/backend/slony1_funcs.sql,v
retrieving revision 1.103
diff -c -r1.103 slony1_funcs.sql
*** src/backend/slony1_funcs.sql 15 Dec 2006 05:34:18 -0000 1.103
--- src/backend/slony1_funcs.sql 18 Dec 2006 04:27:53 -0000
***************
*** 3664,3669 ****
--- 3664,3671 ----
Processes DROP_TRIGGER event to make sure that trigger trig_tgname on
replicated table trig_tabid IS disabled.';
+
+
-- ----------------------------------------------------------------------
-- FUNCTION ddlScript_prepare (set_id, only_on_node)
--
***************
*** 3671,3680 ****
--- 3673,3700 ----
-- ----------------------------------------------------------------------
create or replace function @NAMESPACE at .ddlScript_prepare (int4, int4)
returns integer
+ as '
+ begin
+ return @NAMESPACE at .ddlScirpt_prepare($1,$2,null);
+ end;
+ ' language plpgsql;
+
+
+ comment on function @NAMESPACE at .ddlScript_prepare (int4, int4) is
+ 'Prepare for DDL script execution on origin. All replicated tables will be prepared';
+
+ -- ----------------------------------------------------------------------
+ -- FUNCTION ddlScript_prepare (set_id, only_on_node,p_lock_tab_ids)
+ --
+ -- Generate the DDL_SCRIPT event
+ -- ----------------------------------------------------------------------
+ create or replace function @NAMESPACE at .ddlScript_prepare (int4, int4,int4[])
+ returns integer
as '
declare
p_set_id alias for $1;
p_only_on_node alias for $2;
+ p_lock_tab_ids alias for $3;
v_set_origin int4;
begin
-- ----
***************
*** 3697,3714 ****
p_set_id;
end if;
-- ----
-- Create a SYNC event, run the script and generate the DDL_SCRIPT event
-- ----
- perform @NAMESPACE at .alterTableRestore(tab_id) from @NAMESPACE at .sl_table where tab_set in (select set_id from @NAMESPACE at .sl_set where set_origin = @NAMESPACE at .getLocalNodeId(''_ at CLUSTERNAME@''));
-
perform @NAMESPACE at .createEvent(''_ at CLUSTERNAME@'', ''SYNC'', NULL);
return 1;
end;
' language plpgsql;
! comment on function @NAMESPACE at .ddlScript_prepare (int4, int4) is
! 'Prepare for DDL script execution on origin';
-- perform @NAMESPACE at .ddlScript_int(p_set_id, p_script, p_only_on_node);
--- 3717,3747 ----
p_set_id;
end if;
+
+
+ if p_lock_tab_ids is not null then
+
+ perform @NAMESPACE at .alterTableRestore(tab_id) from @NAMESPACE at .sl_table where tab_set in (select set_id from @NAMESPACE at .sl_set where set_origin = @NAMESPACE at .getLocalNodeId(''_ at CLUSTERNAME@''))
+ and tab_id =any (p_lock_tab_ids)
+ ;
+ else
+
+ perform @NAMESPACE at .alterTableRestore(tab_id) from @NAMESPACE at .sl_table where tab_set in (select set_id from @NAMESPACE at .sl_set where set_origin = @NAMESPACE at .getLocalNodeId(''_ at CLUSTERNAME@''));
+ end if;
+
-- ----
-- Create a SYNC event, run the script and generate the DDL_SCRIPT event
-- ----
perform @NAMESPACE at .createEvent(''_ at CLUSTERNAME@'', ''SYNC'', NULL);
return 1;
end;
' language plpgsql;
!
! comment on function @NAMESPACE at .ddlScript_prepare (int4, int4,int4[]) is
! 'Prepare for DDL script execution on origin. All replicated tables will be prepared if
! lock_tab_ids is null otherwise just the specified tables will be prepared. ';
!
-- perform @NAMESPACE at .ddlScript_int(p_set_id, p_script, p_only_on_node);
***************
*** 3720,3756 ****
create or replace function @NAMESPACE at .ddlScript_complete (int4, text, int4)
returns integer
as '
declare
p_set_id alias for $1;
p_script alias for $2;
p_only_on_node alias for $3;
v_set_origin int4;
begin
perform @NAMESPACE at .updateRelname(p_set_id, p_only_on_node);
! perform @NAMESPACE at .alterTableForReplication(tab_id) from @NAMESPACE at .sl_table where tab_set in (select set_id from @NAMESPACE at .sl_set where set_origin = @NAMESPACE at .getLocalNodeId(''_ at CLUSTERNAME@''));
return @NAMESPACE at .createEvent(''_ at CLUSTERNAME@'', ''DDL_SCRIPT'',
! p_set_id, p_script, p_only_on_node);
end;
' language plpgsql;
comment on function @NAMESPACE at .ddlScript_complete(int4, text, int4) is
! 'ddlScript_complete(set_id, script, only_on_node)
After script has run on origin, this fixes up relnames, restores
triggers, and generates a DDL_SCRIPT event to request it to be run on
! replicated slaves.';
-- ----------------------------------------------------------------------
! -- FUNCTION ddlScript_prepare_int (set_id, only_on_node)
--
-- Prepare for the DDL_SCRIPT event
-- ----------------------------------------------------------------------
! create or replace function @NAMESPACE at .ddlScript_prepare_int (int4, int4)
returns int4
as '
declare
p_set_id alias for $1;
p_only_on_node alias for $2;
v_set_origin int4;
v_no_id int4;
v_row record;
--- 3753,3813 ----
create or replace function @NAMESPACE at .ddlScript_complete (int4, text, int4)
returns integer
as '
+ begin
+ return @NAMESPACE at .ddlScript_complete($1,$2,$3,null);
+ end;
+ ' language plpgsql;
+
+
+ -- perform @NAMESPACE at .ddlScript_int(p_set_id, p_script, p_only_on_node);
+
+ -- ----------------------------------------------------------------------
+ -- FUNCTION ddlScript_complete (set_id, script, only_on_node)
+ --
+ -- Generate the DDL_SCRIPT event
+ -- ----------------------------------------------------------------------
+ create or replace function @NAMESPACE at .ddlScript_complete (int4, text, int4,int4[])
+ returns integer
+ as '
declare
p_set_id alias for $1;
p_script alias for $2;
p_only_on_node alias for $3;
+ p_lock_tab_ids alias for $4;
v_set_origin int4;
begin
perform @NAMESPACE at .updateRelname(p_set_id, p_only_on_node);
!
! if p_lock_tab_ids is not null then
! perform @NAMESPACE at .alterTableForReplication(tab_id) from @NAMESPACE at .sl_table where tab_set in (select set_id from @NAMESPACE at .sl_set where set_origin = @NAMESPACE at .getLocalNodeId(''_ at CLUSTERNAME@'')) and tab_id = any (p_lock_tab_ids) ;
! else
! perform @NAMESPACE at .alterTableForReplication(tab_id) from @NAMESPACE at .sl_table where tab_set in (select set_id from @NAMESPACE at .sl_set where set_origin = @NAMESPACE at .getLocalNodeId(''_ at CLUSTERNAME@''));
! end if;
!
return @NAMESPACE at .createEvent(''_ at CLUSTERNAME@'', ''DDL_SCRIPT'',
! p_set_id, p_script, p_only_on_node,array_to_string(p_lock_tab_ids,'',''));
end;
' language plpgsql;
comment on function @NAMESPACE at .ddlScript_complete(int4, text, int4) is
! 'ddlScript_complete(set_id, script, only_on_node,p_lock_tab_ids)
After script has run on origin, this fixes up relnames, restores
triggers, and generates a DDL_SCRIPT event to request it to be run on
! replicated slaves. ';
-- ----------------------------------------------------------------------
! -- FUNCTION ddlScript_prepare_int (set_id, only_on_node,lock_table_ids)
--
-- Prepare for the DDL_SCRIPT event
-- ----------------------------------------------------------------------
! create or replace function @NAMESPACE at .ddlScript_prepare_int (int4, int4,int4[])
returns int4
as '
declare
p_set_id alias for $1;
p_only_on_node alias for $2;
+ p_lock_table_ids alias for $3;
v_set_origin int4;
v_no_id int4;
v_row record;
***************
*** 3788,3797 ****
return 0;
end if;
-- ----
-- Restore all original triggers and rules of all sets
-- ----
! for v_row in select * from @NAMESPACE at .sl_table
loop
perform @NAMESPACE at .alterTableRestore(v_row.tab_id);
end loop;
--- 3845,3856 ----
return 0;
end if;
+
-- ----
-- Restore all original triggers and rules of all sets
-- ----
! for v_row in select * from @NAMESPACE at .sl_table
! where tab_id =any (p_lock_table_ids) or p_lock_table_ids is null
loop
perform @NAMESPACE at .alterTableRestore(v_row.tab_id);
end loop;
***************
*** 3799,3805 ****
end;
' language plpgsql;
! comment on function @NAMESPACE at .ddlScript_prepare_int (int4, int4) is
'ddlScript_prepare_int (set_id, only_on_node)
Do preparatory work for a DDL script, restoring
--- 3858,3864 ----
end;
' language plpgsql;
! comment on function @NAMESPACE at .ddlScript_prepare_int (int4, int4,int4[]) is
'ddlScript_prepare_int (set_id, only_on_node)
Do preparatory work for a DDL script, restoring
***************
*** 3807,3828 ****
-- ----------------------------------------------------------------------
! -- FUNCTION ddlScript_complete_int (set_id, only_on_node)
--
-- Complete the DDL_SCRIPT event
-- ----------------------------------------------------------------------
! create or replace function @NAMESPACE at .ddlScript_complete_int (int4, int4)
returns int4
as '
declare
p_set_id alias for $1;
p_only_on_node alias for $2;
v_row record;
begin
-- ----
-- Put all tables back into replicated mode
-- ----
for v_row in select * from @NAMESPACE at .sl_table
loop
perform @NAMESPACE at .alterTableForReplication(v_row.tab_id);
end loop;
--- 3866,3889 ----
-- ----------------------------------------------------------------------
! -- FUNCTION ddlScript_complete_int (set_id, only_on_node,p_lock_table_ids)
--
-- Complete the DDL_SCRIPT event
-- ----------------------------------------------------------------------
! create or replace function @NAMESPACE at .ddlScript_complete_int (int4, int4,int4[])
returns int4
as '
declare
p_set_id alias for $1;
p_only_on_node alias for $2;
+ p_lock_table_ids alias for $3;
v_row record;
begin
-- ----
-- Put all tables back into replicated mode
-- ----
for v_row in select * from @NAMESPACE at .sl_table
+ where tab_id =any (p_lock_table_ids) or p_lock_table_ids is null
loop
perform @NAMESPACE at .alterTableForReplication(v_row.tab_id);
end loop;
***************
*** 3830,3836 ****
return p_set_id;
end;
' language plpgsql;
! comment on function @NAMESPACE at .ddlScript_complete_int(int4, int4) is
'ddlScript_complete_int(set_id, script, only_on_node)
Complete processing the DDL_SCRIPT event. This puts tables back into
--- 3891,3897 ----
return p_set_id;
end;
' language plpgsql;
! comment on function @NAMESPACE at .ddlScript_complete_int(int4, int4,int4[]) is
'ddlScript_complete_int(set_id, script, only_on_node)
Complete processing the DDL_SCRIPT event. This puts tables back into
***************
*** 5902,5904 ****
--- 5963,5994 ----
to specify fields for the passed-in tab_id.
In PG versions > 7.3, this looks like (field1,field2,...fieldn)';
+
+
+
+
+
+ -- ----------------------------------------------------------------------
+ -- FUNCTION getTabId(fully_qualifed_name)
+ -- Get the slony table id for the fully qualified name
+ --
+ --
+ -- ----------------------------------------------------------------------
+ create or replace function @NAMESPACE at .getTabId(text)
+ returns integer
+ as '
+ declare
+ p_fq_name alias for $1;
+ result integer;
+ begin
+
+ select into result tab_id from @NAMESPACE at .sl_table where
+ tab_nspname || ''.'' || tab_relname = p_fq_name limit 1;
+ return result;
+ end;
+ ' language plpgsql;
+
+ comment on function @NAMESPACE at .getTabId(text) is
+ 'Returns the slony table_id for the fully qualified (schema.tablename) passed.
+ If no such table exists null is returned.
+ ';
\ No newline at end of file
Index: src/slon/remote_worker.c
===================================================================
RCS file: /usr/local/cvsroot/slony1/slony1-engine/src/slon/remote_worker.c,v
retrieving revision 1.131
diff -c -r1.131 remote_worker.c
*** src/slon/remote_worker.c 12 Dec 2006 20:13:01 -0000 1.131
--- src/slon/remote_worker.c 18 Dec 2006 04:27:57 -0000
***************
*** 1340,1360 ****
char *ddl_script = event->ev_data2;
int ddl_only_on_node = (int)strtol(event->ev_data3, NULL, 10);
int num_statements = -1, stmtno;
!
PGresult *res;
ExecStatusType rstat;
!
!
! slon_appendquery(&query1,
! "select %s.ddlScript_prepare_int(%d, %d); ",
! rtcfg_namespace,
! ddl_setid, ddl_only_on_node);
!
! if (query_execute(node, local_dbconn, &query1) < 0) {
! slon_log(SLON_ERROR, "remoteWorkerThread_%d: DDL preparation failed - set %d - only on node %\n",
! node->no_id, ddl_setid, ddl_only_on_node);
! slon_retry();
}
num_statements = scan_for_statements (ddl_script);
slon_log(SLON_CONFIG, "remoteWorkerThread_%d: DDL request with %d statements\n",
--- 1340,1371 ----
char *ddl_script = event->ev_data2;
int ddl_only_on_node = (int)strtol(event->ev_data3, NULL, 10);
int num_statements = -1, stmtno;
! const char * lock_table_list = event->ev_data4;
!
PGresult *res;
ExecStatusType rstat;
!
! if(lock_table_list != NULL )
! {
! slon_appendquery(&query1,
! "select %s.ddlScript_prepare_int(%d,%d, '{%s}'); ",
! rtcfg_namespace,
! ddl_setid, ddl_only_on_node,lock_table_list);
! }/*locks*/
! else
! {
! slon_appendquery(&query1,
! "select %s.ddlScript_prepare_int(%d, %d,null); ",
! rtcfg_namespace,
! ddl_setid, ddl_only_on_node);
! }
! if (query_execute(node, local_dbconn, &query1) < 0)
! {
! slon_log(SLON_ERROR, "remoteWorkerThread_%d: DDL preparation failed - set %d - only on node %d\n",
! node->no_id, ddl_setid, ddl_only_on_node);
! slon_retry();
}
+
num_statements = scan_for_statements (ddl_script);
slon_log(SLON_CONFIG, "remoteWorkerThread_%d: DDL request with %d statements\n",
***************
*** 1402,1411 ****
slon_log (SLON_CONFIG, "DDL success - %s\n", PQresStatus(rstat));
}
! slon_mkquery(&query1, "select %s.ddlScript_complete_int(%d, %d); ",
! rtcfg_namespace,
! ddl_setid,
! ddl_only_on_node);
/* DDL_SCRIPT needs to be turned into a log shipping script */
/* Note that the issue about parsing that mandates breaking
--- 1413,1437 ----
slon_log (SLON_CONFIG, "DDL success - %s\n", PQresStatus(rstat));
}
!
! if(lock_table_list != NULL )
! {
!
! slon_mkquery(&query1, "select %s.ddlScript_complete_int(%d,%d,'{%s}'); ",
! rtcfg_namespace,
! ddl_setid,
! ddl_only_on_node,lock_table_list);
!
! }
! else
! {
!
!
! slon_mkquery(&query1, "select %s.ddlScript_complete_int(%d, %d,null); ",
! rtcfg_namespace,
! ddl_setid,
! ddl_only_on_node);
! }
/* DDL_SCRIPT needs to be turned into a log shipping script */
/* Note that the issue about parsing that mandates breaking
***************
*** 6091,6093 ****
--- 6117,6122 ----
}
slon_log(SLON_DEBUG3, " compressed actionseq subquery... %s\n", dstring_data(action_subquery));
}
+
+
+
Index: src/slonik/parser.y
===================================================================
RCS file: /usr/local/cvsroot/slony1/slony1-engine/src/slonik/parser.y,v
retrieving revision 1.27
diff -c -r1.27 parser.y
*** src/slonik/parser.y 31 Oct 2006 22:09:40 -0000 1.27
--- src/slonik/parser.y 18 Dec 2006 04:27:58 -0000
***************
*** 50,60 ****
O_USE_KEY,
O_WAIT_CONFIRMED,
O_WAIT_ON,
!
END_OF_OPTIONS = -1
} option_code;
/*
* Common given option list
*/
--- 50,70 ----
O_USE_KEY,
O_WAIT_CONFIRMED,
O_WAIT_ON,
! O_LOCK_TABLES,
END_OF_OPTIONS = -1
} option_code;
+ /**
+ * A structure that stores a list of table names as a linked list.
+ * Table names are stored in fully qualified format.
+ */
+ typedef struct table_list {
+ char * name;
+ struct table_list * next;
+ } table_list;
+
+
/*
* Common given option list
*/
***************
*** 63,69 ****
int lineno;
int32 ival;
char *str;
!
struct option_list *next;
} option_list;
--- 73,79 ----
int lineno;
int32 ival;
char *str;
! table_list * table_list;
struct option_list *next;
} option_list;
***************
*** 76,86 ****
int lineno;
int ival;
char *str;
} statement_option;
! #define STMT_OPTION_INT(_code,_dfl) {_code, -1, _dfl, NULL}
! #define STMT_OPTION_STR(_code,_dfl) {_code, -1, -1, _dfl}
! #define STMT_OPTION_YN(_code,_dfl) {_code, -1, _dfl, NULL}
! #define STMT_OPTION_END {END_OF_OPTIONS, -1, -1, NULL}
/*
--- 86,100 ----
int lineno;
int ival;
char *str;
+ table_list * table_list;
} statement_option;
! #define STMT_OPTION_INT(_code,_dfl) {_code, -1, _dfl, NULL,NULL}
! #define STMT_OPTION_STR(_code,_dfl) {_code, -1, -1, _dfl,NULL}
! #define STMT_OPTION_YN(_code,_dfl) {_code, -1, _dfl, NULL,NULL}
! #define STMT_OPTION_TBLLIST(_code,_dfl) {_code, -1,-1,NULL,_dfl}
! #define STMT_OPTION_END {END_OF_OPTIONS, -1, -1, NULL,NULL}
!
!
/*
***************
*** 109,114 ****
--- 123,129 ----
option_list *opt_list;
SlonikAdmInfo *adm_info;
SlonikStmt *statement;
+ table_list * table_list;
}
%type <ival> id
***************
*** 169,175 ****
%type <opt_list> option_item_id
%type <opt_list> option_item_literal
%type <opt_list> option_item_yn
!
/*
* Keyword tokens
--- 184,191 ----
%type <opt_list> option_item_id
%type <opt_list> option_item_literal
%type <opt_list> option_item_yn
! %type <table_list> table_list
! %type <table_list> table_list_items
/*
* Keyword tokens
***************
*** 247,253 ****
%token K_WAIT
%token K_SYNC
%token K_SLEEP
!
/*
* Other scanner tokens
*/
--- 263,269 ----
%token K_WAIT
%token K_SYNC
%token K_SLEEP
! %token K_TABLES
/*
* Other scanner tokens
*/
***************
*** 1345,1350 ****
--- 1361,1367 ----
STMT_OPTION_STR( O_FILENAME, NULL ),
STMT_OPTION_INT( O_EVENT_NODE, 1 ),
STMT_OPTION_INT( O_EXECUTE_ONLY_ON, -1 ),
+ STMT_OPTION_TBLLIST( O_LOCK_TABLES,NULL),
STMT_OPTION_END
};
***************
*** 1354,1366 ****
new->hdr.stmt_type = STMT_DDL_SCRIPT;
new->hdr.stmt_filename = current_file;
new->hdr.stmt_lno = $1;
!
if (assign_options(opt, $4) == 0)
{
new->ddl_setid = opt[0].ival;
new->ddl_fname = opt[1].str;
new->ev_origin = opt[2].ival;
new->only_on_node = opt[3].ival;
new->ddl_fd = NULL;
}
else
--- 1371,1410 ----
new->hdr.stmt_type = STMT_DDL_SCRIPT;
new->hdr.stmt_filename = current_file;
new->hdr.stmt_lno = $1;
!
if (assign_options(opt, $4) == 0)
{
+ table_list * lock_list_ptr;
+ int lock_count;
+ int table_ind;
new->ddl_setid = opt[0].ival;
new->ddl_fname = opt[1].str;
new->ev_origin = opt[2].ival;
new->only_on_node = opt[3].ival;
+ lock_count=0;
+ for(lock_list_ptr=opt[4].table_list;
+ lock_list_ptr!=NULL;
+ lock_list_ptr=lock_list_ptr->next)
+ {
+ lock_count++;
+ }
+
+ if(lock_count > 0 )
+ {
+ new->table_locks=malloc(sizeof(char*)*lock_count+1);
+ for(lock_list_ptr=opt[4].table_list,table_ind=0;
+ lock_list_ptr!=NULL;
+ lock_list_ptr=lock_list_ptr->next,table_ind++)
+ {
+ new->table_locks[table_ind] = lock_list_ptr->name;
+
+ }
+ new->table_locks[table_ind]=NULL;
+ }
+ else
+ {
+ new->table_locks=NULL;
+ }
new->ddl_fd = NULL;
}
else
***************
*** 1662,1667 ****
--- 1706,1712 ----
new->ival = 1;
new->str = NULL;
new->lineno = yylineno;
+ new->table_list=NULL;
new->next = NULL;
$$ = new;
***************
*** 1685,1690 ****
--- 1730,1736 ----
new->ival = -2;
new->str = NULL;
new->lineno = yylineno;
+ new->table_list=NULL;
new->next = NULL;
$$ = new;
***************
*** 1703,1708 ****
--- 1749,1755 ----
new->ival = -2;
new->str = NULL;
new->lineno = yylineno;
+ new->table_list=NULL;
new->next = NULL;
$$ = new;
***************
*** 1732,1737 ****
--- 1779,1796 ----
$3->opt_code = O_SECONDS;
$$ = $3;
}
+ | K_LOCK K_TABLES '=' table_list
+ {
+ option_list * new;
+
+ new = (option_list*) malloc(sizeof(option_list));
+ new->ival=-1;
+ new->str=NULL;
+ new->next=NULL;
+ new->table_list=$4;
+ new->opt_code = O_LOCK_TABLES;
+ $$=new;
+ }
;
option_item_id : id
***************
*** 1742,1747 ****
--- 1801,1807 ----
new->ival = $1;
new->str = NULL;
new->lineno = yylineno;
+ new->table_list=NULL;
new->next = NULL;
$$ = new;
***************
*** 1756,1761 ****
--- 1816,1822 ----
new->ival = -1;
new->str = $1;
new->lineno = yylineno;
+ new->table_list=NULL;
new->next = NULL;
$$ = new;
***************
*** 1770,1775 ****
--- 1831,1837 ----
new->ival = 1;
new->str = NULL;
new->lineno = yylineno;
+ new->table_list=NULL;
new->next = NULL;
$$ = new;
***************
*** 1782,1787 ****
--- 1844,1850 ----
new->ival = 0;
new->str = NULL;
new->lineno = yylineno;
+ new->table_list=NULL;
new->next = NULL;
$$ = new;
***************
*** 1829,1836 ****
;
lno :
! { $$ = yylineno; }
;
%%
--- 1892,1920 ----
;
lno :
! { $$ = yylineno; }
;
+ table_list : '(' table_list_items ')'
+ {
+ $$=$2;
+ }
+ ;
+
+
+ table_list_items : table_list_items ',' literal
+ {
+ $$ = malloc(sizeof(table_list));
+ $$->name=$3;
+ $$->next = $1;
+ }
+ | literal
+ {
+ $$ = malloc(sizeof(table_list));
+ $$->name = $1;
+ $$->next=NULL;
+ }
+ ;
+
%%
***************
*** 1876,1881 ****
--- 1960,1966 ----
case O_USE_KEY: return "key";
case O_WAIT_CONFIRMED: return "confirmed";
case O_WAIT_ON: return "wait on";
+ case O_LOCK_TABLES: return "lock tables";
case END_OF_OPTIONS: return "???";
}
return "???";
***************
*** 1924,1929 ****
--- 2009,2015 ----
s_opt->lineno = u_opt->lineno;
s_opt->ival = u_opt->ival;
s_opt->str = u_opt->str;
+ s_opt->table_list = u_opt->table_list;
}
return errors;
Index: src/slonik/scan.l
===================================================================
RCS file: /usr/local/cvsroot/slony1/slony1-engine/src/slonik/scan.l,v
retrieving revision 1.26
diff -c -r1.26 scan.l
*** src/slonik/scan.l 31 Oct 2006 22:09:40 -0000 1.26
--- src/slonik/scan.l 18 Dec 2006 04:27:58 -0000
***************
*** 139,145 ****
update { return K_UPDATE; }
yes { return K_YES; }
wait { return K_WAIT; }
!
{digit}+ { return T_NUMBER; }
{identifier} { return T_IDENT; }
--- 139,145 ----
update { return K_UPDATE; }
yes { return K_YES; }
wait { return K_WAIT; }
! tables { return K_TABLES; }
{digit}+ { return T_NUMBER; }
{identifier} { return T_IDENT; }
Index: src/slonik/slonik.c
===================================================================
RCS file: /usr/local/cvsroot/slony1/slony1-engine/src/slonik/slonik.c,v
retrieving revision 1.71
diff -c -r1.71 slonik.c
*** src/slonik/slonik.c 12 Dec 2006 14:54:48 -0000 1.71
--- src/slonik/slonik.c 18 Dec 2006 04:28:00 -0000
***************
*** 3834,3846 ****
char rex4[256];
PGresult *res;
ExecStatusType rstat;
#define PARMCOUNT 1
const char *params[PARMCOUNT];
int paramlens[PARMCOUNT];
int paramfmts[PARMCOUNT];
!
adminfo1 = get_active_adminfo((SlonikStmt *) stmt, stmt->ev_origin);
if (adminfo1 == NULL)
return -1;
--- 3834,3847 ----
char rex4[256];
PGresult *res;
ExecStatusType rstat;
+ SlonDString lock_tab_ids;
#define PARMCOUNT 1
const char *params[PARMCOUNT];
int paramlens[PARMCOUNT];
int paramfmts[PARMCOUNT];
!
adminfo1 = get_active_adminfo((SlonikStmt *) stmt, stmt->ev_origin);
if (adminfo1 == NULL)
return -1;
***************
*** 3863,3879 ****
dstring_nappend(&script, buf, rc);
}
dstring_terminate(&script);
-
dstring_init(&query);
slon_mkquery(&query,
! "select \"_%s\".ddlScript_prepare(%d, %d); ",
! stmt->hdr.script->clustername,
! stmt->ddl_setid, /* dstring_data(&script), */
! stmt->only_on_node);
!
if (db_exec_evcommand((SlonikStmt *) stmt, adminfo1, &query) < 0)
{
dstring_free(&query);
return -1;
}
--- 3864,3943 ----
dstring_nappend(&script, buf, rc);
}
dstring_terminate(&script);
dstring_init(&query);
+ dstring_init(&lock_tab_ids);
+
+ if(stmt->table_locks!=NULL)
+ {
+
+
+ char ** table;
+ /**
+ * Only Obtain locks on the specified tables.
+ */
+ dstring_append(&lock_tab_ids,"'{");
+ for(table=stmt->table_locks;
+ *table!=NULL;
+ table++)
+ {
+ int tab_id;
+ /**
+ * Get the tab_id for each
+ */
+ slon_mkquery(&query,
+ "select \"_%s\".getTabId('%s');",
+ stmt->hdr.script->clustername,*table);
+ res = db_exec_select((SlonikStmt*) stmt,adminfo1,&query);
+ if(res==NULL)
+ {
+ dstring_free(&query);
+ dstring_free(&lock_tab_ids);
+ return -1;
+ }
+ if(PQntuples(res)==0 || PQgetisnull(res,0,0) )
+ {
+ printf("%s is not a replicated table\n",*table);
+ dstring_free(&query);
+ dstring_free(&lock_tab_ids);
+ PQclear(res);
+ return -1;
+ }
+ tab_id = atoi(PQgetvalue(res,0,0));
+ PQclear(res);
+ if(table==stmt->table_locks)
+ {
+ sprintf(buf,"%d",tab_id);
+ dstring_append(&lock_tab_ids,buf);
+ }
+ else
+ {
+ sprintf(buf,",%d",tab_id);
+ dstring_append(&lock_tab_ids,buf);
+ }
+ }
+ dstring_append(&lock_tab_ids,"}'");
+
+ }
+ else {
+ dstring_append(&lock_tab_ids,"null");
+ }
+ dstring_terminate(&lock_tab_ids);
+ /**
+ * Lock replicated tables requested. (If none requested all tables get locked)
+ */
+
+ dstring_reset(&query);
slon_mkquery(&query,
! "select \"_%s\".ddlScript_prepare(%d, %d,%s); ",
! stmt->hdr.script->clustername,
! stmt->ddl_setid, /* dstring_data(&script), */
! stmt->only_on_node,
! dstring_data(&lock_tab_ids));
!
if (db_exec_evcommand((SlonikStmt *) stmt, adminfo1, &query) < 0)
{
dstring_free(&query);
+ dstring_free(&lock_tab_ids);
return -1;
}
***************
*** 3923,3932 ****
printf("Submit DDL Event to subscribers...\n");
! slon_mkquery(&query, "select \"_%s\".ddlScript_complete(%d, $1::text, %d); ",
stmt->hdr.script->clustername,
stmt->ddl_setid,
! stmt->only_on_node);
paramlens[PARMCOUNT-1] = 0;
paramfmts[PARMCOUNT-1] = 0;
--- 3987,3997 ----
printf("Submit DDL Event to subscribers...\n");
! slon_mkquery(&query, "select \"_%s\".ddlScript_complete(%d, $1::text, %d,%s); ",
stmt->hdr.script->clustername,
stmt->ddl_setid,
! stmt->only_on_node,
! dstring_data(&lock_tab_ids));
paramlens[PARMCOUNT-1] = 0;
paramfmts[PARMCOUNT-1] = 0;
***************
*** 3950,3955 ****
--- 4015,4021 ----
dstring_free(&script);
dstring_free(&query);
+ dstring_free(&lock_tab_ids);
return 0;
}
Index: src/slonik/slonik.h
===================================================================
RCS file: /usr/local/cvsroot/slony1/slony1-engine/src/slonik/slonik.h,v
retrieving revision 1.29
diff -c -r1.29 slonik.h
*** src/slonik/slonik.h 31 Oct 2006 22:09:40 -0000 1.29
--- src/slonik/slonik.h 18 Dec 2006 04:28:00 -0000
***************
*** 408,413 ****
--- 408,414 ----
int ev_origin;
int only_on_node;
FILE *ddl_fd;
+ char ** table_locks;
};
Index: tests/testddl/exec_ddl.sh
===================================================================
RCS file: /usr/local/cvsroot/slony1/slony1-engine/tests/testddl/exec_ddl.sh,v
retrieving revision 1.2
diff -c -r1.2 exec_ddl.sh
*** tests/testddl/exec_ddl.sh 29 Mar 2006 17:10:31 -0000 1.2
--- tests/testddl/exec_ddl.sh 18 Dec 2006 04:28:00 -0000
***************
*** 5,8 ****
--- 5,16 ----
FILENAME = '${testname}/ddl_updates.sql',
EVENT NODE = 1
);
+
+ EXECUTE SCRIPT (
+ SET ID=1,
+ FILENAME = '${testname}/ddl_updates_tbl_locks.sql',
+ EVENT NODE=1,
+ LOCK TABLES=('public.table5','public.table1')
+
+ );
"
Index: tests/testddl/init_add_tables.ik
===================================================================
RCS file: /usr/local/cvsroot/slony1/slony1-engine/tests/testddl/init_add_tables.ik,v
retrieving revision 1.2
diff -c -r1.2 init_add_tables.ik
*** tests/testddl/init_add_tables.ik 9 Jan 2006 20:12:56 -0000 1.2
--- tests/testddl/init_add_tables.ik 18 Dec 2006 04:28:00 -0000
***************
*** 4,6 ****
--- 4,7 ----
set add table (id=3, set id=1, origin=1, fully qualified name = 'public.table3', key = SERIAL);
set add table (id=4, set id=1, origin=1, fully qualified name = 'public.table4');
set add table (id=5, set id=1, origin=1, fully qualified name = 'public.billing_discount');
+ set add table (id=6, set id=1, origin=1, fully qualified name='public.table5');
\ No newline at end of file
Index: tests/testddl/init_schema.sql
===================================================================
RCS file: /usr/local/cvsroot/slony1/slony1-engine/tests/testddl/init_schema.sql,v
retrieving revision 1.2
diff -c -r1.2 init_schema.sql
*** tests/testddl/init_schema.sql 9 Jan 2006 20:12:56 -0000 1.2
--- tests/testddl/init_schema.sql 18 Dec 2006 04:28:00 -0000
***************
*** 26,31 ****
--- 26,32 ----
primary key (id1, id2)
);
+
insert into table4 (data) values ('BA Baracus');
insert into table4 (data) values ('HM Murdoch');
insert into table4 (data) values ('Face');
***************
*** 48,50 ****
--- 49,61 ----
ALTER TABLE ONLY billing_discount
ADD CONSTRAINT billing_discount_pkey PRIMARY KEY (billing_discount_id);
+
+ CREATE TABLE table5 (
+
+ id serial4
+ ,a int4
+ ,PRIMARY KEY(id)
+ );
+
+ INSERT INTO table5(a) VALUES (1);
+ INSERT INTO table5(b) VALUES (2);
- Previous message: [Slony1-general] Slony-I Release 1.2.2
- Next message: [Slony1-general] "CREATE OR REPLACE function ..."
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
More information about the Slony1-general mailing list