Bug 22284: DBRev 19.12.00.003
[koha-ffzg.git] / installer / data / mysql / updatedatabase.pl
index 21d65ca..d61b4e8 100755 (executable)
@@ -27,8 +27,7 @@
 
 # NOTE: Please keep the version in kohaversion.pl up-to-date!
 
-use strict;
-use warnings;
+use Modern::Perl;
 
 use feature 'say';
 
@@ -12320,9 +12319,6 @@ if ( $column_has_been_used ) {
 
 $DBversion = "3.23.00.050";
 if ( CheckVersion($DBversion) ) {
-    use Koha::SearchMarcMaps;
-    use Koha::SearchFields;
-    use Koha::SearchEngine::Elasticsearch;
 
     $dbh->do(q|INSERT IGNORE INTO systempreferences (variable,value,explanation,options,type)
                     VALUES('SearchEngine','Zebra','Choose Search Engine','','Choice')|);
@@ -12384,12 +12380,10 @@ $dbh->do(q|
             ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
         |);
 
-        # Insert default mappings
-        Koha::SearchEngine::Elasticsearch->reset_elasticsearch_mappings;
-
-print "Upgrade to $DBversion done (Bug 12478 - Elasticsearch support for Koha)\n";
+    print "WARNING: If you plan to use Elasticsearch you should go to 'Home › Administration › Search engine configuration' and reset the mappings\n";
+    print "Upgrade to $DBversion done (Bug 12478 - Elasticsearch support for Koha)\n";
     SetVersion($DBversion);
-    }
+}
 
 
 $DBversion = "3.23.00.051";
@@ -13042,7 +13036,7 @@ if ( CheckVersion($DBversion) ) {
         INSERT IGNORE INTO systempreferences (variable,value,explanation,options,type) VALUES ('TrackLastPatronActivity', '0', 'If set, the field borrowers.lastseen will be updated everytime a patron is seen', NULL, 'YesNo');
     });
 
-    print "Upgrade to $DBversion done (Bug 16274 - Make the selfregistration branchcode selection configurable)\n";
+    print "Upgrade to $DBversion done (Bug 16276: Add a new pref TrackLastPatronActivity and new column borrowers.lastseen)\n";
     SetVersion($DBversion);
 }
 
@@ -14354,32 +14348,40 @@ if( CheckVersion( $DBversion ) ) {
 $DBversion = '16.12.00.032';
 if( CheckVersion( $DBversion ) ) {
     require Koha::Calendar;
-    require Koha::Holds;
 
     $dbh->do(q{
         INSERT IGNORE INTO systempreferences (variable,value,explanation,options,type) 
         VALUES ('ExcludeHolidaysFromMaxPickUpDelay', '0', 'If ON, reserves max pickup delay takes into account the closed days.', NULL, 'Integer');
     });
 
-    my $waiting_holds = Koha::Holds->search({ found => 'W', priority => 0 });
+    my $waiting_holds = $dbh->selectall_arrayref(q|
+        SELECT expirationdate, waitingdate, branchcode
+        FROM reserves
+        WHERE found = 'W' AND priority = 0
+    |, { Slice => {} });
+    my $update_sth = $dbh->prepare(q|
+        UPDATE reserves
+        SET expirationdate = ?
+        WHERE reserve_id = ?
+    |);
     my $max_pickup_delay = C4::Context->preference("ReservesMaxPickUpDelay");
-    while ( my $hold = $waiting_holds->next ) {
+    for my $hold ( @$waiting_holds ) {
 
         my $requested_expiration;
-        if ($hold->expirationdate) {
-            $requested_expiration = dt_from_string($hold->expirationdate);
+        if ($hold->{expirationdate}) {
+            $requested_expiration = dt_from_string($hold->{expirationdate});
         }
 
-        my $expirationdate = dt_from_string($hold->waitingdate);
+        my $expirationdate = dt_from_string($hold->{waitingdate});
         if ( C4::Context->preference("ExcludeHolidaysFromMaxPickUpDelay") ) {
-            my $calendar = Koha::Calendar->new( branchcode => $hold->branchcode );
+            my $calendar = Koha::Calendar->new( branchcode => $hold->{branchcode} );
             $expirationdate = $calendar->days_forward( $expirationdate, $max_pickup_delay );
         } else {
             $expirationdate->add( days => $max_pickup_delay );
         }
 
         my $cmp = $requested_expiration ? DateTime->compare($requested_expiration, $expirationdate) : 0;
-        $hold->expirationdate($cmp == -1 ? $requested_expiration->ymd : $expirationdate->ymd)->store;
+        $update_sth->execute($cmp == -1 ? $requested_expiration->ymd : $expirationdate->ymd, $hold->{reserve_id});
     }
 
     SetVersion( $DBversion );
@@ -15923,7 +15925,7 @@ if( CheckVersion( $DBversion ) ) {
         INSERT IGNORE INTO systempreferences ( `variable`, `value`, `options`, `explanation`, `type` ) VALUES ('UpdateItemWhenLostFromHoldList','',NULL,'This is a list of values to update an item when it is marked as lost from the holds to pull screen','Free');
     } );
     $dbh->do( q{
-        UPDATE systempreferences SET options="batchmod|moredetail|cronjob|additem|pendingreserves", value="batchmod|moredetail|cronjob|additem|pendingreserves" WHERE variable="MarkLostItemsAsReturned";
+        UPDATE systempreferences SET options="batchmod|moredetail|cronjob|additem|pendingreserves" WHERE variable="MarkLostItemsAsReturned";
     } );
 
     SetVersion( $DBversion );
@@ -16134,7 +16136,8 @@ if( CheckVersion( $DBversion ) ) {
         unless ( foreign_key_exists('aqorders', 'aqorders_created_by') ) {
             $dbh->do( "ALTER TABLE aqorders ADD CONSTRAINT aqorders_created_by FOREIGN KEY (created_by) REFERENCES borrowers (borrowernumber) ON DELETE SET NULL ON UPDATE CASCADE;" );
         }
-        $dbh->do( "UPDATE aqorders, aqbasket SET aqorders.created_by = aqbasket.authorisedby  WHERE aqorders.basketno = aqbasket.basketno AND aqorders.created_by IS NULL;" );
+        $dbh->do( "UPDATE aqbasket LEFT JOIN borrowers ON ( aqbasket.authorisedby = borrowers.borrowernumber ) SET aqbasket.authorisedby = NULL WHERE borrowers.borrowernumber IS NULL;" );
+        $dbh->do( "UPDATE aqorders LEFT JOIN aqbasket ON ( aqorders.basketno = aqbasket.basketno ) SET aqorders.created_by = aqbasket.authorisedby WHERE aqorders.created_by IS NULL;" );
     }
     SetVersion( $DBversion );
     print "Upgrade to $DBversion done (Bug 12395 - Save order line's creator)\n";
@@ -16561,42 +16564,3732 @@ if( CheckVersion( $DBversion ) ) {
     print "Upgrade to $DBversion done (Bug 15520 - Add more granular permission for only editing own library's circ rules)\n";
 }
 
-# SEE bug 13068
-# if there is anything in the atomicupdate, read and execute it.
+$DBversion = '18.06.00.040';
+if( CheckVersion( $DBversion ) ) {
+    # Stock Rotation Rotas
+    unless (TableExists('stockrotationrotas')){
+        $dbh->do(q{
+          CREATE TABLE `stockrotationrotas` (
+            `rota_id` int(11) auto_increment,         -- Stockrotation rota ID
+            `title` varchar(100) NOT NULL,            -- Title for this rota
+            `description` text NOT NULL,              -- Description for this rota
+            `cyclical` tinyint(1) NOT NULL default 0, -- Should items on this rota keep cycling?
+            `active` tinyint(1) NOT NULL default 0,   -- Is this rota currently active?
+            PRIMARY KEY (`rota_id`),
+            CONSTRAINT `stockrotationrotas_title`
+            UNIQUE (`title`)
+          ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+        });
+    }
+    # Stock Rotation Stages
+    unless (TableExists('stockrotationstages')){
+        $dbh->do(q{
+          CREATE TABLE `stockrotationstages` (
+              `stage_id` int(11) auto_increment,     -- Unique stage ID
+              `position` int(11) NOT NULL,           -- The position of this stage within its rota
+              `rota_id` int(11) NOT NULL,            -- The rota this stage belongs to
+              `branchcode_id` varchar(10) NOT NULL,  -- Branch this stage relates to
+              `duration` int(11) NOT NULL default 4, -- The number of days items shoud occupy this stage
+              PRIMARY KEY (`stage_id`),
+              CONSTRAINT `stockrotationstages_rifk`
+                FOREIGN KEY (`rota_id`)
+                REFERENCES `stockrotationrotas` (`rota_id`)
+                ON UPDATE CASCADE ON DELETE CASCADE,
+              CONSTRAINT `stockrotationstages_bifk`
+                FOREIGN KEY (`branchcode_id`)
+                REFERENCES `branches` (`branchcode`)
+                ON UPDATE CASCADE ON DELETE CASCADE
+          ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+        });
+    }
+    # Stock Rotation Items
+    unless (TableExists('stockrotationitems')){
+        $dbh->do(q{
+          CREATE TABLE `stockrotationitems` (
+              `itemnumber_id` int(11) NOT NULL,         -- Itemnumber to link to a stage & rota
+              `stage_id` int(11) NOT NULL,              -- stage ID to link the item to
+              `indemand` tinyint(1) NOT NULL default 0, -- Should this item be skipped for rotation?
+              `fresh` tinyint(1) NOT NULL default 0,    -- Flag showing item is only just added to rota
+              PRIMARY KEY (itemnumber_id),
+              CONSTRAINT `stockrotationitems_iifk`
+                FOREIGN KEY (`itemnumber_id`)
+                REFERENCES `items` (`itemnumber`)
+                ON UPDATE CASCADE ON DELETE CASCADE,
+              CONSTRAINT `stockrotationitems_sifk`
+                FOREIGN KEY (`stage_id`)
+                REFERENCES `stockrotationstages` (`stage_id`)
+                ON UPDATE CASCADE ON DELETE CASCADE
+          ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+        });
+    }
+    # System preferences
+    $dbh->do(q{
+        INSERT IGNORE INTO `systempreferences` (`variable`,`value`,`explanation`,`options`,`type`)
+        VALUES ('StockRotation','0','If ON, enables the stock rotation module','','YesNo'),
+               ('RotationPreventTransfers','0','If ON, prevent any transfers for items on stock rotation rotas, except for stock rotation transfers','','YesNo');
+    });
+    # Permissions
+    $dbh->do(q{
+        INSERT IGNORE INTO `userflags` (`bit`, `flag`, `flagdesc`, `defaulton`)
+        VALUES (24, 'stockrotation', 'Manage stockrotation operations', 0);
+    });
+    $dbh->do(q{
+        INSERT IGNORE INTO `permissions` (`module_bit`, `code`, `description`)
+        VALUES (24, 'manage_rotas', 'Create, edit and delete rotas'),
+               (24, 'manage_rota_items', 'Add and remove items from rotas');
+    });
+    # Notices
+    $dbh->do(q{
+        INSERT IGNORE INTO `letter` (`module`, `code`, `branchcode`, `name`, `is_html`, `title`, `content`, `message_transport_type`)
+        VALUES ('circulation', 'SR_SLIP', '', 'Stock Rotation Slip', 0, 'Stockrotation Report', 'Stockrotation report for [% branch.name %]:\r\n\r\n[% IF branch.items.size %][% branch.items.size %] items to be processed for this branch.\r\n[% ELSE %]No items to be processed for this branch\r\n[% END %][% FOREACH item IN branch.items %][% IF item.reason ne \'in-demand\' %]Title: [% item.title %]\r\nAuthor: [% item.author %]\r\nCallnumber: [% item.callnumber %]\r\nLocation: [% item.location %]\r\nBarcode: [% item.barcode %]\r\nOn loan?: [% item.onloan %]\r\nStatus: [% item.reason %]\r\nCurrent Library: [% item.branch.branchname %] [% item.branch.branchcode %]\r\n\r\n[% END %][% END %]', 'email');
+    });
+    print "Upgrade to $DBversion done (Bug 11897 - Add Stock Rotation Feature)\n";
+    SetVersion( $DBversion );
+}
 
-my $update_dir = C4::Context->config('intranetdir') . '/installer/data/mysql/atomicupdate/';
-opendir( my $dirh, $update_dir );
-foreach my $file ( sort readdir $dirh ) {
-    next if $file !~ /\.(sql|perl)$/;  #skip other files
-    next if $file eq 'skeleton.perl'; # skip the skeleton file
-    print "DEV atomic update: $file\n";
-    if ( $file =~ /\.sql$/ ) {
-        my $installer = C4::Installer->new();
-        my $rv = $installer->load_sql( $update_dir . $file ) ? 0 : 1;
-    } elsif ( $file =~ /\.perl$/ ) {
-        my $code = read_file( $update_dir . $file );
-        eval $code;
-        say "Atomic update generated errors: $@" if $@;
+$DBversion = '18.06.00.041';
+if( CheckVersion( $DBversion ) ) {
+
+     if( !column_exists( 'illrequests', 'price_paid' ) ) {
+        $dbh->do(q{
+            ALTER TABLE illrequests
+                ADD COLUMN price_paid varchar(20) DEFAULT NULL
+                AFTER cost
+        });
+     }
+
+     if( !column_exists( 'illrequestattributes', 'readonly' ) ) {
+        $dbh->do(q{
+            ALTER TABLE illrequestattributes
+                ADD COLUMN readonly tinyint(1) NOT NULL DEFAULT 1
+                AFTER value
+        });
+        $dbh->do(q{
+            UPDATE illrequestattributes SET readonly = 1
+        });
+     }
+
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 20772 - Add illrequestattributes.readonly and illrequest.price_paid columns)\n";
+}
+
+$DBversion = '18.06.00.042';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do( "alter table statistics change column ccode ccode varchar(80) default NULL" );
+
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 21617: Make statistics.ccode longer)\n";
+}
+
+$DBversion = "18.06.00.043";
+if ( CheckVersion($DBversion) ) {
+    if ( !column_exists( 'issuingrules', 'holds_per_day' ) ) {
+        $dbh->do(q{
+            ALTER TABLE `issuingrules`
+                ADD COLUMN `holds_per_day` SMALLINT(6) DEFAULT NULL
+                AFTER `holds_per_record`
+        });
     }
+    print "Upgrade to $DBversion done (Bug 15486: Restrict number of holds placed by day)\n";
+    SetVersion($DBversion);
 }
 
-=head1 FUNCTIONS
+$DBversion = '18.06.00.044';
+if( CheckVersion( $DBversion ) ) {
+    unless( column_exists( 'creator_batches', 'description' ) ) {
+        $dbh->do(q|ALTER TABLE creator_batches ADD description mediumtext default NULL AFTER batch_id|);
+    }
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 15766: Add column creator_batches.description)\n";
+}
 
-=head2 TableExists($table)
+$DBversion = '18.06.00.045';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do(q(
+        INSERT IGNORE INTO message_transports
+        (message_attribute_id,message_transport_type,is_digest,letter_module,letter_code)
+        VALUES
+        (2, 'phone', 0, 'circulation', 'PREDUE'),
+        (2, 'phone', 1, 'circulation', 'PREDUEDGST'),
+        (4, 'phone', 0, 'reserves',    'HOLD')
+        ));
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 21639 - Add phone transports by default)\n";
+}
 
-=cut
+$DBversion = '18.06.00.046';
+if( CheckVersion( $DBversion ) ) {
+    unless (TableExists('illcomments')) {
+        $dbh->do(q{
+            CREATE TABLE illcomments (
+                illcomment_id int(11) NOT NULL AUTO_INCREMENT, -- Unique ID of the comment
+                illrequest_id bigint(20) unsigned NOT NULL,    -- ILL request number
+                borrowernumber integer DEFAULT NULL,           -- Link to the user who made the comment (could be librarian, patron or ILL partner library)
+                comment text DEFAULT NULL,                     -- The text of the comment
+                timestamp timestamp DEFAULT CURRENT_TIMESTAMP, -- Date and time when the comment was made
+                PRIMARY KEY  ( illcomment_id ),
+                CONSTRAINT illcomments_bnfk
+                  FOREIGN KEY ( borrowernumber )
+                  REFERENCES  borrowers  ( borrowernumber )
+                  ON UPDATE CASCADE ON DELETE CASCADE,
+                CONSTRAINT illcomments_ifk
+                  FOREIGN KEY (illrequest_id)
+                  REFERENCES illrequests ( illrequest_id )
+                  ON UPDATE CASCADE ON DELETE CASCADE
+            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+        });
+    }
 
-sub TableExists {
-    my $table = shift;
-    eval {
-                local $dbh->{PrintError} = 0;
-                local $dbh->{RaiseError} = 1;
-                $dbh->do(qq{SELECT * FROM $table WHERE 1 = 0 });
-            };
-    return 1 unless $@;
-    return 0;
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 18591 - Add comments to ILL requests)\n";
+}
+
+$DBversion = '18.06.00.047';
+if( CheckVersion( $DBversion ) ) {
+    # insert the authorized_value_category for CONTROL_NUM_SEQUENCE
+    $dbh->do( "INSERT IGNORE INTO authorised_value_categories values ('CONTROL_NUM_SEQUENCE');" );
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 19263 - Advanced Editor - Rancor - Add auto control number (001) widget)\n";
+}
+
+$DBversion = '18.06.00.048';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do( "ALTER TABLE stockrotationrotas CHANGE COLUMN description description text" );
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 21682 - Remove default on stockrotationrotas.description)\n";
+}
+
+$DBversion = '18.06.00.049';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do(q{
+        UPDATE letter SET content = REPLACE(content,"item.reason ne \'in-demand\'","item.reason != \'in-demand\'")
+        WHERE code="SR_SLIP";
+    });
+    print "Upgrade to $DBversion done (Bug 21656 - Stock Rotation Notice, Template Toolkit Syntax Correction)\n";
+    SetVersion( $DBversion );
+}
+
+$DBversion = '18.06.00.050';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do(q{
+        INSERT IGNORE INTO systempreferences (`variable`, `value`, `options`, `explanation`, `type`) VALUES ('OpacHiddenItemsExceptions','',NULL,'List of borrower categories, separated by |, that can see items otherwise hidden by OpacHiddenItems','Textarea');
+    });
+    print "Upgrade to $DBversion done (Bug 14385 - Add OpacHiddenItemExceptions)\n";
+    SetVersion( $DBversion );
+}
+
+$DBversion = '18.06.00.051';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do(q{
+        INSERT IGNORE INTO `systempreferences` (`variable`, `value`, `options`, `explanation`, `type`) VALUES
+        ('AdlibrisCoversEnabled', '0', NULL, 'Display cover images in OPAC results and detail listing from Swedish retailer Adlibris.','YesNo'),
+        ('AdlibrisCoversURL', 'http://www.adlibris.com/se/organisationer/showimagesafe.aspx', NULL, 'Base URL for Adlibris cover image web service.', 'Free');
+    });
+    print "Upgrade to $DBversion done (Bug 8630 - Add covers from AdLibris to the OPAC and Intranet)\n";
+    SetVersion( $DBversion );
+}
+
+$DBversion = '18.06.00.052';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do(q{
+        INSERT IGNORE INTO permissions (module_bit, code, description) VALUES
+           ( 3, 'manage_sysprefs', 'Manage global system preferences'),
+           ( 3, 'manage_libraries', 'Manage libraries and library groups'),
+           ( 3, 'manage_itemtypes', 'Manage item types'),
+           ( 3, 'manage_auth_values', 'Manage authorized values'),
+           ( 3, 'manage_patron_categories', 'Manage patron categories'),
+           ( 3, 'manage_patron_attributes', 'Manage extended patron attributes'),
+           ( 3, 'manage_transfers', 'Manage library transfer limits and transport cost matrix'),
+           ( 3, 'manage_item_circ_alerts', 'Manage item circulation alerts'),
+           ( 3, 'manage_cities', 'Manage cities and towns'),
+           ( 3, 'manage_marc_frameworks', 'Manage MARC bibliographic and authority frameworks'),
+           ( 3, 'manage_keywords2koha_mappings', 'Manage keywords to Koha mappings'),
+           ( 3, 'manage_classifications', 'Manage classification sources'),
+           ( 3, 'manage_matching_rules', 'Manage record matching rules'),
+           ( 3, 'manage_oai_sets', 'Manage OAI sets'),
+           ( 3, 'manage_item_search_fields', 'Manage item search fields'),
+           ( 3, 'manage_search_engine_config', 'Manage search engine configuration'),
+           ( 3, 'manage_search_targets', 'Manage Z39.50 and SRU server configuration'),
+           ( 3, 'manage_didyoumean', 'Manage Did you mean? configuration'),
+           ( 3, 'manage_column_config', 'Manage column configuration'),
+           ( 3, 'manage_sms_providers', 'Manage SMS cellular providers'),
+           ( 3, 'manage_audio_alerts', 'Manage audio alerts'),
+           ( 3, 'manage_usage_stats', 'Manage usage statistics settings');
+    });
+    $dbh->do(q{
+        INSERT INTO user_permissions (borrowernumber, module_bit, code)
+            SELECT borrowernumber, 3, 'manage_sysprefs' FROM borrowers WHERE borrowernumber IN (SELECT borrowernumber FROM user_permissions WHERE code = 'parameters_remaining_permissions');
+    });
+    $dbh->do(q{
+        INSERT INTO user_permissions (borrowernumber, module_bit, code)
+            SELECT borrowernumber, 3, 'manage_libraries' FROM borrowers WHERE borrowernumber IN (SELECT borrowernumber FROM user_permissions WHERE code = 'parameters_remaining_permissions');
+    });
+    $dbh->do(q{
+        INSERT INTO user_permissions (borrowernumber, module_bit, code)
+            SELECT borrowernumber, 3, 'manage_itemtypes' FROM borrowers WHERE borrowernumber IN (SELECT borrowernumber FROM user_permissions WHERE code = 'parameters_remaining_permissions');
+    });
+    $dbh->do(q{
+        INSERT INTO user_permissions (borrowernumber, module_bit, code)
+            SELECT borrowernumber, 3, 'manage_auth_values' FROM borrowers WHERE borrowernumber IN (SELECT borrowernumber FROM user_permissions WHERE code = 'parameters_remaining_permissions');
+    });
+    $dbh->do(q{
+        INSERT INTO user_permissions (borrowernumber, module_bit, code)
+            SELECT borrowernumber, 3, 'manage_patron_categories' FROM borrowers WHERE borrowernumber IN (SELECT borrowernumber FROM user_permissions WHERE code = 'parameters_remaining_permissions');
+    });
+    $dbh->do(q{
+        INSERT INTO user_permissions (borrowernumber, module_bit, code)
+            SELECT borrowernumber, 3, 'manage_patron_attributes' FROM borrowers WHERE borrowernumber IN (SELECT borrowernumber FROM user_permissions WHERE code = 'parameters_remaining_permissions');
+    });
+    $dbh->do(q{
+        INSERT INTO user_permissions (borrowernumber, module_bit, code)
+            SELECT borrowernumber, 3, 'manage_transfers' FROM borrowers WHERE borrowernumber IN (SELECT borrowernumber FROM user_permissions WHERE code = 'parameters_remaining_permissions');
+    });
+    $dbh->do(q{
+        INSERT INTO user_permissions (borrowernumber, module_bit, code)
+            SELECT borrowernumber, 3, 'manage_item_circ_alerts' FROM borrowers WHERE borrowernumber IN (SELECT borrowernumber FROM user_permissions WHERE code = 'parameters_remaining_permissions');
+    });
+    $dbh->do(q{
+        INSERT INTO user_permissions (borrowernumber, module_bit, code)
+            SELECT borrowernumber, 3, 'manage_cities' FROM borrowers WHERE borrowernumber IN (SELECT borrowernumber FROM user_permissions WHERE code = 'parameters_remaining_permissions');
+    });
+    $dbh->do(q{
+        INSERT INTO user_permissions (borrowernumber, module_bit, code)
+            SELECT borrowernumber, 3, 'manage_marc_frameworks' FROM borrowers WHERE borrowernumber IN (SELECT borrowernumber FROM user_permissions WHERE code = 'parameters_remaining_permissions');
+    });
+    $dbh->do(q{
+        INSERT INTO user_permissions (borrowernumber, module_bit, code)
+            SELECT borrowernumber, 3, 'manage_keywords2koha_mappings' FROM borrowers WHERE borrowernumber IN (SELECT borrowernumber FROM user_permissions WHERE code = 'parameters_remaining_permissions');
+    });
+    $dbh->do(q{
+        INSERT INTO user_permissions (borrowernumber, module_bit, code)
+            SELECT borrowernumber, 3, 'manage_classifications' FROM borrowers WHERE borrowernumber IN (SELECT borrowernumber FROM user_permissions WHERE code = 'parameters_remaining_permissions');
+    });
+    $dbh->do(q{
+        INSERT INTO user_permissions (borrowernumber, module_bit, code)
+            SELECT borrowernumber, 3, 'manage_matching_rules' FROM borrowers WHERE borrowernumber IN (SELECT borrowernumber FROM user_permissions WHERE code = 'parameters_remaining_permissions');
+    });
+    $dbh->do(q{
+        INSERT INTO user_permissions (borrowernumber, module_bit, code)
+            SELECT borrowernumber, 3, 'manage_oai_sets' FROM borrowers WHERE borrowernumber IN (SELECT borrowernumber FROM user_permissions WHERE code = 'parameters_remaining_permissions');
+    });
+    $dbh->do(q{
+        INSERT INTO user_permissions (borrowernumber, module_bit, code)
+            SELECT borrowernumber, 3, 'manage_item_search_fields' FROM borrowers WHERE borrowernumber IN (SELECT borrowernumber FROM user_permissions WHERE code = 'parameters_remaining_permissions');
+    });
+    $dbh->do(q{
+        INSERT INTO user_permissions (borrowernumber, module_bit, code)
+            SELECT borrowernumber, 3, 'manage_search_engine_config' FROM borrowers WHERE borrowernumber IN (SELECT borrowernumber FROM user_permissions WHERE code = 'parameters_remaining_permissions');
+    });
+    $dbh->do(q{
+        INSERT INTO user_permissions (borrowernumber, module_bit, code)
+            SELECT borrowernumber, 3, 'manage_search_targets' FROM borrowers WHERE borrowernumber IN (SELECT borrowernumber FROM user_permissions WHERE code = 'parameters_remaining_permissions');
+    });
+    $dbh->do(q{
+        INSERT INTO user_permissions (borrowernumber, module_bit, code)
+            SELECT borrowernumber, 3, 'manage_didyoumean' FROM borrowers WHERE borrowernumber IN (SELECT borrowernumber FROM user_permissions WHERE code = 'parameters_remaining_permissions');
+    });
+    $dbh->do(q{
+        INSERT INTO user_permissions (borrowernumber, module_bit, code)
+            SELECT borrowernumber, 3, 'manage_column_config' FROM borrowers WHERE borrowernumber IN (SELECT borrowernumber FROM user_permissions WHERE code = 'parameters_remaining_permissions');
+    });
+    $dbh->do(q{
+        INSERT INTO user_permissions (borrowernumber, module_bit, code)
+            SELECT borrowernumber, 3, 'manage_sms_providers' FROM borrowers WHERE borrowernumber IN (SELECT borrowernumber FROM user_permissions WHERE code = 'parameters_remaining_permissions');
+    });
+    $dbh->do(q{
+        INSERT INTO user_permissions (borrowernumber, module_bit, code)
+            SELECT borrowernumber, 3, 'manage_audio_alerts' FROM borrowers WHERE borrowernumber IN (SELECT borrowernumber FROM user_permissions WHERE code = 'parameters_remaining_permissions');
+    });
+    $dbh->do(q{
+        INSERT INTO user_permissions (borrowernumber, module_bit, code)
+            SELECT borrowernumber, 3, 'manage_usage_stats' FROM borrowers WHERE borrowernumber IN (SELECT borrowernumber FROM user_permissions WHERE code = 'parameters_remaining_permissions');
+    });
+    $dbh->do(q{
+        INSERT INTO user_permissions (borrowernumber, module_bit, code)
+            SELECT borrowernumber, 3, 'manage_item_search_fields' FROM borrowers WHERE flags & (1 << 2);
+    });
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 14391: Add granular permissions to the administration module)\n";
+}
+
+$DBversion = '18.06.00.053';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do( "INSERT IGNORE INTO systempreferences (variable,value,options,explanation,type) VALUES ('ItemsDeniedRenewal','','','This syspref allows to define custom rules for denying renewal of specific items.','Textarea')" );
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 15494 - Block renewals by arbitrary item values)\n";
+}
+
+$DBversion = '18.06.00.054';
+if( CheckVersion( $DBversion ) ) {
+    if( !column_exists( 'search_field', 'weight' ) ) {
+        $dbh->do( "ALTER TABLE `search_field` ADD COLUMN `weight` decimal(5,2) DEFAULT NULL AFTER `type`" );
+    }
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 18316 - Add column search_field.weight)\n";
+}
+
+$DBversion = '18.06.00.055';
+if( CheckVersion( $DBversion ) ) {
+    unless( column_exists( 'issuingrules', 'note' ) ) {
+        $dbh->do(q|ALTER TABLE `issuingrules` ADD `note` varchar(100) default NULL AFTER `article_requests`|);
+    }
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 12365: Add column issuingrules.note)\n";
+}
+
+$DBversion = '18.06.00.056';
+if( CheckVersion( $DBversion ) ) {
+
+    # All attributes we're potentially interested in
+    my $ff_req = $dbh->selectall_arrayref(
+        'SELECT a.illrequest_id, a.type, a.value '.
+        'FROM illrequests r, illrequestattributes a '.
+        'WHERE r.illrequest_id = a.illrequest_id '.
+        'AND r.backend = "FreeForm"',
+        { Slice => {} }
+    );
+
+    # Before we go any further, identify whether we've done
+    # this before, we test for the presence of "container_title"
+    # We stop as soon as we find one
+    foreach my $req(@{$ff_req}) {
+        if ($req->{type} eq 'container_title') {
+            warn "Upgrade already carried out";
+        }
+    }
+
+    # Transform into a hashref with the key of the request ID
+    my $requests = {};
+    foreach my $request(@{$ff_req}) {
+        my $id = $request->{illrequest_id};
+        if (!exists $requests->{$id}) {
+            $requests->{$id} = {};
+        }
+        $requests->{$id}->{$request->{type}} = $request->{value};
+    }
+
+    # Transform any article requests
+    my $transformed = {};
+    foreach my $id(keys %{$requests}) {
+        if (lc($requests->{$id}->{type}) eq 'article') {
+            $transformed->{$id} = $requests->{$id};
+            $transformed->{$id}->{type} = 'article';
+            $transformed->{$id}->{container_title} = $transformed->{$id}->{title}
+                if defined $transformed->{$id}->{title} &&
+                    length $transformed->{$id}->{title} > 0;
+            $transformed->{$id}->{title} = $transformed->{$id}->{article_title}
+                if defined $transformed->{$id}->{article_title} &&
+                    length $transformed->{$id}->{article_title} > 0;
+            $transformed->{$id}->{author} = $transformed->{$id}->{article_author}
+                if defined $transformed->{$id}->{article_author} &&
+                    length $transformed->{$id}->{article_author} > 0;
+            $transformed->{$id}->{pages} = $transformed->{$id}->{article_pages}
+                if defined $transformed->{$id}->{article_pages} &&
+                    length $transformed->{$id}->{article_pages} > 0;
+        }
+    }
+
+    # Now write back the transformed data
+    # Rather than selectively replace, we just remove all attributes we've
+    # transformed and re-write them
+    my @changed = keys %{$transformed};
+    my $changed_str = join(',', @changed);
+
+    if (scalar @changed > 0) {
+        my ($raise_error) = $dbh->{RaiseError};
+        $dbh->{AutoCommit} = 0;
+        $dbh->{RaiseError} = 1;
+        eval {
+            my $del = $dbh->do(
+                "DELETE FROM illrequestattributes ".
+                "WHERE illrequest_id IN ($changed_str)"
+            );
+            foreach my $reqid(keys %{$transformed}) {
+                my $attr = $transformed->{$reqid};
+                foreach my $key(keys %{$attr}) {
+                    my $sth = $dbh->prepare(
+                        'INSERT INTO illrequestattributes '.
+                        '(illrequest_id, type, value) '.
+                        'VALUES '.
+                        '(?, ?, ?)'
+                    );
+                    $sth->execute(
+                        $reqid,
+                        $key,
+                        $attr->{$key}
+                    );
+                }
+            }
+            $dbh->commit;
+        };
+
+        if ($@) {
+            warn "Upgrade to $DBversion failed: $@\n";
+            eval { $dbh->rollback };
+        } else {
+            SetVersion( $DBversion );
+            print "Upgrade to $DBversion done (Bug 21079 - Unify metadata schema across backends)\n";
+        }
+
+        $dbh->{AutoCommit} = 1;
+        $dbh->{RaiseError} = $raise_error;
+    }
+
+}
+
+$DBversion = '18.06.00.057';
+if( CheckVersion( $DBversion ) ) {
+    # System preferences
+    $dbh->do(q{
+        INSERT IGNORE INTO `systempreferences` (`variable`,`value`,`explanation`,`options`,`type`)
+        VALUES ('showLastPatron','0','','If ON, enables the last patron feature in the intranet','YesNo');
+    });
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 20312 - Add showLastPatron systempreference)\n";
+}
+
+$DBversion = '18.06.00.058';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do(q{
+        INSERT IGNORE INTO systempreferences (`variable`, `value`, `options`, `explanation`, `type`) VALUES
+        ('MarcFieldForCreatorId','',NULL,'Where to store the borrowernumber of the record''s creator','Free'),
+        ('MarcFieldForCreatorName','',NULL,'Where to store the name of the record''s creator','Free'),
+        ('MarcFieldForModifierId','',NULL,'Where to store the borrowernumber of the record''s last modifier','Free'),
+        ('MarcFieldForModifierName','',NULL,'Where to store the name of the record''s last modifier','Free')
+    });
+
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 19349 - Add system preferences MarcFieldForCreatorId, MarcFieldForCreatorName, MarcFieldForModifierId, MarcFieldForModifierName)\n";
+}
+
+$DBversion = '18.06.00.059';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do(q{
+        INSERT IGNORE INTO systempreferences ( `variable`, `value`, `options`, `explanation`, `type`) VALUES  ('EmailSMSSendDriverFromAddress', '', '', 'Email SMS send driver from address override', 'Free');
+    });
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 20356 - Add EmailSMSSendDriverFromAddress system preference)\n";
 }
 
