Mon Apr 11 16:45:57 PDT 2005
- Previous message: [Slony1-commit] By darcyb: Since as of 7.4 truncate is transaction safe, lets use it in
- Next message: [Slony1-commit] By cbbrowne: More docs for log shipping and on the slon options
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Log Message: ----------- This patch adds two new functions: - slon_quote_brute is used in internal functions to add quotes around identifiers. It replaces all calls to quote_ident in all our functions. This way we quote every identifier, instead of just the reserved ones. Pro: we catch every problem with names in Caps and reserved words. Con: This will increase the size of a row in sl_log_1, as everything is quoted. - slon_quote_input is used in internal functions to make sure that user input is quoted properly. Known issues: Indexes with problematic names are not supported yet! This patch touches a lot of functions, so please test this while we are still in beta! Modified Files: -------------- slony1-engine/src/backend: slony1_funcs.sql (r1.56 -> r1.57) -------------- next part -------------- Index: slony1_funcs.sql =================================================================== RCS file: /usr/local/cvsroot/slony1/slony1-engine/src/backend/slony1_funcs.sql,v retrieving revision 1.56 retrieving revision 1.57 diff -Lsrc/backend/slony1_funcs.sql -Lsrc/backend/slony1_funcs.sql -u -w -r1.56 -r1.57 --- src/backend/slony1_funcs.sql +++ src/backend/slony1_funcs.sql @@ -252,6 +252,89 @@ comment on function @NAMESPACE at .cleanupListener() is 'look for stale pg_listener entries and submit Async_Unlisten() to them'; +-- ---------------------------------------------------------------------- +-- FUNCTION slon_quote_brute(text) +-- +-- Function that quotes a given string. +-- All existing quotes will be escaped. +-- +-- This function will be used to quote output of internal functions. +-- ---------------------------------------------------------------------- + +create or replace function @NAMESPACE at .slon_quote_brute(text) returns text +as ' +declare + p_tab_fqname alias for $1; + v_fqname text default ''''; +begin + v_fqname := ''"'' || replace(p_tab_fqname,''\"'',''\\\\"'') || ''"''; + return v_fqname; +end; +' language plpgsql; + +comment on function @NAMESPACE at .slon_quote_brute(text) is + 'Brutally quote the given text'; + +-- ---------------------------------------------------------------------- +-- FUNCTION slon_quote_input(text) +-- +-- Function that quotes a given fqn. This function quotes every +-- word that isn't quoted yet. Words or groups of words that are +-- already quoted will be untouched. +-- +-- This function will be used to quote user input. +-- ---------------------------------------------------------------------- + +create or replace function @NAMESPACE at .slon_quote_input (text) returns text +as ' +declare + p_tab_fqname alias for $1; + v_temp_fqname text default ''''; + v_pre_quoted text[] default ''{}''; + v_pre_quote_counter smallint default 0; + v_count_fqname smallint default 0; + v_fqname_split text[]; + v_quoted_fqname text default ''''; +begin + v_temp_fqname := p_tab_fqname; + + LOOP + v_pre_quote_counter := v_pre_quote_counter + 1; + v_pre_quoted[v_pre_quote_counter] := + substring(v_temp_fqname from ''%#"\"%\"#"%'' for ''#''); + IF v_pre_quoted[v_pre_quote_counter] <> '''' THEN + v_temp_fqname := replace(v_temp_fqname, + v_pre_quoted[v_pre_quote_counter], ''@'' || + v_pre_quote_counter); + ELSE + EXIT; + END IF; + END LOOP; + + v_fqname_split := string_to_array(v_temp_fqname , ''.''); + v_count_fqname := array_upper (v_fqname_split, 1); + + FOR i in 1..v_count_fqname LOOP + IF substring(v_fqname_split[i],1,1) = ''@'' THEN + v_quoted_fqname := v_quoted_fqname || + v_pre_quoted[substring (v_fqname_split[i] from 2)::int]; + ELSE + v_quoted_fqname := v_quoted_fqname || ''"'' || + v_fqname_split[i] || ''"''; + END IF; + + IF i < v_count_fqname THEN + v_quoted_fqname := v_quoted_fqname || ''.'' ; + END IF; + END LOOP; + + return v_quoted_fqname; +end; +' language plpgsql; + +comment on function @NAMESPACE at .slon_quote_input(text) is + 'quote all words that aren''t quoted yet'; + -- ********************************************************************** -- * PL/pgSQL functions for administrative tasks -- ********************************************************************** @@ -1635,8 +1718,8 @@ -- Place the lockedSet trigger on all tables in the set. -- ---- for v_tab_row in select T.tab_id, - "pg_catalog".quote_ident(PGN.nspname) || ''.'' || - "pg_catalog".quote_ident(PGC.relname) as tab_fqname + @NAMESPACE at .slon_quote_brute(PGN.nspname) || ''.'' || + @NAMESPACE at .slon_quote_brute(PGC.relname) as tab_fqname from @NAMESPACE at .sl_table T, "pg_catalog".pg_class PGC, "pg_catalog".pg_namespace PGN where T.tab_set = p_set_id @@ -1711,8 +1794,8 @@ -- Drop the lockedSet trigger from all tables in the set. -- ---- for v_tab_row in select T.tab_id, - "pg_catalog".quote_ident(PGN.nspname) || ''.'' || - "pg_catalog".quote_ident(PGC.relname) as tab_fqname + @NAMESPACE at .slon_quote_brute(PGN.nspname) || ''.'' || + @NAMESPACE at .slon_quote_brute(PGC.relname) as tab_fqname from @NAMESPACE at .sl_table T, "pg_catalog".pg_class PGC, "pg_catalog".pg_namespace PGN where T.tab_set = p_set_id @@ -2362,8 +2445,8 @@ select PGC.oid, PGC.relkind, PGC.relname, PGN.nspname into v_tab_reloid, v_relkind, v_tab_relname, v_tab_nspname from "pg_catalog".pg_class PGC, "pg_catalog".pg_namespace PGN where PGC.relnamespace = PGN.oid - and p_fqname = "pg_catalog".quote_ident(PGN.nspname) || - ''.'' || "pg_catalog".quote_ident(PGC.relname); + and @NAMESPACE at .slon_quote_input(p_fqname) = @NAMESPACE at .slon_quote_brute(PGN.nspname) || + ''.'' || @NAMESPACE at .slon_quote_brute(PGC.relname); if not found then raise exception ''Slony-I: setAddTable(): table % not found'', p_fqname; @@ -2638,8 +2721,8 @@ into v_seq_reloid, v_relkind, v_seq_relname, v_seq_nspname from "pg_catalog".pg_class PGC, "pg_catalog".pg_namespace PGN where PGC.relnamespace = PGN.oid - and p_fqname = "pg_catalog".quote_ident(PGN.nspname) || - ''.'' || "pg_catalog".quote_ident(PGC.relname); + and @NAMESPACE at .slon_quote_input(p_fqname) = @NAMESPACE at .slon_quote_brute(PGN.nspname) || + ''.'' || @NAMESPACE at .slon_quote_brute(PGC.relname); if not found then raise exception ''Slony-I: setAddSequence_int(): sequence % not found'', p_fqname; @@ -3067,8 +3150,8 @@ -- ---- -- Get the sequences fully qualified name -- ---- - select "pg_catalog".quote_ident(PGN.nspname) || ''.'' || - "pg_catalog".quote_ident(PGC.relname) into v_fqname + select @NAMESPACE at .slon_quote_brute(PGN.nspname) || ''.'' || + @NAMESPACE at .slon_quote_brute(PGC.relname) into v_fqname from @NAMESPACE at .sl_sequence SQ, "pg_catalog".pg_class PGC, "pg_catalog".pg_namespace PGN where SQ.seq_id = p_seq_id @@ -3425,8 +3508,8 @@ -- ---- select T.tab_reloid, T.tab_set, T.tab_idxname, T.tab_altered, S.set_origin, PGX.indexrelid, - "pg_catalog".quote_ident(PGN.nspname) || ''.'' || - "pg_catalog".quote_ident(PGC.relname) as tab_fqname + @NAMESPACE at .slon_quote_brute(PGN.nspname) || ''.'' || + @NAMESPACE at .slon_quote_brute(PGC.relname) as tab_fqname into v_tab_row from @NAMESPACE at .sl_table T, @NAMESPACE at .sl_set S, "pg_catalog".pg_class PGC, "pg_catalog".pg_namespace PGN, @@ -3563,8 +3646,8 @@ -- ---- select T.tab_reloid, T.tab_set, T.tab_altered, S.set_origin, PGX.indexrelid, - "pg_catalog".quote_ident(PGN.nspname) || ''.'' || - "pg_catalog".quote_ident(PGC.relname) as tab_fqname + @NAMESPACE at .slon_quote_brute(PGN.nspname) || ''.'' || + @NAMESPACE at .slon_quote_brute(PGC.relname) as tab_fqname into v_tab_row from @NAMESPACE at .sl_table T, @NAMESPACE at .sl_set S, "pg_catalog".pg_class PGC, "pg_catalog".pg_namespace PGN, @@ -4146,10 +4229,12 @@ as ' declare p_tab_fqname alias for $1; + v_tab_fqname_quoted text default ''''; v_attkind text default ''''; v_attrow record; v_have_serial bool default ''f''; begin + v_tab_fqname_quoted := @NAMESPACE at .slon_quote_input(p_tab_fqname); -- -- Loop over the attributes of this relation -- and add a "v" for every user column, and a "k" @@ -4159,8 +4244,8 @@ from "pg_catalog".pg_class PGC, "pg_catalog".pg_namespace PGN, "pg_catalog".pg_attribute PGA - where "pg_catalog".quote_ident(PGN.nspname) || ''.'' || - "pg_catalog".quote_ident(PGC.relname) = p_tab_fqname + where @NAMESPACE at .slon_quote_brute(PGN.nspname) || ''.'' || + @NAMESPACE at .slon_quote_brute(PGC.relname) = v_tab_fqname_quoted and PGN.oid = PGC.relnamespace and PGA.attrelid = PGC.oid and not PGA.attisdropped @@ -4180,7 +4265,7 @@ -- anything means the table does not exist. -- if not found then - raise exception ''Slony-I: table % not found'', p_tab_fqname; + raise exception ''Slony-I: table % not found'', v_tab_fqname_quoted; end if; -- @@ -4191,11 +4276,11 @@ -- updating all existing rows. -- if not v_have_serial then - execute ''lock table '' || p_tab_fqname || + execute ''lock table '' || v_tab_fqname_quoted || '' in access exclusive mode''; - execute ''alter table only '' || p_tab_fqname || + execute ''alter table only '' || v_tab_fqname_quoted || '' add column "_Slony-I_ at CLUSTERNAME@_rowID" bigint;''; - execute ''alter table only '' || p_tab_fqname || + execute ''alter table only '' || v_tab_fqname_quoted || '' alter column "_Slony-I_ at CLUSTERNAME@_rowID" '' || '' set default "pg_catalog".nextval(''''@NAMESPACE at .sl_rowid_seq'''');''; @@ -4236,8 +4321,8 @@ -- ---- -- Construct the tables fully qualified name and get its oid -- ---- - select "pg_catalog".quote_ident(PGN.nspname) || ''.'' || - "pg_catalog".quote_ident(PGC.relname), + select @NAMESPACE at .slon_quote_brute(PGN.nspname) || ''.'' || + @NAMESPACE at .slon_quote_brute(PGC.relname), PGC.oid into v_tab_fqname, v_tab_oid from @NAMESPACE at .sl_table T, "pg_catalog".pg_class PGC, @@ -4282,19 +4367,21 @@ as ' declare p_tab_fqname alias for $1; + v_tab_fqname_quoted text default ''''; p_idx_name alias for $2; v_idxrow record; begin + v_tab_fqname_quoted := @NAMESPACE at .slon_quote_input(p_tab_fqname); -- -- Ensure that the table exists -- if (select PGC.relname from "pg_catalog".pg_class PGC, "pg_catalog".pg_namespace PGN - where "pg_catalog".quote_ident(PGN.nspname) || ''.'' || - "pg_catalog".quote_ident(PGC.relname) = p_tab_fqname + where @NAMESPACE at .slon_quote_brute(PGN.nspname) || ''.'' || + @NAMESPACE at .slon_quote_brute(PGC.relname) = v_tab_fqname_quoted and PGN.oid = PGC.relnamespace) is null then - raise exception ''Slony-I: table % not found'', p_tab_fqname; + raise exception ''Slony-I: table % not found'', v_tab_fqname_quoted; end if; -- @@ -4307,15 +4394,15 @@ "pg_catalog".pg_namespace PGN, "pg_catalog".pg_index PGX, "pg_catalog".pg_class PGXC - where "pg_catalog".quote_ident(PGN.nspname) || ''.'' || - "pg_catalog".quote_ident(PGC.relname) = p_tab_fqname + where @NAMESPACE at .slon_quote_brute(PGN.nspname) || ''.'' || + @NAMESPACE at .slon_quote_brute(PGC.relname) = v_tab_fqname_quoted and PGN.oid = PGC.relnamespace and PGX.indrelid = PGC.oid and PGX.indexrelid = PGXC.oid and PGX.indisprimary; if not found then raise exception ''Slony-I: table % has no primary key'', - p_tab_fqname; + v_tab_fqname_quoted; end if; else select PGXC.relname @@ -4324,8 +4411,8 @@ "pg_catalog".pg_namespace PGN, "pg_catalog".pg_index PGX, "pg_catalog".pg_class PGXC - where "pg_catalog".quote_ident(PGN.nspname) || ''.'' || - "pg_catalog".quote_ident(PGC.relname) = p_tab_fqname + where @NAMESPACE at .slon_quote_brute(PGN.nspname) || ''.'' || + @NAMESPACE at .slon_quote_brute(PGC.relname) = v_tab_fqname_quoted and PGN.oid = PGC.relnamespace and PGX.indrelid = PGC.oid and PGX.indexrelid = PGXC.oid @@ -4333,7 +4420,7 @@ and PGXC.relname = p_idx_name; if not found then raise exception ''Slony-I: table % has no unique index %'', - p_tab_fqname, p_idx_name; + v_tab_fqname_quoted, p_idx_name; end if; end if; @@ -4360,8 +4447,10 @@ as ' declare p_tab_fqname alias for $1; + v_tab_fqname_quoted text default ''''; v_row record; begin + v_tab_fqname_quoted := @NAMESPACE at .slon_quote_input(p_tab_fqname); -- -- Lookup the table name alone -- @@ -4369,12 +4458,12 @@ into v_row from "pg_catalog".pg_class PGC, "pg_catalog".pg_namespace PGN - where "pg_catalog".quote_ident(PGN.nspname) || ''.'' || - "pg_catalog".quote_ident(PGC.relname) = p_tab_fqname + where @NAMESPACE at .slon_quote_brute(PGN.nspname) || ''.'' || + @NAMESPACE at .slon_quote_brute(PGC.relname) = v_tab_fqname_quoted and PGN.oid = PGC.relnamespace; if not found then raise exception ''Slony-I: table % not found'', - p_tab_fqname; + v_tab_fqname_quoted; end if; -- @@ -4399,7 +4488,9 @@ as ' declare p_tab_fqname alias for $1; + v_tab_fqname_quoted text default ''''; p_idx_name alias for $2; + v_idx_name_quoted text; v_idxrow record; v_attrow record; v_i integer; @@ -4407,16 +4498,18 @@ v_attkind text default ''''; v_attfound bool; begin + v_tab_fqname_quoted := @NAMESPACE at .slon_quote_input(p_tab_fqname); + v_idx_name_quoted := @NAMESPACE at .slon_quote_input(p_idx_name); -- -- Ensure that the table exists -- if (select PGC.relname from "pg_catalog".pg_class PGC, "pg_catalog".pg_namespace PGN - where "pg_catalog".quote_ident(PGN.nspname) || ''.'' || - "pg_catalog".quote_ident(PGC.relname) = p_tab_fqname + where @NAMESPACE at .slon_quote_brute(PGN.nspname) || ''.'' || + @NAMESPACE at .slon_quote_brute(PGC.relname) = v_tab_fqname_quoted and PGN.oid = PGC.relnamespace) is null then - raise exception ''Slony-I: table % not found'', p_tab_fqname; + raise exception ''Slony-I: table % not found'', v_tab_fqname_quoted; end if; -- @@ -4431,16 +4524,16 @@ "pg_catalog".pg_namespace PGN, "pg_catalog".pg_index PGX, "pg_catalog".pg_class PGXC - where "pg_catalog".quote_ident(PGN.nspname) || ''.'' || - "pg_catalog".quote_ident(PGC.relname) = p_tab_fqname + where @NAMESPACE at .slon_quote_brute(PGN.nspname) || ''.'' || + @NAMESPACE at .slon_quote_brute(PGC.relname) = v_tab_fqname_quoted and PGN.oid = PGC.relnamespace and PGX.indrelid = PGC.oid and PGX.indexrelid = PGXC.oid and PGX.indisunique - and PGXC.relname = p_idx_name; + and @NAMESPACE at .slon_quote_brute(PGXC.relname::text) = v_idx_name_quoted; if not found then raise exception ''Slony-I: table % has no unique index %'', - p_tab_fqname, p_idx_name; + v_tab_fqname_quoted, p_idx_name; end if; end if; @@ -4453,8 +4546,8 @@ from "pg_catalog".pg_class PGC, "pg_catalog".pg_namespace PGN, "pg_catalog".pg_attribute PGA - where "pg_catalog".quote_ident(PGN.nspname) || ''.'' || - "pg_catalog".quote_ident(PGC.relname) = p_tab_fqname + where @NAMESPACE at .slon_quote_brute(PGN.nspname) || ''.'' || + @NAMESPACE at .slon_quote_brute(PGC.relname) = v_tab_fqname_quoted and PGN.oid = PGC.relnamespace and PGA.attrelid = PGC.oid and not PGA.attisdropped @@ -4511,10 +4604,12 @@ as ' declare p_tab_fqname alias for $1; + v_tab_fqname_quoted text default ''''; v_attkind text default ''''; v_attrow record; v_have_serial bool default ''f''; begin + v_tab_fqname_quoted := @NAMESPACE at .slon_quote_input(p_tab_fqname); -- -- Loop over the attributes of this relation -- and add a "v" for every user column, and a "k" @@ -4524,8 +4619,8 @@ from "pg_catalog".pg_class PGC, "pg_catalog".pg_namespace PGN, "pg_catalog".pg_attribute PGA - where "pg_catalog".quote_ident(PGN.nspname) || ''.'' || - "pg_catalog".quote_ident(PGC.relname) = p_tab_fqname + where @NAMESPACE at .slon_quote_brute(PGN.nspname) || ''.'' || + @NAMESPACE at .slon_quote_brute(PGC.relname) = v_tab_fqname_quoted and PGN.oid = PGC.relnamespace and PGA.attrelid = PGC.oid and not PGA.attisdropped @@ -4545,7 +4640,7 @@ -- anything means the table does not exist. -- if not found then - raise exception ''Slony-I: table % not found'', p_tab_fqname; + raise exception ''Slony-I: table % not found'', v_tab_fqname_quoted; end if; -- @@ -4554,15 +4649,15 @@ -- if not v_have_serial then raise exception ''Slony-I: table % does not have the serial key'', - p_tab_fqname; + v_tab_fqname_quoted; end if; - execute ''update '' || p_tab_fqname || + execute ''update '' || v_tab_fqname_quoted || '' set "_Slony-I_ at CLUSTERNAME@_rowID" ='' || '' "pg_catalog".nextval(''''@NAMESPACE at .sl_rowid_seq'''');''; - execute ''alter table only '' || p_tab_fqname || + execute ''alter table only '' || v_tab_fqname_quoted || '' add unique ("_Slony-I_ at CLUSTERNAME@_rowID");''; - execute ''alter table only '' || p_tab_fqname || + execute ''alter table only '' || v_tab_fqname_quoted || '' alter column "_Slony-I_ at CLUSTERNAME@_rowID" '' || '' set not null;''; @@ -4748,14 +4843,16 @@ as ' declare p_tab_fqname alias for $1; + v_tab_fqname_quoted text default ''''; v_attnum int2; begin + v_tab_fqname_quoted := @NAMESPACE at .slon_quote_input(p_tab_fqname); select PGA.attnum into v_attnum from "pg_catalog".pg_class PGC, "pg_catalog".pg_namespace PGN, "pg_catalog".pg_attribute PGA - where "pg_catalog".quote_ident(PGN.nspname) || ''.'' || - "pg_catalog".quote_ident(PGC.relname) = p_tab_fqname + where @NAMESPACE at .slon_quote_brute(PGN.nspname) || ''.'' || + @NAMESPACE at .slon_quote_brute(PGC.relname) = v_tab_fqname_quoted and PGC.relnamespace = PGN.oid and PGA.attrelid = PGC.oid and PGA.attname = ''_Slony-I_ at CLUSTERNAME@_rowID'' @@ -4882,16 +4979,16 @@ update @NAMESPACE at .sl_table set tab_reloid = PGC.oid from pg_catalog.pg_class PGC, pg_catalog.pg_namespace PGN - where pg_catalog.quote_ident(@NAMESPACE at .sl_table.tab_relname) = pg_catalog.quote_ident(PGC.relname) + where @NAMESPACE at .slon_quote_brute(@NAMESPACE at .sl_table.tab_relname) = @NAMESPACE at .slon_quote_brute(PGC.relname) and PGC.relnamespace = PGN.oid - and pg_catalog.quote_ident(PGN.nspname) = pg_catalog.quote_ident(@NAMESPACE at .sl_table.tab_nspname); + and @NAMESPACE at .slon_quote_brute(PGN.nspname) = @NAMESPACE at .slon_quote_brute(@NAMESPACE at .sl_table.tab_nspname); update @NAMESPACE at .sl_sequence set seq_reloid = PGC.oid from pg_catalog.pg_class PGC, pg_catalog.pg_namespace PGN - where pg_catalog.quote_ident(@NAMESPACE at .sl_sequence.seq_relname) = pg_catalog.quote_ident(PGC.relname) + where @NAMESPACE at .slon_quote_brute(@NAMESPACE at .sl_sequence.seq_relname) = @NAMESPACE at .slon_quote_brute(PGC.relname) and PGC.relnamespace = PGN.oid - and pg_catalog.quote_ident(PGN.nspname) = pg_catalog.quote_ident(@NAMESPACE at .sl_sequence.seq_nspname); + and @NAMESPACE at .slon_quote_brute(PGN.nspname) = @NAMESPACE at .slon_quote_brute(@NAMESPACE at .sl_sequence.seq_nspname); return @NAMESPACE at .createEvent(''_ at CLUSTERNAME@'', ''RESET_CONFIG'', p_set_id, p_only_on_node); @@ -4920,11 +5017,11 @@ v_query text; BEGIN select 1 into v_row from pg_namespace n, pg_class c, pg_attribute a - where quote_ident(n.nspname) = p_namespace and + where @NAMESPACE at .slon_quote_brute(n.nspname) = p_namespace and c.relnamespace = n.oid and - quote_ident(c.relname) = p_table and + @NAMESPACE at .slon_quote_brute(c.relname) = p_table and a.attrelid = c.oid and - quote_ident(a.attname) = p_field; + @NAMESPACE at .slon_quote_brute(a.attname) = p_field; if not found then raise notice ''Upgrade table %.% - add field %'', p_namespace, p_table, p_field; v_query := ''alter table '' || p_namespace || ''.'' || p_table || '' add column '';
- Previous message: [Slony1-commit] By darcyb: Since as of 7.4 truncate is transaction safe, lets use it in
- Next message: [Slony1-commit] By cbbrowne: More docs for log shipping and on the slon options
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
More information about the Slony1-commit mailing list