fields_requiring_mapping was removed
[migration-tools.git] / sql / base / 00-infrastructure.sql
1 -- Copyright 2009-2012, Equinox Software, Inc.
2 --
3 -- This program is free software; you can redistribute it and/or
4 -- modify it under the terms of the GNU General Public License
5 -- as published by the Free Software Foundation; either version 2
6 -- of the License, or (at your option) any later version.
7 --
8 -- This program is distributed in the hope that it will be useful,
9 -- but WITHOUT ANY WARRANTY; without even the implied warranty of
10 -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 -- GNU General Public License for more details.
12 --
13 -- You should have received a copy of the GNU General Public License
14 -- along with this program; if not, write to the Free Software
15 -- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
16
17 --------------------------------------------------------------------------
18 -- An example of how to use:
19 -- 
20 -- DROP SCHEMA foo CASCADE; CREATE SCHEMA foo; 
21 -- \i base.sql
22 -- SELECT migration_tools.init('foo');
23 -- SELECT migration_tools.build('foo');
24 -- \d foo.actor_usr
25 -- create some incoming ILS specific staging tables, like CREATE foo.legacy_items ( l_barcode TEXT, .. ) INHERITS (foo.asset_copy);
26 -- Do some mapping, like UPDATE foo.legacy_items SET barcode = TRIM(BOTH ' ' FROM l_barcode);
27 -- Then, to move into production, do things like:
28 --  insert into asset.copy select * from asset_copy where id not in (select id from asset_copy_legacy where not x_migrate);
29
30 DROP SCHEMA IF EXISTS migration_tools CASCADE;
31 CREATE SCHEMA migration_tools;
32
33 CREATE OR REPLACE FUNCTION migration_tools.production_tables (TEXT) RETURNS TEXT[] AS $$
34     DECLARE
35         migration_schema ALIAS FOR $1;
36         output  RECORD;
37     BEGIN
38         FOR output IN
39             EXECUTE 'SELECT string_to_array(value,'','') AS tables FROM ' || migration_schema || '.config WHERE key = ''production_tables'';'
40         LOOP
41             RETURN output.tables;
42         END LOOP;
43     END;
44 $$ LANGUAGE PLPGSQL STRICT STABLE;
45
46 CREATE OR REPLACE FUNCTION migration_tools.init (TEXT) RETURNS VOID AS $$
47     DECLARE
48         migration_schema ALIAS FOR $1;
49         sql TEXT;
50     BEGIN
51         EXECUTE 'DROP TABLE IF EXISTS ' || migration_schema || '.config;';
52         EXECUTE 'CREATE TABLE ' || migration_schema || '.config ( key TEXT UNIQUE, value TEXT);';
53         EXECUTE 'INSERT INTO ' || migration_schema || '.config (key,value) VALUES ( ''production_tables'', ''asset.call_number,asset.call_number_prefix,asset.call_number_suffix,asset.copy_location,asset.copy,asset.copy_alert,asset.stat_cat,asset.stat_cat_entry,asset.stat_cat_entry_copy_map,asset.copy_note,actor.usr,actor.card,actor.usr_address,actor.stat_cat,actor.stat_cat_entry,actor.stat_cat_entry_usr_map,actor.usr_note,actor.usr_standing_penalty,actor.usr_setting,action.circulation,action.hold_request,action.hold_notification,action.hold_request_note,action.hold_transit_copy,action.transit_copy,money.grocery,money.billing,money.cash_payment,money.forgive_payment,acq.provider,acq.provider_address,acq.provider_note,acq.provider_contact,acq.provider_contact_address,acq.fund,acq.fund_allocation,acq.fund_tag,acq.fund_tag_map,acq.funding_source,acq.funding_source_credit,acq.lineitem,acq.purchase_order,acq.po_item,acq.invoice,acq.invoice_item,acq.invoice_entry,acq.lineitem_detail,acq.fund_debit,acq.fund_transfer,acq.po_note,config.circ_matrix_matchpoint,config.circ_matrix_limit_set_map,config.hold_matrix_matchpoint,asset.copy_tag,asset.copy_tag_copy_map,config.copy_tag_type,serial.item,serial.item_note,serial.record_entry,biblio.record_entry'' );';
54     END;
55 $$ LANGUAGE PLPGSQL STRICT VOLATILE;
56
57 CREATE OR REPLACE FUNCTION migration_tools.build (TEXT) RETURNS VOID AS $$
58     DECLARE
59         migration_schema ALIAS FOR $1;
60         production_tables TEXT[];
61     BEGIN
62         SELECT migration_tools.production_tables(migration_schema) INTO STRICT production_tables;
63         PERFORM migration_tools.build_base_staging_tables(migration_schema,production_tables);
64         EXECUTE 'CREATE UNIQUE INDEX ' || migration_schema || '_patron_barcode_key ON ' || migration_schema || '.m_actor_card ( barcode );';
65         EXECUTE 'CREATE UNIQUE INDEX ' || migration_schema || '_patron_usrname_key ON ' || migration_schema || '.m_actor_usr ( usrname );';
66         EXECUTE 'CREATE UNIQUE INDEX ' || migration_schema || '_copy_barcode_key ON ' || migration_schema || '.m_asset_copy ( barcode );';
67         EXECUTE 'CREATE UNIQUE INDEX ' || migration_schema || '_copy_id_key ON ' || migration_schema || '.m_asset_copy ( id );';
68         EXECUTE 'CREATE INDEX ' || migration_schema || '_callnum_record_idx ON ' || migration_schema || '.m_asset_call_number ( record );';
69         EXECUTE 'CREATE INDEX ' || migration_schema || '_callnum_upper_label_id_lib_idx ON ' || migration_schema || '.m_asset_call_number ( UPPER(label),id,owning_lib );';
70         EXECUTE 'CREATE UNIQUE INDEX ' || migration_schema || '_callnum_label_once_per_lib ON ' || migration_schema || '.m_asset_call_number ( record,owning_lib,label,prefix,suffix );';
71     END;
72 $$ LANGUAGE PLPGSQL STRICT VOLATILE;
73
74 CREATE OR REPLACE FUNCTION migration_tools.build_base_staging_tables (TEXT,TEXT[]) RETURNS VOID AS $$
75     DECLARE
76         migration_schema ALIAS FOR $1;
77         production_tables ALIAS FOR $2;
78     BEGIN
79         FOR i IN array_lower(production_tables,1) .. array_upper(production_tables,1) LOOP
80             PERFORM migration_tools.build_specific_base_staging_table(migration_schema,production_tables[i]);
81         END LOOP;
82     END;
83 $$ LANGUAGE PLPGSQL STRICT VOLATILE;
84
85 CREATE OR REPLACE FUNCTION migration_tools.build_specific_base_staging_table (TEXT,TEXT) RETURNS VOID AS $$
86     DECLARE
87         migration_schema ALIAS FOR $1;
88         production_table ALIAS FOR $2;
89         base_staging_table TEXT;
90         columns RECORD;
91     BEGIN
92         base_staging_table = REPLACE( 'm_' || production_table, '.', '_' );
93         EXECUTE 'CREATE TABLE ' || migration_schema || '.' || base_staging_table || ' ( LIKE ' || production_table || ' INCLUDING DEFAULTS EXCLUDING CONSTRAINTS );';
94         FOR columns IN 
95             SELECT table_schema, table_name, column_name, data_type
96             FROM information_schema.columns 
97             WHERE table_schema = migration_schema AND table_name = base_staging_table AND is_nullable = 'NO' AND column_default IS NULL
98         LOOP
99             EXECUTE 'ALTER TABLE ' || columns.table_schema || '.' || columns.table_name || ' ALTER COLUMN ' || columns.column_name || ' DROP NOT NULL;';
100         END LOOP;
101     END;
102 $$ LANGUAGE PLPGSQL STRICT VOLATILE;
103
104 CREATE OR REPLACE FUNCTION migration_tools.create_linked_legacy_table_from (TEXT,TEXT,TEXT) RETURNS VOID AS $$
105     DECLARE
106         migration_schema ALIAS FOR $1;
107         parent_table ALIAS FOR $2;
108         source_table ALIAS FOR $3;
109         columns RECORD;
110         create_sql TEXT;
111         insert_sql TEXT;
112         column_list TEXT := '';
113         column_count INTEGER := 0;
114     BEGIN
115         create_sql := 'CREATE TABLE ' || migration_schema || '.' || parent_table || '_legacy ( ';
116         FOR columns IN
117             SELECT table_schema, table_name, column_name, data_type, numeric_precision, numeric_scale
118             FROM information_schema.columns
119             WHERE table_schema = migration_schema AND table_name = source_table
120         LOOP
121             column_count := column_count + 1;
122             if column_count > 1 then
123                 create_sql := create_sql || ', ';
124                 column_list := column_list || ', ';
125             end if;
126             create_sql := create_sql || columns.column_name || ' ';
127             if columns.data_type = 'ARRAY' then
128                 create_sql := create_sql || 'TEXT[]';
129             elsif columns.data_type = 'numeric' then
130                 create_sql := create_sql || 'NUMERIC('||columns.numeric_precision||','||columns.numeric_scale||')';
131             else
132                 create_sql := create_sql || columns.data_type;
133             end if;
134             column_list := column_list || columns.column_name;
135         END LOOP;
136         create_sql := create_sql || ' ) INHERITS ( ' || migration_schema || '.' || parent_table || ' );';
137         --RAISE INFO 'create_sql = %', create_sql;
138         EXECUTE create_sql;
139         insert_sql := 'INSERT INTO ' || migration_schema || '.' || parent_table || '_legacy (' || column_list || ') SELECT ' || column_list || ' FROM ' || migration_schema || '.' || source_table || ';';
140         --RAISE INFO 'insert_sql = %', insert_sql;
141         EXECUTE insert_sql;
142     END;
143 $$ LANGUAGE PLPGSQL STRICT VOLATILE;
144
145 -- creates other child table so you can have more than one child table in a schema from a base table 
146 CREATE OR REPLACE FUNCTION migration_tools.build_variant_staging_table(text, text, text)
147  RETURNS void
148  LANGUAGE plpgsql
149  STRICT
150 AS $function$
151     DECLARE
152         migration_schema ALIAS FOR $1;
153         production_table ALIAS FOR $2;
154         base_staging_table ALIAS FOR $3;
155         columns RECORD;
156     BEGIN
157         --RAISE INFO 'In migration_tools.build_specific_base_staging_table(%,%) -> %', migration_schema, production_table, base_staging_table;
158         EXECUTE 'CREATE TABLE ' || migration_schema || '.' || base_staging_table || ' ( LIKE ' || production_table || ' INCLUDING DEFAULTS EXCLUDING CONSTRAINTS );';
159         FOR columns IN
160             SELECT table_schema, table_name, column_name, data_type
161             FROM information_schema.columns
162             WHERE table_schema = migration_schema AND table_name = base_staging_table AND is_nullable = 'NO' AND column_default IS NULL
163         LOOP
164             EXECUTE 'ALTER TABLE ' || columns.table_schema || '.' || columns.table_name || ' ALTER COLUMN ' || columns.column_name || ' DROP NOT NULL;';
165         END LOOP;
166     END;
167 $function$;
168
169 CREATE OR REPLACE FUNCTION migration_tools.assert (BOOLEAN) RETURNS VOID AS $$
170     DECLARE
171         test ALIAS FOR $1;
172     BEGIN
173         IF NOT test THEN
174             RAISE EXCEPTION 'assertion';
175         END IF;
176     END;
177 $$ LANGUAGE PLPGSQL STRICT VOLATILE;
178
179 CREATE OR REPLACE FUNCTION migration_tools.assert (BOOLEAN,TEXT) RETURNS VOID AS $$
180     DECLARE
181         test ALIAS FOR $1;
182         msg ALIAS FOR $2;
183     BEGIN
184         IF NOT test THEN
185             RAISE EXCEPTION '%', msg;
186         END IF;
187     END;
188 $$ LANGUAGE PLPGSQL STRICT VOLATILE;
189
190 CREATE OR REPLACE FUNCTION migration_tools.assert (BOOLEAN,TEXT,TEXT) RETURNS TEXT AS $$
191     DECLARE
192         test ALIAS FOR $1;
193         fail_msg ALIAS FOR $2;
194         success_msg ALIAS FOR $3;
195     BEGIN
196         IF NOT test THEN
197             RAISE EXCEPTION '%', fail_msg;
198         END IF;
199         RETURN success_msg;
200     END;
201 $$ LANGUAGE PLPGSQL STRICT VOLATILE;
202