+$DBversion = '18.06.00.060';
+if( CheckVersion( $DBversion ) ) {
+    unless( TableExists( 'class_split_rules' ) ) {
+        $dbh->do(q|
+            CREATE TABLE class_split_rules (
+              class_split_rule varchar(10) NOT NULL default '',
+              description LONGTEXT,
+              split_routine varchar(30) NOT NULL default '',
+              split_regex varchar(255) NOT NULL default '',
+              PRIMARY KEY (class_split_rule),
+              UNIQUE KEY class_split_rule_idx (class_split_rule)
+            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
+        |);
+
+        $dbh->do(q|
+            ALTER TABLE class_sources
+            ADD COLUMN class_split_rule varchar(10) NOT NULL default ''
+            AFTER class_sort_rule
+        |);
+
+        $dbh->do(q|
+            UPDATE class_sources
+            SET class_split_rule = class_sort_rule
+        |);
+
+        $dbh->do(q|
+            UPDATE class_sources
+            SET class_split_rule = 'generic'
+            WHERE class_split_rule NOT IN('dewey', 'generic', 'lcc')
+        |);
+
+        $dbh->do(q|
+            INSERT INTO class_split_rules(class_split_rule, description, split_routine)
+            VALUES
+            ('dewey', 'Default sorting rules for DDC', 'Dewey'),
+            ('lcc', 'Default sorting rules for LCC', 'LCC'),
+            ('generic', 'Generic call number sorting rules', 'Generic')
+        |);
+
+        $dbh->do(q|
+            ALTER TABLE class_sources
+            ADD CONSTRAINT class_source_ibfk_2 FOREIGN KEY (class_split_rule)
+            REFERENCES class_split_rules (class_split_rule)
+        |);
+    }
+
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 15836 - Add class_sort_rules.split_routine and split_regex)\n";
+}
+
+$DBversion = '18.06.00.061';
+if ( CheckVersion($DBversion) ) {
+    $dbh->do(q{
+        INSERT IGNORE INTO `systempreferences` (`variable`,`value`,`explanation`,`options`,`type`) VALUES
+        ('ElasticsearchIndexStatus_biblios', '0', 'Biblios index status', NULL, NULL),
+        ('ElasticsearchIndexStatus_authorities', '0', 'Authorities index status', NULL, NULL)
+    });
+    SetVersion($DBversion);
+    print "Upgrade to $DBversion done (Bug 19893 - Add elasticsearch index status preferences)\n";
+}
+
+$DBversion = '18.06.00.062';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do( "INSERT IGNORE INTO authorised_value_categories (category_name) VALUES ('PA_CLASS');");
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 21730: Add new authorised value category PA_CLASS)\n";
+}
+
+$DBversion = '18.11.00.000';
+if( CheckVersion( $DBversion ) ) {
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (18.11.00 release)\n";
+}
+
+$DBversion = '18.12.00.000';
+if( CheckVersion( $DBversion ) ) {
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (...and Steven!)\n";
+}
+
+$DBversion = '18.12.00.001';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do(q{
+        UPDATE permissions SET code = 'manage_didyoumean' WHERE code = 'manage_didyouean';
+    });
+    $dbh->do(q{
+        UPDATE user_permissions SET code = 'manage_didyoumean' WHERE code = 'manage_didyouean';
+    });
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion (Bug 21961 - Fix typo in manage_didyoumean permission)\n";
+}
+
+$DBversion = '18.12.00.002';
+if( CheckVersion( $DBversion ) ) {
+    my $sth = $dbh->prepare(q|SELECT * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE CONSTRAINT_NAME='accountlines_ibfk_1'|);
+    $sth->execute;
+    if ($sth->fetchrow_hashref) {
+        $dbh->do(q|
+            ALTER TABLE accountlines DROP FOREIGN KEY accountlines_ibfk_1;
+        |);
+        $dbh->do(q|
+            ALTER TABLE accountlines CHANGE COLUMN borrowernumber borrowernumber INT(11) DEFAULT NULL;
+        |);
+        $dbh->do(q|
+            ALTER TABLE accountlines ADD CONSTRAINT accountlines_ibfk_borrowers FOREIGN KEY (borrowernumber) REFERENCES borrowers (borrowernumber) ON DELETE SET NULL ON UPDATE CASCADE;
+        |);
+    }
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 21065 - Set ON DELETE SET NULL on accountlines.borrowernumber)\n";
+}
+
+$DBversion = '18.12.00.003';
+if( CheckVersion( $DBversion ) ) {
+    # On a new installation the class_sources.sql will have failed, so we need to add all missing data
+    my( $sort_cnt ) = $dbh->selectrow_array( q|SELECT COUNT(*) FROM class_sort_rules|);
+    if( !$sort_cnt ) {
+        $dbh->do(q|INSERT INTO `class_sort_rules` (`class_sort_rule`, `description`, `sort_routine`) VALUES
+                               ('dewey', 'Default filing rules for DDC', 'Dewey'),
+                               ('lcc', 'Default filing rules for LCC', 'LCC'),
+                               ('generic', 'Generic call number filing rules', 'Generic')
+            |);
+    }
+
+    my ( $split_cnt ) = $dbh->selectrow_array( q|SELECT COUNT(*) FROM class_split_rules|);
+    if( !$split_cnt ) {
+        $dbh->do(q|INSERT INTO `class_split_rules` (`class_split_rule`, `description`, `split_routine`) VALUES
+                               ('dewey', 'Default splitting rules for DDC', 'Dewey'),
+                               ('lcc', 'Default splitting rules for LCC', 'LCC'),
+                               ('generic', 'Generic call number splitting rules', 'Generic')
+            |);
+    }
+
+    my( $source_cnt ) = $dbh->selectrow_array( q|SELECT COUNT(*) FROM class_sources|);
+    if( !$source_cnt ) {
+        $dbh->do(q|INSERT INTO `class_sources` (`cn_source`, `description`, `used`, `class_sort_rule`, `class_split_rule`) VALUES
+                            ('ddc', 'Dewey Decimal Classification', 1, 'dewey', 'dewey'),
+                            ('lcc', 'Library of Congress Classification', 1, 'lcc', 'lcc'),
+                            ('udc', 'Universal Decimal Classification', 0, 'generic', 'generic'),
+                            ('sudocs', 'SuDoc Classification (U.S. GPO)', 0, 'generic', 'generic'),
+                            ('anscr', 'ANSCR (Sound Recordings)', 0, 'generic', 'generic'),
+                            ('z', 'Other/Generic Classification Scheme', 0, 'generic', 'generic')
+            |);
+
+    }
+
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 22024 - Add missing splitting rule definitions)\n";
+}
+
+$DBversion = '18.12.00.004';
+if( CheckVersion( $DBversion ) ) {
+    if( !column_exists( 'accountlines', 'branchcode' ) ) {
+        $dbh->do("ALTER TABLE accountlines ADD branchcode VARCHAR( 10 ) NULL DEFAULT NULL AFTER manager_id");
+        $dbh->do("ALTER TABLE accountlines ADD CONSTRAINT accountlines_ibfk_branches FOREIGN KEY (branchcode) REFERENCES branches (branchcode) ON DELETE SET NULL ON UPDATE CASCADE");
+    }
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 19066 - Add branchcode to accountlines)\n";
+}
+
+$DBversion = '18.12.00.005';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do(q{
+        INSERT IGNORE INTO systempreferences ( `variable`, `value`, `options`, `explanation`, `type` ) VALUES
+        ('OverDriveUsername','cardnumber','cardnumber|userid','Which patron information should be passed as OverDrive username','Choice')
+    });
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 22030: Add OverDriveUsername syspref)\n";
+}
+
+$DBversion = '18.12.00.006';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do(q{
+        INSERT IGNORE INTO systempreferences (variable,value,explanation,options,type) VALUES
+        ('AccountAutoReconcile','0','If enabled, patron balances will get reconciled automatically on each transaction.',NULL,'YesNo');
+    });
+    SetVersion($DBversion);
+    print "Upgrade to $DBversion done (Bug 21915 - Add a way to automatically reconcile balance for patrons)\n";
+}
+
+$DBversion = '18.12.00.007';
+if( CheckVersion( $DBversion ) ) {
+    if( column_exists( 'issuingrules', 'chargename' ) ) {
+        $dbh->do( "ALTER TABLE issuingrules DROP chargename" );
+    }
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 21753: Drop chargename from issuingrules )\n";
+}
+
+$DBversion = '18.12.00.008';
+if( CheckVersion( $DBversion ) ) {
+    if( !column_exists( 'subscription', 'mana_id' ) ) {
+        $dbh->do( "ALTER TABLE subscription ADD mana_id int(11) NULL DEFAULT NULL" );
+    }
+
+    if( !column_exists( 'saved_sql', 'mana_id' ) ) {
+        $dbh->do( "ALTER TABLE saved_sql ADD mana_id int(11) NULL DEFAULT NULL" );
+    }
+    $dbh->do(q{
+        INSERT IGNORE INTO systempreferences ( `variable`, `value`, `options`, `explanation`, `type` ) VALUES
+        ('Mana','2',NULL,'request to Mana Webservice. Mana centralize common information between other Koha to facilitate the creation of new subscriptions, vendors, report queries etc... You can search, share, import and comment the content of Mana.','YesNo');
+    });
+    $dbh->do(q{
+        INSERT IGNORE INTO systempreferences ( `variable`, `value`, `options`, `explanation`, `type` ) VALUES
+        ('AutoShareWithMana','','','defines datas automatically shared with mana','multiple');
+    });
+    $dbh->do(q{
+        INSERT IGNORE INTO systempreferences ( `variable`, `value`, `options`, `explanation`, `type` ) VALUES
+        ('ManaToken','',NULL,'Security token used for authentication on Mana KB service (anti spam)','Textarea');
+    });
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 17047 - Mana knowledge base)\n";
+}
+
+$DBversion = '18.12.00.009';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do(q{
+        INSERT IGNORE INTO systempreferences (variable, value, options, explanation, type) VALUES ('FallbackToSMSIfNoEmail', 0, 'Enable|Disable', 'Send messages by SMS if no patron email is defined', 'YesNo');
+    });
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 21241 - Add FallbackToSMSIfNoEmail syspref )\n";
+}
+
+$DBversion = '18.12.00.010';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do(q{
+        INSERT IGNORE INTO systempreferences
+            ( variable, value, options, explanation, type )
+        VALUES
+            ('RESTPublicAPI','1',NULL,'If enabled, the REST API will expose the /public endpoints.','YesNo')
+    });
+
+    # Always end with this (adjust the bug info)
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 22061 - Add a /public namespace that can be switched on/off)\n";
+}
+
+$DBversion = '18.12.00.011';
+if( CheckVersion( $DBversion ) ) {
+    if ( column_exists( 'biblio_metadata', 'marcflavour' ) ) {
+        $dbh->do(q{
+            ALTER TABLE biblio_metadata
+                CHANGE COLUMN marcflavour `schema` VARCHAR(16)
+        });
+    }
+    if ( column_exists( 'deletedbiblio_metadata', 'marcflavour' ) ) {
+        $dbh->do(q{
+            ALTER TABLE deletedbiblio_metadata
+                CHANGE COLUMN marcflavour `schema` VARCHAR(16)
+        });
+    }
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 22155 - biblio_metadata.marcflavour should be renamed 'schema')\n";
+}
+
+$DBversion = '18.12.00.012';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do(q{
+        INSERT IGNORE INTO systempreferences
+            (variable, value, options, explanation, type )
+        VALUES
+            ('RESTBasicAuth','0',NULL,'If enabled, Basic authentication is enabled for the REST API.','YesNo')
+    });
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 22132 - Add Basic authentication)\n";
+}
+
+$DBversion = '18.12.00.013';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do(q{
+        INSERT IGNORE INTO permissions (module_bit, code, description) VALUES ( 3, 'manage_mana', 'Manage Mana KB content sharing');
+    });
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 22198 - Add ghranular permission setting for Mana KB)\n";
+}
+
+$DBversion = '18.12.00.014';
+if( CheckVersion( $DBversion ) ) {
+    unless( foreign_key_exists( 'messages', 'messages_borrowernumber' ) ) {
+        $dbh->do(q|
+            DELETE m FROM messages m
+            LEFT JOIN borrowers b ON m.borrowernumber=b.borrowernumber
+            WHERE b.borrowernumber IS NULL
+        |);
+        $dbh->do(q|
+            ALTER TABLE messages
+            ADD CONSTRAINT messages_borrowernumber
+            FOREIGN KEY (borrowernumber) REFERENCES borrowers (borrowernumber) ON DELETE CASCADE ON UPDATE CASCADE
+        |);
+    }
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 13515 - Add a FOREIGN KEY constaint on messages.borrowernumber)\n";
+}
+
+$DBversion = '18.12.00.015';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do( "UPDATE action_logs SET info = REPLACE(info,'cardnumber_replaced','cardnumber') WHERE module='MEMBERS' AND action='MODIFY'" );
+    $dbh->do( "UPDATE action_logs SET info = REPLACE(info,'previous_cardnumber','before') WHERE module='MEMBERS' AND action='MODIFY'" );
+    $dbh->do( "UPDATE action_logs SET info = REPLACE(info,'new_cardnumber','after') WHERE module='MEMBERS' AND action='MODIFY'" );
+
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 3820 - Update patron modification logs)\n";
+}
+
+$DBversion = '18.12.00.016';
+if( CheckVersion( $DBversion ) ) {
+
+    if ( !column_exists( 'illrequests', 'status_alias' ) ) {
+        # Fresh upgrade, just add the column and constraint
+        $dbh->do( "ALTER TABLE illrequests ADD COLUMN status_alias varchar(80) DEFAULT NULL AFTER status" );
+    } else {
+        # Migrate all existing foreign keys from referencing authorised_values.id
+        # to referencing authorised_values.authorised_value
+        # First remove the foreign key constraint and index
+        if ( foreign_key_exists( 'illrequests', 'illrequests_safk' ) ) {
+            $dbh->do( "ALTER TABLE illrequests DROP FOREIGN KEY illrequests_safk");
+        }
+        if ( index_exists( 'illrequests', 'illrequests_safk' ) ) {
+            $dbh->do( "DROP INDEX illrequests_safk ON illrequests" );
+        }
+        # Now change the illrequests.status_alias column definition from int to varchar
+        $dbh->do( "ALTER TABLE illrequests MODIFY COLUMN status_alias varchar(80)" );
+        # Now replace all references to authorised_values.id with their
+        # corresponding authorised_values.authorised_value
+        my $sth = $dbh->prepare( "SELECT illrequest_id, status_alias FROM illrequests WHERE status_alias IS NOT NULL" );
+        $sth->execute();
+        while (my @row = $sth->fetchrow_array()) {
+            my $r_id = $row[0];
+            my $av_id = $row[1];
+            # Get the authorised value's authorised_value value
+            my ($av_val) = $dbh->selectrow_array( "SELECT authorised_value FROM authorised_values WHERE id = ?", {}, $av_id );
+            # Now update illrequests.status_alias
+            if ($av_val) {
+                $dbh->do( "UPDATE illrequests SET status_alias = ? WHERE illrequest_id = ?", {}, ($av_val, $r_id) );
+            }
+        }
+    }
+    if ( !foreign_key_exists( 'illrequests', 'illrequests_safk' ) ) {
+        $dbh->do( "ALTER TABLE illrequests ADD CONSTRAINT illrequests_safk FOREIGN KEY (status_alias) REFERENCES authorised_values(authorised_value) ON UPDATE CASCADE ON DELETE SET NULL" );
+    }
+    $dbh->do( "INSERT IGNORE INTO authorised_value_categories SET category_name = 'ILLSTATUS'");
+
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 20581 - Allow manual selection of custom ILL request statuses)\n";
+}
+
+$DBversion = '18.12.00.017';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do(q{
+        INSERT IGNORE INTO account_offset_types ( type ) VALUES ( 'fine_increase' ), ( 'fine_decrease' );
+    });
+    $dbh->do(q{
+        UPDATE account_offsets SET type = 'fine_increase' WHERE type = 'Fine Update' AND amount > 0;
+    });
+    $dbh->do(q{
+        UPDATE account_offsets SET type = 'fine_decrease' WHERE type = 'Fine Update' AND amount < 0;
+    });
+
+    $dbh->do(q{
+        DELETE FROM account_offset_types WHERE type = 'Fine Update';
+    });
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 21747 - Update account_offset_types to include 'fine_increase' and 'fine_decrease')\n";
+}
+
+$DBversion = '18.12.00.018';
+if( CheckVersion( $DBversion ) ) {
+  $dbh->do( "UPDATE `search_field` SET `name` = 'date-of-publication', `label` = 'date-of-publication' WHERE `name` = 'pubdate'" );
+  $dbh->do( "UPDATE `search_field` SET `name` = 'title-series', `label` = 'title-series' WHERE `name` = 'se'" );
+  $dbh->do( "UPDATE `search_field` SET `name` = 'identifier-standard', `label` = 'identifier-standard' WHERE `name` = 'identifier-standard'" );
+  $dbh->do( "UPDATE `search_field` SET `name` = 'author', `label` = 'author' WHERE `name` = 'author'" );
+  $dbh->do( "UPDATE `search_field` SET `name` = 'control-number', `label` = 'control-number' WHERE `name` = 'control-number'" );
+  $dbh->do( "UPDATE `search_field` SET `name` = 'place-of-publication', `label` = 'place-of-publication' WHERE `name` = 'place'" );
+  $dbh->do( "UPDATE `search_field` SET `name` = 'date-of-acquisition', `label` = 'date-of-acquisition' WHERE `name` = 'acqdate'" );
+  $dbh->do( "UPDATE `search_field` SET `name` = 'isbn', `label` = 'isbn' WHERE `name` = 'isbn'" );
+  $dbh->do( "UPDATE `search_field` SET `name` = 'koha-auth-number', `label` = 'koha-auth-number' WHERE `name` = 'an'" );
+  $dbh->do( "UPDATE `search_field` SET `name` = 'subject', `label` = 'subject' WHERE `name` = 'subject'" );
+  $dbh->do( "UPDATE `search_field` SET `name` = 'publisher', `label` = 'publisher' WHERE `name` = 'publisher'" );
+  $dbh->do( "UPDATE `search_field` SET `name` = 'record-source', `label` = 'record-source' WHERE `name` = 'record-source'" );
+  $dbh->do( "UPDATE `search_field` SET `name` = 'title', `label` = 'title' WHERE `name` = 'title'" );
+  $dbh->do( "UPDATE `search_field` SET `name` = 'local-classification', `label` = 'local-classification' WHERE `name` = 'local-classification'" );
+  $dbh->do( "UPDATE `search_field` SET `name` = 'bib-level', `label` = 'bib-level' WHERE `name` = 'bib-level'" );
+  $dbh->do( "UPDATE `search_field` SET `name` = 'microform-generation', `label` = 'microform-generation' WHERE `name` = 'microform-generation'" );
+  $dbh->do( "UPDATE `search_field` SET `name` = 'material-type', `label` = 'material-type' WHERE `name` = 'material-type'" );
+  $dbh->do( "UPDATE `search_field` SET `name` = 'bgf-number', `label` = 'bgf-number' WHERE `name` = 'bgf-number'" );
+  $dbh->do( "UPDATE `search_field` SET `name` = 'number-db', `label` = 'number-db' WHERE `name` = 'number-db'" );
+  $dbh->do( "UPDATE `search_field` SET `name` = 'number-natl-biblio', `label` = 'number-natl-biblio' WHERE `name` = 'number-natl-biblio'" );
+  $dbh->do( "UPDATE `search_field` SET `name` = 'number-legal-deposit', `label` = 'number-legal-deposit' WHERE `name` = 'number-legal-deposit'" );
+  $dbh->do( "UPDATE `search_field` SET `name` = 'issn', `label` = 'issn' WHERE `name` = 'issn'" );
+  $dbh->do( "UPDATE `search_field` SET `name` = 'local-number', `label` = 'local-number' WHERE `name` = 'local-number'" );
+  $dbh->do( "UPDATE `search_field` SET `name` = 'suppress', `label` = 'supress' WHERE `name` = 'suppress'" );
+  $dbh->do( "UPDATE `search_field` SET `name` = 'bnb-card-number', `label` = 'bnb-card-number' WHERE `name` = 'bnb-card-number'" );
+  $dbh->do( "UPDATE `search_field` SET `name` = 'date/time-last-modified', `label` = 'date/time-last-modified' WHERE `name` = 'date-time-last-modified'" );
+  $dbh->do( "DELETE FROM `search_field` WHERE `name` = 'lc-cardnumber'" );
+  $dbh->do( "DELETE FROM `search_marc_map` WHERE `id` NOT IN(SELECT `search_marc_map_id` FROM `search_marc_to_field`)" );
+  SetVersion( $DBversion );
+  print "Upgrade to $DBversion done (Bug 19575 - Use canonical field names and resolve aliased fields)\n";
+}
+
+$DBversion = '18.12.00.019';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do(q{
+        INSERT IGNORE INTO account_offset_types ( type ) VALUES ( 'Reserve Fee' );
+    });
+
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 21728 - Add 'Reserve Fee' to the account_offset_types table if missing)\n";
+}
+
+$DBversion = '18.12.00.020';
+if( CheckVersion( $DBversion ) ) {
+    if ( TableExists( 'branch_borrower_circ_rules' ) ) {
+        if ( column_exists( 'branch_borrower_circ_rules', 'maxissueqty' ) ) {
+            $dbh->do("
+                INSERT INTO circulation_rules ( categorycode, branchcode, itemtype, rule_name, rule_value )
+                SELECT categorycode, branchcode, NULL, 'patron_maxissueqty', COALESCE( maxissueqty, '' )
+                FROM branch_borrower_circ_rules
+            ");
+            $dbh->do("
+                INSERT INTO circulation_rules ( categorycode, branchcode, itemtype, rule_name, rule_value )
+                SELECT categorycode, branchcode, NULL, 'patron_maxonsiteissueqty', COALESCE( maxonsiteissueqty, '' )
+                FROM branch_borrower_circ_rules
+            ");
+            $dbh->do("DROP TABLE branch_borrower_circ_rules");
+        }
+    }
+
+    if ( TableExists( 'default_borrower_circ_rules' ) ) {
+        if ( column_exists( 'default_borrower_circ_rules', 'maxissueqty' ) ) {
+            $dbh->do("
+                INSERT INTO circulation_rules ( categorycode, branchcode, itemtype, rule_name, rule_value )
+                SELECT categorycode, NULL, NULL, 'patron_maxissueqty', COALESCE( maxissueqty, '' )
+                FROM default_borrower_circ_rules
+            ");
+            $dbh->do("
+                INSERT INTO circulation_rules ( categorycode, branchcode, itemtype, rule_name, rule_value )
+                SELECT categorycode, NULL, NULL, 'patron_maxonsiteissueqty', COALESCE( maxonsiteissueqty, '' )
+                FROM default_borrower_circ_rules
+            ");
+            $dbh->do("DROP TABLE default_borrower_circ_rules");
+        }
+    }
+
+    if ( column_exists( 'default_circ_rules', 'maxissueqty' ) ) {
+        $dbh->do("
+            INSERT INTO circulation_rules ( categorycode, branchcode, itemtype, rule_name, rule_value )
+            SELECT NULL, NULL, NULL, 'patron_maxissueqty', COALESCE( maxissueqty, '' )
+            FROM default_circ_rules
+        ");
+        $dbh->do("
+            INSERT INTO circulation_rules ( categorycode, branchcode, itemtype, rule_name, rule_value )
+            SELECT NULL, NULL, NULL, 'patron_maxonsiteissueqty', COALESCE( maxonsiteissueqty, '' )
+            FROM default_circ_rules
+        ");
+        $dbh->do("ALTER TABLE default_circ_rules DROP COLUMN maxissueqty, DROP COLUMN maxonsiteissueqty");
+    }
+
+    if ( column_exists( 'default_branch_circ_rules', 'maxissueqty' ) ) {
+        $dbh->do("
+            INSERT INTO circulation_rules ( categorycode, branchcode, itemtype, rule_name, rule_value )
+            SELECT NULL, branchcode, NULL, 'patron_maxissueqty', COALESCE( maxissueqty, '' )
+            FROM default_branch_circ_rules
+        ");
+        $dbh->do("
+            INSERT INTO circulation_rules ( categorycode, branchcode, itemtype, rule_name, rule_value )
+            SELECT NULL, NULL, NULL, 'patron_maxonsiteissueqty', COALESCE( maxonsiteissueqty, '' )
+            FROM default_branch_circ_rules
+        ");
+        $dbh->do("ALTER TABLE default_branch_circ_rules DROP COLUMN maxissueqty, DROP COLUMN maxonsiteissueqty");
+    }
+
+    if ( column_exists( 'issuingrules', 'maxissueqty' ) ) {
+        # Cleaning invalid rules before, to avoid FK contraints to fail
+        $dbh->do(q|
+            DELETE FROM issuingrules WHERE categorycode != '*' AND categorycode NOT IN (SELECT categorycode FROM categories);
+        |);
+        $dbh->do(q|
+            DELETE FROM issuingrules WHERE branchcode != '*' AND branchcode NOT IN (SELECT branchcode FROM branches);
+        |);
+        $dbh->do(q|
+            DELETE FROM issuingrules WHERE itemtype != '*' AND itemtype NOT IN (SELECT itemtype FROM itemtypes);
+        |);
+
+        $dbh->do("
+            INSERT INTO circulation_rules ( categorycode, branchcode, itemtype, rule_name, rule_value )
+            SELECT IF(categorycode='*', NULL, categorycode),
+                   IF(branchcode='*', NULL, branchcode),
+                   IF(itemtype='*', NULL, itemtype),
+                   'maxissueqty',
+                   COALESCE( maxissueqty, '' )
+            FROM issuingrules
+        ");
+        $dbh->do("
+            INSERT INTO circulation_rules ( categorycode, branchcode, itemtype, rule_name, rule_value )
+            SELECT IF(categorycode='*', NULL, categorycode),
+                   IF(branchcode='*', NULL, branchcode),
+                   IF(itemtype='*', NULL, itemtype),
+                   'maxonsiteissueqty',
+                   COALESCE( maxonsiteissueqty, '' )
+            FROM issuingrules
+        ");
+        $dbh->do("ALTER TABLE issuingrules DROP COLUMN maxissueqty, DROP COLUMN maxonsiteissueqty");
+    }
+
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 18925 - Move maxissueqty and maxonsiteissueqty to circulation_rules)\n";
+}
+
+$DBversion = '18.12.00.021';
+if ( CheckVersion($DBversion) ) {
+
+    if ( !column_exists( 'itemtypes', 'rentalcharge_daily' ) ) {
+        $dbh->do("ALTER TABLE `itemtypes` ADD COLUMN `rentalcharge_daily` decimal(28,6) default NULL AFTER `rentalcharge`");
+    }
+
+    if ( !column_exists( 'itemtypes', 'rentalcharge_hourly' ) ) {
+        $dbh->do("ALTER TABLE `itemtypes` ADD COLUMN `rentalcharge_hourly` decimal(28,6) default NULL AFTER `rentalcharge_daily`");
+    }
+
+    if ( column_exists( 'itemtypes', 'rental_charge_daily' ) ) {
+        $dbh->do("UPDATE `itemtypes` SET `rentalcharge_daily` = `rental_charge_daily`");
+        $dbh->do("ALTER TABLE `itemtypes` DROP COLUMN `rental_charge_daily`");
+    }
+
+    SetVersion($DBversion);
+    print "Upgrade to $DBversion done (Bug 20912 - Support granular rental charges)\n";
+}
+
+$DBversion = '18.12.00.022';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do( q{
+        INSERT IGNORE INTO permissions (module_bit,code,description)
+        VALUES
+        (3,'manage_additional_fields','Add, edit, or delete additional custom fields for baskets or subscriptions (also requires order_manage or edit_subscription permissions)')
+    });
+    $dbh->do( q{
+        INSERT INTO user_permissions (borrowernumber, module_bit, code)
+        SELECT borrowernumber, 3, 'manage_additional_fields' FROM borrowers WHERE borrowernumber IN (SELECT DISTINCT borrowernumber FROM user_permissions WHERE code = 'order_manage' OR code = 'edit_subscription');
+    });
+    $dbh->do( q{
+        INSERT INTO user_permissions (borrowernumber, module_bit, code)
+        SELECT borrowernumber, 3, 'manage_additional_fields' FROM borrowers WHERE borrowernumber IN (SELECT borrowernumber FROM borrowers WHERE MOD(flags DIV POWER(2,11),2)=1 OR MOD(flags DIV POWER(2,15),2) =1);
+    });
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 15774 - Add permission for managing additional fields)\n";
+}
+
+$DBversion = '18.12.00.023';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do(q|
+      INSERT IGNORE INTO systempreferences (variable,value,explanation,options,type)
+      VALUES ('ILLOpacbackends',NULL,NULL,'ILL backends to enabled for OPAC initiated requests','multiple');
+    |);
+
+    # Always end with this (adjust the bug info)
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 20639 - Add ILLOpacbackends syspref)\n";
+}
+
+$DBversion = '18.12.00.024';
+if ( CheckVersion($DBversion) ) {
+
+    # Fixup any pre-existing bad suggestedby, manageddate, accepteddate dates
+    $dbh->do(
+        "UPDATE suggestions SET suggesteddate = '1970-01-01' WHERE suggesteddate = '0000-00-00';"    
+    );
+    $dbh->do(
+        "UPDATE suggestions SET manageddate = '1970-01-01' WHERE manageddate = '0000-00-00';"    
+    );
+    $dbh->do(
+        "UPDATE suggestions SET accepteddate = '1970-01-01' WHERE accepteddate = '0000-00-00';"    
+    );
+
+    # Add constraint for suggestedby
+    unless ( foreign_key_exists( 'suggestions', 'suggestions_ibfk_suggestedby' ) )
+    {
+        $dbh->do(
+"ALTER TABLE suggestions CHANGE COLUMN suggestedby suggestedby INT(11) NULL DEFAULT NULL;"
+        );
+        $dbh->do(
+"UPDATE suggestions LEFT JOIN borrowers ON (suggestions.suggestedby = borrowers.borrowernumber) SET suggestedby = null WHERE borrowernumber IS null"
+        );
+        $dbh->do(
+"ALTER TABLE suggestions ADD CONSTRAINT `suggestions_ibfk_suggestedby` FOREIGN KEY (`suggestedby`) REFERENCES `borrowers` (`borrowernumber`) ON DELETE SET NULL ON UPDATE CASCADE"
+        );
+    }
+
+    # Add constraint for managedby
+    unless ( foreign_key_exists( 'suggestions', 'suggestions_ibfk_managedby' ) )
+    {
+        $dbh->do(
+"UPDATE suggestions LEFT JOIN borrowers ON (suggestions.managedby = borrowers.borrowernumber) SET managedby = null WHERE borrowernumber IS NULL"
+        );
+        $dbh->do(
+"ALTER TABLE suggestions ADD CONSTRAINT `suggestions_ibfk_managedby` FOREIGN KEY (`managedby`) REFERENCES `borrowers` (`borrowernumber`) ON DELETE SET NULL ON UPDATE CASCADE"
+        );
+    }
+
+    # Add constraint for acceptedby
+    unless (
+        foreign_key_exists( 'suggestions', 'suggestions_ibfk_acceptedby' ) )
+    {
+        $dbh->do(
+"UPDATE suggestions LEFT JOIN borrowers ON (suggestions.acceptedby = borrowers.borrowernumber) SET acceptedby = null WHERE borrowernumber IS NULL"
+        );
+        $dbh->do(
+"ALTER TABLE suggestions ADD CONSTRAINT `suggestions_ibfk_acceptedby` FOREIGN KEY (`acceptedby`) REFERENCES `borrowers` (`borrowernumber`) ON DELETE SET NULL ON UPDATE CASCADE"
+        );
+    }
+
+    # Add constraint for rejectedby
+    unless (
+        foreign_key_exists( 'suggestions', 'suggestions_ibfk_rejectedby' ) )
+    {
+        $dbh->do(
+"UPDATE suggestions LEFT JOIN borrowers ON (suggestions.rejectedby = borrowers.borrowernumber) SET rejectedby = null WHERE borrowernumber IS null"
+        );
+        $dbh->do(
+"ALTER TABLE suggestions ADD CONSTRAINT `suggestions_ibfk_rejectedby` FOREIGN KEY (`rejectedby`) REFERENCES `borrowers` (`borrowernumber`) ON DELETE SET NULL ON UPDATE CASCADE"
+        );
+    }
+
+    # Add constraint for biblionumber
+    unless (
+        foreign_key_exists( 'suggestions', 'suggestions_ibfk_biblionumber' ) )
+    {
+        $dbh->do(
+"UPDATE suggestions s LEFT JOIN biblio b ON (s.biblionumber = b.biblionumber) SET s.biblionumber = null WHERE b.biblionumber IS null"
+        );
+        $dbh->do(
+"ALTER TABLE suggestions ADD CONSTRAINT `suggestions_ibfk_biblionumber` FOREIGN KEY (`biblionumber`) REFERENCES `biblio` (`biblionumber`) ON DELETE SET NULL ON UPDATE CASCADE"
+        );
+    }
+
+    # Add constraint for branchcode
+    unless (
+        foreign_key_exists( 'suggestions', 'suggestions_ibfk_branchcode' ) )
+    {
+        $dbh->do(
+"UPDATE suggestions s LEFT JOIN branches b ON (s.branchcode = b.branchcode) SET s.branchcode = null WHERE b.branchcode IS null"
+        );
+        $dbh->do(
+"ALTER TABLE suggestions ADD CONSTRAINT `suggestions_ibfk_branchcode` FOREIGN KEY (`branchcode`) REFERENCES `branches` (`branchcode`) ON DELETE SET NULL ON UPDATE CASCADE"
+        );
+    }
+
+    SetVersion($DBversion);
+    print
+"Upgrade to $DBversion done (Bug 22368 - Add missing constraints to suggestions)\n";
+}
+
+$DBversion = '18.12.00.025';
+if( CheckVersion( $DBversion ) ) {
+
+    $dbh->do('SET FOREIGN_KEY_CHECKS=0');
+
+    # Change columns accordingly
+    $dbh->do(q{
+        ALTER TABLE tags_index
+            MODIFY COLUMN term VARCHAR(191) COLLATE utf8mb4_bin NOT NULL;
+    });
+
+    $dbh->do(q{
+        ALTER TABLE tags_approval
+            MODIFY COLUMN term VARCHAR(191) COLLATE utf8mb4_bin NOT NULL;
+    });
+
+    $dbh->do(q{
+        ALTER TABLE tags_all
+            MODIFY COLUMN term VARCHAR(191) COLLATE utf8mb4_bin NOT NULL;
+    });
+
+    $dbh->do('SET FOREIGN_KEY_CHECKS=1');
+
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 21846 - Using emoji as tags has broken weights)\n";
+    my $maintenance_script = C4::Context->config("intranetdir") . "/misc/maintenance/fix_tags_weight.pl";
+    print "WARNING: (Bug 21846) You need to manually run $maintenance_script to fix possible issues with tags.\n";
+}
+
+$DBversion = '18.12.00.026';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do( "INSERT IGNORE INTO systempreferences (variable, value, explanation, type) VALUES ('IllLog', 0, 'If ON, log information about ILL requests', 'YesNo')" );
+
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 20750 - Allow timestamped auditing of ILL request events)\n";
+}
+
+$DBversion = '18.12.00.027';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do(q{
+INSERT IGNORE INTO systempreferences (variable,value,explanation,options,type) VALUES
+       ('ILLModuleUnmediated','0','','If enabled, try to immediately progress newly placed ILL requests.','YesNo');
+    });
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 18837: Add ILLModuleUnmediated Syspref)\n";
+}
+
+$DBversion = '18.12.00.028';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do(q{
+        INSERT IGNORE INTO account_offset_types ( type ) VALUES ( 'Account Fee' );
+    });
+
+    $dbh->do(q{
+        INSERT IGNORE INTO account_offset_types ( type ) VALUES ( 'Hold Expired' );
+    });
+
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 21756 - Add 'Account Fee' and 'Hold Expired' to the account_offset_types table if missing)\n";
+}
+
+$DBversion = '18.12.00.029';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do( "INSERT IGNORE INTO systempreferences (variable,value,explanation,options,type) VALUES ('OrderPriceRounding',NULL,'Local preference for rounding orders before calculations to ensure correct calculations','|nearest_cent','Choice')" );
+
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 18736 - Add syspref to control order rounding)\n";
+}
+
+$DBversion = '18.12.00.030';
+if( CheckVersion( $DBversion ) ) {
+    if( column_exists( 'accountlines', 'accountno' ) ) {
+        $dbh->do( "ALTER TABLE accountlines DROP COLUMN accountno" );
+    }
+    if( column_exists( 'statistics', 'proccode' ) ) {
+        $dbh->do( "ALTER TABLE statistics DROP COLUMN proccode" );
+    }
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 21683 - Remove accountlines.accountno and statistics.proccode fields)\n";
+}
+
+$DBversion = '18.12.00.031';
+if( CheckVersion( $DBversion ) ) {
+
+    # Add constraint for manager_id
+    unless( foreign_key_exists( 'accountlines', 'accountlines_ibfk_borrowers_2' ) ) {
+        $dbh->do("ALTER TABLE accountlines CHANGE COLUMN manager_id manager_id INT(11) NULL DEFAULT NULL");
+        $dbh->do("UPDATE accountlines a LEFT JOIN borrowers b ON ( a.manager_id = b.borrowernumber) SET a.manager_id = NULL WHERE b.borrowernumber IS NULL");
+        $dbh->do("ALTER TABLE accountlines ADD CONSTRAINT `accountlines_ibfk_borrowers_2` FOREIGN KEY (`manager_id`) REFERENCES `borrowers` (`borrowernumber`) ON DELETE SET NULL ON UPDATE CASCADE");
+    }
+
+    # Rename accountlines_ibfk_2 to accountlines_ibfk_items
+    if ( foreign_key_exists( 'accountlines', 'accountlines_ibfk_2' ) && !foreign_key_exists( 'accountlines', 'accountlines_ibfk_items' ) ) {
+        $dbh->do("ALTER TABLE accountlines DROP FOREIGN KEY accountlines_ibfk_2");
+        $dbh->do("ALTER TABLE accountlines ADD CONSTRAINT `accountlines_ibfk_items` FOREIGN KEY (`itemnumber`) REFERENCES `items` (`itemnumber`) ON DELETE SET NULL ON UPDATE CASCADE");
+    }
+
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 22008 - Add missing constraints for accountlines.manager_id)\n";
+}
+
+$DBversion = '18.12.00.032';
+if( CheckVersion( $DBversion ) ) {
+    if( !column_exists( 'search_field', 'facet_order' ) ) {
+        $dbh->do("ALTER TABLE search_field ADD COLUMN facet_order TINYINT(4) DEFAULT NULL AFTER weight");
+    }
+    $dbh->do("UPDATE search_field SET facet_order=1 WHERE name='author'");
+    $dbh->do("UPDATE search_field SET facet_order=2 WHERE name='itype'");
+    $dbh->do("UPDATE search_field SET facet_order=3 WHERE name='location'");
+    $dbh->do("UPDATE search_field SET facet_order=4 WHERE name='su-geo'");
+    $dbh->do("UPDATE search_field SET facet_order=5 WHERE name='title-series'");
+    $dbh->do("UPDATE search_field SET facet_order=6 WHERE name='subject'");
+    $dbh->do("UPDATE search_field SET facet_order=7 WHERE name='ccode'");
+    $dbh->do("UPDATE search_field SET facet_order=8 WHERE name='holdingbranch'");
+    $dbh->do("UPDATE search_field SET facet_order=9 WHERE name='homebranch'");
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 18235 - Elastic search - make facets configurable)\n";
+}
+
+$DBversion = '18.12.00.033';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do( "UPDATE search_field SET facet_order=10 WHERE name='ln'" );
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 18213 - Add language facets to Elasticsearch)\n";
+}
+
+$DBversion = '18.12.00.034';
+if( CheckVersion( $DBversion ) ) {
+
+    if ( column_exists( 'accountlines', 'lastincrement' ) ) {
+        $dbh->do("ALTER TABLE `accountlines` DROP COLUMN `lastincrement`");
+    }
+
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 22516 - Drop deprecated accountlines.lastincrement field)\n";
+}
+
+$DBversion = '18.12.00.035';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do( "INSERT IGNORE INTO systempreferences (variable, value, options, explanation, type)
+               VALUES ('MaxItemsToDisplayForBatchMod','1000',NULL,'Display up to a given number of items in a single item modification batch.','Integer')"
+            );
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 19722 - Add a MaxItemsToDisplayForBatchMod preference)\n";
+}
+
+$DBversion = '18.12.00.036';
+if ( CheckVersion($DBversion) ) {
+
+    my $rows = $dbh->do(
+        qq{
+        UPDATE `accountlines`
+        SET
+          `accounttype` = 'FU'
+        WHERE
+          `accounttype` = 'O'
+      }
+    );
+
+    SetVersion($DBversion);
+    printf "Upgrade to $DBversion done (Bug 22518 - Fix accounttype 'O' to 'FU' - %d updated)\n", $rows;
+}
+
+$DBversion = '18.12.00.037';
+if( CheckVersion( $DBversion ) ) {
+
+    $dbh->do( "UPDATE issues SET renewals = 0 WHERE renewals IS NULL" );
+    $dbh->do( "UPDATE old_issues SET renewals = 0 WHERE renewals IS NULL" );
+
+    $dbh->do( "ALTER TABLE issues MODIFY COLUMN renewals tinyint(4) NOT NULL default 0");
+    $dbh->do( "ALTER TABLE old_issues MODIFY COLUMN renewals tinyint(4) NOT NULL default 0");
+
+    # Always end with this (adjust the bug info)
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 22607 - Set default value of issues.renewals to 0)\n";
+}
+
+$DBversion = '18.12.00.038';
+if ( CheckVersion($DBversion) ) {
+
+    if ( !column_exists( 'accountlines', 'status' ) ) {
+        $dbh->do(
+            qq{
+            ALTER TABLE `accountlines`
+            ADD
+              `status` varchar(16) DEFAULT NULL
+            AFTER
+              `accounttype`
+          }
+        );
+    }
+
+    SetVersion($DBversion);
+    print "Upgrade to $DBversion done (Bug 22512 - Add status to accountlines)\n";
+}
+
+$DBversion = '18.12.00.039';
+if ( CheckVersion($DBversion) ) {
+
+    if ( !column_exists( 'accountlines', 'interface' ) ) {
+        $dbh->do(
+            qq{
+            ALTER TABLE `accountlines`
+            ADD
+              `interface` varchar(16)
+            AFTER
+              `manager_id`;
+          }
+        );
+    }
+
+    $dbh->do(qq{
+        UPDATE
+          `accountlines`
+        SET
+          interface = 'opac'
+        WHERE
+          borrowernumber = manager_id;
+    });
+
+    $dbh->do(qq{
+        UPDATE
+          `accountlines`
+        SET
+          interface = 'cron'
+        WHERE
+          manager_id IS NULL
+        AND
+          branchcode IS NULL;
+    });
+
+    $dbh->do(qq{
+        UPDATE
+          `accountlines`
+        SET
+          interface = 'intranet'
+        WHERE
+          interface IS NULL;
+    });
+
+    $dbh->do(qq{
+        ALTER TABLE `accountlines`
+        MODIFY COLUMN `interface` varchar(16) NOT NULL;
+    });
+
+    SetVersion($DBversion);
+    print "Upgrade to $DBversion done (Bug 22600 - Add interface to accountlines)\n";
+}
+
+$DBversion = '18.12.00.040';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do("UPDATE accountlines SET description = REPLACE(description, 'Reserve Charge - ', '') WHERE description LIKE 'Reserve Charge - %'");
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 12166 - Remove 'Reserve Charge' text from accountlines description)\n";
+}
+
+$DBversion = '18.12.00.041';
+if( CheckVersion( $DBversion ) ) {
+    my $table_sth = $dbh->prepare('SHOW CREATE TABLE `search_marc_map`');
+    $table_sth->execute();
+    my @table = $table_sth->fetchrow_array();
+    unless ( $table[1] =~ /`marc_field`.*COLLATE utf8mb4_bin/ ) { #catches utf8mb4 collated tables
+        $dbh->do("ALTER TABLE `search_marc_map` MODIFY `marc_field` VARCHAR(255) NOT NULL COLLATE utf8mb4_bin COMMENT 'the MARC specifier for this field'");
+    }
+
+    # Always end with this (adjust the bug info)
+    SetVersion( $DBversion );
+       print "Upgrade to $DBversion done (Bug 19670 - Change collation of marc_field to allow mixed case search field mappings)\n";
+}
+
+$DBversion = '18.12.00.042';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do( "UPDATE systempreferences SET value = 'default' WHERE variable = 'XSLTDetailsDisplay' AND value = ''" );
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 29891 - Remove non-XSLT detail view in the staff client)\n";
+}
+
+$DBversion = '18.12.00.043';
+if ( CheckVersion($DBversion) ) {
+    $dbh->do("UPDATE accountlines SET description = REPLACE(description, 'Lost Item ', '') WHERE description LIKE 'Lost Item %'");
+    SetVersion($DBversion);
+    print "Upgrade to $DBversion done (Bug 21953 - Remove 'Lost Item' text from accountlines description)\n";
+}
+
+$DBversion = '18.12.00.044';
+if( CheckVersion( $DBversion ) ) {
+
+    if ( !column_exists( 'categories', 'reset_password' ) ) {
+        $dbh->do(q{
+            ALTER TABLE categories
+                ADD COLUMN reset_password TINYINT(1) NULL DEFAULT NULL
+                AFTER checkprevcheckout
+        });
+    }
+
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 21890 - Patron password reset by category)\n";
+}
+
+$DBversion = '18.12.00.045';
+if( CheckVersion( $DBversion ) ) {
+
+    if ( !column_exists( 'categories', 'change_password' ) ) {
+        $dbh->do(q{
+            ALTER TABLE categories
+                ADD COLUMN change_password TINYINT(1) NULL DEFAULT NULL
+                AFTER reset_password
+        });
+    }
+
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 10796 - Patron password change by category)\n";
+}
+
+$DBversion = '18.12.00.046';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do( "UPDATE systempreferences SET value = 'default' WHERE variable = 'XSLTResultsDisplay' AND value = ''" );
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 22695 - Remove non-XSLT search results view from the staff client)\n";
+}
+
+$DBversion = '18.12.00.047';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do(q|
+        INSERT IGNORE INTO systempreferences (variable,value,explanation,options,type) VALUES ('LibrisKey', '', 'This key must be obtained at http://api.libris.kb.se/. It is unique for the IP of the server.', NULL, 'Free');
+    |);
+    $dbh->do(q|
+        INSERT IGNORE INTO systempreferences (variable,value,explanation,options,type) VALUES ('LibrisURL', 'http://api.libris.kb.se/bibspell/', 'This is the base URL for the Libris spellchecking API.',NULL,'Free');
+    |);
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 14557: Add Libris spellchecking system preferences)\n";
+}
+
+$DBversion = '18.12.00.048';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do( q{
+        INSERT IGNORE INTO systempreferences (variable,value,explanation,options,type)
+        VALUES ('NoRenewalBeforePrecision', 'exact_time', 'Calculate "No renewal before" based on date or exact time. Only relevant for loans calculated in days, hourly loans are not affected.', 'date|exact_time', 'Choice');
+    });
+    $dbh->do("UPDATE systempreferences SET value='exact_time' WHERE variable='NoRenewalBeforePrecision' AND value IS NULL;" );
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 22044 - Set a default value for NoRenewalBeforePrecision)\n";
+}
+
+$DBversion = '18.12.00.049';
+if( CheckVersion( $DBversion ) ) {
+
+    $dbh->do(q{
+        ALTER TABLE borrowers
+            ADD COLUMN flgAnonymized tinyint DEFAULT 0
+            AFTER overdrive_auth_token
+    }) if !column_exists('borrowers', 'flgAnonymized');
+
+    $dbh->do(q{
+        ALTER TABLE deletedborrowers
+            ADD COLUMN flgAnonymized tinyint DEFAULT 0
+            AFTER overdrive_auth_token
+    }) if !column_exists('deletedborrowers', 'flgAnonymized');
+
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 21336 - Add field flgAnonymized)\n";
+}
+
+$DBversion = '18.12.00.050';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do( q|
+INSERT IGNORE INTO systempreferences ( `variable`, `value`, `options`, `explanation`, `type` )
+VALUES
+('UnsubscribeReflectionDelay','',NULL,'Delay for locking unsubscribers', 'Integer'),
+('PatronAnonymizeDelay','',NULL,'Delay for anonymizing patrons', 'Integer'),
+('PatronRemovalDelay','',NULL,'Delay for removing anonymized patrons', 'Integer')
+    |);
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 21336 - Add preferences)\n";
+}
+
+$DBversion = '18.12.00.051';
+if( CheckVersion( $DBversion ) ) {
+    my $failed_attempts = C4::Context->preference('FailedLoginAttempts');
+    $dbh->do( "UPDATE borrowers SET login_attempts = ? WHERE login_attempts > ?", undef, $failed_attempts, $failed_attempts ) if $failed_attempts && $failed_attempts > 0;
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 21336 - Reset login_attempts)\n";
+}
+
+$DBversion = '18.12.00.052';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do(q{
+        INSERT IGNORE INTO systempreferences ( `variable`, `value`, `options`, `explanation`, `type` ) VALUES
+        ('OpacMoreSearches', '', NULL, 'Add additional elements to the OPAC more searches bar', 'Textarea')
+    } );
+
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 22311 - Add a SysPref to allow adding content to the #moresearches div in the opac)\n";
+}
+
+$DBversion = '18.12.00.053';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do(q{
+        INSERT IGNORE INTO `systempreferences` (`variable`, `value`, `options`, `explanation`, `type`) VALUES
+        ('AutoReturnCheckedOutItems', '0', '', 'If disabled, librarian must confirm return of checked out item when checking out to another.', 'YesNo');
+    });
+
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 17171 - Add a syspref to allow currently issued items to be issued to a new patron without staff confirmation)\n";
+}
+
+$DBversion = '18.12.00.054';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do(q{
+        INSERT IGNORE permissions (module_bit, code, description)
+        VALUES
+        (9,'advanced_editor','Use the advanced cataloging editor')
+    });
+    if( C4::Context->preference('EnableAdvancedCatalogingEditor') ){
+        $dbh->do(q{
+            INSERT INTO user_permissions (borrowernumber, module_bit, code)
+            SELECT borrowernumber, 9, 'advanced_editor' FROM borrowers WHERE borrowernumber IN (SELECT DISTINCT borrowernumber FROM user_permissions WHERE code = 'edit_catalogue');
+        });
+    }
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 20128: Add permission for Advanced Cataloging Editor)\n";
+}
+
+$DBversion = '18.12.00.055';
+if ( CheckVersion($DBversion) ) {
+
+    $dbh->do(qq{
+        UPDATE
+          `account_offset_types`
+        SET
+          type = 'OVERDUE'
+        WHERE
+          type = 'Fine';
+    });
+
+    $dbh->do(qq{
+        UPDATE
+          `account_offset_types`
+        SET
+          type = 'OVERDUE_INCREASE'
+        WHERE
+          type = 'fine_increase';
+    });
+
+    $dbh->do(qq{
+        UPDATE
+          `account_offset_types`
+        SET
+          type = 'OVERDUE_DECREASE'
+        WHERE
+          type = 'fine_decrease';
+    });
+
+    if ( column_exists( 'accountlines', 'accounttype' ) ) {
+        $dbh->do(
+            qq{
+            ALTER TABLE `accountlines`
+            CHANGE COLUMN `accounttype`
+              `accounttype` varchar(16) DEFAULT NULL;
+          }
+        );
+    }
+
+    $dbh->do(qq{
+        UPDATE
+          accountlines
+        SET
+          accounttype = 'OVERDUE',
+          status = 'UNRETURNED'
+        WHERE
+          accounttype = 'FU';
+    });
+
+    $dbh->do(qq{
+        UPDATE
+          accountlines
+        SET
+          accounttype = 'OVERDUE',
+          status = 'FORGIVEN'
+        WHERE
+          accounttype = 'FFOR';
+    });
+
+    $dbh->do(qq{
+        UPDATE
+          accountlines
+        SET
+          accounttype = 'OVERDUE',
+          status = 'RETURNED'
+        WHERE
+          accounttype = 'F';
+    });
+    SetVersion($DBversion);
+    print "Upgrade to $DBversion done (Bug 22521 - Update accountlines.accounttype to varchar(16), and map new statuses)\n";
+}
+
+$DBversion = '18.12.00.056';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do( "UPDATE systempreferences SET explanation = 'This syspref allows to define custom rules for hiding specific items at the OPAC. See http://wiki.koha-community.org/wiki/OpacHiddenItems for more information.' WHERE variable = 'OpacHiddenItems'");
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 8701 - Update OpacHiddenItems system preference description)\n";
+}
+
+$DBversion = '18.12.00.057';
+if( CheckVersion( $DBversion ) ) {
+    if( column_exists('statistics', 'associatedborrower') ) {
+        $dbh->do(q{ ALTER TABLE statistics DROP COLUMN associatedborrower });
+    }
+    if( column_exists('statistics', 'usercode') ) {
+        $dbh->do(q{ ALTER TABLE statistics DROP COLUMN usercode });
+    }
+
+    SetVersion($DBversion);
+    print "Upgrade to $DBversion done (Bug 13795 - Delete unused fields from statistics table)\n";
+}
+
+$DBversion = '18.12.00.058';
+if( CheckVersion( $DBversion ) ) {
+    my $opaclang = C4::Context->preference("opaclanguages");
+    my @langs;
+    push @langs, split ( '\,', $opaclang );
+    # Get any existing value from the OpacNavRight system preference
+    my ($OpacNavRight) = $dbh->selectrow_array( q|
+        SELECT value FROM systempreferences WHERE variable='OpacNavRight';
+    |);
+    if( $OpacNavRight ){
+        # If there is a value in the OpacNavRight preference, insert it into opac_news
+        $dbh->do("INSERT INTO opac_news (branchcode, lang, title, content ) VALUES (NULL, ?, '', ?)", undef, "OpacNavRight_$langs[0]", $OpacNavRight);
+    }
+    # Remove the OpacNavRight system preference
+    $dbh->do("DELETE FROM systempreferences WHERE variable='OpacNavRight'");
+    SetVersion ($DBversion);
+    print "Upgrade to $DBversion done (Bug 22318: Move contents of OpacNavRight preference to Koha news system)\n";
+}
+
+$DBversion = '18.12.00.059';
+if( CheckVersion( $DBversion ) ) {
+    if( column_exists( 'import_records', 'z3950random' ) ) {
+        $dbh->do( "ALTER TABLE import_records DROP COLUMN z3950random" );
+    }
+
+    # Always end with this (adjust the bug info)
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 22532 - Remove import_records z3950random column)\n";
+}
+
+$DBversion = '18.12.00.060';
+if ( CheckVersion($DBversion) ) {
+
+    my $rows = $dbh->do(
+        qq{
+        UPDATE `accountlines`
+        SET
+          `accounttype` = 'L',
+          `status`      = 'REPLACED'
+        WHERE
+          `accounttype` = 'Rep'
+      }
+    );
+
+    SetVersion($DBversion);
+    printf "Upgrade to $DBversion done (Bug 22564 - Fix accounttype 'Rep' - %d updated)\n", $rows;
+}
+
+$DBversion = '18.12.00.061';
+if( CheckVersion( $DBversion ) ) {
+
+    if ( column_exists( 'borrowers', 'flgAnonymized' ) ) {
+        $dbh->do(q{
+            UPDATE borrowers SET flgAnonymized = 0 WHERE flgAnonymized IS NULL
+        });
+        $dbh->do(q{
+            ALTER TABLE borrowers
+                CHANGE `flgAnonymized` `anonymized` TINYINT(1) NOT NULL DEFAULT 0
+        });
+    }
+
+    if ( column_exists( 'deletedborrowers', 'flgAnonymized' ) ) {
+        $dbh->do(q{
+            UPDATE deletedborrowers SET flgAnonymized = 0 WHERE flgAnonymized IS NULL
+        });
+        $dbh->do(q{
+            ALTER TABLE deletedborrowers
+                CHANGE `flgAnonymized` `anonymized` TINYINT(1) NOT NULL DEFAULT 0
+        });
+    }
+
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 21336 - (follow-up) Rename flgAnonymized column)\n";
+}
+
+$DBversion = '18.12.00.062';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do( q|
+        UPDATE search_marc_map SET marc_field='007_/0'
+          WHERE marc_type IN ('marc21', 'normarc') AND marc_field='007_/1' AND id IN
+            (SELECT search_marc_map_id FROM search_marc_to_field WHERE search_field_id IN
+              (SELECT id FROM search_field WHERE label='ff7-00')
+            )
+    |);
+
+    $dbh->do( q|
+        UPDATE search_marc_map SET marc_field='007_/1'
+          WHERE marc_type IN ('marc21', 'normarc') AND marc_field='007_/2' AND id IN
+            (SELECT search_marc_map_id FROM search_marc_to_field WHERE search_field_id IN
+              (SELECT id FROM search_field WHERE label='ff7-01')
+            )
+    |);
+
+    $dbh->do( q|
+        UPDATE search_marc_map SET marc_field='007_/2'
+          WHERE marc_type IN ('marc21', 'normarc') AND marc_field='007_/3' AND id IN
+            (SELECT search_marc_map_id FROM search_marc_to_field WHERE search_field_id IN
+              (SELECT id FROM search_field WHERE label='ff7-02')
+            )
+    |);
+
+    # N.B. ff7-01-02 really is 00-01!
+    $dbh->do( q|
+        UPDATE search_marc_map SET marc_field='007_/0-1'
+          WHERE marc_type IN ('marc21', 'normarc') AND marc_field='007_/1-2' AND id IN
+            (SELECT search_marc_map_id FROM search_marc_to_field WHERE search_field_id IN
+              (SELECT id FROM search_field WHERE label='ff7-01-02')
+            )
+    |);
+
+    $dbh->do( q|
+        UPDATE search_marc_map SET marc_field='008_/0-5'
+          WHERE marc_type IN ('marc21', 'normarc') AND marc_field='008_/1-5' AND id IN
+            (SELECT search_marc_map_id FROM search_marc_to_field WHERE search_field_id IN
+              (SELECT id FROM search_field WHERE label='date-entered-on-file')
+            )
+    |);
+
+    $dbh->do( q|
+        UPDATE search_marc_map SET marc_field='leader_/0-4'
+          WHERE marc_type IN ('marc21', 'normarc') AND marc_field='leader_/1-5' AND id IN
+            (SELECT search_marc_map_id FROM search_marc_to_field WHERE search_field_id IN
+              (SELECT id FROM search_field WHERE label='llength')
+            )
+    |);
+
+    # Always end with this (adjust the bug info)
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 22339 - Fix search field mappings of MARC fixed fields)\n";
+}
+
+$DBversion = '18.12.00.063';
+if ( CheckVersion($DBversion) ) {
+
+    my $types_map = {
+        'Writeoff'      => 'W',
+        'Payment'       => 'Pay',
+        'Lost Item'     => 'CR',
+        'Manual Credit' => 'C',
+        'Forgiven'      => 'FOR'
+    };
+
+    my $sth = $dbh->prepare( "SELECT accountlines_id FROM accountlines WHERE accounttype = 'VOID'" );
+    my $sth2 = $dbh->prepare( "SELECT type FROM account_offsets WHERE credit_id = ? ORDER BY created_on LIMIT 1" );
+    my $sth3 = $dbh->prepare( "UPDATE accountlines SET accounttype = ?, status = 'VOID' WHERE accountlines_id = ?" );
+    $sth->execute();
+    while (my $row = $sth->fetchrow_hashref) {
+        $sth2->execute($row->{accountlines_id});
+        my $result = $sth2->fetchrow_hashref;
+        my $type = $types_map->{$result->{'type'}} // 'Pay';
+        $sth3->execute($type,$row->{accountlines_id});
+    }
+
+    SetVersion($DBversion);
+    print "Upgrade to $DBversion done (Bug 22511 - Update existing VOID accountlines)\n";
+}
+
+$DBversion = '18.12.00.064';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do(q{
+        INSERT IGNORE INTO systempreferences (variable,value,options,explanation,type) VALUES ('UpdateItemLocationOnCheckin', 'PROC: _PERM_\n', 'NULL', 'This is a list of value pairs.\n Examples:\n PROC: FIC - causes an item in the Processing Center location to be updated into the Fiction location on check in.\n FIC: GEN - causes an item in the Fiction location to be updated into the General stacks location on check in.\n _BLANK_:FIC - causes an item that has no location to be updated into the Fiction location on check in.\nFIC: _BLANK_ - causes an item in location FIC to be updated to a blank location on check in.\n_ALL_:FIC - causes all items to be updated into the Fiction location on check in.\nPROC: _PERM_ - causes an item that is in the Processing Center to be updated to it''s permanent location.\nGeneral rule: if the location value on the left matches the item''s current location, it will be updated to match the location value on the right.\nNote: PROC and CART are special values, for these locations only can location and permanent_location differ, in all other cases an update will affect both. Items in the CART location will be returned to their permanent location on checkout.\nThe special term _BLANK_ may be used on either side of a value pair to update or remove the location from items with no location assigned. The special term _ALL_ is used on the left side of the colon (:) to affect all items.\nThe special term _PERM_ is used on the right side of the colon (:) to return items to their permanent location.', 'Free');
+    });
+    $dbh->do(q{
+        UPDATE systempreferences s1, (SELECT IF(value,'PROC: CART\n','') AS p2c FROM systempreferences WHERE variable='InProcessingToShelvingCart') s2 SET s1.value= CONCAT(s2.p2c, REPLACE(s1.value,'PROC: _PERM_\n','') ) WHERE s1.variable='UpdateItemLocationOnCheckin' AND s1.value NOT LIKE '%PROC: CART%';
+    });
+    $dbh->do(q{
+        DELETE FROM systempreferences WHERE variable='InProcessingToShelvingCart';
+    });
+    $dbh->do(q{
+        UPDATE systempreferences s1, (SELECT IF(value,'_ALL_: CART\n','') AS rtc FROM systempreferences WHERE variable='ReturnToShelvingCart') s2 SET s1.value= CONCAT(s2.rtc,s1.value) WHERE s1.variable='UpdateItemLocationOnCheckin' AND s1.value NOT LIKE '%_ALL_: CART%';
+    });
+    $dbh->do(q{
+        DELETE FROM systempreferences WHERE variable='ReturnToShelvingCart';
+    });
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 14576: Add UpdateItemLocationOnCheckin syspref)\n";
+}
+
+$DBversion = '18.12.00.065';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do( q{
+        INSERT IGNORE INTO systempreferences ( `variable`, `value`, `options`, `explanation`, `type` )
+        SELECT 'IndependentBranchesTransfers', value, NULL, 'Allow non-superlibrarians to transfer items between libraries','YesNo'
+        FROM systempreferences WHERE variable = 'IndependentBranches'
+    });
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 10300 - Allow transferring of items to be have separate IndependentBranches syspref)\n";
+}
+
+$DBversion = '18.12.00.066';
+if ( CheckVersion($DBversion) ) {
+    $dbh->do(q{
+        INSERT IGNORE INTO `systempreferences` (`variable`, `value`, `explanation`, `options`, `type`) VALUES
+          ('OpenURLResolverURL', '', 'URL of OpenURL Resolver', NULL, 'Free'),
+          ('OpenURLText', '', 'Text of OpenURL links (or image title if OpenURLImageLocation is defined)', NULL, 'Free'),
+          ('OpenURLImageLocation', '', 'Location of image for OpenURL links', NULL, 'Free'),
+          ('OPACShowOpenURL', '', 'Enable display of OpenURL links in OPAC search results and detail page', NULL, 'YesNo'),
+          ('OPACOpenURLItemTypes', '', 'Show the OpenURL link only for these item types', NULL, 'Free');
+    });
+
+    SetVersion($DBversion);
+    print
+"Upgrade to $DBversion done (Bug 8995 - Add new preferences for OpenURLResolvers)\n";
+}
+
+$DBversion = '18.12.00.067';
+if ( CheckVersion($DBversion) ) {
+    $dbh->do(q{
+        INSERT IGNORE INTO systempreferences (variable,value,options,explanation,type)
+        VALUES ('SendAllEmailsTo','',NULL,'All emails will be redirected to this email if it is not empty','free');
+    });
+    SetVersion($DBversion);
+    print
+"Upgrade to $DBversion done (Bug 8000 - Add new preferences for SendAllEmailsTo)\n";
+}
+
+$DBversion = '18.12.00.068';
+if ( CheckVersion($DBversion) ) {
+    $dbh->do(q{
+        INSERT IGNORE INTO systempreferences (variable,value,explanation,options,type) VALUES
+        ('AllowRenewalOnHoldOverride','0','','If on, allow items on hold to be renewed with a specified due date','YesNo');
+    });
+    SetVersion($DBversion);
+    print "Upgrade to $DBversion done (Bug 7088: Cannot renew items on hold even with override)\n";
+}
+
+$DBversion = '18.12.00.069';
+if( CheckVersion( $DBversion ) ) {
+
+    $dbh->do(q{
+        INSERT INTO plugin_data
+            (plugin_class, plugin_key, plugin_value)
+        SELECT
+            plugin_class,
+            '__ENABLED__',
+            1
+        FROM plugin_data
+        WHERE plugin_key='__INSTALLED_VERSION__'
+    });
+
+    # Always end with this (adjust the bug info)
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 22053 - enable all plugins)\n";
+}
+
+$DBversion = '18.12.00.070';
+if ( CheckVersion($DBversion) ) {
+    $dbh->do(q{
+        INSERT IGNORE INTO systempreferences
+            ( `variable`, `value`, `options`, `explanation`, `type` )
+        VALUES
+        ('SelfCheckAllowByIPRanges','',NULL,'(Leave blank if not used. Use ranges or simple ip addresses separated by spaces, like <code>192.168.1.1 192.168.0.0/24</code>.)','Short');
+    });
+    SetVersion($DBversion);
+    print "Upgrade to $DBversion done (Bug 14407 - Limit web-based self-checkout to specific IP addresses)\n";
+}
+
+$DBversion = '18.12.00.071';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do(q{
+INSERT IGNORE INTO `letter` (`module`, `code`, `branchcode`, `name`, `is_html`, `title`, `content`, `message_transport_type`, `lang`) VALUES
+('circulation', 'ACCOUNT_CREDIT', '', 'Account payment', 0, 'Account payment', '<table>
+[% IF ( LibraryName ) %]
+ <tr>
+    <th colspan="4" class="centerednames">
+        <h3>[% LibraryName | html %]</h3>
+    </th>
+ </tr>
+[% END %]
+ <tr>
+    <th colspan="4" class="centerednames">
+        <h2><u>Fee receipt</u></h2>
+    </th>
+ </tr>
+ <tr>
+    <th colspan="4" class="centerednames">
+        <h2>[% Branches.GetName( patron.branchcode ) | html %]</h2>
+    </th>
+ </tr>
+ <tr>
+    <th colspan="4">
+        Received with thanks from  [% patron.firstname | html %] [% patron.surname | html %] <br />
+        Card number: [% patron.cardnumber | html %]<br />
+    </th>
+ </tr>
+  <tr>
+    <th>Date</th>
+    <th>Description of charges</th>
+    <th>Note</th>
+    <th>Amount</th>
+ </tr>
+
+  [% FOREACH account IN accounts %]
+    <tr class="highlight">
+      <td>[% account.date | $KohaDates %]</td>
+      <td>
+        [% PROCESS account_type_description account=account %]
+        [%- IF account.description %], [% account.description | html %][% END %]
+      </td>
+      <td>[% account.note | html %]</td>
+      [% IF ( account.amountcredit ) %]<td class="credit">[% ELSE %]<td class="debit">[% END %][% account.amount | $Price %]</td>
+    </tr>
+
+  [% END %]
+<tfoot>
+  <tr>
+    <td colspan="3">Total outstanding dues as on date: </td>
+    [% IF ( totalcredit ) %]<td class="credit">[% ELSE %]<td class="debit">[% END %][% total | $Price %]</td>
+  </tr>
+</tfoot>
+</table>', 'print', 'default');
+    });
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 22809 - Move 'ACCOUNT_CREDIT' from template to a slip)\n";
+}
+
+$DBversion = '18.12.00.072';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do(q{
+INSERT IGNORE INTO `letter` (`module`, `code`, `branchcode`, `name`, `is_html`, `title`, `content`, `message_transport_type`, `lang`) VALUES
+('circulation', 'ACCOUNT_DEBIT', '', 'Account fee', 0, 'Account fee', '<table>
+  [% IF ( LibraryName ) %]
+    <tr>
+      <th colspan="5" class="centerednames">
+        <h3>[% LibraryName | html %]</h3>
+      </th>
+    </tr>
+  [% END %]
+
+  <tr>
+    <th colspan="5" class="centerednames">
+      <h2><u>INVOICE</u></h2>
+    </th>
+  </tr>
+  <tr>
+    <th colspan="5" class="centerednames">
+      <h2>[% Branches.GetName( patron.branchcode ) | html %]</h2>
+    </th>
+  </tr>
+  <tr>
+    <th colspan="5" >
+      Bill to: [% patron.firstname | html %] [% patron.surname | html %] <br />
+      Card number: [% patron.cardnumber | html %]<br />
+    </th>
+  </tr>
+  <tr>
+    <th>Date</th>
+    <th>Description of charges</th>
+    <th>Note</th>
+    <th style="text-align:right;">Amount</th>
+    <th style="text-align:right;">Amount outstanding</th>
+  </tr>
+
+  [% FOREACH account IN accounts %]
+    <tr class="highlight">
+      <td>[% account.date | $KohaDates%]</td>
+      <td>
+        [% PROCESS account_type_description account=account %]
+        [%- IF account.description %], [% account.description | html %][% END %]
+      </td>
+      <td>[% account.note | html %]</td>
+      [% IF ( account.amountcredit ) %]<td class="credit">[% ELSE %]<td class="debit">[% END %][% account.amount | $Price %]</td>
+      [% IF ( account.amountoutstandingcredit ) %]<td class="credit">[% ELSE %]<td class="debit">[% END %][% account.amountoutstanding | $Price %]</td>
+    </tr>
+  [% END %]
+
+  <tfoot>
+    <tr>
+      <td colspan="4">Total outstanding dues as on date: </td>
+      [% IF ( totalcredit ) %]<td class="credit">[% ELSE %]<td class="debit">[% END %][% total | $Price %]</td>
+    </tr>
+  </tfoot>
+</table>', 'print', 'default');
+    });
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 22809 - Move 'INVOICE' from template to a slip)\n";
+}
+
+$DBversion = '18.12.00.073';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do( q{
+            INSERT IGNORE INTO systempreferences (variable,value,options,explanation,type) VALUES
+            ('EmailPurchaseSuggestions','0','0|EmailAddressForSuggestions|BranchEmailAddress|KohaAdminEmailAddress','Choose email address that will be sent new purchase suggestions','Choice'),
+            ('EmailAddressForSuggestions','','','If you choose EmailAddressForSuggestions you should enter a valid email address','free')
+    });
+
+    $dbh->do( q{
+            INSERT IGNORE INTO `letter` (module, code, name, title, content, is_html, message_transport_type) VALUES
+            ('suggestions','NEW_SUGGESTION','New suggestion','New suggestion','<h3>Suggestion pending approval</h3>
+                <p><h4>Suggested by</h4>
+                    <ul>
+                        <li><<borrowers.firstname>> <<borrowers.surname>></li>
+                        <li><<borrowers.cardnumber>></li>
+                        <li><<borrowers.phone>></li>
+                        <li><<borrowers.email>></li>
+                    </ul>
+                </p>
+                <p><h4>Title suggested</h4>
+                    <ul>
+                        <li><b>Library:</b> <<branches.branchname>></li>
+                        <li><b>Title:</b> <<suggestions.title>></li>
+                        <li><b>Author:</b> <<suggestions.author>></li>
+                        <li><b>Copyright date:</b> <<suggestions.copyrightdate>></li>
+                        <li><b>Standard number (ISBN, ISSN or other):</b> <<suggestions.isbn>></li>
+                        <li><b>Publisher:</b> <<suggestions.publishercode>></li>
+                        <li><b>Collection title:</b> <<suggestions.collectiontitle>></li>
+                        <li><b>Publication place:</b> <<suggestions.place>></li>
+                        <li><b>Quantity:</b> <<suggestions.quantity>></li>
+                        <li><b>Item type:</b> <<suggestions.itemtype>></li>
+                        <li><b>Reason for suggestion:</b> <<suggestions.patronreason>></li>
+                        <li><b>Notes:</b> <<suggestions.note>></li>
+                    </ul>
+                </p>',1, 'email')
+    });
+
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 5770 - Email librarian when purchase suggestion made)\n";
+}
+
+$DBversion = '18.12.00.074';
+if( CheckVersion( $DBversion ) ) {
+    unless ( TableExists( 'keyboard_shortcuts' ) ) {
+        $dbh->do(q|
+            CREATE TABLE keyboard_shortcuts (
+            shortcut_name varchar(80) NOT NULL,
+            shortcut_keys varchar(80) NOT NULL,
+            PRIMARY KEY (shortcut_name)
+            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;|
+        );
+    }
+    $dbh->do(q|
+        INSERT IGNORE INTO keyboard_shortcuts (shortcut_name, shortcut_keys) VALUES
+        ("insert_copyright","Alt-C"),
+        ("insert_copyright_sound","Alt-P"),
+        ("insert_delimiter","Ctrl-D"),
+        ("subfield_help","Ctrl-H"),
+        ("link_authorities","Shift-Ctrl-L"),
+        ("delete_field","Ctrl-X"),
+        ("delete_subfield","Shift-Ctrl-X"),
+        ("new_line","Enter"),
+        ("line_break","Shift-Enter"),
+        ("next_position","Tab"),
+        ("prev_position","Shift-Tab")
+        ;|
+    );
+    $dbh->do(q|
+        INSERT IGNORE permissions (module_bit, code, description)
+        VALUES
+        (3,'manage_keyboard_shortcuts','Manage keyboard shortcuts for advanced cataloging editor')
+        ;|
+    );
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 21411 - Add keyboard_shortcuts table)\n";
+}
+
+$DBversion = '18.12.00.075';
+if( CheckVersion( $DBversion ) ) {
+    # you can use $dbh here like:
+    unless ( foreign_key_exists( 'tmp_holdsqueue', 'tmp_holdsqueue_ibfk_1' ) ) {
+        $dbh->do(q{
+            DELETE t FROM tmp_holdsqueue t
+            LEFT JOIN items i ON t.itemnumber=i.itemnumber
+            WHERE i.itemnumber IS NULL
+        });
+        $dbh->do(q{
+            ALTER TABLE tmp_holdsqueue
+            ADD CONSTRAINT `tmp_holdsqueue_ibfk_1` FOREIGN KEY (`itemnumber`)
+            REFERENCES `items` (`itemnumber`) ON DELETE CASCADE ON UPDATE CASCADE
+        });
+    }
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 22899 - Add items constraint to tmp_holdsqueue)\n";
+}
+
+$DBversion = '19.05.00.000';
+if( CheckVersion( $DBversion ) ) {
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (19.05.00 release)\n";
+}
+
+$DBversion = '19.06.00.000';
+if( CheckVersion( $DBversion ) ) {
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Wingardium Leviosa!)\n";
+}
+
+$DBversion = '19.06.00.001'; 
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do( q{
+        UPDATE systempreferences 
+        SET explanation = 'This is a list of value pairs.\n Examples:\n PROC: FIC - causes an item in the Processing Center location to be updated into the Fiction location on check in.\n FIC: GEN - causes an item in the Fiction location to be updated into the General stacks location on check in.\n _BLANK_:FIC - causes an item that has no location to be updated into the Fiction location on check in.\nFIC: _BLANK_ - causes an item in location FIC to be updated to a blank location on check in.\n_ALL_:FIC - causes all items to be updated into the Fiction location on check in.\nPROC: _PERM_ - causes an item that is in the Processing Center to be updated to it''s permanent location.\nGeneral rule: if the location value on the left matches the item''s current location, it will be updated to match the location value on the right.\nNote: PROC and CART are special values, for these locations only can location and permanent_location differ, in all other cases an update will affect both. Items in the CART location will be returned to their permanent location on checkout.\nThe special term _BLANK_ may be used on either side of a value pair to update or remove the location from items with no location assigned. The special term _ALL_ is used on the left side of the colon (:) to affect all items.\nThe special term _PERM_ is used on the right side of the colon (:) to return items to their permanent location.' 
+        WHERE variable = 'UpdateItemLocationOnCheckin'
+    });
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 22960: Fix typo in syspref description)\n";
+}
+
+$DBversion = '19.06.00.002';
+if ( CheckVersion($DBversion) ) {
+
+    $dbh->do(q{ALTER TABLE subscriptionhistory CHANGE opacnote opacnote LONGTEXT NULL});
+    $dbh->do(q{ALTER TABLE subscriptionhistory CHANGE librariannote librariannote LONGTEXT NULL});
+
+    $dbh->do(q{UPDATE subscriptionhistory SET opacnote = NULL WHERE opacnote = ''});
+    $dbh->do(q{UPDATE subscriptionhistory SET librariannote = NULL WHERE librariannote = ''});
+
+    SetVersion ($DBversion);
+    print "Upgrade to $DBversion done (Bug 10215: Increase the size of opacnote and librariannote for table subscriptionhistory)\n";
+}
+
+$DBversion = '19.06.00.003';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do(q{UPDATE systempreferences SET value = REPLACE( value, ' ', '|' ) WHERE variable = 'UniqueItemFields'; });
+
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 22867: UniqueItemFields preference value should be pipe-delimited)\n";
+}
+
+$DBversion = '19.06.00.004';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do( 'UPDATE language_descriptions SET description = "Griechisch (Modern 1453-)"
+      WHERE subtag = "el" and type = "language" and lang ="de"' );
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 22770: Fix typo in language description for el in German)\n";
+}
+
+$DBversion = '19.06.00.005';
+if( CheckVersion( $DBversion ) ) {
+    unless ( column_exists( 'reserves', 'item_level_hold' ) ) {
+        $dbh->do( "ALTER TABLE reserves ADD COLUMN item_level_hold BOOLEAN NOT NULL DEFAULT 0 AFTER itemtype" );
+    }
+    unless ( column_exists( 'old_reserves', 'item_level_hold' ) ) {
+        $dbh->do( "ALTER TABLE old_reserves ADD COLUMN item_level_hold BOOLEAN NOT NULL DEFAULT 0 AFTER itemtype" );
+    }
+
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug  9834: Add the reserves.item_level_hold column)\n";
+}
+
+$DBversion = '19.06.00.006';
+if( CheckVersion( $DBversion ) ) {
+
+    unless ( TableExists('plugin_methods') ) {
+        $dbh->do(q{
+            CREATE TABLE plugin_methods (
+              plugin_class varchar(255) NOT NULL,
+              plugin_method varchar(255) NOT NULL,
+              PRIMARY KEY ( `plugin_class` (191), `plugin_method` (191) )
+            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+        });
+    }
+
+    require Koha::Plugins;
+    Koha::Plugins->new({ enable_plugins => 1 })->InstallPlugins;
+
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 21073: Improve plugin performance)\n";
+}
+
+$DBversion = '19.06.00.007';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do( "DELETE FROM systempreferences WHERE variable = 'RotationPreventTransfers'" );
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 22653: Remove unimplemented RotationPreventTransfers system preference)\n";
+}
+
+$DBversion = '19.06.00.008';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do( "UPDATE userflags SET flagdesc = 'Allow staff members to modify permissions and passwords for other staff members' WHERE flag = 'staffaccess'" );
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 23109: Improve description of staffaccess permission)\n";
+}
+
+$DBversion = '19.06.00.009';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do(q{
+        INSERT IGNORE INTO keyboard_shortcuts (shortcut_name, shortcut_keys)
+            VALUES ("toggle_keyboard", "Shift-Ctrl-K")
+    });
+
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 17178: add shortcut to keyboard_shortcuts)\n";
+}
+
+$DBversion = '19.06.00.010';
+if( CheckVersion( $DBversion ) ) {
+
+    if ( TableExists('default_circ_rules') ) {
+        if ( column_exists( 'default_circ_rules', 'holdallowed' ) ) {
+            $dbh->do("
+                INSERT IGNORE INTO circulation_rules ( categorycode, branchcode, itemtype, rule_name, rule_value )
+                SELECT NULL, NULL, NULL, 'holdallowed', holdallowed
+                FROM default_circ_rules
+            ");
+            $dbh->do("
+                INSERT IGNORE INTO circulation_rules ( categorycode, branchcode, itemtype, rule_name, rule_value )
+                SELECT NULL, NULL, NULL, 'hold_fulfillment_policy', hold_fulfillment_policy
+                FROM default_circ_rules
+            ");
+            $dbh->do("
+                INSERT IGNORE INTO circulation_rules ( categorycode, branchcode, itemtype, rule_name, rule_value )
+                SELECT NULL, NULL, NULL, 'returnbranch', returnbranch
+                FROM default_circ_rules
+            ");
+            $dbh->do("DROP TABLE default_circ_rules");
+        }
+    }
+
+    if ( TableExists('default_branch_circ_rules') ) {
+        if ( column_exists( 'default_branch_circ_rules', 'holdallowed' ) ) {
+            $dbh->do("
+                INSERT IGNORE INTO circulation_rules ( categorycode, branchcode, itemtype, rule_name, rule_value )
+                SELECT NULL, branchcode, NULL, 'holdallowed', holdallowed
+                FROM default_branch_circ_rules
+            ");
+            $dbh->do("
+                INSERT IGNORE INTO circulation_rules ( categorycode, branchcode, itemtype, rule_name, rule_value )
+                SELECT NULL, branchcode, NULL, 'hold_fulfillment_policy', hold_fulfillment_policy
+                FROM default_branch_circ_rules
+            ");
+            $dbh->do("
+                INSERT IGNORE INTO circulation_rules ( categorycode, branchcode, itemtype, rule_name, rule_value )
+                SELECT NULL, branchcode, NULL, 'returnbranch', returnbranch
+                FROM default_branch_circ_rules
+            ");
+            $dbh->do("DROP TABLE default_branch_circ_rules");
+        }
+    }
+
+    if ( TableExists('branch_item_rules') ) {
+        if ( column_exists( 'branch_item_rules', 'holdallowed' ) ) {
+            $dbh->do("
+                INSERT IGNORE INTO circulation_rules ( categorycode, branchcode, itemtype, rule_name, rule_value )
+                SELECT NULL, branchcode, itemtype, 'holdallowed', holdallowed
+                FROM branch_item_rules
+            ");
+            $dbh->do("
+                INSERT IGNORE INTO circulation_rules ( categorycode, branchcode, itemtype, rule_name, rule_value )
+                SELECT NULL, branchcode, itemtype, 'hold_fulfillment_policy', hold_fulfillment_policy
+                FROM branch_item_rules
+            ");
+            $dbh->do("
+                INSERT IGNORE INTO circulation_rules ( categorycode, branchcode, itemtype, rule_name, rule_value )
+                SELECT NULL, branchcode, itemtype, 'returnbranch', returnbranch
+                FROM branch_item_rules
+            ");
+            $dbh->do("DROP TABLE branch_item_rules");
+        }
+    }
+
+    if ( TableExists('default_branch_item_rules') ) {
+        if ( column_exists( 'default_branch_item_rules', 'holdallowed' ) ) {
+            $dbh->do("
+                INSERT IGNORE INTO circulation_rules ( categorycode, branchcode, itemtype, rule_name, rule_value )
+                SELECT NULL, NULL, itemtype, 'holdallowed', holdallowed
+                FROM default_branch_item_rules
+            ");
+            $dbh->do("
+                INSERT IGNORE INTO circulation_rules ( categorycode, branchcode, itemtype, rule_name, rule_value )
+                SELECT NULL, NULL, itemtype, 'hold_fulfillment_policy', hold_fulfillment_policy
+                FROM default_branch_item_rules
+            ");
+            $dbh->do("
+                INSERT IGNORE INTO circulation_rules ( categorycode, branchcode, itemtype, rule_name, rule_value )
+                SELECT NULL, NULL, itemtype, 'returnbranch', returnbranch
+                FROM default_branch_item_rules
+            ");
+            $dbh->do("DROP TABLE default_branch_item_rules");
+        }
+    }
+
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 18928: Move holdallowed, hold_fulfillment_policy, returnbranch to circulation_rules)\n";
+}
+
+$DBversion = '19.06.00.011';
+if( CheckVersion( $DBversion ) ) {
+
+    if ( TableExists('refund_lost_item_fee_rules') ) {
+        if ( column_exists( 'refund_lost_item_fee_rules', 'refund' ) ) {
+            $dbh->do("
+                INSERT INTO circulation_rules ( categorycode, branchcode, itemtype, rule_name, rule_value )
+                SELECT NULL, IF(branchcode='*', NULL, branchcode), NULL, 'refund', refund
+                FROM refund_lost_item_fee_rules
+            ");
+            $dbh->do("DROP TABLE refund_lost_item_fee_rules");
+        }
+    }
+
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 18930: Move lost item refund rules to circulation_rules table)\n";
+}
+
+$DBversion = '19.06.00.012';
+if ( CheckVersion($DBversion) ) {
+
+    # Find and correct pathological cases of LR becoming a credit
+    my $sth = $dbh->prepare( "SELECT accountlines_id, issue_id, borrowernumber, itemnumber, amount, manager_id FROM accountlines WHERE accounttype = 'LR' AND amount < 0" );
+    $sth->execute();
+    while ( my $row = $sth->fetchrow_hashref ) {
+        $dbh->do(
+            "INSERT INTO accountlines (accounttype, issue_id, borrowernumber, itemnumber, amount, manager_id, interface) VALUES ( ?, ?, ?, ?, ?, ?, ? );",
+            {},
+            (
+                'CR',                   $row->{issue_id},
+                $row->{borrowernumber}, $row->{itemnumber},
+                $row->{amount},         $row->{manager_id},
+                'upgrade'
+            )
+        );
+        my $credit_id = $dbh->last_insert_id(undef, undef, 'accountlines', undef);
+        my $amount = $row->{amount} * -1;
+        $dbh->do("INSERT INTO account_offsets (credit_id, debit_id, type, amount) VALUES (?,?,?,?);",{},($credit_id, $row->{accountlines_id}, 'Lost Item', $amount));
+        $dbh->do("UPDATE accountlines SET amount = '$amount' WHERE accountlines_id = '$row->{accountlines_id}';");
+    }
+
+    $dbh->do(qq{
+        UPDATE
+          accountlines
+        SET
+          accounttype = 'LOST',
+          status = 'RETURNED'
+        WHERE
+          accounttype = 'LR';
+    });
+
+    # Find and correct pathalogical cases of L having been converted to W
+    $sth = $dbh->prepare( "SELECT accountlines_id, issue_id, borrowernumber, itemnumber, amount, manager_id FROM accountlines WHERE accounttype = 'W' AND itemnumber IS NOT NULL" );
+    $sth->execute();
+    while ( my $row = $sth->fetchrow_hashref ) {
+        my $amount = $row->{amount} * -1;
+        $dbh->do(
+            "INSERT INTO accountlines (accounttype, issue_id, borrowernumber, itemnumber, amount, manager_id, interface) VALUES ( ?, ?, ?, ?, ?, ?, ? );",
+            {},
+            (
+                'LOST', $row->{issue_id}, $row->{borrowernumber},
+                $row->{itemnumber}, $amount, $row->{manager_id},
+                'upgrade'
+            )
+        );
+        my $debit_id = $dbh->last_insert_id(undef, undef, 'accountlines', undef);
+        $dbh->do(
+            "INSERT INTO account_offsets (credit_id, debit_id, type, amount) VALUES (?,?,?,?);",
+            {},
+            (
+                $row->{accountlines_id}, $debit_id,
+                'Lost Item',    $amount
+            )
+        );
+    }
+
+    $dbh->do(qq{
+        UPDATE
+          accountlines
+        SET
+          accounttype = 'LOST'
+        WHERE
+          accounttype = 'L';
+    });
+
+    $dbh->do(qq{
+        UPDATE
+          accountlines
+        SET
+          accounttype = 'LOST_RETURNED'
+        WHERE
+          accounttype = 'CR';
+    });
+
+    SetVersion($DBversion);
+    print "Upgrade to $DBversion done (Bug 22563: Fix accounttypes for 'L', 'LR' and 'CR')\n";
+}
+
+$DBversion = '19.06.00.013';
+if ( CheckVersion( $DBversion ) ) {
+    unless ( column_exists( 'borrower_modifications', 'changed_fields' ) ) {
+        $dbh->do("ALTER TABLE borrower_modifications ADD changed_fields MEDIUMTEXT AFTER verification_token;");
+    }
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 23151: Add borrower_modifications.changed_fields column)\n";
+}
+
+$DBversion = '19.06.00.014';
+if ( CheckVersion($DBversion) ) {
+
+    $dbh->do(qq{
+        UPDATE
+          accountlines
+        SET
+          accounttype = 'RENT_DAILY_RENEW'
+        WHERE
+          accounttype = 'Rent'
+        AND
+          description LIKE 'Renewal of Daily Rental Item%';
+    });
+
+    $dbh->do(qq{
+        UPDATE
+          accountlines
+        SET
+          accounttype = 'RENT_DAILY'
+        WHERE
+          accounttype = 'Rent'
+        AND
+          description LIKE 'Daily rental';
+    });
+
+
+    $dbh->do(qq{
+        UPDATE
+          accountlines
+        SET
+          accounttype = 'RENT_RENEW'
+        WHERE
+          accounttype = 'Rent'
+        AND
+          description LIKE 'Renewal of Rental Item%';
+    });
+
+    $dbh->do(qq{
+        UPDATE
+          accountlines
+        SET
+          accounttype = 'RENT'
+        WHERE
+          accounttype = 'Rent';
+    });
+
+    SetVersion($DBversion);
+    print "Upgrade to $DBversion done (Bug 11573: Fix accounttypes for 'Rent')\n";
+}
+
+$DBversion = '19.06.00.015';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do( "UPDATE `search_field` SET `name` = 'date-time-last-modified', `label` = 'date-time-last-modified' WHERE `name` = 'date/time-last-modified'" );
+
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 22524: Fix date/time-last-modified search with Elasticsearch)\n";
+}
+
+$DBversion = '19.06.00.016';
+if( CheckVersion( $DBversion ) ) {
+
+    $dbh->do(q|
+        INSERT IGNORE INTO keyboard_shortcuts (shortcut_name, shortcut_keys) VALUES
+            ("insert_copyright","Alt-C"),
+            ("insert_copyright_sound","Alt-P"),
+            ("insert_delimiter","Ctrl-D"),
+            ("subfield_help","Ctrl-H"),
+            ("link_authorities","Shift-Ctrl-L"),
+            ("delete_field","Ctrl-X"),
+            ("delete_subfield","Shift-Ctrl-X"),
+            ("new_line","Enter"),
+            ("line_break","Shift-Enter"),
+            ("next_position","Tab"),
+            ("prev_position","Shift-Tab"),
+            ("toggle_keyboard", "Shift-Ctrl-K")
+    ;|);
+
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 23396: Fix missing keyboard_shortcuts table)\n";
+}
+
+$DBversion = '19.06.00.017';
+if ( CheckVersion($DBversion) ) {
+
+    $dbh->do(qq{
+        INSERT INTO
+          authorised_values (category,authorised_value,lib)
+        VALUES
+          ('PAYMENT_TYPE','SIP00','Cash via SIP2'),
+          ('PAYMENT_TYPE','SIP01','VISA via SIP2'),
+          ('PAYMENT_TYPE','SIP02','Creditcard via SIP2')
+    });
+
+    $dbh->do(qq{
+        UPDATE
+          accountlines
+        SET
+          accounttype  = 'Pay',
+          payment_type = 'SIP00'
+        WHERE
+          accounttype = 'Pay00';
+    });
+
+    $dbh->do(qq{
+        UPDATE
+          accountlines
+        SET
+          accounttype  = 'Pay',
+          payment_type = 'SIP01'
+        WHERE
+          accounttype = 'Pay01';
+    });
+
+    $dbh->do(qq{
+        UPDATE
+          accountlines
+        SET
+          accounttype  = 'Pay',
+          payment_type = 'SIP02'
+        WHERE
+          accounttype = 'Pay02';
+    });
+
+    my $sth = $dbh->prepare( q{SELECT * FROM accountlines WHERE accounttype REGEXP '^Pay[[:digit:]]{2}$' } );
+    $sth->execute();
+    my $seen = {};
+    while (my $row = $sth->fetchrow_hashref) {
+        my $type = $row->{accounttype};
+        my $sipcode = $type;
+        $sipcode =~ s/Pay/SIP/g;
+        unless ($seen->{$sipcode}) {
+            $dbh->do(qq{
+                INSERT INTO
+                  authorised_values (category,authorised_value,lib)
+                VALUES
+                  ('PAYMENT_TYPE',"$sipcode",'Unrecognised SIP2 payment type')
+            });
+
+             $dbh->do(qq{
+                UPDATE
+                  accountlines
+                SET
+                  accounttype  = 'Pay',
+                  payment_type = "$sipcode"
+                WHERE
+                  accounttype = "$type";
+            });
+
+            $seen->{$sipcode} = 1;
+        }
+    }
+
+    SetVersion($DBversion);
+    print "Upgrade to $DBversion done (Bug 22610: Fix accounttypes for SIP2 payments)\n";
+}
+
+$DBversion = '19.06.00.018';
+if( CheckVersion( $DBversion ) ) {
+    if( !column_exists( 'biblio', 'subtitle' ) ) {
+        $dbh->do( "ALTER TABLE biblio ADD COLUMN medium LONGTEXT AFTER title" );
+        $dbh->do( "ALTER TABLE biblio ADD COLUMN subtitle LONGTEXT AFTER medium" );
+        $dbh->do( "ALTER TABLE biblio ADD COLUMN part_number LONGTEXT AFTER subtitle" );
+        $dbh->do( "ALTER TABLE biblio ADD COLUMN part_name LONGTEXT AFTER part_number" );
+
+        $dbh->do( "ALTER TABLE deletedbiblio ADD COLUMN medium LONGTEXT AFTER title" );
+        $dbh->do( "ALTER TABLE deletedbiblio ADD COLUMN subtitle LONGTEXT AFTER medium" );
+        $dbh->do( "ALTER TABLE deletedbiblio ADD COLUMN part_number LONGTEXT AFTER subtitle" );
+        $dbh->do( "ALTER TABLE deletedbiblio ADD COLUMN part_name LONGTEXT AFTER part_number" );
+    }
+
+    $dbh->do( "UPDATE marc_subfield_structure SET kohafield='biblio.subtitle' WHERE kohafield='bibliosubtitle.subtitle'" );
+
+    my $marcflavour = C4::Context->preference('marcflavour');
+
+    if ( $marcflavour eq 'UNIMARC' ) {
+        $dbh->do(qq{
+            UPDATE marc_subfield_structure SET kohafield='biblio.medium'
+            WHERE (kohafield IS NULL OR kohafield='') AND frameworkcode='' AND tagfield='200' AND tagsubfield='b'
+        });
+        $dbh->do(qq{
+            UPDATE marc_subfield_structure SET kohafield='biblio.subtitle'
+            WHERE (kohafield IS NULL OR kohafield='') AND frameworkcode='' AND tagfield='200' AND tagsubfield='e'
+        });
+        $dbh->do(qq{
+            UPDATE marc_subfield_structure SET kohafield='biblio.part_number'
+            WHERE (kohafield IS NULL OR kohafield='') AND frameworkcode='' AND tagfield='200' AND tagsubfield='h'
+        });
+        $dbh->do(qq{
+            UPDATE marc_subfield_structure SET kohafield='biblio.part_name'
+            WHERE (kohafield IS NULL OR kohafield='') AND frameworkcode='' AND tagfield='200' AND tagsubfield='i'
+        });
+    } else {
+        $dbh->do(qq{
+            UPDATE marc_subfield_structure SET kohafield='biblio.medium'
+            WHERE (kohafield IS NULL OR kohafield='') AND frameworkcode='' AND tagfield='245' AND tagsubfield='h'
+        });
+        $dbh->do(qq{
+            UPDATE marc_subfield_structure SET kohafield='biblio.subtitle'
+            WHERE (kohafield IS NULL OR kohafield='') AND frameworkcode='' AND tagfield='245' AND tagsubfield='b'
+        });
+        $dbh->do(qq{
+            UPDATE marc_subfield_structure SET kohafield='biblio.part_number'
+            WHERE (kohafield IS NULL OR kohafield='') AND frameworkcode='' AND tagfield='245' AND tagsubfield='n'
+        });
+        $dbh->do(qq{
+            UPDATE marc_subfield_structure SET kohafield='biblio.part_name'
+            WHERE (kohafield IS NULL OR kohafield='') AND frameworkcode='' AND tagfield='245' AND tagsubfield='p'
+        });
+    }
+
+    $dbh->do("UPDATE marc_subfield_structure JOIN fieldmapping ON tagfield = fieldcode AND subfieldcode=tagsubfield SET kohafield='biblio.subtitle' WHERE fieldmapping.frameworkcode=''");
+    $sth = $dbh->prepare("SELECT * FROM fieldmapping WHERE frameworkcode != '' OR field != 'subtitle'");
+    $sth->execute;
+    my @fails_11529;
+    if ( $sth->rows ) {
+        while ( my $value = $sth->fetchrow_hashref() ) {
+            my $framework =
+              $value->{frameworkcode} eq ""
+              ? "Default"
+              : $value->{frameworkcode};
+            push @fails_11529,
+              {
+                field        => $value->{field},
+                fieldcode    => $value->{fieldcode},
+                subfieldcode => $value->{subfieldcode},
+                framework    => $framework
+              };
+        }
+    }
+
+    $dbh->do( "DROP TABLE IF EXISTS fieldmapping" );
+
+    $dbh->do( "DELETE FROM user_permissions WHERE code='manage_keywords2koha_mappings'" );
+
+    $dbh->do( "DELETE FROM permissions WHERE code='manage_keywords2koha_mappings'" );
+
+    # Always end with this (adjust the bug info)
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 11529: Add medium, subtitle and part information to biblio table)\n";
+    if ( @fails_11529 ) {
+        print "WARNING: Not all Keyword to MARC mappings could be preserved\n";
+        for my $fail_11529 ( @fails_11529 ) {
+            print "    keyword: "
+              . $fail_11529->{field}
+              . " to field: "
+              . $fail_11529->{fieldcode} . "\$"
+              . $fail_11529->{subfieldcode} . " for "
+              . $fail_11529->{framework}
+              . " framework\n";
+        }
+        print "You will need to remap using Koha to MARC mappings in administration\n";
+    }
+    print "NOTE: misc/batchRebuildBiblioTables.pl should be run to populate the fields introduced in bug 11529. It may take some time for larger databases.\n\n"
+}
+
+$DBversion = '19.06.00.019';
+if ( CheckVersion($DBversion) ) {
+    $dbh->do(q{
+        INSERT IGNORE INTO systempreferences (variable, value, options, explanation, type)
+        VALUES
+          (
+            'FinePaymentAutoPopup',
+            '0',
+            NULL,
+            'If enabled, automatically display a print dialog for a payment receipt when making a payment.',
+            'YesNo'
+          )
+    });
+
+    SetVersion($DBversion);
+    print
+"Upgrade to $DBversion done (Bug 23228: Add option to automatically display payment receipt for printing after making a payment)\n";
+}
+
+$DBversion = '19.06.00.020';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do(q|
+        INSERT IGNORE INTO systempreferences ( `variable`, `value`, `options`, `explanation`, `type` ) VALUES
+        ('PreserveSerialNotes','1','','When a new "Expected" issue is generated, should it be prefilled with last created issue notes?','YesNo');
+    |);
+
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 23416: Add PreserveSerialNotes syspref)\n";
+}
+
+$DBversion = '19.06.00.021';
+if( CheckVersion( $DBversion ) ) {
+
+    $dbh->do(q|
+        ALTER TABLE marc_subfield_structure CHANGE COLUMN hidden hidden TINYINT(1) DEFAULT 8 NOT NULL;
+    |);
+    # Always end with this (adjust the bug info)
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 23309: Can't add new subfields to bibliographic frameworks in strict mode)\n";
+}
+
+$DBversion = '19.06.00.022';
+if ( CheckVersion($DBversion) ) {
+
+    unless ( TableExists('borrower_relationships') ) {
+        $dbh->do(q{
+            CREATE TABLE `borrower_relationships` (
+                  id INT(11) NOT NULL AUTO_INCREMENT,
+                  guarantor_id INT(11) NOT NULL,
+                  guarantee_id INT(11) NOT NULL,
+                  relationship VARCHAR(100) NOT NULL,
+                  PRIMARY KEY (id),
+                  UNIQUE KEY `guarantor_guarantee_idx` ( `guarantor_id`, `guarantee_id` ),
+                  CONSTRAINT r_guarantor FOREIGN KEY ( guarantor_id ) REFERENCES borrowers ( borrowernumber ) ON UPDATE CASCADE ON DELETE CASCADE,
+                  CONSTRAINT r_guarantee FOREIGN KEY ( guarantee_id ) REFERENCES borrowers ( borrowernumber ) ON UPDATE CASCADE ON DELETE CASCADE
+            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+        });
+
+        $dbh->do(q{
+            UPDATE borrowers
+            LEFT JOIN borrowers guarantor ON ( borrowers.guarantorid = guarantor.borrowernumber )
+            SET borrowers.guarantorid = NULL WHERE guarantor.borrowernumber IS NULL;
+        });
+
+        # Bad data handling: guarantorid IS NOT NULL AND relationship IS NULL
+        $dbh->do(q{
+            UPDATE borrowers
+            SET relationship = '_bad_data'
+            WHERE guarantorid IS NOT NULL AND
+                  relationship IS NULL
+        });
+
+        $dbh->do(q{
+            INSERT INTO borrower_relationships ( guarantor_id, guarantee_id, relationship )
+            SELECT guarantorid, borrowernumber, relationship FROM borrowers WHERE guarantorid IS NOT NULL;
+        });
+
+        # Clean migrated guarantor data
+        $dbh->do(q{
+            UPDATE borrowers
+            SET contactname=NULL,
+                contactfirstname=NULL,
+                relationship=NULL
+            WHERE guarantorid IS NOT NULL
+        });
+    }
+
+    if ( column_exists( 'borrowers', 'guarantorid' ) ) {
+        $dbh->do(q{
+            ALTER TABLE borrowers DROP guarantorid;
+        });
+    }
+
+    if ( column_exists( 'deletedborrowers', 'guarantorid' ) ) {
+        $dbh->do(q{
+            ALTER TABLE deletedborrowers DROP guarantorid;
+        });
+    }
+
+    if ( column_exists( 'borrower_modifications', 'guarantorid' ) ) {
+        $dbh->do(q{
+            ALTER TABLE borrower_modifications DROP guarantorid;
+        });
+    }
+
+    SetVersion($DBversion);
+    print "Upgrade to $DBversion done (Bug 14570: Make it possible to add multiple guarantors to a record)\n";
+}
+
+$DBversion = '19.06.00.023';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do(q{
+        INSERT IGNORE INTO `systempreferences` (`variable`,`value`,`explanation`,`options`,`type`) VALUES
+        ('ElasticsearchMARCFormat', 'ISO2709', 'ISO2709|ARRAY', 'Elasticsearch MARC format. ISO2709 format is recommended as it is faster and takes less space, whereas array is searchable.', 'Choice')
+    });
+
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 22258: Add ElasticsearchMARCFormat preference)\n";
+}
+
+$DBversion = '19.06.00.024';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do(q{ALTER TABLE accountlines CHANGE COLUMN accounttype accounttype varchar(80) default NULL});
+
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 23539: accountlines.accounttype should match authorised_values.authorised_value in size)\n";
+}
+
+$DBversion = '19.06.00.025';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do( q/INSERT IGNORE INTO systempreferences (variable,value,options,explanation,type) VALUES (?, ?, ?, ?, ?)/, undef, 'BarcodeSeparators','\s\r\n','','Splitting characters for barcodes','Free' );
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 22996: Add pref BarcodeSeparators)\n";
+}
+
+$DBversion = '19.06.00.026';
+if( CheckVersion( $DBversion ) ) {
+
+    unless ( column_exists( 'borrowers', 'privacy_guarantor_fines' ) ) {
+        $dbh->do(q{
+            ALTER TABLE borrowers
+                ADD privacy_guarantor_fines TINYINT(1) NOT NULL DEFAULT '0' AFTER privacy;
+        });
+    }
+
+    unless ( column_exists( 'deletedborrowers', 'privacy_guarantor_fines' ) ) {
+        $dbh->do(q{
+            ALTER TABLE deletedborrowers
+                ADD privacy_guarantor_fines TINYINT(1) NOT NULL DEFAULT '0' AFTER privacy;
+        });
+    }
+
+    $dbh->do(q{
+        INSERT IGNORE INTO systempreferences (variable, value, options, explanation, type )
+        VALUES (
+            'AllowStaffToSetFinesVisibilityForGuarantor',  '0', NULL,
+            'If enabled, library staff can set a patron''s fines to be visible to linked patrons from the opac.',  'YesNo'
+        ), (
+            'AllowPatronToSetFinesVisibilityForGuarantor',  '0', NULL,
+            'If enabled, the patron can set fines to be visible to  his or her guarantor',  'YesNo'
+        )
+    });
+
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 20691: Add ability for guarantors to view guarantee's fines in OPAC)\n";
+}
+
+$DBversion = '19.06.00.027';
+if( CheckVersion( $DBversion ) ) {
+
+    if( !TableExists( 'itemtypes_branches' ) ) {
+       $dbh->do( "
+            CREATE TABLE itemtypes_branches( -- association table between authorised_values and branches
+                itemtype VARCHAR(10) NOT NULL,
+                branchcode VARCHAR(10) NOT NULL,
+                FOREIGN KEY (itemtype) REFERENCES itemtypes(itemtype) ON DELETE CASCADE,
+                FOREIGN KEY (branchcode) REFERENCES branches(branchcode) ON DELETE CASCADE
+            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+        ");
+    }
+
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 15497: Add itemtypes_branches table)\n";
+}
+
+$DBversion = '19.06.00.028';
+if ( CheckVersion($DBversion) ) {
+
+    $dbh->do(qq{
+        UPDATE
+          accountlines
+        SET
+          accounttype = 'ACCOUNT'
+        WHERE
+          accounttype = 'A';
+    });
+
+    SetVersion($DBversion);
+    print "Upgrade to $DBversion done (Bug 11573: Fix accounttypes for 'A')\n";
+}
+
+$DBversion = '19.06.00.029';
+if ( CheckVersion($DBversion) ) {
+
+    unless ( TableExists( 'cash_registers' ) ) {
+        $dbh->do(qq{
+    CREATE TABLE `cash_registers` (
+    `id` int(11) NOT NULL auto_increment, -- unique identifier for each account register
+    `name` varchar(24) NOT NULL, -- the user friendly identifier for each account register
+    `description` longtext NOT NULL, -- the user friendly description for each account register
+    `branch` varchar(10) NOT NULL, -- the foreign key the library this account register belongs
+    `branch_default` tinyint(1) NOT NULL DEFAULT 0, -- boolean flag to denote that this till is the branch default
+    `starting_float` decimal(28, 6), -- the starting float this account register should be assigned
+    `archived` tinyint(1) NOT NULL DEFAULT 0, -- boolean flag to denote if this till is archived or not
+    PRIMARY KEY (`id`),
+    UNIQUE KEY `name` (`name`,`branch`),
+    CONSTRAINT cash_registers_branch FOREIGN KEY (branch) REFERENCES branches (branchcode) ON UPDATE CASCADE ON DELETE CASCADE
+    ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
+        });
+    }
+
+    unless ( column_exists( 'accountlines', 'register_id' ) ) {
+        $dbh->do(qq{ALTER TABLE `accountlines` ADD `register_id` int(11) NULL DEFAULT NULL AFTER `manager_id`});
+        $dbh->do(qq{
+            ALTER TABLE `accountlines`
+            ADD CONSTRAINT `accountlines_ibfk_registers` FOREIGN KEY (`register_id`)
+            REFERENCES `cash_registers` (`id`) ON DELETE SET NULL ON UPDATE CASCADE
+        });
+    }
+
+    $dbh->do(qq{
+        INSERT IGNORE INTO `userflags` (`bit`, `flag`, `flagdesc`, `defaulton`)
+        VALUES (25, 'cash_management', 'Cash management', 0)
+    });
+
+    $dbh->do(qq{
+        INSERT IGNORE permissions (module_bit, code, description)
+        VALUES
+        (25, 'manage_cash_registers', 'Add and remove cash registers')
+    });
+
+    $dbh->do(qq{
+        INSERT IGNORE INTO systempreferences (variable,value,options,explanation,type) VALUES
+        ('UseCashRegisters','0','','Use cash registers with the accounting system and assign patron transactions to them.','YesNo')
+    });
+
+    SetVersion($DBversion);
+    print "Upgrade to $DBversion done (Bug 23321: Add cash_registers table, permissions and preferences)\n";
+}
+
+$DBversion = '19.06.00.030';
+if( CheckVersion( $DBversion ) ) {
+
+    $dbh->do(q|
+        CREATE TABLE IF NOT EXISTS club_holds (
+            id        INT(11) NOT NULL AUTO_INCREMENT,
+            club_id   INT(11) NOT NULL, -- id for the club the hold was generated for
+            biblio_id INT(11) NOT NULL, -- id for the bibliographic record the hold has been placed against
+            item_id   INT(11) NULL DEFAULT NULL, -- If item-level, the id for the item the hold has been placed agains
+            date_created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, -- Timestamp for the placed hold
+            PRIMARY KEY (id),
+            -- KEY club_id (club_id),
+            CONSTRAINT clubs_holds_ibfk_1 FOREIGN KEY (club_id)   REFERENCES clubs  (id) ON DELETE CASCADE ON UPDATE CASCADE,
+            CONSTRAINT clubs_holds_ibfk_2 FOREIGN KEY (biblio_id) REFERENCES biblio (biblionumber) ON DELETE CASCADE ON UPDATE CASCADE,
+            CONSTRAINT clubs_holds_ibfk_3 FOREIGN KEY (item_id)   REFERENCES items  (itemnumber) ON DELETE CASCADE ON UPDATE CASCADE
+        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+    |);
+
+    $dbh->do(q|
+        CREATE TABLE IF NOT EXISTS club_holds_to_patron_holds (
+            id              INT(11) NOT NULL AUTO_INCREMENT,
+            club_hold_id    INT(11) NOT NULL,
+            patron_id       INT(11) NOT NULL,
+            hold_id         INT(11),
+            error_code      ENUM ( 'damaged', 'ageRestricted', 'itemAlreadyOnHold',
+                                'tooManyHoldsForThisRecord', 'tooManyReservesToday',
+                                'tooManyReserves', 'notReservable', 'cannotReserveFromOtherBranches',
+                                'libraryNotFound', 'libraryNotPickupLocation', 'cannotBeTransferred'
+                            ) NULL DEFAULT NULL,
+            error_message   varchar(100) NULL DEFAULT NULL,
+            PRIMARY KEY (id),
+            -- KEY club_hold_id (club_hold_id),
+            CONSTRAINT clubs_holds_paton_holds_ibfk_1 FOREIGN KEY (club_hold_id) REFERENCES club_holds (id) ON DELETE CASCADE ON UPDATE CASCADE,
+            CONSTRAINT clubs_holds_paton_holds_ibfk_2 FOREIGN KEY (patron_id) REFERENCES borrowers (borrowernumber) ON DELETE CASCADE ON UPDATE CASCADE,
+            CONSTRAINT clubs_holds_paton_holds_ibfk_3 FOREIGN KEY (hold_id) REFERENCES reserves (reserve_id) ON DELETE CASCADE ON UPDATE CASCADE
+        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+    |);
+
+    # Always end with this (adjust the bug info)
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 19618: add club_holds tables)\n";
+}
+
+$DBversion = '19.06.00.031';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do(q|
+        INSERT IGNORE INTO systempreferences ( `variable`, `value`, `options`, `explanation`, `type` ) VALUES
+        ('OPACDetailQRCode','0','','Enable the display of a QR Code on the OPAC detail page','YesNo');
+    |);
+
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 23566: Add OPACDetailQRCode system preference)\n";
+}
+
+$DBversion = '19.06.00.032';
+if ( CheckVersion($DBversion) ) {
+    if ( !column_exists( 'search_marc_to_field', 'search' ) ) {
+        $dbh->do(q|
+            ALTER TABLE `search_marc_to_field` ADD COLUMN `search` tinyint(1) NOT NULL DEFAULT 1
+        |);
+    }
+    if ( !column_exists( 'search_field', 'staff_client' ) ) {
+        $dbh->do(q|
+            ALTER TABLE `search_field` ADD COLUMN `staff_client` tinyint(1) NOT NULL DEFAULT 1
+        |);
+    }
+    if ( !column_exists( 'search_field', 'opac' ) ) {
+        $dbh->do(q|
+            ALTER TABLE `search_field` ADD COLUMN `opac` tinyint(1) NOT NULL DEFAULT 1
+        |);
+    }
+
+    SetVersion($DBversion);
+    print
+"Upgrade to $DBversion done (Bug 20589: Add field boosting and use elastic query fields parameter instead of depricated _all)\n";
+}
+
+$DBversion = '19.06.00.033';
+if( CheckVersion( $DBversion ) ) {
+
+    $dbh->do(qq{
+        INSERT IGNORE INTO systempreferences (variable,value,options,explanation,type) VALUES
+        ('OnSiteCheckoutAutoCheck','0','','Enable/Do not enable onsite checkout by default if last checkout was an onsite checkout','YesNo')
+    });
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 23686: Add OnSiteCheckoutAutoCheck system preference)\n";
+}
+
+$DBversion = '19.06.00.034';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do(q{
+        INSERT IGNORE INTO systempreferences ( `variable`, `value`, `options`, `explanation`, `type` ) VALUES
+        ('TransfersBlockCirc','1',NULL,'Should the transfer modal block circulation staff from continuing scanning items','YesNo')
+    });
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 23007: Make transfer modals optionally block circ)\n";
+}
+
+$DBversion = '19.06.00.035';
+if( CheckVersion( $DBversion ) ) {
+
+    $dbh->do(q{
+        INSERT IGNORE INTO systempreferences (variable,value,options,explanation,type) VALUES
+        ( 'IntranetCoce','0', NULL, 'If on, enables cover retrieval from the configured Coce server in the staff client', 'YesNo')
+    });
+
+    $dbh->do(qq{
+        UPDATE systempreferences SET 
+          variable = 'OpacCoce', 
+          explanation = 'If on, enables cover retrieval from the configured Coce server in the OPAC'
+        WHERE 
+          variable = 'Coce'
+    });
+
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 18421: Add Coce image cache to the Intranet)\n";
+}
+
+$DBversion = '19.06.00.036';
+if( CheckVersion( $DBversion ) ) {
+
+    $dbh->do(q{
+        INSERT IGNORE INTO systempreferences ( `variable`, `value`, `options`, `explanation`, `type`) VALUES  
+        ('QueryRegexEscapeOptions', 'escape', 'dont_escape|escape|unescape_escaped', 'Escape option for regexps delimiters in Elasicsearch queries.', 'Choice')
+    });
+
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 20334: Add elasticsearch escape options preference)\n";
+}
+
+$DBversion = '19.06.00.037';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do(q{
+        INSERT IGNORE INTO systempreferences ( `variable`, `value`, `options`, `explanation`, `type` )
+        VALUES ('PayPalReturnURL','BaseURL','BaseURL|OPACAlias','Specify whether PayPal will return to the url specified in the OPACBaseURL option or to the OPAC\'s alias url.','Choice')
+    });
+
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 21701: PayPal return URL option)\n";
+}
+
+$DBversion = '19.06.00.038';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do( "UPDATE systempreferences SET variable='PatronAutoComplete' WHERE variable='CircAutocompl' LIMIT 1" );
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 23697: Rename CircAutocompl system preference to PatronAutoComplete)\n";
+}
+
+$DBversion = '19.06.00.039';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do(q|
+        INSERT IGNORE INTO keyboard_shortcuts (shortcut_name, shortcut_keys) VALUES
+        ("copy_line","Ctrl-C"),
+        ("copy_subfield","Shift-Ctrl-C"),
+        ("paste_line","Ctrl-P"),
+        ("insert_line","Ctrl-I")
+        ;
+    |);
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 17179: Add additional keyboard_shortcuts)\n";
+}
+
+$DBversion = '19.06.00.040';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do(q|
+        INSERT IGNORE INTO systempreferences
+        (variable,value,explanation,options,type)
+        VALUES
+        ('RoundFinesAtPayment','0','If enabled any fines with fractions of a cent will be rounded to the nearest cent when payments are collected. e.g. 1.004 will be paid off by a 1.00 payment','0','YesNo')
+    |);
+
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 17140: Add pref to allow rounding fines at payment)\n";
+}
+
+$DBversion = '19.06.00.041';
+if( CheckVersion( $DBversion ) ) {
+    my ($socialnetworks) = $dbh->selectrow_array( q|
+        SELECT value FROM systempreferences WHERE variable='socialnetworks';
+    |);
+    if( $socialnetworks ){
+        # If the socialnetworks preference is enabled, enable all social networks
+        $dbh->do("UPDATE systempreferences SET value = 'email,facebook,linkedin,twitter', explanation = 'email|facebook|linkedin|twitter', type = 'multiple'  WHERE variable = 'SocialNetworks'");
+    } else {
+        $dbh->do("UPDATE systempreferences SET value = '', explanation = 'email|facebook|linkedin|twitter', type = 'multiple'  WHERE variable = 'SocialNetworks'");
+    }
+    SetVersion ($DBversion);
+    print "Upgrade to $DBversion done (Bug 22880: Allow granular control of socialnetworks preference)\n";
+}
+
+$DBversion = '19.06.00.042';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do(q{
+        INSERT IGNORE INTO systempreferences
+            ( variable, value, options, explanation, type )
+        VALUES
+            ('CustomCoverImages','0',NULL,'If enabled, the custom cover images will be displayed in the staff client. CustomCoverImagesURL must be defined.','YesNo'),
+            ('OPACCustomCoverImages','0',NULL,'If enabled, the custom cover images will be displayed at the OPAC. CustomCoverImagesURL must be defined.','YesNo'),
+            ('CustomCoverImagesURL','',NULL,'Define an URL serving book cover images, using the following patterns: {issn}, {isbn}, {normalized_isbn}, {field$subfield} (use it with CustomCoverImages and/or OPACCustomCoverImages)','free')
+    });
+
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 22445: Add new pref *CustomCoverImages*)\n";
+}
+
+$DBversion = '19.06.00.043';
+if ( CheckVersion($DBversion) ) {
+
+    # Adding account_debit_types
+    $dbh->do(
+        qq{
+            CREATE TABLE IF NOT EXISTS account_debit_types (
+              code varchar(80) NOT NULL,
+              description varchar(200) NULL,
+              can_be_added_manually tinyint(4) NOT NULL DEFAULT 1,
+              default_amount decimal(28, 6) NULL,
+              is_system tinyint(1) NOT NULL DEFAULT 0,
+              archived tinyint(1) NOT NULL DEFAULT 0,
+              PRIMARY KEY (code)
+            ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci
+          }
+    );
+
+    # Adding account_debit_types_branches
+    $dbh->do(
+        qq{
+            CREATE TABLE IF NOT EXISTS account_debit_types_branches (
+                debit_type_code VARCHAR(80),
+                branchcode VARCHAR(10),
+                FOREIGN KEY (debit_type_code) REFERENCES account_debit_types(code) ON DELETE CASCADE,
+                FOREIGN KEY (branchcode) REFERENCES branches(branchcode) ON DELETE CASCADE
+            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
+        }
+    );
+
+    # Populating account_debit_types
+    $dbh->do(
+        qq{
+            INSERT IGNORE INTO account_debit_types (
+              code,
+              description,
+              can_be_added_manually,
+              default_amount,
+              is_system
+            )
+            VALUES
+              ('ACCOUNT', 'Account creation fee', 0, NULL, 1),
+              ('ACCOUNT_RENEW', 'Account renewal fee', 0, NULL, 1),
+              ('RESERVE_EXPIRED', 'Hold waiting too long', 0, NULL, 1),
+              ('LOST', 'Lost item', 1, NULL, 1),
+              ('MANUAL', 'Manual fee', 1, NULL, 0),
+              ('NEW_CARD', 'New card fee', 1, NULL, 1),
+              ('OVERDUE', 'Overdue fine', 0, NULL, 1),
+              ('PROCESSING', 'Lost item processing fee', 0, NULL, 1),
+              ('RENT', 'Rental fee', 0, NULL, 1),
+              ('RENT_DAILY', 'Daily rental fee', 0, NULL, 1),
+              ('RENT_RENEW', 'Renewal of rental item', 0, NULL, 1),
+              ('RENT_DAILY_RENEW', 'Rewewal of daily rental item', 0, NULL, 1),
+              ('RESERVE', 'Hold fee', 0, NULL, 1)
+        }
+    );
+
+    # Update accountype 'Res' to 'RESERVE'
+    $dbh->do(
+        qq{
+          UPDATE accountlines SET accounttype = 'RESERVE' WHERE accounttype = 'Res'
+        }
+    );
+
+    # Update accountype 'PF' to 'PROCESSING'
+    $dbh->do(
+        qq{
+          UPDATE accountlines SET accounttype = 'PROCESSING' WHERE accounttype = 'PF'
+        }
+    );
+
+    # Update accountype 'HE' to 'RESERVE_EXPIRED'
+    $dbh->do(
+        qq{
+          UPDATE accountlines SET accounttype = 'RESERVE_EXPIRED' WHERE accounttype = 'HE'
+        }
+    );
+
+    # Update accountype 'N' to 'NEW_CARD'
+    $dbh->do(
+        qq{
+          UPDATE accountlines SET accounttype = 'NEW_CARD' WHERE accounttype = 'N'
+        }
+    );
+
+    # Update accountype 'M' to 'MANUAL'
+    $dbh->do(
+        qq{
+          UPDATE accountlines SET accounttype = 'MANUAL' WHERE accounttype = 'M'
+        }
+    );
+
+    # Catch 'F' cases introduced since bug 22521
+    $dbh->do(qq{
+        UPDATE
+          accountlines
+        SET
+          accounttype = 'OVERDUE',
+          status = 'RETURNED'
+        WHERE
+          accounttype = 'F';
+    });
+
+    # Moving MANUAL_INV to account_debit_types
+    $dbh->do(
+        qq{
+            INSERT IGNORE INTO account_debit_types (
+              code,
+              default_amount,
+              description,
+              can_be_added_manually,
+              is_system
+            )
+            SELECT
+              authorised_value,
+              lib,
+              authorised_value,
+              1,
+              0
+            FROM
+              authorised_values
+            WHERE
+              category = 'MANUAL_INV'
+          }
+    );
+
+    # Update uncaught partial accounttypes left behind after bugs 23539 and 22521
+    my $sth = $dbh->prepare( "SELECT code, SUBSTR(code, 1,5) AS subcode FROM account_debit_types" );
+    $sth->execute();
+    while ( my $row = $sth->fetchrow_hashref ) {
+        $dbh->do(
+            qq{
+              UPDATE accountlines SET accounttype = ? WHERE accounttype = ?
+            },
+            {},
+            (
+                $row->{code},
+                $row->{subcode}
+            )
+        );
+    }
+
+    # Add any unexpected accounttype codes to debit_types as appropriate
+    $dbh->do(
+        qq{
+          INSERT IGNORE INTO account_debit_types (
+            code,
+            description,
+            can_be_added_manually,
+            default_amount,
+            is_system
+          )
+          SELECT
+            DISTINCT(accounttype),
+            "Unexpected type found during upgrade",
+            1,
+            NULL,
+            0
+          FROM
+            accountlines
+          WHERE
+            amount >= 0
+        }
+    );
+
+    # Adding debit_type_code to accountlines
+    unless ( column_exists('accountlines', 'debit_type_code') ) {
+        $dbh->do(
+            qq{
+                ALTER TABLE accountlines
+                ADD
+                  debit_type_code varchar(80) DEFAULT NULL
+                AFTER
+                  accounttype
+              }
+        );
+    }
+
+    # Linking debit_type_code in accountlines to code in account_debit_types
+    unless ( foreign_key_exists( 'accountlines', 'accountlines_ibfk_debit_type' ) ) {
+        $dbh->do(
+            qq{
+            ALTER TABLE accountlines ADD CONSTRAINT `accountlines_ibfk_debit_type` FOREIGN KEY (`debit_type_code`) REFERENCES `account_debit_types` (`code`) ON DELETE RESTRICT ON UPDATE CASCADE
+              }
+        );
+    }
+
+    # Populating debit_type_code
+    $dbh->do(
+        qq{
+        UPDATE accountlines SET debit_type_code = accounttype, accounttype = NULL WHERE accounttype IN (SELECT code from account_debit_types)
+        }
+    );
+
+    # Remove MANUAL_INV
+    $dbh->do(
+        qq{
+        DELETE FROM authorised_values WHERE category = 'MANUAL_INV'
+        }
+    );
+    $dbh->do(
+        qq{
+        DELETE FROM authorised_value_categories WHERE category_name = 'MANUAL_INV'
+        }
+    );
+
+    # Add new permission
+    $dbh->do(
+        q{
+            INSERT IGNORE INTO permissions (module_bit, code, description)
+            VALUES
+              (
+                3,
+                'manage_accounts',
+                'Manage Account Debit and Credit Types'
+              )
+        }
+    );
+
+    SetVersion($DBversion);
+    print "Upgrade to $DBversion done (Bug 23049: Add account debit_types)\n";
+}
+
+$DBversion = '19.06.00.044';
+if ( CheckVersion($DBversion) ) {
+
+    # Adding account_credit_types
+    $dbh->do(
+        qq{
+            CREATE TABLE IF NOT EXISTS account_credit_types (
+              code varchar(80) NOT NULL,
+              description varchar(200) NULL,
+              can_be_added_manually tinyint(4) NOT NULL DEFAULT 1,
+              is_system tinyint(1) NOT NULL DEFAULT 0,
+              PRIMARY KEY (code)
+            ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci
+          }
+    );
+
+    # Adding account_credit_types_branches
+    $dbh->do(
+        qq{
+            CREATE TABLE IF NOT EXISTS account_credit_types_branches (
+                credit_type_code VARCHAR(80),
+                branchcode VARCHAR(10),
+                FOREIGN KEY (credit_type_code) REFERENCES account_credit_types(code) ON DELETE CASCADE,
+                FOREIGN KEY (branchcode) REFERENCES branches(branchcode) ON DELETE CASCADE
+            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
+        }
+    );
+
+    # Populating account_credit_types
+    $dbh->do(
+        qq{
+            INSERT IGNORE INTO account_credit_types (
+              code,
+              description,
+              can_be_added_manually,
+              is_system
+            )
+            VALUES
+              ('PAYMENT', 'Payment', 0, 1),
+              ('WRITEOFF', 'Writeoff', 0, 1),
+              ('FORGIVEN', 'Forgiven', 1, 1),
+              ('CREDIT', 'Credit', 1, 1),
+              ('LOST_RETURN', 'Lost item fee refund', 0, 1)
+        }
+    );
+
+    # Adding credit_type_code to accountlines
+    unless ( column_exists('accountlines', 'credit_type_code') ) {
+        $dbh->do(
+            qq{
+                ALTER TABLE accountlines
+                ADD
+                  credit_type_code varchar(80) DEFAULT NULL
+                AFTER
+                  accounttype
+              }
+        );
+    }
+
+    # Linking credit_type_code in accountlines to code in account_credit_types
+    unless ( foreign_key_exists( 'accountlines', 'accountlines_ibfk_credit_type' ) ) {
+        $dbh->do(
+            qq{
+                ALTER TABLE accountlines
+                ADD CONSTRAINT
+                  `accountlines_ibfk_credit_type`
+                FOREIGN KEY (`credit_type_code`) REFERENCES `account_credit_types` (`code`)
+                ON DELETE RESTRICT
+                ON UPDATE CASCADE
+              }
+        );
+    }
+
+    # Update accountype 'C' to 'CREDIT'
+    $dbh->do(
+        qq{
+          UPDATE accountlines SET accounttype = 'CREDIT' WHERE accounttype = 'C' OR accounttype = 'CR'
+        }
+    );
+
+    # Update accountype 'FOR' to 'FORGIVEN'
+    $dbh->do(
+        qq{
+          UPDATE accountlines SET accounttype = 'FORGIVEN' WHERE accounttype = 'FOR' OR accounttype = 'FORW'
+        }
+    );
+
+    # Update accountype 'Pay' to 'PAYMENT'
+    $dbh->do(
+        qq{
+          UPDATE accountlines SET accounttype = 'PAYMENT' WHERE accounttype = 'Pay' OR accounttype = 'PAY'
+        }
+    );
+
+    # Update accountype 'W' to 'WRITEOFF'
+    $dbh->do(
+        qq{
+          UPDATE accountlines SET accounttype = 'WRITEOFF' WHERE accounttype = 'W' OR accounttype = 'WO'
+        }
+    );
+
+    # Add any unexpected accounttype codes to credit_types as appropriate
+    $dbh->do(
+        qq{
+          INSERT IGNORE INTO account_credit_types (
+            code,
+            description,
+            can_be_added_manually,
+            is_system
+          )
+          SELECT
+            DISTINCT(accounttype),
+            "Unexpected type found during upgrade",
+            1,
+            0
+          FROM
+            accountlines
+          WHERE
+            amount < 0
+        }
+    );
+
+    # Populating credit_type_code
+    $dbh->do(
+        qq{
+          UPDATE
+            accountlines 
+          SET
+            credit_type_code = accounttype, accounttype = NULL
+          WHERE accounttype IN (SELECT code from account_credit_types)
+        }
+    );
+
+    # Drop accounttype field
+    $dbh->do(
+        qq{
+          ALTER TABLE accountlines
+          DROP COLUMN `accounttype`
+        }
+    );
+
+    SetVersion($DBversion);
+    print "Upgrade to $DBversion done (Bug 23805: Add account credit_types)\n";
+}
+
+$DBversion = '19.06.00.045';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do( "UPDATE systempreferences SET value = '2' WHERE value = '0' AND variable = 'UsageStats'" );
+
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 23866: Set HEA syspref to prompt for review)\n";
+}
+
+$DBversion = '19.06.00.046';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do(qq{
+        UPDATE systempreferences
+        SET 
+          options = "Calendar|Days|Datedue|Dayweek", 
+          explanation = "Choose the method for calculating due date: select Calendar, Datedue or Dayweek to use the holidays module, and Days to ignore the holidays module"
+        WHERE
+          variable = "useDaysMode"
+    });
+
+    # Always end with this (adjust the bug info)
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 15260: Option for extended loan with useDaysMode)\n";
+}
+
+$DBversion = '19.06.00.047';
+if ( CheckVersion($DBversion) ) {
+    if ( !TableExists('return_claims') ) {
+        $dbh->do(
+            q{
+            CREATE TABLE return_claims (
+                id int(11) auto_increment,                             -- Unique ID of the return claim
+                itemnumber int(11) NOT NULL,                           -- ID of the item
+                issue_id int(11) NULL DEFAULT NULL,                    -- ID of the checkout that triggered the claim
+                borrowernumber int(11) NOT NULL,                       -- ID of the patron
+                notes MEDIUMTEXT DEFAULT NULL,                         -- Notes about the claim
+                created_on TIMESTAMP NULL,                             -- Time and date the claim was created
+                created_by int(11) NULL DEFAULT NULL,                  -- ID of the staff member that registered the claim
+                updated_on TIMESTAMP NULL ON UPDATE CURRENT_TIMESTAMP, -- Time and date of the latest change on the claim (notes)
+                updated_by int(11) NULL DEFAULT NULL,                  -- ID of the staff member that updated the claim
+                resolution  varchar(80) NULL DEFAULT NULL,             -- Resolution code (RETURN_CLAIM_RESOLUTION AVs)
+                resolved_on TIMESTAMP NULL DEFAULT NULL,               -- Time and date the claim was resolved
+                resolved_by int(11) NULL DEFAULT NULL,                 -- ID of the staff member that resolved the claim
+                PRIMARY KEY (`id`),
+                KEY `itemnumber` (`itemnumber`),
+                CONSTRAINT UNIQUE `issue_id` ( issue_id ),
+                CONSTRAINT `issue_id` FOREIGN KEY (`issue_id`) REFERENCES `issues` (`issue_id`) ON DELETE SET NULL ON UPDATE CASCADE,
+                CONSTRAINT `rc_items_ibfk` FOREIGN KEY (`itemnumber`) REFERENCES `items` (`itemnumber`) ON DELETE CASCADE ON UPDATE CASCADE,
+                CONSTRAINT `rc_borrowers_ibfk` FOREIGN KEY (`borrowernumber`) REFERENCES `borrowers` (`borrowernumber`) ON DELETE CASCADE ON UPDATE CASCADE,
+                CONSTRAINT `rc_created_by_ibfk` FOREIGN KEY (`created_by`) REFERENCES `borrowers` (`borrowernumber`) ON DELETE SET NULL ON UPDATE CASCADE,
+                CONSTRAINT `rc_updated_by_ibfk` FOREIGN KEY (`updated_by`) REFERENCES `borrowers` (`borrowernumber`) ON DELETE SET NULL ON UPDATE CASCADE,
+                CONSTRAINT `rc_resolved_by_ibfk` FOREIGN KEY (`resolved_by`) REFERENCES `borrowers` (`borrowernumber`) ON DELETE SET NULL ON UPDATE CASCADE
+            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+        }
+        );
+    }
+
+    $dbh->do(
+        q{
+        INSERT IGNORE INTO systempreferences ( `variable`, `value`, `options`, `explanation`, `type` ) VALUES
+        ('ClaimReturnedChargeFee', 'ask', 'ask|charge|no_charge', 'Controls whether or not a lost item fee is charged for return claims', 'Choice'),
+        ('ClaimReturnedLostValue', '', '', 'Sets the LOST AV value that represents "Claims returned" as a lost value', 'Free'),
+        ('ClaimReturnedWarningThreshold', '', '', 'Sets the number of return claims past which the librarian will be warned the patron has many return claims', 'Integer');
+    }
+    );
+
+    $dbh->do(
+        q{
+        INSERT IGNORE INTO authorised_value_categories ( category_name ) VALUES
+            ('RETURN_CLAIM_RESOLUTION');
+    }
+    );
+
+    $dbh->do(
+        q{
+        INSERT IGNORE INTO `authorised_values` ( category, authorised_value, lib )
+        VALUES
+          ('RETURN_CLAIM_RESOLUTION', 'RET_BY_PATRON', 'Returned by patron'),
+          ('RETURN_CLAIM_RESOLUTION', 'FOUND_IN_LIB', 'Found in library');
+    }
+    );
+
+    SetVersion($DBversion);
+    print
+"Upgrade to $DBversion done (Bug 14697: Extend and enhance 'Claims returned' lost status)\n";
+}
+
+$DBversion = '19.06.00.048';
+if( CheckVersion( $DBversion ) ) {
+    # you can use $dbh here like:
+    $dbh->do( qq{
+        INSERT IGNORE INTO systempreferences ( `variable`, `value`, `options`, `explanation`, `type` )
+        VALUES  ('OPACShowMusicalInscripts','0','','Display musical inscripts on the OPAC record details page when available.','YesNo'),
+                ('OPACPlayMusicalInscripts','0','','If displayed musical inscripts, play midi conversion on the OPAC record details page.','YesNo')
+    } );
+
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 22581: add new OPACShowMusicalInscripts and OPACPlayMusicalInscripts system preferences)\n";
+}
+
+$DBversion = '19.06.00.049';
+if( CheckVersion( $DBversion ) ) {
+
+    $dbh->do(q{
+        INSERT IGNORE INTO systempreferences (variable,value,options,explanation,type)
+        SELECT
+            'SuspensionsCalendar',
+            IF( value='noFinesWhenClosed', 'noSuspensionsWhenClosed', 'ignoreCalendar'),
+            'ignoreCalendar|noSuspensionsWhenClosed',
+            'Specify whether to use the Calendar in calculating suspensions',
+            'Choice'
+        FROM systempreferences
+        WHERE variable='finesCalendar';
+    });
+
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 13958: Add a SuspensionsCalendar syspref)\n";
+}
+
+$DBversion = '19.06.00.050';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do( q{
+            INSERT IGNORE INTO systempreferences (variable,value,options,explanation,type)
+            VALUES ('OPACFineNoRenewalsIncludeCredits','1',NULL,'If enabled the value specified in OPACFineNoRenewals should include any unapplied account credits in the calculation','YesNo')
+    });
+
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 23293: Add 'OPACFineNoRenewalsIncludeCredits' system preference)\n";
+}
+
+$DBversion = '19.11.00.000';
+if( CheckVersion( $DBversion ) ) {
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (19.11.00 release)\n";
+}
+
+$DBversion = '19.12.00.000';
+if( CheckVersion( $DBversion ) ) {
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Dobbie is a free elf...)\n";
+}
+
+$DBversion = '19.12.00.001';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do( "UPDATE marc_subfield_structure SET kohafield = NULL WHERE kohafield = 'bibliosubject.subject';" );
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 17831 - Remove non-existing bibliosubject.subject from frameworks)\n";
+}
+
+$DBversion = '19.12.00.002';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do(q{
+        UPDATE systempreferences SET
+        variable = 'AllowItemsOnHoldCheckoutSIP',
+        explanation = 'Do not generate RESERVE_WAITING and RESERVED warning when checking out items reserved to someone else via SIP. This allows self checkouts for those items.'
+        WHERE variable = 'AllowItemsOnHoldCheckout'
+    });
+
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 23233 - Rename AllowItemsOnHoldCheckout syspref)\n";
+}
+
+$DBversion = '19.12.00.003';
+if( CheckVersion( $DBversion ) ) {
+
+    if( !column_exists( 'library_groups', 'ft_local_hold_group' ) ) {
+        $dbh->do( "ALTER TABLE library_groups ADD COLUMN ft_local_hold_group tinyint(1) NOT NULL DEFAULT 0 AFTER ft_search_groups_staff" );
+    }
+
+    # Always end with this (adjust the bug info)
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 22284 - Add ft_local_hold_group column to library_groups)\n";
+}
+
+# SEE bug 13068
+# if there is anything in the atomicupdate, read and execute it.
+my $update_dir = C4::Context->config('intranetdir') . '/installer/data/mysql/atomicupdate/';
+opendir( my $dirh, $update_dir );
+foreach my $file ( sort readdir $dirh ) {
+    next if $file !~ /\.(sql|perl)$/;  #skip other files
+    next if $file eq 'skeleton.perl'; # skip the skeleton file
+    print "DEV atomic update: $file\n";
+    if ( $file =~ /\.sql$/ ) {
+        my $installer = C4::Installer->new();
+        my $rv = $installer->load_sql( $update_dir . $file ) ? 0 : 1;
+    } elsif ( $file =~ /\.perl$/ ) {
+        my $code = read_file( $update_dir . $file );
+        eval $code;
+        say "Atomic update generated errors: $@" if $@;
+    }
+}
+
+=head1 FUNCTIONS
+
 =head2 DropAllForeignKeys($table)
 
 Drop all foreign keys of the table $table