COMMENT ON FUNCTION evergreen.xml_pretty_print(input XML) IS
'Simple pretty printer for XML, as written by Andrew Dunstan at http://goo.gl/zBHIk';
+CREATE OR REPLACE FUNCTION evergreen.could_be_serial_holding_code(TEXT) RETURNS BOOL AS $$
+ use JSON::XS;
+ use MARC::Field;
+
+ eval {
+ my $holding_code = (new JSON::XS)->decode(shift);
+ new MARC::Field('999', @$holding_code);
+ };
+ return 0 if $@;
+ # verify that subfield labels are exactly one character long
+ foreach (keys %{ { @$holding_code } }) {
+ return 0 if length($_) != 1;
+ }
+ return 1;
+$$ LANGUAGE PLPERLU;
+
+COMMENT ON FUNCTION evergreen.could_be_serial_holding_code(TEXT) IS
+ 'Return true if parameter is valid JSON representing an array that at minimum doesn''t make MARC::Field balk and only has subfield labels exactly one character long. Otherwise false.';
+
COMMIT;
date_published TIMESTAMP WITH TIME ZONE,
caption_and_pattern INT REFERENCES serial.caption_and_pattern (id)
DEFERRABLE INITIALLY DEFERRED,
- holding_code TEXT,
+ holding_code TEXT CONSTRAINT issuance_holding_code_check CHECK (
+ holding_code IS NULL OR could_be_serial_holding_code(holding_code)
+ ),
holding_type TEXT CONSTRAINT valid_holding_type CHECK
(
holding_type IS NULL
--- /dev/null
+BEGIN;
+
+SELECT evergreen.upgrade_deps_block_check('XXXX', :eg_version);
+
+CREATE OR REPLACE FUNCTION evergreen.could_be_serial_holding_code(TEXT) RETURNS BOOL AS $$
+ use JSON::XS;
+ use MARC::Field;
+
+ eval {
+ my $holding_code = (new JSON::XS)->decode(shift);
+ new MARC::Field('999', @$holding_code);
+ };
+ return 0 if $@;
+ # verify that subfield labels are exactly one character long
+ foreach (keys %{ { @$holding_code } }) {
+ return 0 if length($_) != 1;
+ }
+ return 1;
+$$ LANGUAGE PLPERLU;
+
+COMMENT ON FUNCTION evergreen.could_be_serial_holding_code(TEXT) IS
+ 'Return true if parameter is valid JSON representing an array that at minimu
+m doesn''t make MARC::Field balk and only has subfield labels exactly one character long. Otherwise false.';
+
+
+-- This UPDATE throws away data, but only bad data that makes things break
+-- anyway.
+UPDATE serial.issuance
+ SET holding_code = NULL
+ WHERE NOT could_be_serial_holding_code(holding_code);
+
+ALTER TABLE serial.issuance
+ DROP CONSTRAINT IF EXISTS issuance_holding_code_check;
+
+ALTER TABLE serial.issuance
+ ADD CHECK (holding_code IS NULL OR could_be_serial_holding_code(holding_code));
+
+COMMIT;