+sub add_print_templates {
+  my ($self, $src_dir, @files) = @_;
+
+  $::lxdebug->message(LXDebug::DEBUG1(), "add_print_templates: src_dir $src_dir files " . join('  ', @files));
+
+  foreach (@files) {
+    croak "File '${src_dir}/$_' does not exist" unless -f "${src_dir}/$_";
+  }
+
+  return 1 unless my $template_dir = $::instance_conf->reload->get_templates;
+  $::lxdebug->message(LXDebug::DEBUG1(), "add_print_templates: template_dir $template_dir");
+
+  foreach my $src_file (@files) {
+    my $dest_file = $template_dir . '/' . $src_file;
+
+    if (-f $dest_file) {
+      $::lxdebug->message(LXDebug::DEBUG1(), "add_print_templates: dest_file exists, skipping: ${dest_file}");
+      next;
+    }
+
+    my $dest_dir = File::Basename::dirname($dest_file);
+
+    if ($dest_dir && !-d $dest_dir) {
+      File::Path::make_path($dest_dir) or die "Cannot create directory '${dest_dir}': $!";
+    }
+
+    File::Copy::copy($src_dir . '/' . $src_file, $dest_file) or die "Cannot copy '${src_dir}/${src_file}' to '${dest_file}': $!";
+
+    $::lxdebug->message(LXDebug::DEBUG1(), "add_print_templates: copied '${src_dir}/${src_file}' to '${dest_file}'");
+  }
+
+  return 1;
+}
+
+sub drop_constraints {
+  my ($self, %params) = @_;
+
+  croak "Missing parameter 'table'" unless $params{table};
+  $params{type}   ||= 'FOREIGN KEY';
+  $params{schema} ||= 'public';
+
+  my $constraints = $self->dbh->selectall_arrayref(<<SQL, undef, $params{type}, $params{schema}, $params{table});
+    SELECT constraint_name
+    FROM information_schema.table_constraints
+    WHERE (constraint_type = ?)
+      AND (table_schema    = ?)
+      AND (table_name      = ?)
+SQL
+
+  $self->db_query(qq|ALTER TABLE $params{schema}."$params{table}" DROP CONSTRAINT "${_}"|) for map { $_->[0] } @{ $constraints };
+}
+