3 INSERT INTO config.upgrade_log (version, applied_to) VALUES ('1056', :eg_version); -- miker/gmcharlt
5 INSERT INTO permission.perm_list (id,code,description) VALUES (592,'CONTAINER_BATCH_UPDATE','Allow batch update via buckets');
7 INSERT INTO container.user_bucket_type (code,label) SELECT code,label FROM container.copy_bucket_type where code = 'staff_client';
9 CREATE TABLE action.fieldset_group (
10 id SERIAL PRIMARY KEY,
12 create_time TIMESTAMPTZ NOT NULL DEFAULT NOW(),
13 complete_time TIMESTAMPTZ,
14 container INT, -- Points to a container of some type ...
15 container_type TEXT, -- One of 'biblio_record_entry', 'user', 'call_number', 'copy'
16 can_rollback BOOL DEFAULT TRUE,
17 rollback_group INT REFERENCES action.fieldset_group (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
18 rollback_time TIMESTAMPTZ,
19 creator INT NOT NULL REFERENCES actor.usr (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
20 owning_lib INT NOT NULL REFERENCES actor.org_unit (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED
23 ALTER TABLE action.fieldset ADD COLUMN fieldset_group INT REFERENCES action.fieldset_group (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED;
24 ALTER TABLE action.fieldset ADD COLUMN error_msg TEXT;
25 ALTER TABLE container.biblio_record_entry_bucket ADD COLUMN owning_lib INT REFERENCES actor.org_unit (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED;
26 ALTER TABLE container.user_bucket ADD COLUMN owning_lib INT REFERENCES actor.org_unit (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED;
27 ALTER TABLE container.call_number_bucket ADD COLUMN owning_lib INT REFERENCES actor.org_unit (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED;
28 ALTER TABLE container.copy_bucket ADD COLUMN owning_lib INT REFERENCES actor.org_unit (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED;
30 UPDATE query.stored_query SET id = id + 1000 WHERE id < 1000;
31 UPDATE query.from_relation SET id = id + 1000 WHERE id < 1000;
32 UPDATE query.expression SET id = id + 1000 WHERE id < 1000;
34 SELECT SETVAL('query.stored_query_id_seq', 1, FALSE);
35 SELECT SETVAL('query.from_relation_id_seq', 1, FALSE);
36 SELECT SETVAL('query.expression_id_seq', 1, FALSE);
38 INSERT INTO query.bind_variable (name,type,description,label)
39 SELECT 'bucket','number','ID of the bucket to pull items from','Bucket ID'
40 WHERE NOT EXISTS (SELECT 1 FROM query.bind_variable WHERE name = 'bucket');
42 -- Assumes completely empty 'query' schema
43 INSERT INTO query.stored_query (type, use_distinct) VALUES ('SELECT', TRUE); -- 1
45 INSERT INTO query.from_relation (type, table_name, class_name, table_alias) VALUES ('RELATION', 'container.user_bucket_item', 'cubi', 'cubi'); -- 1
46 UPDATE query.stored_query SET from_clause = 1;
48 INSERT INTO query.expr_xcol (table_alias, column_name) VALUES ('cubi', 'target_user'); -- 1
49 INSERT INTO query.select_item (stored_query,seq_no,expression) VALUES (1,1,1);
51 INSERT INTO query.expr_xcol (table_alias, column_name) VALUES ('cubi', 'bucket'); -- 2
52 INSERT INTO query.expr_xbind (bind_variable) VALUES ('bucket'); -- 3
54 INSERT INTO query.expr_xop (left_operand, operator, right_operand) VALUES (2, '=', 3); -- 4
55 UPDATE query.stored_query SET where_clause = 4;
57 SELECT SETVAL('query.stored_query_id_seq', 1000, TRUE) FROM query.stored_query;
58 SELECT SETVAL('query.from_relation_id_seq', 1000, TRUE) FROM query.from_relation;
59 SELECT SETVAL('query.expression_id_seq', 10000, TRUE) FROM query.expression;
61 CREATE OR REPLACE FUNCTION action.apply_fieldset(
62 fieldset_id IN INT, -- id from action.fieldset
63 table_name IN TEXT, -- table to be updated
64 pkey_name IN TEXT, -- name of primary key column in that table
65 query IN TEXT -- query constructed by qstore (for query-based
66 -- fieldsets only; otherwise null
82 fs_obj action.fieldset%ROWTYPE;
83 fs_group action.fieldset_group%ROWTYPE;
87 IF fieldset_id IS NULL THEN
88 RETURN 'Fieldset ID parameter is NULL';
90 IF table_name IS NULL THEN
91 RETURN 'Table name parameter is NULL';
93 IF pkey_name IS NULL THEN
94 RETURN 'Primary key name parameter is NULL';
99 quote_literal( pkey_value )
109 -- Build the WHERE clause. This differs according to whether it's a
110 -- single-row fieldset or a query-based fieldset.
112 IF query IS NULL AND fs_pkey_value IS NULL THEN
113 RETURN 'Incomplete fieldset: neither a primary key nor a query available';
114 ELSIF query IS NOT NULL AND fs_pkey_value IS NULL THEN
115 fs_query := rtrim( query, ';' );
116 where_clause := 'WHERE ' || pkey_name || ' IN ( '
118 ELSIF query IS NULL AND fs_pkey_value IS NOT NULL THEN
119 where_clause := 'WHERE ' || pkey_name || ' = ';
120 IF pkey_name = 'id' THEN
121 where_clause := where_clause || fs_pkey_value;
122 ELSIF pkey_name = 'code' THEN
123 where_clause := where_clause || quote_literal(fs_pkey_value);
125 RETURN 'Only know how to handle "id" and "code" pkeys currently, received ' || pkey_name;
127 ELSE -- both are not null
128 RETURN 'Ambiguous fieldset: both a primary key and a query provided';
131 IF fs_status IS NULL THEN
132 RETURN 'No fieldset found for id = ' || fieldset_id;
133 ELSIF fs_status = 'APPLIED' THEN
134 RETURN 'Fieldset ' || fieldset_id || ' has already been applied';
137 SELECT * INTO fs_obj FROM action.fieldset WHERE id = fieldset_id;
138 SELECT * INTO fs_group FROM action.fieldset_group WHERE id = fs_obj.fieldset_group;
140 IF fs_group.can_rollback THEN
141 -- This is part of a non-rollback group. We need to record the current values for future rollback.
143 INSERT INTO action.fieldset_group (can_rollback, name, creator, owning_lib, container, container_type)
144 VALUES (FALSE, 'ROLLBACK: '|| fs_group.name, fs_group.creator, fs_group.owning_lib, fs_group.container, fs_group.container_type);
146 fsg_id := CURRVAL('action.fieldset_group_id_seq');
148 FOR rb_row IN EXECUTE 'SELECT * FROM ' || table_name || ' ' || where_clause LOOP
149 IF pkey_name = 'id' THEN
150 fs_pkey_value := rb_row.id;
151 ELSIF pkey_name = 'code' THEN
152 fs_pkey_value := rb_row.code;
154 RETURN 'Only know how to handle "id" and "code" pkeys currently, received ' || pkey_name;
156 INSERT INTO action.fieldset (fieldset_group,owner,owning_lib,status,classname,name,pkey_value)
157 VALUES (fsg_id, fs_obj.owner, fs_obj.owning_lib, 'PENDING', fs_obj.classname, fs_obj.name || ' ROLLBACK FOR ' || fs_pkey_value, fs_pkey_value);
159 fs_id := CURRVAL('action.fieldset_id_seq');
163 FROM action.fieldset_col_val
164 WHERE fieldset = fieldset_id
166 EXECUTE 'INSERT INTO action.fieldset_col_val (fieldset, col, val) ' ||
167 'SELECT '|| fs_id || ', '||quote_literal(cv.col)||', '||cv.col||' FROM '||table_name||' WHERE '||pkey_name||' = '||fs_pkey_value;
172 statement := 'UPDATE ' || table_name || ' SET';
178 FROM action.fieldset_col_val
179 WHERE fieldset = fieldset_id
181 statement := statement || sep || ' ' || cv.col
182 || ' = ' || coalesce( quote_literal( cv.val ), 'NULL' );
187 RETURN 'Fieldset ' || fieldset_id || ' has no column values defined';
189 statement := statement || ' ' || where_clause;
192 -- Execute the update
196 GET DIAGNOSTICS update_count = ROW_COUNT;
198 IF update_count = 0 THEN
199 RAISE data_exception;
202 IF fsg_id IS NOT NULL THEN
203 UPDATE action.fieldset_group SET rollback_group = fsg_id WHERE id = fs_group.id;
206 IF fs_group.id IS NOT NULL THEN
207 UPDATE action.fieldset_group SET complete_time = now() WHERE id = fs_group.id;
210 UPDATE action.fieldset SET status = 'APPLIED', applied_time = now() WHERE id = fieldset_id;
212 EXCEPTION WHEN data_exception THEN
213 msg := 'No eligible rows found for fieldset ' || fieldset_id;
214 UPDATE action.fieldset SET status = 'ERROR', applied_time = now() WHERE id = fieldset_id;
221 EXCEPTION WHEN OTHERS THEN
222 msg := 'Unable to apply fieldset ' || fieldset_id || ': ' || sqlerrm;
223 UPDATE action.fieldset SET status = 'ERROR', applied_time = now() WHERE id = fieldset_id;