]> git.donarmstrong.com Git - debbugs.git/commitdiff
Merge remote-tracking branch 'local/master' into database
authorDon Armstrong <don@donarmstrong.com>
Sat, 12 Aug 2017 15:58:14 +0000 (08:58 -0700)
committerDon Armstrong <don@donarmstrong.com>
Sat, 12 Aug 2017 15:58:14 +0000 (08:58 -0700)
84 files changed:
Debbugs/Bugs.pm
Debbugs/CGI/Bugreport.pm
Debbugs/Common.pm
Debbugs/Config.pm
Debbugs/DB.pm [new file with mode: 0644]
Debbugs/DB/Load.pm [new file with mode: 0644]
Debbugs/DB/Result/.gitignore [new file with mode: 0644]
Debbugs/DB/Result/Arch.pm [new file with mode: 0644]
Debbugs/DB/Result/BinAssociation.pm [new file with mode: 0644]
Debbugs/DB/Result/BinPkg.pm [new file with mode: 0644]
Debbugs/DB/Result/BinVer.pm [new file with mode: 0644]
Debbugs/DB/Result/BinaryVersion.pm [new file with mode: 0644]
Debbugs/DB/Result/Bug.pm [new file with mode: 0644]
Debbugs/DB/Result/BugAffectsBinpackage.pm [new file with mode: 0644]
Debbugs/DB/Result/BugAffectsSrcpackage.pm [new file with mode: 0644]
Debbugs/DB/Result/BugBinpackage.pm [new file with mode: 0644]
Debbugs/DB/Result/BugBlock.pm [new file with mode: 0644]
Debbugs/DB/Result/BugMerged.pm [new file with mode: 0644]
Debbugs/DB/Result/BugMessage.pm [new file with mode: 0644]
Debbugs/DB/Result/BugPackage.pm [new file with mode: 0644]
Debbugs/DB/Result/BugSrcpackage.pm [new file with mode: 0644]
Debbugs/DB/Result/BugStatusCache.pm [new file with mode: 0644]
Debbugs/DB/Result/BugTag.pm [new file with mode: 0644]
Debbugs/DB/Result/BugUserTag.pm [new file with mode: 0644]
Debbugs/DB/Result/BugVer.pm [new file with mode: 0644]
Debbugs/DB/Result/Correspondent.pm [new file with mode: 0644]
Debbugs/DB/Result/CorrespondentFullName.pm [new file with mode: 0644]
Debbugs/DB/Result/Maintainer.pm [new file with mode: 0644]
Debbugs/DB/Result/Message.pm [new file with mode: 0644]
Debbugs/DB/Result/MessageCorrespondent.pm [new file with mode: 0644]
Debbugs/DB/Result/MessageRef.pm [new file with mode: 0644]
Debbugs/DB/Result/Severity.pm [new file with mode: 0644]
Debbugs/DB/Result/SrcAssociation.pm [new file with mode: 0644]
Debbugs/DB/Result/SrcPkg.pm [new file with mode: 0644]
Debbugs/DB/Result/SrcVer.pm [new file with mode: 0644]
Debbugs/DB/Result/Suite.pm [new file with mode: 0644]
Debbugs/DB/Result/Tag.pm [new file with mode: 0644]
Debbugs/DB/Result/UserTag.pm [new file with mode: 0644]
Debbugs/DB/ResultSet/Arch.pm [new file with mode: 0644]
Debbugs/DB/ResultSet/BinAssociation.pm [new file with mode: 0644]
Debbugs/DB/ResultSet/BinPkg.pm [new file with mode: 0644]
Debbugs/DB/ResultSet/BinVer.pm [new file with mode: 0644]
Debbugs/DB/ResultSet/Bug.pm [new file with mode: 0644]
Debbugs/DB/ResultSet/BugStatusCache.pm [new file with mode: 0644]
Debbugs/DB/ResultSet/Correspondent.pm [new file with mode: 0644]
Debbugs/DB/ResultSet/Maintainer.pm [new file with mode: 0644]
Debbugs/DB/ResultSet/Message.pm [new file with mode: 0644]
Debbugs/DB/ResultSet/SrcAssociation.pm [new file with mode: 0644]
Debbugs/DB/ResultSet/SrcPkg.pm [new file with mode: 0644]
Debbugs/DB/ResultSet/SrcVer.pm [new file with mode: 0644]
Debbugs/DB/ResultSet/Suite.pm [new file with mode: 0644]
Debbugs/DB/Util.pm [new file with mode: 0644]
Debbugs/DBase.pm [deleted file]
Debbugs/DBase/Log.pm [deleted file]
Debbugs/DBase/Log/Html.pm [deleted file]
Debbugs/DBase/Log/Mail.pm [deleted file]
Debbugs/DBase/Log/Message.pm [deleted file]
Debbugs/DBase/LogEntry.pm [deleted file]
Debbugs/Email.pm [deleted file]
Debbugs/Log.pm
Debbugs/MIME.pm
Debbugs/Packages.pm
Debbugs/Status.pm
README_sql.md [new file with mode: 0644]
bin/debbugs-installsql [new file with mode: 0755]
bin/debbugs-loadsql [new file with mode: 0755]
bin/debbugs-loadsql-debinfo [new file with mode: 0755]
bin/debbugs-loadsql-versions [new file with mode: 0755]
bin/debbugs-updatesqlcache [new file with mode: 0755]
debian/control
sql/PostgreSQL/deploy/1/001-auto-__VERSION.sql [new file with mode: 0644]
sql/PostgreSQL/deploy/1/001-auto.sql [new file with mode: 0644]
sql/PostgreSQL/deploy/5/001-auto.sql [new file with mode: 0644]
sql/PostgreSQL/deploy/6/001-auto.sql [new file with mode: 0644]
sql/PostgreSQL/upgrade/1-1/001-auto.sql [new file with mode: 0644]
sql/PostgreSQL/upgrade/5-6/001-auto.sql [new file with mode: 0644]
sql/README.mdwn [new file with mode: 0644]
sql/_source/deploy/1/001-auto-__VERSION.yml [new file with mode: 0644]
sql/_source/deploy/1/001-auto.yml [new file with mode: 0644]
sql/_source/deploy/5/001-auto.yml [new file with mode: 0644]
sql/_source/deploy/6/001-auto.yml [new file with mode: 0644]
sql/dbicdump.conf [new file with mode: 0644]
sql/dbicdump_command.sh [new file with mode: 0755]
sql/debbugs_schema.sql [new file with mode: 0644]

index f8e049ddf6633fd755762a697abda6e9e6ee70f8..32bb390ddf47109f8b1c1de6d7ee52e009fa66b1 100644 (file)
@@ -37,6 +37,7 @@ incomplete) to slowest (and most complete).]
 
 use warnings;
 use strict;
+use feature 'state';
 use vars qw($VERSION $DEBUG %EXPORT_TAGS @EXPORT_OK @EXPORT);
 use Exporter qw(import);
 
@@ -55,7 +56,7 @@ use Params::Validate qw(validate_with :types);
 use IO::File;
 use Debbugs::Status qw(splitpackages get_bug_status);
 use Debbugs::Packages qw(getsrcpkgs getpkgsrc);
-use Debbugs::Common qw(getparsedaddrs package_maintainer getmaintainers make_list);
+use Debbugs::Common qw(getparsedaddrs package_maintainer getmaintainers make_list hash_slice);
 use Fcntl qw(O_RDONLY);
 use MLDBM qw(DB_File Storable);
 use List::AllUtils qw(first);
@@ -152,55 +153,65 @@ bug should not.
 
 =cut
 
+state $_non_search_key_regex = qr/^(bugs|archive|usertags|schema)$/;
+
+my %_get_bugs_common_options =
+    (package   => {type => SCALAR|ARRAYREF,
+                   optional => 1,
+                  },
+     src       => {type => SCALAR|ARRAYREF,
+                   optional => 1,
+                  },
+     maint     => {type => SCALAR|ARRAYREF,
+                   optional => 1,
+                  },
+     submitter => {type => SCALAR|ARRAYREF,
+                   optional => 1,
+                  },
+     severity  => {type => SCALAR|ARRAYREF,
+                   optional => 1,
+                  },
+     status    => {type => SCALAR|ARRAYREF,
+                   optional => 1,
+                  },
+     tag       => {type => SCALAR|ARRAYREF,
+                   optional => 1,
+                  },
+     owner     => {type => SCALAR|ARRAYREF,
+                   optional => 1,
+                  },
+     dist      => {type => SCALAR|ARRAYREF,
+                   optional => 1,
+                  },
+     correspondent => {type => SCALAR|ARRAYREF,
+                       optional => 1,
+                      },
+     affects   => {type => SCALAR|ARRAYREF,
+                   optional => 1,
+                  },
+     function  => {type => CODEREF,
+                   optional => 1,
+                  },
+     bugs      => {type => SCALAR|ARRAYREF,
+                   optional => 1,
+                  },
+     archive   => {type => BOOLEAN|SCALAR,
+                   default => 0,
+                  },
+     usertags  => {type => HASHREF,
+                   optional => 1,
+                  },
+     schema => {type     => OBJECT,
+                optional => 1,
+               },
+    );
+
+
+state $_get_bugs_options = {%_get_bugs_common_options};
 sub get_bugs{
      my %param = validate_with(params => \@_,
-                              spec   => {package   => {type => SCALAR|ARRAYREF,
-                                                       optional => 1,
-                                                      },
-                                         src       => {type => SCALAR|ARRAYREF,
-                                                       optional => 1,
-                                                      },
-                                         maint     => {type => SCALAR|ARRAYREF,
-                                                       optional => 1,
-                                                      },
-                                         submitter => {type => SCALAR|ARRAYREF,
-                                                       optional => 1,
-                                                      },
-                                         severity  => {type => SCALAR|ARRAYREF,
-                                                       optional => 1,
-                                                      },
-                                         status    => {type => SCALAR|ARRAYREF,
-                                                       optional => 1,
-                                                      },
-                                         tag       => {type => SCALAR|ARRAYREF,
-                                                       optional => 1,
-                                                      },
-                                         owner     => {type => SCALAR|ARRAYREF,
-                                                       optional => 1,
-                                                      },
-                                         dist      => {type => SCALAR|ARRAYREF,
-                                                       optional => 1,
-                                                      },
-                                         correspondent => {type => SCALAR|ARRAYREF,
-                                                           optional => 1,
-                                                          },
-                                         affects   => {type => SCALAR|ARRAYREF,
-                                                       optional => 1,
-                                                      },
-                                         function  => {type => CODEREF,
-                                                       optional => 1,
-                                                      },
-                                         bugs      => {type => SCALAR|ARRAYREF,
-                                                       optional => 1,
-                                                      },
-                                         archive   => {type => BOOLEAN|SCALAR,
-                                                       default => 0,
-                                                      },
-                                         usertags  => {type => HASHREF,
-                                                       optional => 1,
-                                                      },
-                                        },
-                             );
+                              spec   => $_get_bugs_options,
+                              );
 
      # Normalize options
      my %options = %param;
@@ -213,7 +224,7 @@ sub get_bugs{
          return keys %bugs;
      }
      # A configuration option will set an array that we'll use here instead.
-     for my $routine (qw(Debbugs::Bugs::get_bugs_by_idx Debbugs::Bugs::get_bugs_flatfile)) {
+     for my $routine (qw(Debbugs::Bugs::get_bugs_by_db Debbugs::Bugs::get_bugs_by_idx Debbugs::Bugs::get_bugs_flatfile)) {
          my ($package) = $routine =~ m/^(.+)\:\:/;
          eval "use $package;";
          if ($@) {
@@ -388,45 +399,17 @@ searches.
 
 =cut
 
+
+state $_get_bugs_by_idx_options =
+   {hash_slice(%_get_bugs_common_options,
+               (qw(package submitter severity tag archive),
+                qw(owner src maint bugs correspondent),
+                qw(affects usertags))
+              )
+   };
 sub get_bugs_by_idx{
      my %param = validate_with(params => \@_,
-                              spec   => {package   => {type => SCALAR|ARRAYREF,
-                                                       optional => 1,
-                                                      },
-                                         submitter => {type => SCALAR|ARRAYREF,
-                                                       optional => 1,
-                                                      },
-                                         severity  => {type => SCALAR|ARRAYREF,
-                                                       optional => 1,
-                                                      },
-                                         tag       => {type => SCALAR|ARRAYREF,
-                                                       optional => 1,
-                                                      },
-                                         archive   => {type => BOOLEAN,
-                                                       default => 0,
-                                                      },
-                                         owner     => {type => SCALAR|ARRAYREF,
-                                                       optional => 1,
-                                                      },
-                                         src       => {type => SCALAR|ARRAYREF,
-                                                       optional => 1,
-                                                      },
-                                         maint     => {type => SCALAR|ARRAYREF,
-                                                       optional => 1,
-                                                      },
-                                         bugs      => {type => SCALAR|ARRAYREF,
-                                                       optional => 1,
-                                                      },
-                                         correspondent => {type => SCALAR|ARRAYREF,
-                                                           optional => 1,
-                                                          },
-                                         affects => {type => SCALAR|ARRAYREF,
-                                                     optional => 1,
-                                                    },
-                                         usertags  => {type => HASHREF,
-                                                       optional => 1,
-                                                      },
-                                        },
+                              spec   => $_get_bugs_by_idx_options
                              );
      my %bugs = ();
 
@@ -450,11 +433,11 @@ sub get_bugs_by_idx{
          delete @param{qw(maint src)};
          $param{package} = [@packages];
      }
-     my $keys = grep {$_ !~ /^(archive|usertags|bugs)$/} keys(%param);
+     my $keys = grep {$_ !~ $_non_search_key_regex} keys(%param);
      die "Need at least 1 key to search by" unless $keys;
      my $arc = $param{archive} ? '-arc':'';
      my %idx;
-     for my $key (grep {$_ !~ /^(archive|usertags|bugs)$/} keys %param) {
+     for my $key (grep {$_ !~ $_non_search_key_regex} keys %param) {
          my $index = $key;
          $index = 'submitter-email' if $key eq 'submitter';
          $index = "$config{spool_dir}/by-${index}${arc}.idx";
@@ -497,6 +480,140 @@ sub get_bugs_by_idx{
 }
 
 
+=head2 get_bugs_by_db
+
+This routine uses the database to try to speed up
+searches.
+
+
+=cut
+
+state $_get_bugs_by_db_options =
+   {hash_slice(%_get_bugs_common_options,
+               (qw(package submitter severity tag archive),
+                qw(owner src maint bugs correspondent),
+                qw(affects usertags))
+              ),
+    schema => {type     => OBJECT,
+              },
+   };
+sub get_bugs_by_db{
+     my %param = validate_with(params => \@_,
+                              spec   => $_get_bugs_by_db_options,
+                              );
+     my %bugs = ();
+
+     my $keys = grep {$_ !~ $_non_search_key_regex} keys(%param);
+     die "Need at least 1 key to search by" unless $keys;
+     my $rs = $param{schema}->resultset('Bug');
+     if (exists $param{package}) {
+        $rs = $rs->search({-or => {map 'bin_package.'}})
+     }
+     if (exists $param{severity}) {
+         $rs = $rs->search({'severity.severity' =>
+                           [make_list($param{severity})],
+                          },
+                          {join => 'severity'},
+                          );
+     }
+     for my $key (qw(owner submitter done)) {
+         if (exists $param{$key}) {
+             $rs = $rs->search({"${key}.addr" =>
+                               [make_list($param{$key})],
+                              },
+                              {join => $key},
+                              );
+         }
+     }
+     if (exists $param{correspondent}) {
+         $rs = $rs->search({'message_correspondents.addr' =>
+                           [make_list($param{correspondent})],
+                          },
+                          {join => {correspondent =>
+                                   {bug_messages =>
+                                   {message => 'message_correspondents'}}}},
+                          );
+     }
+     if (exists $param{affects}) {
+        my @aff_list = make_list($param{affects});
+         $rs = $rs->search({-or => {'bin_pkg.pkg' =>
+                                   [@aff_list],
+                                   'src_pkg.pkg' =>
+                                   [@aff_list],
+                                  },
+                          },
+                          {join => [{bug_affects_binpackages => 'bin_pkg'},
+                                   {bug_affects_srcpackages => 'src_pkg'},
+                                   ],
+                          },
+                          );
+     }
+     if (exists $param{package}) {
+         $rs = $rs->search({'bin_pkg.pkg' =>
+                           [make_list($param{package})],
+                          },
+                          {join => {bug_binpackages => 'bin_pkg'}});
+     }
+     if (exists $param{maintainer}) {
+        my @maint_list =
+            map {$_ eq '' ? undef : $_}
+            make_list($param{maintainer});
+        $rs = $rs->search({-or => {correspondent => [@maint_list],
+                                   correspondent2 => [@maint_list],
+                                  },
+                          },
+                         {join => {bug_affects_binpackage =>
+                                  {bin_pkg =>
+                                  {bin_ver =>
+                                  {src_ver =>
+                                  {maintainer => 'correspondent'}
+                                  }}},
+                                  {bug_affects_srcpackage =>
+                                  {src_pkg =>
+                                  {src_ver =>
+                                  {maintainer => 'correspondent'}
+                                  }}}}
+                         }
+                         );
+     }
+     if (exists $param{src}) {
+         $rs = $rs->search({-or => {map {('src_pkg.pkg' => $_)}
+                                   make_list($param{src})},
+                          },
+                          {join => {bug_srcpackages => 'src_pkg'}});
+     }
+     # tags are very odd, because we must handle usertags.
+     if (exists $param{tag}) {
+         # bugs from usertags which matter
+         my %bugs_matching_usertags;
+         for my $bug (make_list(grep {defined $_ }
+                               @{$param{usertags}}{make_list($param{tag})})) {
+             $bugs_matching_usertags{$bug} = 1;
+         }
+         # we want all bugs which either match the tag name given in
+         # param, or have a usertag set which matches one of the tag
+         # names given in param.
+         $rs = $rs->search({-or => {map {('tag.tag' => $_)}
+                                   make_list($param{tag}),
+                                   map {('me.id' => $_)}
+                                   keys %bugs_matching_usertags
+                                  },
+                          },
+                          {join => {bug_tags => 'tag'}});
+     }
+     if (exists $param{bugs}) {
+         $rs = $rs->search({-or => {map {('me.id' => $_)}
+                                   make_list($param{bugs})}
+                          });
+     }
+     # handle archive
+     if (defined $param{archive} and $param{archive} ne 'both') {
+         $rs = $rs->search({'me.archived' => $param{archive}});
+     }
+     return $rs->get_column('id')->all();
+}
+
+
 =head2 get_bugs_flatfile
 
 This is the fallback search routine. It should be able to complete all
@@ -504,55 +621,15 @@ searches. [Or at least, that's the idea.]
 
 =cut
 
+state $_get_bugs_flatfile_options =
+   {hash_slice(%_get_bugs_common_options,
+               map {$_ eq 'dist'?():($_)} keys %_get_bugs_common_options
+              )
+   };
+
 sub get_bugs_flatfile{
      my %param = validate_with(params => \@_,
-                              spec   => {package   => {type => SCALAR|ARRAYREF,
-                                                       optional => 1,
-                                                      },
-                                         src       => {type => SCALAR|ARRAYREF,
-                                                       optional => 1,
-                                                      },
-                                         maint     => {type => SCALAR|ARRAYREF,
-                                                       optional => 1,
-                                                      },
-                                         submitter => {type => SCALAR|ARRAYREF,
-                                                       optional => 1,
-                                                      },
-                                         severity  => {type => SCALAR|ARRAYREF,
-                                                       optional => 1,
-                                                      },
-                                         status    => {type => SCALAR|ARRAYREF,
-                                                       optional => 1,
-                                                      },
-                                         tag       => {type => SCALAR|ARRAYREF,
-                                                       optional => 1,
-                                                      },
-                                         owner     => {type => SCALAR|ARRAYREF,
-                                                       optional => 1,
-                                                      },
-                                         correspondent => {type => SCALAR|ARRAYREF,
-                                                           optional => 1,
-                                                          },
-                                         affects   => {type => SCALAR|ARRAYREF,
-                                                       optional => 1,
-                                                      },
-# not yet supported
-#                                        dist      => {type => SCALAR|ARRAYREF,
-#                                                      optional => 1,
-#                                                     },
-                                         bugs      => {type => SCALAR|ARRAYREF,
-                                                       optional => 1,
-                                                      },
-                                         archive   => {type => BOOLEAN,
-                                                       default => 1,
-                                                      },
-                                         usertags  => {type => HASHREF,
-                                                       optional => 1,
-                                                      },
-                                         function  => {type => CODEREF,
-                                                       optional => 1,
-                                                      },
-                                        },
+                              spec   => $_get_bugs_flatfile_options
                              );
      my $flatfile;
      if ($param{archive}) {
@@ -753,7 +830,7 @@ sub __handle_pkg_src_and_maint{
      return grep {$packages{$_} >= $package_keys} keys %packages;
 }
 
-my %field_match = (
+state %field_match = (
     'subject' => \&__contains_field_match,
     'tags' => sub {
         my ($field, $values, $status) = @_; 
index f02bf784a74ee79c9e3ba3ab3736579453eab2a6..4a47506434d5b2cb42e7804837e2ef61736fc4d9 100644 (file)
@@ -35,7 +35,7 @@ use IO::Scalar;
 use Params::Validate qw(validate_with :types);
 use Digest::MD5 qw(md5_hex);
 use Debbugs::Mail qw(get_addresses :reply);
-use Debbugs::MIME qw(decode_rfc1522 create_mime_message);
+use Debbugs::MIME qw(decode_rfc1522 create_mime_message parse_to_mime_entity);
 use Debbugs::CGI qw(:url :html :util);
 use Debbugs::Common qw(globify_scalar english_join);
 use Debbugs::UTF8;
@@ -335,17 +335,7 @@ sub handle_email_message{
      my $entity;
      my $tempdir;
      if (not blessed $record) {
-         my $parser = MIME::Parser->new();
-         # this will be cleaned up once it goes out of scope
-         $tempdir = File::Temp->newdir();
-         $parser->output_under($tempdir->dirname());
-         if ($record->{inner_file}) {
-             $entity = $parser->parse($record->{fh}) or
-                 die "Unable to parse entity";
-         } else {
-             $entity = $parser->parse_data($record->{text}) or
-                 die "Unable to parse entity";
-         }
+        $entity = parse_to_mime_entity($record);
      } else {
          $entity = $record;
      }
index e892d701d411164e742ec47d0dd9242e445e0ce0..ae7d8b4724c32f693ab4ef76403e6b9ec9da2fa5 100644 (file)
@@ -40,6 +40,7 @@ BEGIN{
      @EXPORT = ();
      %EXPORT_TAGS = (util   => [qw(getbugcomponent getbuglocation getlocationpath get_hashname),
                                qw(appendfile overwritefile buglog getparsedaddrs getmaintainers),
+                                qw(getsourcemaintainers getsourcemaintainers_reverse),
                                qw(bug_status),
                                qw(getmaintainers_reverse),
                                qw(getpseudodesc),
@@ -333,6 +334,36 @@ sub getmaintainers_reverse{
      return $_maintainer_rev;
 }
 
+=head2 getsourcemaintainers
+
+     my $maintainer = getsourcemaintainers()->{debbugs}
+
+Returns a hashref of src_package => maintainer pairs.
+
+=cut
+
+our $_source_maintainer = undef;
+our $_source_maintainer_rev = undef;
+sub getsourcemaintainers {
+    return $_source_maintainer if defined $_source_maintainer;
+    package_maintainer(rehash => 1);
+    return $_source_maintainer;
+}
+
+=head2 getsourcemaintainers_reverse
+
+     my @src_packages = @{getsourcemaintainers_reverse->{'don@debian.org'}||[]};
+
+Returns a hashref of maintainer => [qw(list of source packages)] pairs.
+
+=cut
+
+sub getsourcemaintainers_reverse{
+     return $_source_maintainer_rev if defined $_source_maintainer_rev;
+     package_maintainer(rehash => 1);
+     return $_source_maintainer_rev;
+}
+
 =head2 package_maintainer
 
      my @s = package_maintainer(source => [qw(foo bar baz)],
@@ -358,8 +389,6 @@ files; defaults to 0
 
 =cut
 
-our $_source_maintainer = undef;
-our $_source_maintainer_rev = undef;
 sub package_maintainer {
     my %param = validate_with(params => \@_,
                              spec   => {source => {type => SCALAR|ARRAYREF,
index a02072c65b78565895712f8d09ad554a9635f929..596d053644d79a50b3d4958865a74cdd6284e7bd 100644 (file)
@@ -76,6 +76,7 @@ BEGIN {
                                 qw($gTemplateDir),
                                 qw($gDefaultPackage),
                                 qw($gSpamMaxThreads $gSpamSpamsPerThread $gSpamKeepRunning $gSpamScan $gSpamCrossassassinDb),
+                                 qw($gDebbugsDb),
                                ],
                     text     => [qw($gBadEmailPrefix $gHTMLTail $gHTMLExpireNote),
                                 ],
@@ -1058,6 +1059,20 @@ set_default(\%config,'libravatar_blacklist',[]);
 
 =back
 
+=head2 Database
+
+=over
+
+=item debbugs_db
+
+Name of debbugs PostgreSQL database service. If you wish to not use a service
+file, provide a full DBD::Pg compliant data-source, for example:
+C<"dbi:Pg:dbname=dbname">
+
+=back
+
+set_default(\%config,'debbugs_db',undef);
+
 =head2 Text Fields
 
 The following are the only text fields in general use in the scripts;
diff --git a/Debbugs/DB.pm b/Debbugs/DB.pm
new file mode 100644 (file)
index 0000000..4e6d3cb
--- /dev/null
@@ -0,0 +1,33 @@
+use utf8;
+package Debbugs::DB;
+
+# Created by DBIx::Class::Schema::Loader
+# DO NOT MODIFY THE FIRST PART OF THIS FILE
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::Schema';
+
+__PACKAGE__->load_namespaces;
+
+
+# Created by DBIx::Class::Schema::Loader v0.07025 @ 2012-07-17 10:25:29
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:wiMg1t5hFUhnyufL3yT5fQ
+
+# This version must be incremented any time the schema changes so that
+# DBIx::Class::DeploymentHandler can do its work
+our $VERSION=8;
+
+# You can replace this text with custom code or comments, and it will be preserved on regeneration
+
+# override connect to handle just passing a bare service
+sub connect {
+    my ($self,@rem) = @_;
+    if ($rem[0] !~ /:/) {
+       $rem[0] = 'dbi:Pg:service='.$rem[0];
+    }
+    $self->clone->connection(@rem);
+}
+
+1;
diff --git a/Debbugs/DB/Load.pm b/Debbugs/DB/Load.pm
new file mode 100644 (file)
index 0000000..1af6c65
--- /dev/null
@@ -0,0 +1,751 @@
+# This module is part of debbugs, and is released
+# under the terms of the GPL version 2, or any later version. See the
+# file README and COPYING for more information.
+# Copyright 2013 by Don Armstrong <don@donarmstrong.com>.
+
+package Debbugs::DB::Load;
+
+=head1 NAME
+
+Debbugs::DB::Load -- Utility routines for loading the database
+
+=head1 SYNOPSIS
+
+
+=head1 DESCRIPTION
+
+
+=head1 BUGS
+
+None known.
+
+=cut
+
+use warnings;
+use strict;
+use vars qw($VERSION $DEBUG %EXPORT_TAGS @EXPORT_OK @EXPORT);
+use base qw(Exporter);
+
+BEGIN{
+     ($VERSION) = q$Revision$ =~ /^Revision:\s+([^\s+])/;
+     $DEBUG = 0 unless defined $DEBUG;
+
+     @EXPORT = ();
+     %EXPORT_TAGS = (load_bug    => [qw(load_bug handle_load_bug_queue load_bug_log)],
+                    load_debinfo => [qw(load_debinfo)],
+                    load_package => [qw(load_packages)],
+                    load_suite => [qw(load_suite)],
+                   );
+     @EXPORT_OK = ();
+     Exporter::export_ok_tags(keys %EXPORT_TAGS);
+     $EXPORT_TAGS{all} = [@EXPORT_OK];
+}
+
+use Params::Validate qw(validate_with :types);
+use List::MoreUtils qw(natatime);
+
+use Debbugs::Status qw(read_bug split_status_fields);
+use Debbugs::DB;
+use DateTime;
+use Debbugs::Common qw(make_list getparsedaddrs);
+use Debbugs::Config qw(:config);
+use Debbugs::MIME qw(parse_to_mime_entity decode_rfc1522);
+use DateTime::Format::Mail;
+use Carp;
+
+=head2 Bug loading
+
+Routines to load bug; exported with :load_bug
+
+=over
+
+=item load_bug
+
+     load_bug(db => $schema,
+              data => split_status_fields($data),
+              tags => \%tags,
+              queue => \%queue);
+
+Loads a bug's metadata into the database. (Does not load any messages)
+
+=over
+
+=item db -- Debbugs::DB object
+
+=item data -- Bug data (from read_bug) which has been split with split_status_fields
+
+=item tags -- tag cache (hashref); optional
+
+=item queue -- queue of operations to perform after bug is loaded; optional.
+
+=back
+
+=cut
+
+sub load_bug {
+    my %param = validate_with(params => \@_,
+                              spec => {db => {type => OBJECT,
+                                             },
+                                       data => {type => HASHREF,
+                                                optional => 1,
+                                               },
+                                       bug => {type => SCALAR,
+                                               optional => 1,
+                                              },
+                                       tags => {type => HASHREF,
+                                                default => sub {return {}},
+                                                optional => 1},
+                                       severities => {type => HASHREF,
+                                                      default => sub {return {}},
+                                                      optional => 1,
+                                                     },
+                                       queue => {type => HASHREF,
+                                                 optional => 1},
+                                      packages => {type => HASHREF,
+                                                   default => sub {return {}},
+                                                   optional => 1,
+                                                  },
+                                      });
+    my $s = $param{db};
+    if (not exists $param{data} and not exists $param{bug}) {
+        croak "One of data or bug must be provided to load_bug";
+    }
+    if (not exists $param{data}) {
+        $param{data} = read_bug(bug => $param{bug});
+    }
+    my $data = $param{data};
+    my $tags = $param{tags};
+    my $queue = $param{queue};
+    my $severities = $param{severities};
+    my $can_queue = 1;
+    if (not defined $queue) {
+        $can_queue = 0;
+        $queue = {};
+    }
+    my %tags;
+    $data = split_status_fields($data);
+    for my $tag (make_list($data->{keywords})) {
+       next unless defined $tag and length $tag;
+       # this allows for invalid tags. But we'll use this to try to
+       # find those bugs and clean them up
+       if (not exists $tags->{$tag}) {
+           $tags->{$tag} = $s->resultset('Tag')->
+            find_or_create({tag => $tag});
+       }
+       $tags{$tag} = $tags->{$tag};
+    }
+    my $severity = length($data->{severity}) ? $data->{severity} :
+       $config{default_severity};
+    if (not exists $severities->{$severity}) {
+       $severities->{$severity} =
+           $s->resultset('Severity')->
+            find_or_create({severity => $severity},
+                         );
+    }
+    $severity = $severities->{$severity};
+    my $bug =
+        {id => $data->{bug_num},
+         creation => DateTime->from_epoch(epoch => $data->{date}),
+         log_modified => DateTime->from_epoch(epoch => $data->{log_modified}),
+         last_modified => DateTime->from_epoch(epoch => $data->{last_modified}),
+         archived => $data->{archived},
+         (defined $data->{unarchived} and length($data->{unarchived}))?
+        (unarchived => DateTime->from_epoch(epoch => $data->{unarchived})):(),
+         forwarded => $data->{forwarded} // '',
+         summary => $data->{summary} // '',
+         outlook => $data->{outlook} // '',
+         subject => $data->{subject} // '',
+         done_full => $data->{done} // '',
+         severity => $severity,
+         owner_full => $data->{owner} // '',
+         submitter_full => $data->{originator} // '',
+        };
+    my %addr_map =
+        (done => 'done',
+         owner => 'owner',
+         submitter => 'originator',
+        );
+    for my $addr_type (keys %addr_map) {
+       $bug->{$addr_type} = undef;
+       next unless defined $data->{$addr_map{$addr_type}} and
+           length($data->{$addr_map{$addr_type}});
+        $bug->{$addr_type} =
+           $s->resultset('Correspondent')->
+           get_correspondent_id($data->{$addr_map{$addr_type}})
+    }
+    my $b = $s->resultset('Bug')->update_or_create($bug) or
+        die "Unable to update or create bug $bug->{id}";
+    $s->txn_do(sub {
+                $b->set_related_packages('binpackages',
+                                         [grep {defined $_ and
+                                                  length $_ and $_ !~ /^src:/}
+                                          make_list($data->{package})],
+                                         $param{packages},
+                                        );
+                $b->set_related_packages('srcpackages',
+                                         [map {s/src://;
+                                                $_}
+                                           grep {defined $_ and
+                                                  $_ =~ /^src:/}
+                                          make_list($data->{package})],
+                                         $param{packages},
+                                        );
+                $b->set_related_packages('affects_binpackages',
+                                         [grep {defined $_ and
+                                                  length $_ and $_ !~ /^src:/}
+                                          make_list($data->{affects})
+                                         ],
+                                         $param{packages},
+                                        );
+                $b->set_related_packages('affects_srcpackages',
+                                         [map {s/src://;
+                                                $_}
+                                           grep {defined $_ and
+                                                  $_ =~ /^src:/}
+                                          make_list($data->{affects})],
+                                         $param{packages},
+                                        );
+                for my $ff (qw(found fixed)) {
+                      my @elements = $s->resultset('BugVer')->search({bug => $data->{bug_num},
+                                                                      found  => $ff eq 'found'?1:0,
+                                                                     });
+                      my %elements_to_delete = map {($elements[$_]->ver_string(),
+                                                     $elements[$_])} 0..$#elements;
+                      my %elements_to_add;
+                       my @elements_to_keep;
+                      for my $version (@{$data->{"${ff}_versions"}}) {
+                          if (exists $elements_to_delete{$version}) {
+                              push @elements_to_keep,$version;
+                          } else {
+                              $elements_to_add{$version} = 1;
+                          }
+                      }
+                       for my $version (@elements_to_keep) {
+                           delete $elements_to_delete{$version};
+                       }
+                      for my $element (keys %elements_to_delete) {
+                           $elements_to_delete{$element}->delete();
+                      }
+                      for my $element (keys %elements_to_add) {
+                          # find source package and source version id
+                          my $ne = $s->resultset('BugVer')->new_result({bug => $data->{bug_num},
+                                                                        ver_string => $element,
+                                                                        found => $ff eq 'found'?1:0,
+                                                                       }
+                                                                      );
+                          if (my ($src_pkg,$src_ver) = $element =~ m{^([^\/]+)/(.+)$}) {
+                              my $src_pkg_e = $s->resultset('SrcPkg')->single({pkg => $src_pkg});
+                              if (defined $src_pkg_e) {
+                                  $ne->src_pkg($src_pkg_e->id());
+                                  my $src_ver_e = $s->resultset('SrcVer')->single({src_pkg => $src_pkg_e->id(),
+                                                                                   ver => $src_ver
+                                                                                  });
+                                  $ne->src_ver($src_ver_e->id()) if defined $src_ver_e;
+                              }
+                          }
+                          $ne->insert();
+                      }
+                  }
+              });
+    ### set bug tags
+    $s->txn_do(sub {$b->set_tags([values %tags ] )});
+    # because these bugs reference other bugs which might not exist
+    # yet, we can't handle them until we've loaded all bugs. queue
+    # them up.
+    for my $merge_block (qw(merged block)) {
+        my $data_key = $merge_block;
+        $data_key .= 'with' if $merge_block eq 'merged';
+        if (@{$data->{$data_key}||[]}) {
+            my $count = $s->resultset('Bug')->search({id => [@{$data->{$data_key}}]})->count();
+            if ($count == @{$data->{$data_key}}) {
+                handle_load_bug_queue(db=>$s,
+                                      queue => {$merge_block,
+                                               {$data->{bug_num},[@{$data->{$data_key}}]}
+                                               });
+            } else {
+                $queue->{$merge_block}{$data->{bug_num}} = [@{$data->{$data_key}}];
+            }
+        }
+    }
+
+    if (not $can_queue and keys %{$queue}) {
+        handle_load_bug_queue(db => $s,queue => $queue);
+    }
+
+    # still need to handle merges, versions, etc.
+}
+
+=item handle_load_bug_queue
+
+     handle_load_bug_queue(db => $schema,queue => $queue);
+
+Handles a queue of operations created by load bug. [These operations
+are used to handle cases where a bug referenced by a loaded bug may
+not exist yet. In cases where the bugs should exist, the queue is
+cleared automatically by load_bug if queue is undefined.
+
+=cut
+
+sub handle_load_bug_queue{
+    my %param = validate_with(params => \@_,
+                              spec => {db => {type => OBJECT,
+                                             },
+                                       queue => {type => HASHREF,
+                                                },
+                                      });
+    my $s = $param{db};
+    my $queue = $param{queue};
+    my %queue_types =
+       (merged => {set => 'BugMerged',
+                   columns => [qw(bug merged)],
+                   bug => 'bug',
+                  },
+        blocks => {set => 'BugBlock',
+                   columns => [qw(bug blocks)],
+                   bug => 'bug',
+                  },
+       );
+    for my $queue_type (keys %queue_types) {
+       for my $bug (%{$queue->{$queue_type}}) {
+           my $qt = $queue_types{$queue_type};
+           $s->txn_do(sub {
+                          $s->resultset($qt->{set})->search({$qt->{bug},$bug})->delete();
+                          $s->populate($qt->{set},[[@{$qt->{columns}}],
+                                                    map {[$bug,$_]} @{$queue->{$queue_type}{$bug}}]) if
+                              @{$queue->{$queue_type}{$bug}//[]};
+                      }
+                     );
+       }
+    }
+}
+
+=item load_bug_log -- load bug logs
+
+       load_bug_log(db  => $s,
+                    bug => $bug);
+
+
+=over
+
+=item db -- database 
+
+=item bug -- bug whose log should be loaded
+
+=back
+
+=cut
+
+sub load_bug_log {
+    my %param = validate_with(params => \@_,
+                              spec => {db => {type => OBJECT,
+                                             },
+                                       bug => {type => SCALAR,
+                                              },
+                                       queue => {type => HASHREF,
+                                                 optional => 1},
+                                      });
+    my $s = $param{db};
+    my $msg_num=0;
+    my %seen_msg_ids;
+    my $log = Debbugs::Log->new(bug_num => $param{bug}) or
+        die "Unable to open log for $param{bug} for reading: $!";
+    while (my $record = $log->read_record()) {
+        next unless $record->{type} eq 'incoming-recv';
+        my ($msg_id) = $record->{text} =~ /^Message-Id:\s+<(.+)>/im;
+        next if defined $msg_id and exists $seen_msg_ids{$msg_id};
+        $seen_msg_ids{$msg_id} = 1 if defined $msg_id;
+        next if defined $msg_id and $msg_id =~ /handler\..+\.ack(?:info)?\@/;
+        my $entity = parse_to_mime_entity($record);
+        # search for a message with this message id in the database
+        $msg_id = $entity->head->get('Message-Id') //
+            $entity->head->get('Resent-Message-ID') //
+            '';
+       $msg_id =~ s/^\s*\<//;
+       $msg_id =~ s/>\s*$//;
+       # check to see if the subject, to, and from match. if so, it's
+        # probably the same message.
+       my $subject = decode_rfc1522($entity->head->get('Subject')//'');
+       $subject =~ s/\n(?:(\s)\s*|\s*$)//g;
+       my $to = decode_rfc1522($entity->head->get('To')//'');
+       $to =~ s/\n(?:(\s)\s*|\s*$)//g;
+       my $from = decode_rfc1522($entity->head->get('From')//'');
+       $from =~ s/\n(?:(\s)\s*|\s*$)//g;
+       my $m = $s->resultset('Message')->
+           find({msgid => $msg_id,
+                 from_complete => $from,
+                 to_complete => $to,
+                 subject => $subject
+                });
+       if (not defined $m) {
+           # if not, create a new message
+           $m = $s->resultset('Message')->
+               find_or_create({msgid => $msg_id,
+                               from_complete => $from,
+                               to_complete => $to,
+                               subject => $subject
+                              });
+           eval {
+               my $date = DateTime::Format::Mail->
+                    parse_datetime($entity->head->get('Date',0));
+                if (abs($date->offset) >= 60 * 60 * 12) {
+                    $date = $date->set_time_zone('UTC');
+                }
+                $m->sent_date($date);
+           };
+           my $spam = $entity->head->get('X-Spam-Status',0)//'';
+           if ($spam=~ /score=([\d\.]+)/) {
+               $m->spam_score($1);
+           }
+           my %corr;
+           @{$corr{from}} = getparsedaddrs($from);
+           @{$corr{to}} = getparsedaddrs($to);
+           @{$corr{cc}} = getparsedaddrs($entity->head->get('Cc'));
+           # add correspondents if necessary
+           my @cors;
+           for my $type (keys %corr) {
+               for my $addr (@{$corr{$type}}) {
+                    my $cor = $s->resultset('Correspondent')->
+                        get_correspondent_id($addr);
+                    next unless defined $cor;
+                   push @cors,
+                       {correspondent => $cor,
+                        correspondent_type => $type,
+                       };
+               }
+           }
+           $m->update();
+           $s->txn_do(sub {
+                          $m->message_correspondents()->delete();
+                          $m->add_to_message_correspondents(@cors) if
+                               @cors;
+                      }
+                     );
+       }
+       my $recv;
+       if ($entity->head->get('Received',0)
+           =~ /via spool by (\S+)/) {
+           $recv = $s->resultset('Correspondent')->
+               get_correspondent_id($1);
+           $m->add_to_message_correspondents({correspondent=>$recv,
+                                              correspondent_type => 'recv'});
+       }
+        # link message to bugs if necessary
+       $m->find_or_create_related('bug_messages',
+                                 {bug=>$param{bug},
+                                  message_number => $msg_num});
+    }
+
+}
+
+=back
+
+=head2 Debinfo
+
+Commands to handle src and package version loading from debinfo files
+
+=over
+
+=item load_debinfo
+
+     load_debinfo($schema,$binname, $binver, $binarch, $srcname, $srcver);
+
+
+
+=cut
+
+sub load_debinfo {
+    my ($s,$binname, $binver, $binarch, $srcname, $srcver,$ct_date,$cache) = @_;
+    $cache //= {};
+    my $sp;
+    if (not defined $cache->{sp}{$srcname}) {
+        $cache->{sp}{$srcname} =
+            $s->resultset('SrcPkg')->find_or_create({pkg => $srcname});
+    }
+    $sp = $cache->{sp}{$srcname};
+    # update the creation date if the data we have is earlier
+    if (defined $ct_date and
+        (not defined $sp->creation or
+         $ct_date < $sp->creation)) {
+        $sp->creation($ct_date);
+        $sp->last_modified(DateTime->now);
+        $sp->update;
+    }
+    my $sv;
+    if (not defined $cache->{sv}{$srcname}{$srcver}) {
+        $cache->{sv}{$srcname}{$srcver} =
+            $s->resultset('SrcVer')->
+            find_or_create({src_pkg =>$sp->id(),
+                            ver => $srcver});
+    }
+    $sv = $cache->{sv}{$srcname}{$srcver};
+    if (defined $ct_date and
+        (not defined $sv->upload_date() or $ct_date < $sv->upload_date())) {
+        $sv->upload_date($ct_date);
+        $sv->update;
+    }
+    my $arch;
+    if (not defined $cache->{arch}{$binarch}) {
+        $cache->{arch}{$binarch} =
+            $s->resultset('Arch')->
+            find_or_create({arch => $binarch},
+                          )->id();
+    }
+    $arch = $cache->{arch}{$binarch};
+    my $bp;
+    if (not defined $cache->{bp}{$binname}) {
+        $cache->{bp}{$binname} =
+            $s->resultset('BinPkg')->
+            get_bin_pkg_id($binname);
+    }
+    $bp = $cache->{bp}{$binname};
+    $s->resultset('BinVer')->
+        get_bin_ver_id($bp,$binver,$arch,$sv->id());
+}
+
+
+=back
+
+=head2 Packages
+
+=over
+
+=item load_package
+
+     load_package($schema,$suite,$component,$arch,$pkg)
+
+=cut
+
+sub load_packages {
+    my ($schema,$suite,$pkgs,$p) = @_;
+    my $suite_id = $schema->resultset('Suite')->
+       find_or_create({codename => $suite})->id;
+    my %maint_cache;
+    my %arch_cache;
+    my %source_cache;
+    my $src_max_last_modified = $schema->resultset('SrcAssociation')->
+       search_rs({suite => $suite_id},
+                {order_by => {-desc => ['me.modified']},
+                 rows => 1,
+                 page => 1
+                }
+                )->single();
+    my $bin_max_last_modified = $schema->resultset('BinAssociation')->
+       search_rs({suite => $suite_id},
+                {order_by => {-desc => ['me.modified']},
+                 rows => 1,
+                 page => 1
+                }
+                )->single();
+    my %maints;
+    my %sources;
+    my %bins;
+    for my $pkg_tuple (@{$pkgs}) {
+       my ($arch,$component,$pkg) = @{$pkg_tuple};
+       $maints{$pkg->{Maintainer}} = $pkg->{Maintainer};
+       if ($arch eq 'source') {
+           my $source = $pkg->{Package};
+           my $source_ver = $pkg->{Version};
+           $sources{$source}{$source_ver} = $pkg->{Maintainer};
+       } else {
+           my $source = $pkg->{Source} // $pkg->{Package};
+           my $source_ver = $pkg->{Version};
+           if ($source =~ /^\s*(\S+) \(([^\)]+)\)\s*$/) {
+               ($source,$source_ver) = ($1,$2);
+           }
+           $sources{$source}{$source_ver} = $pkg->{Maintainer};
+           $bins{$arch}{$pkg->{Package}} =
+              {arch => $arch,
+               bin => $pkg->{Package},
+               bin_ver => $pkg->{Version},
+               src_ver => $source_ver,
+               source  => $source,
+               maint   => $pkg->{Maintainer},
+              };
+       }
+    }
+    # Retrieve and Insert new maintainers
+    my $maints =
+       $schema->resultset('Maintainer')->
+       get_maintainers(keys %maints);
+    my $archs =
+       $schema->resultset('Arch')->
+       get_archs(keys %bins);
+    # We want all of the source package/versions which are in this suite to
+    # start with
+    my @sa_to_add;
+    my @sa_to_del;
+    my %included_sa;
+    # Calculate which source packages are no longer in this suite
+    for my $s ($schema->resultset('SrcPkg')->
+              src_pkg_and_ver_in_suite($suite)) {
+       if (not exists $sources{$s->{pkg}} or
+           not exists $sources{$s->{pkg}}{$s->{src_vers}{ver}}
+          ) {
+           push @sa_to_del,
+               $s->{src_associations}{id};
+       }
+       $included_sa{$s->{pkg}}{$s->{src_vers}} = 1;
+    }
+    # Calculate which source packages are newly in this suite
+    for my $s (keys %sources) {
+       for my $v (keys %{$sources{$s}}) {
+           if (not exists $included_sa{$s} and
+               not $included_sa{$s}{$v}) {
+               push @sa_to_add,
+                   [$s,$v,$sources{$s}{$v}];
+           } else {
+               $p->update() if defined $p;
+           }
+       }
+    }
+    # add new source packages
+    my $it = natatime 100, @sa_to_add;
+    while (my @v = $it->()) {
+       $schema->txn_do(
+           sub {
+               for my $svm (@_) {
+                   my $s_id = $schema->resultset('SrcPkg')->
+                       get_src_pkg_id($svm->[0]);
+                   my $sv_id = $schema->resultset('SrcVer')->
+                       get_src_ver_id($s_id,$svm->[1],$maints->{$svm->[2]});
+                   $schema->resultset('SrcAssociation')->
+                       insert_suite_src_ver_association($suite_id,$sv_id);
+               }
+           },
+                       @v
+                      );
+       $p->update($p->last_update()+
+                  scalar @v) if defined $p;
+    }
+    # remove associations for packages not in this suite
+    if (@sa_to_del) {
+        $it = natatime 1000, @sa_to_del;
+        while (my @v = $it->()) {
+            $schema->
+                txn_do(sub {
+                           $schema->resultset('SrcAssociation')->
+                               search_rs({id => \@v})->
+                               delete();
+                       });
+        }
+    }
+    # update packages in this suite to have a modification time of now
+    $schema->resultset('SrcAssociation')->
+       search_rs({suite => $suite_id})->
+       update({modified => 'NOW()'});
+    ## Handle binary packages
+    my @bin_to_del;
+    my @bin_to_add;
+    my %included_bin;
+    # calculate which binary packages are no longer in this suite
+    for my $b ($schema->resultset('BinPkg')->
+              bin_pkg_and_ver_in_suite($suite)) {
+       if (not exists $bins{$b->{arch}{arch}} or
+           not exists $bins{$b->{arch}{arch}}{$b->{pkg}} or
+           ($bins{$b->{arch}{arch}}{$b->{pkg}}{bin_ver} ne
+            $b->{bin_vers}{ver}
+           )
+          ) {
+           push @bin_to_del,
+               $b->{bin_associations}{id};
+       }
+       $included_bin{$b->{arch}{arch}}{$b->{pkg}} =
+           $b->{bin_vers}{ver};
+    }
+    # calculate which binary packages are newly in this suite
+    for my $a (keys %bins) {
+       for my $pkg (keys %{$bins{$a}}) {
+           if (not exists $included_bin{$a} or
+               not exists $included_bin{$a}{$pkg} or
+               $bins{$a}{$pkg}{bin_ver} ne
+               $included_bin{$a}{$pkg}) {
+               push @bin_to_add,
+                   $bins{$a}{$pkg};
+           } else {
+               $p->update() if defined $p;
+           }
+       }
+    }
+    $it = natatime 100, @bin_to_add;
+    while (my @v = $it->()) {
+       $schema->txn_do(
+       sub {
+           for my $bvm (@_) {
+               my $s_id = $schema->resultset('SrcPkg')->
+                   get_src_pkg_id($bvm->{source});
+               my $sv_id = $schema->resultset('SrcVer')->
+                   get_src_ver_id($s_id,$bvm->{src_ver},$maints->{$bvm->{maint}});
+               my $b_id = $schema->resultset('BinPkg')->
+                   get_bin_pkg_id($bvm->{bin});
+               my $bv_id = $schema->resultset('BinVer')->
+                   get_bin_ver_id($b_id,$bvm->{bin_ver},
+                                  $archs->{$bvm->{arch}},$sv_id);
+               $schema->resultset('BinAssociation')->
+                   insert_suite_bin_ver_association($suite_id,$bv_id);
+           }
+       },
+                       @v
+                      );
+       $p->update($p->last_update()+
+                  scalar @v) if defined $p;
+    }
+    if (@bin_to_del) {
+        $it = natatime 1000, @bin_to_del;
+        while (my @v = $it->()) {
+            $schema->
+                txn_do(sub {
+                           $schema->resultset('BinAssociation')->
+                               search_rs({id => \@v})->
+                               delete();
+                       });
+        }
+    }
+    $schema->resultset('BinAssociation')->
+       search_rs({suite => $suite_id})->
+       update({modified => 'NOW()'});
+
+}
+
+
+=back
+
+=cut
+
+=head2 Suites
+
+=over
+
+=item load_suite
+
+     load_suite($schema,$codename,$suite,$version,$active);
+
+=cut
+
+sub load_suite {
+    my ($schema,$codename,$suite,$version,$active) = @_;
+    if (ref($codename)) {
+       ($codename,$suite,$version) =
+           @{$codename}{qw(Codename Suite Version)};
+       $active = 1;
+    }
+    my $s = $schema->resultset('Suite')->find_or_create({codename => $codename});
+    $s->suite_name($suite);
+    $s->version($version);
+    $s->active($active);
+    $s->update();
+    return $s;
+
+}
+
+=back
+
+=cut
+
+1;
+
+
+__END__
+# Local Variables:
+# indent-tabs-mode: nil
+# cperl-indent-level: 4
+# End:
diff --git a/Debbugs/DB/Result/.gitignore b/Debbugs/DB/Result/.gitignore
new file mode 100644 (file)
index 0000000..5a4e08f
--- /dev/null
@@ -0,0 +1,2 @@
+ColumnComment.pm
+TableComment.pm
diff --git a/Debbugs/DB/Result/Arch.pm b/Debbugs/DB/Result/Arch.pm
new file mode 100644 (file)
index 0000000..3045047
--- /dev/null
@@ -0,0 +1,134 @@
+use utf8;
+package Debbugs::DB::Result::Arch;
+
+# Created by DBIx::Class::Schema::Loader
+# DO NOT MODIFY THE FIRST PART OF THIS FILE
+
+=head1 NAME
+
+Debbugs::DB::Result::Arch - Architectures
+
+=cut
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::Core';
+
+=head1 COMPONENTS LOADED
+
+=over 4
+
+=item * L<DBIx::Class::InflateColumn::DateTime>
+
+=item * L<DBIx::Class::TimeStamp>
+
+=back
+
+=cut
+
+__PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp");
+
+=head1 TABLE: C<arch>
+
+=cut
+
+__PACKAGE__->table("arch");
+
+=head1 ACCESSORS
+
+=head2 id
+
+  data_type: 'integer'
+  is_auto_increment: 1
+  is_nullable: 0
+  sequence: 'arch_id_seq'
+
+Architecture id
+
+=head2 arch
+
+  data_type: 'text'
+  is_nullable: 0
+
+Architecture name
+
+=cut
+
+__PACKAGE__->add_columns(
+  "id",
+  {
+    data_type         => "integer",
+    is_auto_increment => 1,
+    is_nullable       => 0,
+    sequence          => "arch_id_seq",
+  },
+  "arch",
+  { data_type => "text", is_nullable => 0 },
+);
+
+=head1 PRIMARY KEY
+
+=over 4
+
+=item * L</id>
+
+=back
+
+=cut
+
+__PACKAGE__->set_primary_key("id");
+
+=head1 UNIQUE CONSTRAINTS
+
+=head2 C<arch_arch_key>
+
+=over 4
+
+=item * L</arch>
+
+=back
+
+=cut
+
+__PACKAGE__->add_unique_constraint("arch_arch_key", ["arch"]);
+
+=head1 RELATIONS
+
+=head2 bin_vers
+
+Type: has_many
+
+Related object: L<Debbugs::DB::Result::BinVer>
+
+=cut
+
+__PACKAGE__->has_many(
+  "bin_vers",
+  "Debbugs::DB::Result::BinVer",
+  { "foreign.arch" => "self.id" },
+  { cascade_copy => 0, cascade_delete => 0 },
+);
+
+=head2 bug_status_caches
+
+Type: has_many
+
+Related object: L<Debbugs::DB::Result::BugStatusCache>
+
+=cut
+
+__PACKAGE__->has_many(
+  "bug_status_caches",
+  "Debbugs::DB::Result::BugStatusCache",
+  { "foreign.arch" => "self.id" },
+  { cascade_copy => 0, cascade_delete => 0 },
+);
+
+
+# Created by DBIx::Class::Schema::Loader v0.07042 @ 2014-11-30 21:56:51
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:9pDiZg68Odz66DpCB9GpsA
+
+
+# You can replace this text with custom code or comments, and it will be preserved on regeneration
+1;
diff --git a/Debbugs/DB/Result/BinAssociation.pm b/Debbugs/DB/Result/BinAssociation.pm
new file mode 100644 (file)
index 0000000..7ae23fa
--- /dev/null
@@ -0,0 +1,179 @@
+use utf8;
+package Debbugs::DB::Result::BinAssociation;
+
+# Created by DBIx::Class::Schema::Loader
+# DO NOT MODIFY THE FIRST PART OF THIS FILE
+
+=head1 NAME
+
+Debbugs::DB::Result::BinAssociation - Binary <-> suite associations
+
+=cut
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::Core';
+
+=head1 COMPONENTS LOADED
+
+=over 4
+
+=item * L<DBIx::Class::InflateColumn::DateTime>
+
+=item * L<DBIx::Class::TimeStamp>
+
+=back
+
+=cut
+
+__PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp");
+
+=head1 TABLE: C<bin_associations>
+
+=cut
+
+__PACKAGE__->table("bin_associations");
+
+=head1 ACCESSORS
+
+=head2 id
+
+  data_type: 'integer'
+  is_auto_increment: 1
+  is_nullable: 0
+  sequence: 'bin_associations_id_seq'
+
+Binary <-> suite association id
+
+=head2 suite
+
+  data_type: 'integer'
+  is_foreign_key: 1
+  is_nullable: 0
+
+Suite id (matches suite)
+
+=head2 bin
+
+  data_type: 'integer'
+  is_foreign_key: 1
+  is_nullable: 0
+
+Binary version id (matches bin_ver)
+
+=head2 created
+
+  data_type: 'timestamp with time zone'
+  default_value: current_timestamp
+  is_nullable: 0
+  original: {default_value => \"now()"}
+
+Time this binary package entered this suite
+
+=head2 modified
+
+  data_type: 'timestamp with time zone'
+  default_value: current_timestamp
+  is_nullable: 0
+  original: {default_value => \"now()"}
+
+Time this entry was modified
+
+=cut
+
+__PACKAGE__->add_columns(
+  "id",
+  {
+    data_type         => "integer",
+    is_auto_increment => 1,
+    is_nullable       => 0,
+    sequence          => "bin_associations_id_seq",
+  },
+  "suite",
+  { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
+  "bin",
+  { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
+  "created",
+  {
+    data_type     => "timestamp with time zone",
+    default_value => \"current_timestamp",
+    is_nullable   => 0,
+    original      => { default_value => \"now()" },
+  },
+  "modified",
+  {
+    data_type     => "timestamp with time zone",
+    default_value => \"current_timestamp",
+    is_nullable   => 0,
+    original      => { default_value => \"now()" },
+  },
+);
+
+=head1 PRIMARY KEY
+
+=over 4
+
+=item * L</id>
+
+=back
+
+=cut
+
+__PACKAGE__->set_primary_key("id");
+
+=head1 UNIQUE CONSTRAINTS
+
+=head2 C<bin_associations_bin_suite>
+
+=over 4
+
+=item * L</bin>
+
+=item * L</suite>
+
+=back
+
+=cut
+
+__PACKAGE__->add_unique_constraint("bin_associations_bin_suite", ["bin", "suite"]);
+
+=head1 RELATIONS
+
+=head2 bin
+
+Type: belongs_to
+
+Related object: L<Debbugs::DB::Result::BinVer>
+
+=cut
+
+__PACKAGE__->belongs_to(
+  "bin",
+  "Debbugs::DB::Result::BinVer",
+  { id => "bin" },
+  { is_deferrable => 0, on_delete => "CASCADE", on_update => "CASCADE" },
+);
+
+=head2 suite
+
+Type: belongs_to
+
+Related object: L<Debbugs::DB::Result::Suite>
+
+=cut
+
+__PACKAGE__->belongs_to(
+  "suite",
+  "Debbugs::DB::Result::Suite",
+  { id => "suite" },
+  { is_deferrable => 0, on_delete => "CASCADE", on_update => "CASCADE" },
+);
+
+
+# Created by DBIx::Class::Schema::Loader v0.07045 @ 2016-11-24 09:00:00
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:3F77iWjlJrHs/98TOfroAA
+
+
+# You can replace this text with custom code or comments, and it will be preserved on regeneration
+1;
diff --git a/Debbugs/DB/Result/BinPkg.pm b/Debbugs/DB/Result/BinPkg.pm
new file mode 100644 (file)
index 0000000..5747fe0
--- /dev/null
@@ -0,0 +1,149 @@
+use utf8;
+package Debbugs::DB::Result::BinPkg;
+
+# Created by DBIx::Class::Schema::Loader
+# DO NOT MODIFY THE FIRST PART OF THIS FILE
+
+=head1 NAME
+
+Debbugs::DB::Result::BinPkg - Binary packages
+
+=cut
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::Core';
+
+=head1 COMPONENTS LOADED
+
+=over 4
+
+=item * L<DBIx::Class::InflateColumn::DateTime>
+
+=item * L<DBIx::Class::TimeStamp>
+
+=back
+
+=cut
+
+__PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp");
+
+=head1 TABLE: C<bin_pkg>
+
+=cut
+
+__PACKAGE__->table("bin_pkg");
+
+=head1 ACCESSORS
+
+=head2 id
+
+  data_type: 'integer'
+  is_auto_increment: 1
+  is_nullable: 0
+  sequence: 'bin_pkg_id_seq'
+
+Binary package id
+
+=head2 pkg
+
+  data_type: 'text'
+  is_nullable: 0
+
+Binary package name
+
+=cut
+
+__PACKAGE__->add_columns(
+  "id",
+  {
+    data_type         => "integer",
+    is_auto_increment => 1,
+    is_nullable       => 0,
+    sequence          => "bin_pkg_id_seq",
+  },
+  "pkg",
+  { data_type => "text", is_nullable => 0 },
+);
+
+=head1 PRIMARY KEY
+
+=over 4
+
+=item * L</id>
+
+=back
+
+=cut
+
+__PACKAGE__->set_primary_key("id");
+
+=head1 UNIQUE CONSTRAINTS
+
+=head2 C<bin_pkg_pkg_key>
+
+=over 4
+
+=item * L</pkg>
+
+=back
+
+=cut
+
+__PACKAGE__->add_unique_constraint("bin_pkg_pkg_key", ["pkg"]);
+
+=head1 RELATIONS
+
+=head2 bin_vers
+
+Type: has_many
+
+Related object: L<Debbugs::DB::Result::BinVer>
+
+=cut
+
+__PACKAGE__->has_many(
+  "bin_vers",
+  "Debbugs::DB::Result::BinVer",
+  { "foreign.bin_pkg" => "self.id" },
+  { cascade_copy => 0, cascade_delete => 0 },
+);
+
+=head2 bug_affects_binpackages
+
+Type: has_many
+
+Related object: L<Debbugs::DB::Result::BugAffectsBinpackage>
+
+=cut
+
+__PACKAGE__->has_many(
+  "bug_affects_binpackages",
+  "Debbugs::DB::Result::BugAffectsBinpackage",
+  { "foreign.bin_pkg" => "self.id" },
+  { cascade_copy => 0, cascade_delete => 0 },
+);
+
+=head2 bug_binpackages
+
+Type: has_many
+
+Related object: L<Debbugs::DB::Result::BugBinpackage>
+
+=cut
+
+__PACKAGE__->has_many(
+  "bug_binpackages",
+  "Debbugs::DB::Result::BugBinpackage",
+  { "foreign.bin_pkg" => "self.id" },
+  { cascade_copy => 0, cascade_delete => 0 },
+);
+
+
+# Created by DBIx::Class::Schema::Loader v0.07042 @ 2014-11-30 21:56:51
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:My1zg7yJ4SSXL78poec5ag
+
+
+# You can replace this text with custom code or comments, and it will be preserved on regeneration
+1;
diff --git a/Debbugs/DB/Result/BinVer.pm b/Debbugs/DB/Result/BinVer.pm
new file mode 100644 (file)
index 0000000..30be6c2
--- /dev/null
@@ -0,0 +1,208 @@
+use utf8;
+package Debbugs::DB::Result::BinVer;
+
+# Created by DBIx::Class::Schema::Loader
+# DO NOT MODIFY THE FIRST PART OF THIS FILE
+
+=head1 NAME
+
+Debbugs::DB::Result::BinVer - Binary versions
+
+=cut
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::Core';
+
+=head1 COMPONENTS LOADED
+
+=over 4
+
+=item * L<DBIx::Class::InflateColumn::DateTime>
+
+=item * L<DBIx::Class::TimeStamp>
+
+=back
+
+=cut
+
+__PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp");
+
+=head1 TABLE: C<bin_ver>
+
+=cut
+
+__PACKAGE__->table("bin_ver");
+
+=head1 ACCESSORS
+
+=head2 id
+
+  data_type: 'integer'
+  is_auto_increment: 1
+  is_nullable: 0
+  sequence: 'bin_ver_id_seq'
+
+Binary version id
+
+=head2 bin_pkg
+
+  data_type: 'integer'
+  is_foreign_key: 1
+  is_nullable: 0
+
+Binary package id (matches bin_pkg)
+
+=head2 src_ver
+
+  data_type: 'integer'
+  is_foreign_key: 1
+  is_nullable: 0
+
+Source version (matchines src_ver)
+
+=head2 arch
+
+  data_type: 'integer'
+  is_foreign_key: 1
+  is_nullable: 0
+
+Architecture id (matches arch)
+
+=head2 ver
+
+  data_type: 'debversion'
+  is_nullable: 0
+
+Binary version
+
+=cut
+
+__PACKAGE__->add_columns(
+  "id",
+  {
+    data_type         => "integer",
+    is_auto_increment => 1,
+    is_nullable       => 0,
+    sequence          => "bin_ver_id_seq",
+  },
+  "bin_pkg",
+  { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
+  "src_ver",
+  { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
+  "arch",
+  { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
+  "ver",
+  { data_type => "debversion", is_nullable => 0 },
+);
+
+=head1 PRIMARY KEY
+
+=over 4
+
+=item * L</id>
+
+=back
+
+=cut
+
+__PACKAGE__->set_primary_key("id");
+
+=head1 UNIQUE CONSTRAINTS
+
+=head2 C<bin_ver_bin_pkg_id_arch_idx>
+
+=over 4
+
+=item * L</bin_pkg>
+
+=item * L</arch>
+
+=item * L</ver>
+
+=back
+
+=cut
+
+__PACKAGE__->add_unique_constraint("bin_ver_bin_pkg_id_arch_idx", ["bin_pkg", "arch", "ver"]);
+
+=head1 RELATIONS
+
+=head2 arch
+
+Type: belongs_to
+
+Related object: L<Debbugs::DB::Result::Arch>
+
+=cut
+
+__PACKAGE__->belongs_to(
+  "arch",
+  "Debbugs::DB::Result::Arch",
+  { id => "arch" },
+  { is_deferrable => 0, on_delete => "CASCADE", on_update => "CASCADE" },
+);
+
+=head2 bin_associations
+
+Type: has_many
+
+Related object: L<Debbugs::DB::Result::BinAssociation>
+
+=cut
+
+__PACKAGE__->has_many(
+  "bin_associations",
+  "Debbugs::DB::Result::BinAssociation",
+  { "foreign.bin" => "self.id" },
+  { cascade_copy => 0, cascade_delete => 0 },
+);
+
+=head2 bin_pkg
+
+Type: belongs_to
+
+Related object: L<Debbugs::DB::Result::BinPkg>
+
+=cut
+
+__PACKAGE__->belongs_to(
+  "bin_pkg",
+  "Debbugs::DB::Result::BinPkg",
+  { id => "bin_pkg" },
+  { is_deferrable => 0, on_delete => "CASCADE", on_update => "CASCADE" },
+);
+
+=head2 src_ver
+
+Type: belongs_to
+
+Related object: L<Debbugs::DB::Result::SrcVer>
+
+=cut
+
+__PACKAGE__->belongs_to(
+  "src_ver",
+  "Debbugs::DB::Result::SrcVer",
+  { id => "src_ver" },
+  { is_deferrable => 0, on_delete => "CASCADE", on_update => "CASCADE" },
+);
+
+
+# Created by DBIx::Class::Schema::Loader v0.07045 @ 2016-11-24 09:08:27
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:DzTzZbPkilT8WMhXoZv9xw
+
+
+sub sqlt_deploy_hook {
+    my ($self, $sqlt_table) = @_;
+    for my $idx (qw(ver bin_pkg src_ver)) {
+       $sqlt_table->add_index(name => 'bin_ver_'.$idx.'_id_idx',
+                              fields => [$idx]);
+    }
+    $sqlt_table->add_index(name => 'bin_ver_src_ver_id_arch_idx',
+                          fields => [qw(src_ver arch)]
+                         );
+}
+
+1;
diff --git a/Debbugs/DB/Result/BinaryVersion.pm b/Debbugs/DB/Result/BinaryVersion.pm
new file mode 100644 (file)
index 0000000..426b725
--- /dev/null
@@ -0,0 +1,112 @@
+use utf8;
+package Debbugs::DB::Result::BinaryVersion;
+
+# Created by DBIx::Class::Schema::Loader
+# DO NOT MODIFY THE FIRST PART OF THIS FILE
+
+=head1 NAME
+
+Debbugs::DB::Result::BinaryVersion
+
+=cut
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::Core';
+
+=head1 COMPONENTS LOADED
+
+=over 4
+
+=item * L<DBIx::Class::InflateColumn::DateTime>
+
+=item * L<DBIx::Class::TimeStamp>
+
+=back
+
+=cut
+
+__PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp");
+__PACKAGE__->table_class("DBIx::Class::ResultSource::View");
+
+=head1 TABLE: C<binary_versions>
+
+=cut
+
+__PACKAGE__->table("binary_versions");
+__PACKAGE__->result_source_instance->view_definition(" SELECT sp.pkg AS src_pkg,\n    sv.ver AS src_ver,\n    bp.pkg AS bin_pkg,\n    a.arch,\n    b.ver AS bin_ver,\n    svb.ver AS src_ver_based_on,\n    spb.pkg AS src_pkg_based_on\n   FROM ((((((bin_ver b\n     JOIN arch a ON ((b.arch = a.id)))\n     JOIN bin_pkg bp ON ((b.bin_pkg = bp.id)))\n     JOIN src_ver sv ON ((b.src_ver = sv.id)))\n     JOIN src_pkg sp ON ((sv.src_pkg = sp.id)))\n     LEFT JOIN src_ver svb ON ((sv.based_on = svb.id)))\n     LEFT JOIN src_pkg spb ON ((spb.id = svb.src_pkg)))");
+
+=head1 ACCESSORS
+
+=head2 src_pkg
+
+  data_type: 'text'
+  is_nullable: 1
+
+=head2 src_ver
+
+  data_type: 'debversion'
+  is_nullable: 1
+
+=head2 bin_pkg
+
+  data_type: 'text'
+  is_nullable: 1
+
+=head2 arch
+
+  data_type: 'text'
+  is_nullable: 1
+
+=head2 bin_ver
+
+  data_type: 'debversion'
+  is_nullable: 1
+
+=head2 src_ver_based_on
+
+  data_type: 'debversion'
+  is_nullable: 1
+
+=head2 src_pkg_based_on
+
+  data_type: 'text'
+  is_nullable: 1
+
+=cut
+
+__PACKAGE__->add_columns(
+  "src_pkg",
+  { data_type => "text", is_nullable => 1 },
+  "src_ver",
+  { data_type => "debversion", is_nullable => 1 },
+  "bin_pkg",
+  { data_type => "text", is_nullable => 1 },
+  "arch",
+  { data_type => "text", is_nullable => 1 },
+  "bin_ver",
+  { data_type => "debversion", is_nullable => 1 },
+  "src_ver_based_on",
+  { data_type => "debversion", is_nullable => 1 },
+  "src_pkg_based_on",
+  { data_type => "text", is_nullable => 1 },
+);
+
+
+# Created by DBIx::Class::Schema::Loader v0.07046 @ 2017-03-04 10:59:03
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:0MeJnGxBc8gdEoPE6Sn6Sw
+
+__PACKAGE__->result_source_instance->view_definition(<<EOF);
+SELECT sp.pkg AS src_pkg, sv.ver AS src_ver, bp.pkg AS bin_pkg, a.arch AS arch, b.ver AS bin_ver,
+svb.ver AS src_ver_based_on, spb.pkg AS src_pkg_based_on
+FROM bin_ver b JOIN arch a ON b.arch = a.id
+                     JOIN bin_pkg bp ON b.bin_pkg  = bp.id
+               JOIN src_ver sv ON b.src_ver  = sv.id
+               JOIN src_pkg sp ON sv.src_pkg = sp.id
+               LEFT OUTER JOIN src_ver svb ON sv.based_on = svb.id
+               LEFT OUTER JOIN src_pkg spb ON spb.id = svb.src_pkg;
+EOF
+
+# You can replace this text with custom code or comments, and it will be preserved on regeneration
+1;
diff --git a/Debbugs/DB/Result/Bug.pm b/Debbugs/DB/Result/Bug.pm
new file mode 100644 (file)
index 0000000..561c0c1
--- /dev/null
@@ -0,0 +1,582 @@
+use utf8;
+package Debbugs::DB::Result::Bug;
+
+# Created by DBIx::Class::Schema::Loader
+# DO NOT MODIFY THE FIRST PART OF THIS FILE
+
+=head1 NAME
+
+Debbugs::DB::Result::Bug - Bugs
+
+=cut
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::Core';
+
+=head1 COMPONENTS LOADED
+
+=over 4
+
+=item * L<DBIx::Class::InflateColumn::DateTime>
+
+=item * L<DBIx::Class::TimeStamp>
+
+=back
+
+=cut
+
+__PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp");
+
+=head1 TABLE: C<bug>
+
+=cut
+
+__PACKAGE__->table("bug");
+
+=head1 ACCESSORS
+
+=head2 id
+
+  data_type: 'integer'
+  is_nullable: 0
+
+Bug number
+
+=head2 creation
+
+  data_type: 'timestamp with time zone'
+  default_value: current_timestamp
+  is_nullable: 0
+  original: {default_value => \"now()"}
+
+Time bug created
+
+=head2 log_modified
+
+  data_type: 'timestamp with time zone'
+  default_value: current_timestamp
+  is_nullable: 0
+  original: {default_value => \"now()"}
+
+Time bug log was last modified
+
+=head2 last_modified
+
+  data_type: 'timestamp with time zone'
+  default_value: current_timestamp
+  is_nullable: 0
+  original: {default_value => \"now()"}
+
+Time bug status was last modified
+
+=head2 archived
+
+  data_type: 'boolean'
+  default_value: false
+  is_nullable: 0
+
+True if bug has been archived
+
+=head2 unarchived
+
+  data_type: 'timestamp with time zone'
+  is_nullable: 1
+
+Time bug was last unarchived; null if bug has never been unarchived
+
+=head2 forwarded
+
+  data_type: 'text'
+  default_value: (empty string)
+  is_nullable: 0
+
+Where bug has been forwarded to; empty if it has not been forwarded
+
+=head2 summary
+
+  data_type: 'text'
+  default_value: (empty string)
+  is_nullable: 0
+
+Summary of the bug; empty if it has no summary
+
+=head2 outlook
+
+  data_type: 'text'
+  default_value: (empty string)
+  is_nullable: 0
+
+Outlook of the bug; empty if it has no outlook
+
+=head2 subject
+
+  data_type: 'text'
+  is_nullable: 0
+
+Subject of the bug
+
+=head2 severity
+
+  data_type: 'integer'
+  is_foreign_key: 1
+  is_nullable: 0
+
+=head2 done
+
+  data_type: 'integer'
+  is_foreign_key: 1
+  is_nullable: 1
+
+Individual who did the -done; empty if it has never been -done
+
+=head2 done_full
+
+  data_type: 'text'
+  default_value: (empty string)
+  is_nullable: 0
+
+=head2 owner
+
+  data_type: 'integer'
+  is_foreign_key: 1
+  is_nullable: 1
+
+Individual who owns this bug; empty if no one owns it
+
+=head2 owner_full
+
+  data_type: 'text'
+  default_value: (empty string)
+  is_nullable: 0
+
+=head2 submitter
+
+  data_type: 'integer'
+  is_foreign_key: 1
+  is_nullable: 1
+
+Individual who submitted this bug; empty if there is no submitter
+
+=head2 submitter_full
+
+  data_type: 'text'
+  default_value: (empty string)
+  is_nullable: 0
+
+=head2 unknown_packages
+
+  data_type: 'text'
+  default_value: (empty string)
+  is_nullable: 0
+
+Package name if the package is not known
+
+=cut
+
+__PACKAGE__->add_columns(
+  "id",
+  { data_type => "integer", is_nullable => 0 },
+  "creation",
+  {
+    data_type     => "timestamp with time zone",
+    default_value => \"current_timestamp",
+    is_nullable   => 0,
+    original      => { default_value => \"now()" },
+  },
+  "log_modified",
+  {
+    data_type     => "timestamp with time zone",
+    default_value => \"current_timestamp",
+    is_nullable   => 0,
+    original      => { default_value => \"now()" },
+  },
+  "last_modified",
+  {
+    data_type     => "timestamp with time zone",
+    default_value => \"current_timestamp",
+    is_nullable   => 0,
+    original      => { default_value => \"now()" },
+  },
+  "archived",
+  { data_type => "boolean", default_value => \"false", is_nullable => 0 },
+  "unarchived",
+  { data_type => "timestamp with time zone", is_nullable => 1 },
+  "forwarded",
+  { data_type => "text", default_value => "", is_nullable => 0 },
+  "summary",
+  { data_type => "text", default_value => "", is_nullable => 0 },
+  "outlook",
+  { data_type => "text", default_value => "", is_nullable => 0 },
+  "subject",
+  { data_type => "text", is_nullable => 0 },
+  "severity",
+  { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
+  "done",
+  { data_type => "integer", is_foreign_key => 1, is_nullable => 1 },
+  "done_full",
+  { data_type => "text", default_value => "", is_nullable => 0 },
+  "owner",
+  { data_type => "integer", is_foreign_key => 1, is_nullable => 1 },
+  "owner_full",
+  { data_type => "text", default_value => "", is_nullable => 0 },
+  "submitter",
+  { data_type => "integer", is_foreign_key => 1, is_nullable => 1 },
+  "submitter_full",
+  { data_type => "text", default_value => "", is_nullable => 0 },
+  "unknown_packages",
+  { data_type => "text", default_value => "", is_nullable => 0 },
+);
+
+=head1 PRIMARY KEY
+
+=over 4
+
+=item * L</id>
+
+=back
+
+=cut
+
+__PACKAGE__->set_primary_key("id");
+
+=head1 RELATIONS
+
+=head2 bug_affects_binpackages
+
+Type: has_many
+
+Related object: L<Debbugs::DB::Result::BugAffectsBinpackage>
+
+=cut
+
+__PACKAGE__->has_many(
+  "bug_affects_binpackages",
+  "Debbugs::DB::Result::BugAffectsBinpackage",
+  { "foreign.bug" => "self.id" },
+  { cascade_copy => 0, cascade_delete => 0 },
+);
+
+=head2 bug_affects_srcpackages
+
+Type: has_many
+
+Related object: L<Debbugs::DB::Result::BugAffectsSrcpackage>
+
+=cut
+
+__PACKAGE__->has_many(
+  "bug_affects_srcpackages",
+  "Debbugs::DB::Result::BugAffectsSrcpackage",
+  { "foreign.bug" => "self.id" },
+  { cascade_copy => 0, cascade_delete => 0 },
+);
+
+=head2 bug_binpackages
+
+Type: has_many
+
+Related object: L<Debbugs::DB::Result::BugBinpackage>
+
+=cut
+
+__PACKAGE__->has_many(
+  "bug_binpackages",
+  "Debbugs::DB::Result::BugBinpackage",
+  { "foreign.bug" => "self.id" },
+  { cascade_copy => 0, cascade_delete => 0 },
+);
+
+=head2 bug_blocks_blocks
+
+Type: has_many
+
+Related object: L<Debbugs::DB::Result::BugBlock>
+
+=cut
+
+__PACKAGE__->has_many(
+  "bug_blocks_blocks",
+  "Debbugs::DB::Result::BugBlock",
+  { "foreign.blocks" => "self.id" },
+  { cascade_copy => 0, cascade_delete => 0 },
+);
+
+=head2 bug_blocks_bugs
+
+Type: has_many
+
+Related object: L<Debbugs::DB::Result::BugBlock>
+
+=cut
+
+__PACKAGE__->has_many(
+  "bug_blocks_bugs",
+  "Debbugs::DB::Result::BugBlock",
+  { "foreign.bug" => "self.id" },
+  { cascade_copy => 0, cascade_delete => 0 },
+);
+
+=head2 bug_merged_bugs
+
+Type: has_many
+
+Related object: L<Debbugs::DB::Result::BugMerged>
+
+=cut
+
+__PACKAGE__->has_many(
+  "bug_merged_bugs",
+  "Debbugs::DB::Result::BugMerged",
+  { "foreign.bug" => "self.id" },
+  { cascade_copy => 0, cascade_delete => 0 },
+);
+
+=head2 bug_mergeds_merged
+
+Type: has_many
+
+Related object: L<Debbugs::DB::Result::BugMerged>
+
+=cut
+
+__PACKAGE__->has_many(
+  "bug_mergeds_merged",
+  "Debbugs::DB::Result::BugMerged",
+  { "foreign.merged" => "self.id" },
+  { cascade_copy => 0, cascade_delete => 0 },
+);
+
+=head2 bug_messages
+
+Type: has_many
+
+Related object: L<Debbugs::DB::Result::BugMessage>
+
+=cut
+
+__PACKAGE__->has_many(
+  "bug_messages",
+  "Debbugs::DB::Result::BugMessage",
+  { "foreign.bug" => "self.id" },
+  { cascade_copy => 0, cascade_delete => 0 },
+);
+
+=head2 bug_srcpackages
+
+Type: has_many
+
+Related object: L<Debbugs::DB::Result::BugSrcpackage>
+
+=cut
+
+__PACKAGE__->has_many(
+  "bug_srcpackages",
+  "Debbugs::DB::Result::BugSrcpackage",
+  { "foreign.bug" => "self.id" },
+  { cascade_copy => 0, cascade_delete => 0 },
+);
+
+=head2 bug_status_caches
+
+Type: has_many
+
+Related object: L<Debbugs::DB::Result::BugStatusCache>
+
+=cut
+
+__PACKAGE__->has_many(
+  "bug_status_caches",
+  "Debbugs::DB::Result::BugStatusCache",
+  { "foreign.bug" => "self.id" },
+  { cascade_copy => 0, cascade_delete => 0 },
+);
+
+=head2 bug_tags
+
+Type: has_many
+
+Related object: L<Debbugs::DB::Result::BugTag>
+
+=cut
+
+__PACKAGE__->has_many(
+  "bug_tags",
+  "Debbugs::DB::Result::BugTag",
+  { "foreign.bug" => "self.id" },
+  { cascade_copy => 0, cascade_delete => 0 },
+);
+
+=head2 bug_user_tags
+
+Type: has_many
+
+Related object: L<Debbugs::DB::Result::BugUserTag>
+
+=cut
+
+__PACKAGE__->has_many(
+  "bug_user_tags",
+  "Debbugs::DB::Result::BugUserTag",
+  { "foreign.bug" => "self.id" },
+  { cascade_copy => 0, cascade_delete => 0 },
+);
+
+=head2 bug_vers
+
+Type: has_many
+
+Related object: L<Debbugs::DB::Result::BugVer>
+
+=cut
+
+__PACKAGE__->has_many(
+  "bug_vers",
+  "Debbugs::DB::Result::BugVer",
+  { "foreign.bug" => "self.id" },
+  { cascade_copy => 0, cascade_delete => 0 },
+);
+
+=head2 done
+
+Type: belongs_to
+
+Related object: L<Debbugs::DB::Result::Correspondent>
+
+=cut
+
+__PACKAGE__->belongs_to(
+  "done",
+  "Debbugs::DB::Result::Correspondent",
+  { id => "done" },
+  {
+    is_deferrable => 0,
+    join_type     => "LEFT",
+    on_delete     => "NO ACTION",
+    on_update     => "NO ACTION",
+  },
+);
+
+=head2 owner
+
+Type: belongs_to
+
+Related object: L<Debbugs::DB::Result::Correspondent>
+
+=cut
+
+__PACKAGE__->belongs_to(
+  "owner",
+  "Debbugs::DB::Result::Correspondent",
+  { id => "owner" },
+  {
+    is_deferrable => 0,
+    join_type     => "LEFT",
+    on_delete     => "NO ACTION",
+    on_update     => "NO ACTION",
+  },
+);
+
+=head2 severity
+
+Type: belongs_to
+
+Related object: L<Debbugs::DB::Result::Severity>
+
+=cut
+
+__PACKAGE__->belongs_to(
+  "severity",
+  "Debbugs::DB::Result::Severity",
+  { id => "severity" },
+  { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" },
+);
+
+=head2 submitter
+
+Type: belongs_to
+
+Related object: L<Debbugs::DB::Result::Correspondent>
+
+=cut
+
+__PACKAGE__->belongs_to(
+  "submitter",
+  "Debbugs::DB::Result::Correspondent",
+  { id => "submitter" },
+  {
+    is_deferrable => 0,
+    join_type     => "LEFT",
+    on_delete     => "NO ACTION",
+    on_update     => "NO ACTION",
+  },
+);
+
+
+# Created by DBIx::Class::Schema::Loader v0.07045 @ 2016-09-24 14:51:07
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:iaipVETTaokcFNrICfIEAw
+
+use Carp;
+use List::MoreUtils qw(uniq);
+
+__PACKAGE__->many_to_many(tags => 'bug_tags','tag');
+__PACKAGE__->many_to_many(user_tags => 'bug_user_tags','user_tag');
+__PACKAGE__->many_to_many(srcpackages => 'bug_srcpackages','src_pkg');
+__PACKAGE__->many_to_many(binpackages => 'bug_binpackages','bin_pkg');
+__PACKAGE__->many_to_many(affects_binpackages => 'bug_affects_binpackages','bin_pkg');
+__PACKAGE__->many_to_many(affects_srcpackages => 'bug_affects_srcpackages','src_pkg');
+__PACKAGE__->many_to_many(messages => 'bug_messages','message');
+
+sub sqlt_deploy_hook {
+    my ($self, $sqlt_table) = @_;
+    # CREATE INDEX bug_idx_owner ON bug(owner);
+    # CREATE INDEX bug_idx_submitter ON bug(submitter);
+    # CREATE INDEX bug_idx_done ON bug(done);
+    # CREATE INDEX bug_idx_forwarded ON bug(forwarded);
+    # CREATE INDEX bug_idx_last_modified ON bug(last_modified);
+    # CREATE INDEX bug_idx_severity ON bug(severity);
+    # CREATE INDEX bug_idx_creation ON bug(creation);
+    # CREATE INDEX bug_idx_log_modified ON bug(log_modified);
+    for my $idx (qw(owner submitter done forwarded last_modified),
+                qw(severity creation log_modified),
+               ) {
+       $sqlt_table->add_index(name => 'bug_idx'.$idx,
+                              fields => [$idx]);
+    }
+}
+
+sub set_related_packages {
+    my ($self,$relationship,$pkgs,$pkg_cache) = @_;
+
+    my @pkg_ids;
+    if ($relationship =~ /binpackages/) {
+        for my $pkg (@{$pkgs}) {
+            push @pkg_ids,
+              $self->result_source->schema->resultset('BinPkg')->
+              get_bin_pkg_id($pkg);
+        }
+    } elsif ($relationship =~ /srcpackages/) {
+        for my $pkg (@{$pkgs}) {
+            push @pkg_ids,
+              $self->result_source->schema->resultset('SrcPkg')->
+              get_src_pkg_id($pkg);
+        }
+    } else {
+        croak "Unsupported relationship $relationship";
+    }
+    @pkg_ids = uniq @pkg_ids;
+    if ($relationship eq 'binpackages') {
+        $self->set_binpackages([map {{id => $_}} @pkg_ids]);
+    } elsif ($relationship eq 'srcpackages') {
+        $self->set_srcpackages([map {{id => $_}} @pkg_ids]);
+    } elsif ($relationship eq 'affects_binpackages') {
+        $self->set_affects_binpackages([map {{id => $_}} @pkg_ids]);
+    } elsif ($relationship eq 'affects_srcpackages') {
+        $self->set_affects_srcpackages([map {{id => $_}} @pkg_ids]);
+    } else {
+        croak "Unsupported relationship $relationship";
+    }
+}
+# You can replace this text with custom code or comments, and it will be preserved on regeneration
+1;
diff --git a/Debbugs/DB/Result/BugAffectsBinpackage.pm b/Debbugs/DB/Result/BugAffectsBinpackage.pm
new file mode 100644 (file)
index 0000000..ce4b57e
--- /dev/null
@@ -0,0 +1,119 @@
+use utf8;
+package Debbugs::DB::Result::BugAffectsBinpackage;
+
+# Created by DBIx::Class::Schema::Loader
+# DO NOT MODIFY THE FIRST PART OF THIS FILE
+
+=head1 NAME
+
+Debbugs::DB::Result::BugAffectsBinpackage - Bug <-> binary package mapping
+
+=cut
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::Core';
+
+=head1 COMPONENTS LOADED
+
+=over 4
+
+=item * L<DBIx::Class::InflateColumn::DateTime>
+
+=item * L<DBIx::Class::TimeStamp>
+
+=back
+
+=cut
+
+__PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp");
+
+=head1 TABLE: C<bug_affects_binpackage>
+
+=cut
+
+__PACKAGE__->table("bug_affects_binpackage");
+
+=head1 ACCESSORS
+
+=head2 bug
+
+  data_type: 'integer'
+  is_foreign_key: 1
+  is_nullable: 0
+
+Bug id (matches bug)
+
+=head2 bin_pkg
+
+  data_type: 'integer'
+  is_foreign_key: 1
+  is_nullable: 0
+
+Binary package id (matches bin_pkg)
+
+=cut
+
+__PACKAGE__->add_columns(
+  "bug",
+  { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
+  "bin_pkg",
+  { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
+);
+
+=head1 UNIQUE CONSTRAINTS
+
+=head2 C<bug_affects_binpackage_id_pkg>
+
+=over 4
+
+=item * L</bug>
+
+=item * L</bin_pkg>
+
+=back
+
+=cut
+
+__PACKAGE__->add_unique_constraint("bug_affects_binpackage_id_pkg", ["bug", "bin_pkg"]);
+
+=head1 RELATIONS
+
+=head2 bin_pkg
+
+Type: belongs_to
+
+Related object: L<Debbugs::DB::Result::BinPkg>
+
+=cut
+
+__PACKAGE__->belongs_to(
+  "bin_pkg",
+  "Debbugs::DB::Result::BinPkg",
+  { id => "bin_pkg" },
+  { is_deferrable => 0, on_delete => "CASCADE", on_update => "CASCADE" },
+);
+
+=head2 bug
+
+Type: belongs_to
+
+Related object: L<Debbugs::DB::Result::Bug>
+
+=cut
+
+__PACKAGE__->belongs_to(
+  "bug",
+  "Debbugs::DB::Result::Bug",
+  { id => "bug" },
+  { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" },
+);
+
+
+# Created by DBIx::Class::Schema::Loader v0.07046 @ 2017-03-04 10:59:03
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:qPJSly5VwC8Fl9hchBtB1Q
+
+
+# You can replace this text with custom code or comments, and it will be preserved on regeneration
+1;
diff --git a/Debbugs/DB/Result/BugAffectsSrcpackage.pm b/Debbugs/DB/Result/BugAffectsSrcpackage.pm
new file mode 100644 (file)
index 0000000..e25fa60
--- /dev/null
@@ -0,0 +1,119 @@
+use utf8;
+package Debbugs::DB::Result::BugAffectsSrcpackage;
+
+# Created by DBIx::Class::Schema::Loader
+# DO NOT MODIFY THE FIRST PART OF THIS FILE
+
+=head1 NAME
+
+Debbugs::DB::Result::BugAffectsSrcpackage - Bug <-> source package mapping
+
+=cut
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::Core';
+
+=head1 COMPONENTS LOADED
+
+=over 4
+
+=item * L<DBIx::Class::InflateColumn::DateTime>
+
+=item * L<DBIx::Class::TimeStamp>
+
+=back
+
+=cut
+
+__PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp");
+
+=head1 TABLE: C<bug_affects_srcpackage>
+
+=cut
+
+__PACKAGE__->table("bug_affects_srcpackage");
+
+=head1 ACCESSORS
+
+=head2 bug
+
+  data_type: 'integer'
+  is_foreign_key: 1
+  is_nullable: 0
+
+Bug id (matches bug)
+
+=head2 src_pkg
+
+  data_type: 'integer'
+  is_foreign_key: 1
+  is_nullable: 0
+
+Source package id (matches src_pkg)
+
+=cut
+
+__PACKAGE__->add_columns(
+  "bug",
+  { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
+  "src_pkg",
+  { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
+);
+
+=head1 UNIQUE CONSTRAINTS
+
+=head2 C<bug_affects_srcpackage_id_pkg>
+
+=over 4
+
+=item * L</bug>
+
+=item * L</src_pkg>
+
+=back
+
+=cut
+
+__PACKAGE__->add_unique_constraint("bug_affects_srcpackage_id_pkg", ["bug", "src_pkg"]);
+
+=head1 RELATIONS
+
+=head2 bug
+
+Type: belongs_to
+
+Related object: L<Debbugs::DB::Result::Bug>
+
+=cut
+
+__PACKAGE__->belongs_to(
+  "bug",
+  "Debbugs::DB::Result::Bug",
+  { id => "bug" },
+  { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" },
+);
+
+=head2 src_pkg
+
+Type: belongs_to
+
+Related object: L<Debbugs::DB::Result::SrcPkg>
+
+=cut
+
+__PACKAGE__->belongs_to(
+  "src_pkg",
+  "Debbugs::DB::Result::SrcPkg",
+  { id => "src_pkg" },
+  { is_deferrable => 0, on_delete => "CASCADE", on_update => "CASCADE" },
+);
+
+
+# Created by DBIx::Class::Schema::Loader v0.07046 @ 2017-03-04 10:59:03
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:1TkTacVNBhXOnzV1ttCF2A
+
+
+# You can replace this text with custom code or comments, and it will be preserved on regeneration
+1;
diff --git a/Debbugs/DB/Result/BugBinpackage.pm b/Debbugs/DB/Result/BugBinpackage.pm
new file mode 100644 (file)
index 0000000..d572994
--- /dev/null
@@ -0,0 +1,125 @@
+use utf8;
+package Debbugs::DB::Result::BugBinpackage;
+
+# Created by DBIx::Class::Schema::Loader
+# DO NOT MODIFY THE FIRST PART OF THIS FILE
+
+=head1 NAME
+
+Debbugs::DB::Result::BugBinpackage - Bug <-> binary package mapping
+
+=cut
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::Core';
+
+=head1 COMPONENTS LOADED
+
+=over 4
+
+=item * L<DBIx::Class::InflateColumn::DateTime>
+
+=item * L<DBIx::Class::TimeStamp>
+
+=back
+
+=cut
+
+__PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp");
+
+=head1 TABLE: C<bug_binpackage>
+
+=cut
+
+__PACKAGE__->table("bug_binpackage");
+
+=head1 ACCESSORS
+
+=head2 bug
+
+  data_type: 'integer'
+  is_foreign_key: 1
+  is_nullable: 0
+
+Bug id (matches bug)
+
+=head2 bin_pkg
+
+  data_type: 'integer'
+  is_foreign_key: 1
+  is_nullable: 0
+
+Binary package id (matches bin_pkg)
+
+=cut
+
+__PACKAGE__->add_columns(
+  "bug",
+  { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
+  "bin_pkg",
+  { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
+);
+
+=head1 UNIQUE CONSTRAINTS
+
+=head2 C<bug_binpackage_id_pkg>
+
+=over 4
+
+=item * L</bug>
+
+=item * L</bin_pkg>
+
+=back
+
+=cut
+
+__PACKAGE__->add_unique_constraint("bug_binpackage_id_pkg", ["bug", "bin_pkg"]);
+
+=head1 RELATIONS
+
+=head2 bin_pkg
+
+Type: belongs_to
+
+Related object: L<Debbugs::DB::Result::BinPkg>
+
+=cut
+
+__PACKAGE__->belongs_to(
+  "bin_pkg",
+  "Debbugs::DB::Result::BinPkg",
+  { id => "bin_pkg" },
+  { is_deferrable => 0, on_delete => "CASCADE", on_update => "CASCADE" },
+);
+
+=head2 bug
+
+Type: belongs_to
+
+Related object: L<Debbugs::DB::Result::Bug>
+
+=cut
+
+__PACKAGE__->belongs_to(
+  "bug",
+  "Debbugs::DB::Result::Bug",
+  { id => "bug" },
+  { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" },
+);
+
+
+# Created by DBIx::Class::Schema::Loader v0.07046 @ 2017-03-04 10:59:03
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:wL+pwSCfWe/mMQOjziKSeg
+
+
+sub sqlt_deploy_hook {
+    my ($self, $sqlt_table) = @_;
+    $sqlt_table->add_index(name => 'bug_binpackage_bin_pkg_idx',
+                          fields => [qw(bin_pkg)],
+                         );
+}
+
+1;
diff --git a/Debbugs/DB/Result/BugBlock.pm b/Debbugs/DB/Result/BugBlock.pm
new file mode 100644 (file)
index 0000000..0200a31
--- /dev/null
@@ -0,0 +1,152 @@
+use utf8;
+package Debbugs::DB::Result::BugBlock;
+
+# Created by DBIx::Class::Schema::Loader
+# DO NOT MODIFY THE FIRST PART OF THIS FILE
+
+=head1 NAME
+
+Debbugs::DB::Result::BugBlock - Bugs which block other bugs
+
+=cut
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::Core';
+
+=head1 COMPONENTS LOADED
+
+=over 4
+
+=item * L<DBIx::Class::InflateColumn::DateTime>
+
+=item * L<DBIx::Class::TimeStamp>
+
+=back
+
+=cut
+
+__PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp");
+
+=head1 TABLE: C<bug_blocks>
+
+=cut
+
+__PACKAGE__->table("bug_blocks");
+
+=head1 ACCESSORS
+
+=head2 id
+
+  data_type: 'integer'
+  is_auto_increment: 1
+  is_nullable: 0
+  sequence: 'bug_blocks_id_seq'
+
+=head2 bug
+
+  data_type: 'integer'
+  is_foreign_key: 1
+  is_nullable: 0
+
+Bug number
+
+=head2 blocks
+
+  data_type: 'integer'
+  is_foreign_key: 1
+  is_nullable: 0
+
+Bug number which is blocked by bug
+
+=cut
+
+__PACKAGE__->add_columns(
+  "id",
+  {
+    data_type         => "integer",
+    is_auto_increment => 1,
+    is_nullable       => 0,
+    sequence          => "bug_blocks_id_seq",
+  },
+  "bug",
+  { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
+  "blocks",
+  { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
+);
+
+=head1 PRIMARY KEY
+
+=over 4
+
+=item * L</id>
+
+=back
+
+=cut
+
+__PACKAGE__->set_primary_key("id");
+
+=head1 UNIQUE CONSTRAINTS
+
+=head2 C<bug_blocks_bug_id_blocks_idx>
+
+=over 4
+
+=item * L</bug>
+
+=item * L</blocks>
+
+=back
+
+=cut
+
+__PACKAGE__->add_unique_constraint("bug_blocks_bug_id_blocks_idx", ["bug", "blocks"]);
+
+=head1 RELATIONS
+
+=head2 block
+
+Type: belongs_to
+
+Related object: L<Debbugs::DB::Result::Bug>
+
+=cut
+
+__PACKAGE__->belongs_to(
+  "block",
+  "Debbugs::DB::Result::Bug",
+  { id => "blocks" },
+  { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" },
+);
+
+=head2 bug
+
+Type: belongs_to
+
+Related object: L<Debbugs::DB::Result::Bug>
+
+=cut
+
+__PACKAGE__->belongs_to(
+  "bug",
+  "Debbugs::DB::Result::Bug",
+  { id => "bug" },
+  { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" },
+);
+
+
+# Created by DBIx::Class::Schema::Loader v0.07042 @ 2014-11-30 21:56:51
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:Rkt0XlA4r2YFX0KnUZmS6A
+
+
+sub sqlt_deploy_hook {
+    my ($self, $sqlt_table) = @_;
+    for my $idx (qw(bug blocks)) {
+       $sqlt_table->add_index(name => 'bug_blocks_'.$idx.'_idx',
+                              fields => [$idx]);
+    }
+}
+
+1;
diff --git a/Debbugs/DB/Result/BugMerged.pm b/Debbugs/DB/Result/BugMerged.pm
new file mode 100644 (file)
index 0000000..477919b
--- /dev/null
@@ -0,0 +1,151 @@
+use utf8;
+package Debbugs::DB::Result::BugMerged;
+
+# Created by DBIx::Class::Schema::Loader
+# DO NOT MODIFY THE FIRST PART OF THIS FILE
+
+=head1 NAME
+
+Debbugs::DB::Result::BugMerged - Bugs which are merged with other bugs
+
+=cut
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::Core';
+
+=head1 COMPONENTS LOADED
+
+=over 4
+
+=item * L<DBIx::Class::InflateColumn::DateTime>
+
+=item * L<DBIx::Class::TimeStamp>
+
+=back
+
+=cut
+
+__PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp");
+
+=head1 TABLE: C<bug_merged>
+
+=cut
+
+__PACKAGE__->table("bug_merged");
+
+=head1 ACCESSORS
+
+=head2 id
+
+  data_type: 'integer'
+  is_auto_increment: 1
+  is_nullable: 0
+  sequence: 'bug_merged_id_seq'
+
+=head2 bug
+
+  data_type: 'integer'
+  is_foreign_key: 1
+  is_nullable: 0
+
+Bug number
+
+=head2 merged
+
+  data_type: 'integer'
+  is_foreign_key: 1
+  is_nullable: 0
+
+Bug number which is merged with bug
+
+=cut
+
+__PACKAGE__->add_columns(
+  "id",
+  {
+    data_type         => "integer",
+    is_auto_increment => 1,
+    is_nullable       => 0,
+    sequence          => "bug_merged_id_seq",
+  },
+  "bug",
+  { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
+  "merged",
+  { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
+);
+
+=head1 PRIMARY KEY
+
+=over 4
+
+=item * L</id>
+
+=back
+
+=cut
+
+__PACKAGE__->set_primary_key("id");
+
+=head1 UNIQUE CONSTRAINTS
+
+=head2 C<bug_merged_bug_id_merged_idx>
+
+=over 4
+
+=item * L</bug>
+
+=item * L</merged>
+
+=back
+
+=cut
+
+__PACKAGE__->add_unique_constraint("bug_merged_bug_id_merged_idx", ["bug", "merged"]);
+
+=head1 RELATIONS
+
+=head2 bug
+
+Type: belongs_to
+
+Related object: L<Debbugs::DB::Result::Bug>
+
+=cut
+
+__PACKAGE__->belongs_to(
+  "bug",
+  "Debbugs::DB::Result::Bug",
+  { id => "bug" },
+  { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" },
+);
+
+=head2 merged
+
+Type: belongs_to
+
+Related object: L<Debbugs::DB::Result::Bug>
+
+=cut
+
+__PACKAGE__->belongs_to(
+  "merged",
+  "Debbugs::DB::Result::Bug",
+  { id => "merged" },
+  { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" },
+);
+
+
+# Created by DBIx::Class::Schema::Loader v0.07042 @ 2014-11-30 21:56:51
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:HdGeCb1Fh2cU08+TTQVi/Q
+
+sub sqlt_deploy_hook {
+    my ($self, $sqlt_table) = @_;
+    for my $idx (qw(bug merged)) {
+       $sqlt_table->add_index(name => 'bug_merged_'.$idx.'_idx',
+                              fields => [$idx]);
+    }
+}
+
+1;
diff --git a/Debbugs/DB/Result/BugMessage.pm b/Debbugs/DB/Result/BugMessage.pm
new file mode 100644 (file)
index 0000000..b5fccc5
--- /dev/null
@@ -0,0 +1,150 @@
+use utf8;
+package Debbugs::DB::Result::BugMessage;
+
+# Created by DBIx::Class::Schema::Loader
+# DO NOT MODIFY THE FIRST PART OF THIS FILE
+
+=head1 NAME
+
+Debbugs::DB::Result::BugMessage
+
+=cut
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::Core';
+
+=head1 COMPONENTS LOADED
+
+=over 4
+
+=item * L<DBIx::Class::InflateColumn::DateTime>
+
+=item * L<DBIx::Class::TimeStamp>
+
+=back
+
+=cut
+
+__PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp");
+
+=head1 TABLE: C<bug_message>
+
+=cut
+
+__PACKAGE__->table("bug_message");
+
+=head1 ACCESSORS
+
+=head2 bug
+
+  data_type: 'integer'
+  is_foreign_key: 1
+  is_nullable: 0
+
+Bug id (matches bug)
+
+=head2 message
+
+  data_type: 'integer'
+  is_foreign_key: 1
+  is_nullable: 0
+
+Message id (matches message)
+
+=head2 message_number
+
+  data_type: 'integer'
+  is_nullable: 0
+
+Message number in the bug log
+
+=head2 bug_log_offset
+
+  data_type: 'integer'
+  is_nullable: 1
+
+Byte offset in the bug log
+
+=head2 offset_valid
+
+  data_type: 'timestamp with time zone'
+  is_nullable: 1
+
+Time offset was valid
+
+=cut
+
+__PACKAGE__->add_columns(
+  "bug",
+  { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
+  "message",
+  { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
+  "message_number",
+  { data_type => "integer", is_nullable => 0 },
+  "bug_log_offset",
+  { data_type => "integer", is_nullable => 1 },
+  "offset_valid",
+  { data_type => "timestamp with time zone", is_nullable => 1 },
+);
+
+=head1 UNIQUE CONSTRAINTS
+
+=head2 C<bug_message_bug_message_idx>
+
+=over 4
+
+=item * L</bug>
+
+=item * L</message>
+
+=back
+
+=cut
+
+__PACKAGE__->add_unique_constraint("bug_message_bug_message_idx", ["bug", "message"]);
+
+=head1 RELATIONS
+
+=head2 bug
+
+Type: belongs_to
+
+Related object: L<Debbugs::DB::Result::Bug>
+
+=cut
+
+__PACKAGE__->belongs_to(
+  "bug",
+  "Debbugs::DB::Result::Bug",
+  { id => "bug" },
+  { is_deferrable => 0, on_delete => "CASCADE", on_update => "CASCADE" },
+);
+
+=head2 message
+
+Type: belongs_to
+
+Related object: L<Debbugs::DB::Result::Message>
+
+=cut
+
+__PACKAGE__->belongs_to(
+  "message",
+  "Debbugs::DB::Result::Message",
+  { id => "message" },
+  { is_deferrable => 0, on_delete => "CASCADE", on_update => "CASCADE" },
+);
+
+
+# Created by DBIx::Class::Schema::Loader v0.07046 @ 2017-03-04 10:59:03
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:BRbN9C6P/wvWWmSmjNGjLA
+
+sub sqlt_deploy_hook {
+    my ($self, $sqlt_table) = @_;
+    $sqlt_table->add_index(name => 'bug_message_idx_bug_message_number',
+                          fields => [qw(bug message_number)],
+                         );
+}
+1;
diff --git a/Debbugs/DB/Result/BugPackage.pm b/Debbugs/DB/Result/BugPackage.pm
new file mode 100644 (file)
index 0000000..db6f200
--- /dev/null
@@ -0,0 +1,86 @@
+use utf8;
+package Debbugs::DB::Result::BugPackage;
+
+# Created by DBIx::Class::Schema::Loader
+# DO NOT MODIFY THE FIRST PART OF THIS FILE
+
+=head1 NAME
+
+Debbugs::DB::Result::BugPackage
+
+=cut
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::Core';
+
+=head1 COMPONENTS LOADED
+
+=over 4
+
+=item * L<DBIx::Class::InflateColumn::DateTime>
+
+=item * L<DBIx::Class::TimeStamp>
+
+=back
+
+=cut
+
+__PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp");
+__PACKAGE__->table_class("DBIx::Class::ResultSource::View");
+
+=head1 TABLE: C<bug_package>
+
+=cut
+
+__PACKAGE__->table("bug_package");
+__PACKAGE__->result_source_instance->view_definition(" SELECT b.bug,\n    b.bin_pkg AS pkg_id,\n    'binary'::text AS pkg_type,\n    bp.pkg AS package\n   FROM (bug_binpackage b\n     JOIN bin_pkg bp ON ((bp.id = b.bin_pkg)))\nUNION\n SELECT s.bug,\n    s.src_pkg AS pkg_id,\n    'source'::text AS pkg_type,\n    sp.pkg AS package\n   FROM (bug_srcpackage s\n     JOIN src_pkg sp ON ((sp.id = s.src_pkg)))\nUNION\n SELECT b.bug,\n    b.bin_pkg AS pkg_id,\n    'binary_affects'::text AS pkg_type,\n    bp.pkg AS package\n   FROM (bug_affects_binpackage b\n     JOIN bin_pkg bp ON ((bp.id = b.bin_pkg)))\nUNION\n SELECT s.bug,\n    s.src_pkg AS pkg_id,\n    'source_affects'::text AS pkg_type,\n    sp.pkg AS package\n   FROM (bug_affects_srcpackage s\n     JOIN src_pkg sp ON ((sp.id = s.src_pkg)))");
+
+=head1 ACCESSORS
+
+=head2 bug
+
+  data_type: 'integer'
+  is_nullable: 1
+
+=head2 pkg_id
+
+  data_type: 'integer'
+  is_nullable: 1
+
+=head2 pkg_type
+
+  data_type: 'text'
+  is_nullable: 1
+
+=head2 package
+
+  data_type: 'text'
+  is_nullable: 1
+
+=cut
+
+__PACKAGE__->add_columns(
+  "bug",
+  { data_type => "integer", is_nullable => 1 },
+  "pkg_id",
+  { data_type => "integer", is_nullable => 1 },
+  "pkg_type",
+  { data_type => "text", is_nullable => 1 },
+  "package",
+  { data_type => "text", is_nullable => 1 },
+);
+
+
+# Created by DBIx::Class::Schema::Loader v0.07046 @ 2017-04-13 11:30:02
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:2Nrl+KO8b94gK5GcCkdNcw
+
+__PACKAGE__->result_source_instance->view_definition(<<EOF);
+SELECT b.bug,b.bin_pkg,'binary',bp.pkg FROM bug_binpackage b JOIN bin_pkg bp ON bp.id=b.bin_pkg UNION
+       SELECT s.bug,s.src_pkg,'source',sp.pkg FROM bug_srcpackage s JOIN src_pkg sp ON sp.id=s.src_pkg;
+EOF
+
+
+# You can replace this text with custom code or comments, and it will be preserved on regeneration
+1;
diff --git a/Debbugs/DB/Result/BugSrcpackage.pm b/Debbugs/DB/Result/BugSrcpackage.pm
new file mode 100644 (file)
index 0000000..d5b6540
--- /dev/null
@@ -0,0 +1,124 @@
+use utf8;
+package Debbugs::DB::Result::BugSrcpackage;
+
+# Created by DBIx::Class::Schema::Loader
+# DO NOT MODIFY THE FIRST PART OF THIS FILE
+
+=head1 NAME
+
+Debbugs::DB::Result::BugSrcpackage - Bug <-> source package mapping
+
+=cut
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::Core';
+
+=head1 COMPONENTS LOADED
+
+=over 4
+
+=item * L<DBIx::Class::InflateColumn::DateTime>
+
+=item * L<DBIx::Class::TimeStamp>
+
+=back
+
+=cut
+
+__PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp");
+
+=head1 TABLE: C<bug_srcpackage>
+
+=cut
+
+__PACKAGE__->table("bug_srcpackage");
+
+=head1 ACCESSORS
+
+=head2 bug
+
+  data_type: 'integer'
+  is_foreign_key: 1
+  is_nullable: 0
+
+Bug id (matches bug)
+
+=head2 src_pkg
+
+  data_type: 'integer'
+  is_foreign_key: 1
+  is_nullable: 0
+
+Source package id (matches src_pkg)
+
+=cut
+
+__PACKAGE__->add_columns(
+  "bug",
+  { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
+  "src_pkg",
+  { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
+);
+
+=head1 UNIQUE CONSTRAINTS
+
+=head2 C<bug_srcpackage_id_pkg>
+
+=over 4
+
+=item * L</bug>
+
+=item * L</src_pkg>
+
+=back
+
+=cut
+
+__PACKAGE__->add_unique_constraint("bug_srcpackage_id_pkg", ["bug", "src_pkg"]);
+
+=head1 RELATIONS
+
+=head2 bug
+
+Type: belongs_to
+
+Related object: L<Debbugs::DB::Result::Bug>
+
+=cut
+
+__PACKAGE__->belongs_to(
+  "bug",
+  "Debbugs::DB::Result::Bug",
+  { id => "bug" },
+  { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" },
+);
+
+=head2 src_pkg
+
+Type: belongs_to
+
+Related object: L<Debbugs::DB::Result::SrcPkg>
+
+=cut
+
+__PACKAGE__->belongs_to(
+  "src_pkg",
+  "Debbugs::DB::Result::SrcPkg",
+  { id => "src_pkg" },
+  { is_deferrable => 0, on_delete => "CASCADE", on_update => "CASCADE" },
+);
+
+
+# Created by DBIx::Class::Schema::Loader v0.07046 @ 2017-03-04 10:59:03
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:5SduyMaGHABDrX19Cxg4fg
+
+sub sqlt_deploy_hook {
+    my ($self, $sqlt_table) = @_;
+    $sqlt_table->add_index(name => 'bug_srcpackage_src_pkg_idx',
+                          fields => [qw(src_pkg)],
+                         );
+}
+
+1;
diff --git a/Debbugs/DB/Result/BugStatusCache.pm b/Debbugs/DB/Result/BugStatusCache.pm
new file mode 100644 (file)
index 0000000..26b850e
--- /dev/null
@@ -0,0 +1,220 @@
+use utf8;
+package Debbugs::DB::Result::BugStatusCache;
+
+# Created by DBIx::Class::Schema::Loader
+# DO NOT MODIFY THE FIRST PART OF THIS FILE
+
+=head1 NAME
+
+Debbugs::DB::Result::BugStatusCache - Bug Status Cache
+
+=cut
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::Core';
+
+=head1 COMPONENTS LOADED
+
+=over 4
+
+=item * L<DBIx::Class::InflateColumn::DateTime>
+
+=item * L<DBIx::Class::TimeStamp>
+
+=back
+
+=cut
+
+__PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp");
+
+=head1 TABLE: C<bug_status_cache>
+
+=cut
+
+__PACKAGE__->table("bug_status_cache");
+
+=head1 ACCESSORS
+
+=head2 bug
+
+  data_type: 'integer'
+  is_foreign_key: 1
+  is_nullable: 0
+
+Bug number (matches bug)
+
+=head2 suite
+
+  data_type: 'integer'
+  is_foreign_key: 1
+  is_nullable: 1
+
+Suite id (matches suite)
+
+=head2 arch
+
+  data_type: 'integer'
+  is_foreign_key: 1
+  is_nullable: 1
+
+Architecture id (matches arch)
+
+=head2 status
+
+  data_type: 'enum'
+  extra: {custom_type_name => "bug_status_type",list => ["absent","found","fixed","undef"]}
+  is_nullable: 0
+
+Status (bug status)
+
+=head2 modified
+
+  data_type: 'timestamp with time zone'
+  default_value: current_timestamp
+  is_nullable: 0
+  original: {default_value => \"now()"}
+
+Time that this status was last modified
+
+=head2 asof
+
+  data_type: 'timestamp with time zone'
+  default_value: current_timestamp
+  is_nullable: 0
+  original: {default_value => \"now()"}
+
+Time that this status was last calculated
+
+=cut
+
+__PACKAGE__->add_columns(
+  "bug",
+  { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
+  "suite",
+  { data_type => "integer", is_foreign_key => 1, is_nullable => 1 },
+  "arch",
+  { data_type => "integer", is_foreign_key => 1, is_nullable => 1 },
+  "status",
+  {
+    data_type => "enum",
+    extra => {
+      custom_type_name => "bug_status_type",
+      list => ["absent", "found", "fixed", "undef"],
+    },
+    is_nullable => 0,
+  },
+  "modified",
+  {
+    data_type     => "timestamp with time zone",
+    default_value => \"current_timestamp",
+    is_nullable   => 0,
+    original      => { default_value => \"now()" },
+  },
+  "asof",
+  {
+    data_type     => "timestamp with time zone",
+    default_value => \"current_timestamp",
+    is_nullable   => 0,
+    original      => { default_value => \"now()" },
+  },
+);
+
+=head1 UNIQUE CONSTRAINTS
+
+=head2 C<bug_status_cache_bug_suite_arch_idx>
+
+=over 4
+
+=item * L</bug>
+
+=item * L</suite>
+
+=item * L</arch>
+
+=back
+
+=cut
+
+__PACKAGE__->add_unique_constraint(
+  "bug_status_cache_bug_suite_arch_idx",
+  ["bug", "suite", "arch"],
+);
+
+=head1 RELATIONS
+
+=head2 arch
+
+Type: belongs_to
+
+Related object: L<Debbugs::DB::Result::Arch>
+
+=cut
+
+__PACKAGE__->belongs_to(
+  "arch",
+  "Debbugs::DB::Result::Arch",
+  { id => "arch" },
+  {
+    is_deferrable => 0,
+    join_type     => "LEFT",
+    on_delete     => "CASCADE",
+    on_update     => "CASCADE",
+  },
+);
+
+=head2 bug
+
+Type: belongs_to
+
+Related object: L<Debbugs::DB::Result::Bug>
+
+=cut
+
+__PACKAGE__->belongs_to(
+  "bug",
+  "Debbugs::DB::Result::Bug",
+  { id => "bug" },
+  { is_deferrable => 0, on_delete => "CASCADE", on_update => "CASCADE" },
+);
+
+=head2 suite
+
+Type: belongs_to
+
+Related object: L<Debbugs::DB::Result::Suite>
+
+=cut
+
+__PACKAGE__->belongs_to(
+  "suite",
+  "Debbugs::DB::Result::Suite",
+  { id => "suite" },
+  {
+    is_deferrable => 0,
+    join_type     => "LEFT",
+    on_delete     => "CASCADE",
+    on_update     => "CASCADE",
+  },
+);
+
+
+# Created by DBIx::Class::Schema::Loader v0.07046 @ 2017-08-07 09:58:56
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:RNAken/j2+82FVCyCTnvQw
+
+sub sqlt_deploy_hook {
+    my ($self, $sqlt_table) = @_;
+#     $sqlt_table->add_index(name => 'bug_status_cache_bug_suite_arch_idx',
+#                         fields => ['bug',
+#                                    q{COALESCE(suite,0)},
+#                                    q{COALESCE(arch,0)},]
+#                        );
+    for my $f (qw(bug status arch suite asof)) {
+       $sqlt_table->add_index(name => 'bug_status_cache_idx_'.$f,
+                              fields => [$f],
+                             );
+    }
+}
+
+1;
diff --git a/Debbugs/DB/Result/BugTag.pm b/Debbugs/DB/Result/BugTag.pm
new file mode 100644 (file)
index 0000000..f5c6c24
--- /dev/null
@@ -0,0 +1,125 @@
+use utf8;
+package Debbugs::DB::Result::BugTag;
+
+# Created by DBIx::Class::Schema::Loader
+# DO NOT MODIFY THE FIRST PART OF THIS FILE
+
+=head1 NAME
+
+Debbugs::DB::Result::BugTag - Bug <-> tag mapping
+
+=cut
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::Core';
+
+=head1 COMPONENTS LOADED
+
+=over 4
+
+=item * L<DBIx::Class::InflateColumn::DateTime>
+
+=item * L<DBIx::Class::TimeStamp>
+
+=back
+
+=cut
+
+__PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp");
+
+=head1 TABLE: C<bug_tag>
+
+=cut
+
+__PACKAGE__->table("bug_tag");
+
+=head1 ACCESSORS
+
+=head2 bug
+
+  data_type: 'integer'
+  is_foreign_key: 1
+  is_nullable: 0
+
+Bug id (matches bug)
+
+=head2 tag
+
+  data_type: 'integer'
+  is_foreign_key: 1
+  is_nullable: 0
+
+Tag id (matches tag)
+
+=cut
+
+__PACKAGE__->add_columns(
+  "bug",
+  { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
+  "tag",
+  { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
+);
+
+=head1 UNIQUE CONSTRAINTS
+
+=head2 C<bug_tag_bug_tag>
+
+=over 4
+
+=item * L</bug>
+
+=item * L</tag>
+
+=back
+
+=cut
+
+__PACKAGE__->add_unique_constraint("bug_tag_bug_tag", ["bug", "tag"]);
+
+=head1 RELATIONS
+
+=head2 bug
+
+Type: belongs_to
+
+Related object: L<Debbugs::DB::Result::Bug>
+
+=cut
+
+__PACKAGE__->belongs_to(
+  "bug",
+  "Debbugs::DB::Result::Bug",
+  { id => "bug" },
+  { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" },
+);
+
+=head2 tag
+
+Type: belongs_to
+
+Related object: L<Debbugs::DB::Result::Tag>
+
+=cut
+
+__PACKAGE__->belongs_to(
+  "tag",
+  "Debbugs::DB::Result::Tag",
+  { id => "tag" },
+  { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" },
+);
+
+
+# Created by DBIx::Class::Schema::Loader v0.07046 @ 2017-03-04 10:59:03
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:yyHP5f8zAxn/AdjOCr8WAg
+
+
+sub sqlt_deploy_hook {
+    my ($self, $sqlt_table) = @_;
+    $sqlt_table->add_index(name => 'bug_tag_tag',
+                          fields => [qw(tag)],
+                         );
+}
+
+1;
diff --git a/Debbugs/DB/Result/BugUserTag.pm b/Debbugs/DB/Result/BugUserTag.pm
new file mode 100644 (file)
index 0000000..6d83c63
--- /dev/null
@@ -0,0 +1,123 @@
+use utf8;
+package Debbugs::DB::Result::BugUserTag;
+
+# Created by DBIx::Class::Schema::Loader
+# DO NOT MODIFY THE FIRST PART OF THIS FILE
+
+=head1 NAME
+
+Debbugs::DB::Result::BugUserTag - Bug <-> user tag mapping
+
+=cut
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::Core';
+
+=head1 COMPONENTS LOADED
+
+=over 4
+
+=item * L<DBIx::Class::InflateColumn::DateTime>
+
+=item * L<DBIx::Class::TimeStamp>
+
+=back
+
+=cut
+
+__PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp");
+
+=head1 TABLE: C<bug_user_tag>
+
+=cut
+
+__PACKAGE__->table("bug_user_tag");
+
+=head1 ACCESSORS
+
+=head2 bug
+
+  data_type: 'integer'
+  is_foreign_key: 1
+  is_nullable: 0
+
+Bug id (matches bug)
+
+=head2 user_tag
+
+  data_type: 'integer'
+  is_foreign_key: 1
+  is_nullable: 0
+
+=cut
+
+__PACKAGE__->add_columns(
+  "bug",
+  { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
+  "user_tag",
+  { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
+);
+
+=head1 UNIQUE CONSTRAINTS
+
+=head2 C<bug_user_tag_bug_tag>
+
+=over 4
+
+=item * L</bug>
+
+=item * L</user_tag>
+
+=back
+
+=cut
+
+__PACKAGE__->add_unique_constraint("bug_user_tag_bug_tag", ["bug", "user_tag"]);
+
+=head1 RELATIONS
+
+=head2 bug
+
+Type: belongs_to
+
+Related object: L<Debbugs::DB::Result::Bug>
+
+=cut
+
+__PACKAGE__->belongs_to(
+  "bug",
+  "Debbugs::DB::Result::Bug",
+  { id => "bug" },
+  { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" },
+);
+
+=head2 user_tag
+
+Type: belongs_to
+
+Related object: L<Debbugs::DB::Result::UserTag>
+
+=cut
+
+__PACKAGE__->belongs_to(
+  "user_tag",
+  "Debbugs::DB::Result::UserTag",
+  { id => "user_tag" },
+  { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" },
+);
+
+
+# Created by DBIx::Class::Schema::Loader v0.07046 @ 2017-03-04 10:59:03
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:jZngUCQ1eBBcfXd/jWCKGA
+
+
+sub sqlt_deploy_hook {
+    my ($self, $sqlt_table) = @_;
+    $sqlt_table->add_index(name => 'bug_user_tag_tag',
+                          fields => [qw(user_tag)],
+                         );
+}
+
+1;
diff --git a/Debbugs/DB/Result/BugVer.pm b/Debbugs/DB/Result/BugVer.pm
new file mode 100644 (file)
index 0000000..472a1df
--- /dev/null
@@ -0,0 +1,247 @@
+use utf8;
+package Debbugs::DB::Result::BugVer;
+
+# Created by DBIx::Class::Schema::Loader
+# DO NOT MODIFY THE FIRST PART OF THIS FILE
+
+=head1 NAME
+
+Debbugs::DB::Result::BugVer - Bug versions
+
+=cut
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::Core';
+
+=head1 COMPONENTS LOADED
+
+=over 4
+
+=item * L<DBIx::Class::InflateColumn::DateTime>
+
+=item * L<DBIx::Class::TimeStamp>
+
+=back
+
+=cut
+
+__PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp");
+
+=head1 TABLE: C<bug_ver>
+
+=cut
+
+__PACKAGE__->table("bug_ver");
+
+=head1 ACCESSORS
+
+=head2 id
+
+  data_type: 'integer'
+  is_auto_increment: 1
+  is_nullable: 0
+  sequence: 'bug_ver_id_seq'
+
+Bug version id
+
+=head2 bug
+
+  data_type: 'integer'
+  is_foreign_key: 1
+  is_nullable: 0
+
+Bug number
+
+=head2 ver_string
+
+  data_type: 'text'
+  is_nullable: 1
+
+Version string
+
+=head2 src_pkg
+
+  data_type: 'integer'
+  is_foreign_key: 1
+  is_nullable: 1
+
+Source package id (matches src_pkg table)
+
+=head2 src_ver
+
+  data_type: 'integer'
+  is_foreign_key: 1
+  is_nullable: 1
+
+Source package version id (matches src_ver table)
+
+=head2 found
+
+  data_type: 'boolean'
+  default_value: true
+  is_nullable: 0
+
+True if this is a found version; false if this is a fixed version
+
+=head2 creation
+
+  data_type: 'timestamp with time zone'
+  default_value: current_timestamp
+  is_nullable: 0
+  original: {default_value => \"now()"}
+
+Time that this entry was created
+
+=head2 last_modified
+
+  data_type: 'timestamp with time zone'
+  default_value: current_timestamp
+  is_nullable: 0
+  original: {default_value => \"now()"}
+
+Time that this entry was modified
+
+=cut
+
+__PACKAGE__->add_columns(
+  "id",
+  {
+    data_type         => "integer",
+    is_auto_increment => 1,
+    is_nullable       => 0,
+    sequence          => "bug_ver_id_seq",
+  },
+  "bug",
+  { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
+  "ver_string",
+  { data_type => "text", is_nullable => 1 },
+  "src_pkg",
+  { data_type => "integer", is_foreign_key => 1, is_nullable => 1 },
+  "src_ver",
+  { data_type => "integer", is_foreign_key => 1, is_nullable => 1 },
+  "found",
+  { data_type => "boolean", default_value => \"true", is_nullable => 0 },
+  "creation",
+  {
+    data_type     => "timestamp with time zone",
+    default_value => \"current_timestamp",
+    is_nullable   => 0,
+    original      => { default_value => \"now()" },
+  },
+  "last_modified",
+  {
+    data_type     => "timestamp with time zone",
+    default_value => \"current_timestamp",
+    is_nullable   => 0,
+    original      => { default_value => \"now()" },
+  },
+);
+
+=head1 PRIMARY KEY
+
+=over 4
+
+=item * L</id>
+
+=back
+
+=cut
+
+__PACKAGE__->set_primary_key("id");
+
+=head1 UNIQUE CONSTRAINTS
+
+=head2 C<bug_ver_bug_ver_string_found_idx>
+
+=over 4
+
+=item * L</bug>
+
+=item * L</ver_string>
+
+=item * L</found>
+
+=back
+
+=cut
+
+__PACKAGE__->add_unique_constraint(
+  "bug_ver_bug_ver_string_found_idx",
+  ["bug", "ver_string", "found"],
+);
+
+=head1 RELATIONS
+
+=head2 bug
+
+Type: belongs_to
+
+Related object: L<Debbugs::DB::Result::Bug>
+
+=cut
+
+__PACKAGE__->belongs_to(
+  "bug",
+  "Debbugs::DB::Result::Bug",
+  { id => "bug" },
+  { is_deferrable => 0, on_delete => "RESTRICT", on_update => "CASCADE" },
+);
+
+=head2 src_pkg
+
+Type: belongs_to
+
+Related object: L<Debbugs::DB::Result::SrcPkg>
+
+=cut
+
+__PACKAGE__->belongs_to(
+  "src_pkg",
+  "Debbugs::DB::Result::SrcPkg",
+  { id => "src_pkg" },
+  {
+    is_deferrable => 0,
+    join_type     => "LEFT",
+    on_delete     => "SET NULL",
+    on_update     => "CASCADE",
+  },
+);
+
+=head2 src_ver
+
+Type: belongs_to
+
+Related object: L<Debbugs::DB::Result::SrcVer>
+
+=cut
+
+__PACKAGE__->belongs_to(
+  "src_ver",
+  "Debbugs::DB::Result::SrcVer",
+  { id => "src_ver" },
+  {
+    is_deferrable => 0,
+    join_type     => "LEFT",
+    on_delete     => "SET NULL",
+    on_update     => "CASCADE",
+  },
+);
+
+
+# Created by DBIx::Class::Schema::Loader v0.07042 @ 2014-11-30 21:56:51
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:cvdjFL2o+rBg2PfcintuNA
+
+
+sub sqlt_deploy_hook {
+    my ($self, $sqlt_table) = @_;
+    for my $idx (qw(src_pkg src_ver)) {
+       $sqlt_table->add_index(name => 'bug_ver_'.$idx.'_id_idx',
+                              fields => [$idx]);
+    }
+    $sqlt_table->add_index(name => 'bug_ver_src_pkg_id_src_ver_id_idx',
+                          fields => [qw(src_pkg src_ver)],
+                         );
+}
+1;
diff --git a/Debbugs/DB/Result/Correspondent.pm b/Debbugs/DB/Result/Correspondent.pm
new file mode 100644 (file)
index 0000000..b0a57ae
--- /dev/null
@@ -0,0 +1,209 @@
+use utf8;
+package Debbugs::DB::Result::Correspondent;
+
+# Created by DBIx::Class::Schema::Loader
+# DO NOT MODIFY THE FIRST PART OF THIS FILE
+
+=head1 NAME
+
+Debbugs::DB::Result::Correspondent - Individual who has corresponded with the BTS
+
+=cut
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::Core';
+
+=head1 COMPONENTS LOADED
+
+=over 4
+
+=item * L<DBIx::Class::InflateColumn::DateTime>
+
+=item * L<DBIx::Class::TimeStamp>
+
+=back
+
+=cut
+
+__PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp");
+
+=head1 TABLE: C<correspondent>
+
+=cut
+
+__PACKAGE__->table("correspondent");
+
+=head1 ACCESSORS
+
+=head2 id
+
+  data_type: 'integer'
+  is_auto_increment: 1
+  is_nullable: 0
+  sequence: 'correspondent_id_seq'
+
+Correspondent ID
+
+=head2 addr
+
+  data_type: 'text'
+  is_nullable: 0
+
+Correspondent address
+
+=cut
+
+__PACKAGE__->add_columns(
+  "id",
+  {
+    data_type         => "integer",
+    is_auto_increment => 1,
+    is_nullable       => 0,
+    sequence          => "correspondent_id_seq",
+  },
+  "addr",
+  { data_type => "text", is_nullable => 0 },
+);
+
+=head1 PRIMARY KEY
+
+=over 4
+
+=item * L</id>
+
+=back
+
+=cut
+
+__PACKAGE__->set_primary_key("id");
+
+=head1 UNIQUE CONSTRAINTS
+
+=head2 C<correspondent_addr_idx>
+
+=over 4
+
+=item * L</addr>
+
+=back
+
+=cut
+
+__PACKAGE__->add_unique_constraint("correspondent_addr_idx", ["addr"]);
+
+=head1 RELATIONS
+
+=head2 bug_owners
+
+Type: has_many
+
+Related object: L<Debbugs::DB::Result::Bug>
+
+=cut
+
+__PACKAGE__->has_many(
+  "bug_owners",
+  "Debbugs::DB::Result::Bug",
+  { "foreign.owner" => "self.id" },
+  { cascade_copy => 0, cascade_delete => 0 },
+);
+
+=head2 bug_submitters
+
+Type: has_many
+
+Related object: L<Debbugs::DB::Result::Bug>
+
+=cut
+
+__PACKAGE__->has_many(
+  "bug_submitters",
+  "Debbugs::DB::Result::Bug",
+  { "foreign.submitter" => "self.id" },
+  { cascade_copy => 0, cascade_delete => 0 },
+);
+
+=head2 bugs_done
+
+Type: has_many
+
+Related object: L<Debbugs::DB::Result::Bug>
+
+=cut
+
+__PACKAGE__->has_many(
+  "bugs_done",
+  "Debbugs::DB::Result::Bug",
+  { "foreign.done" => "self.id" },
+  { cascade_copy => 0, cascade_delete => 0 },
+);
+
+=head2 correspondent_full_names
+
+Type: has_many
+
+Related object: L<Debbugs::DB::Result::CorrespondentFullName>
+
+=cut
+
+__PACKAGE__->has_many(
+  "correspondent_full_names",
+  "Debbugs::DB::Result::CorrespondentFullName",
+  { "foreign.correspondent" => "self.id" },
+  { cascade_copy => 0, cascade_delete => 0 },
+);
+
+=head2 maintainers
+
+Type: has_many
+
+Related object: L<Debbugs::DB::Result::Maintainer>
+
+=cut
+
+__PACKAGE__->has_many(
+  "maintainers",
+  "Debbugs::DB::Result::Maintainer",
+  { "foreign.correspondent" => "self.id" },
+  { cascade_copy => 0, cascade_delete => 0 },
+);
+
+=head2 message_correspondents
+
+Type: has_many
+
+Related object: L<Debbugs::DB::Result::MessageCorrespondent>
+
+=cut
+
+__PACKAGE__->has_many(
+  "message_correspondents",
+  "Debbugs::DB::Result::MessageCorrespondent",
+  { "foreign.correspondent" => "self.id" },
+  { cascade_copy => 0, cascade_delete => 0 },
+);
+
+=head2 user_tags
+
+Type: has_many
+
+Related object: L<Debbugs::DB::Result::UserTag>
+
+=cut
+
+__PACKAGE__->has_many(
+  "user_tags",
+  "Debbugs::DB::Result::UserTag",
+  { "foreign.correspondent" => "self.id" },
+  { cascade_copy => 0, cascade_delete => 0 },
+);
+
+
+# Created by DBIx::Class::Schema::Loader v0.07045 @ 2016-09-24 14:51:07
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:CUVcqt94wCYJOPbiPt00+Q
+
+
+# You can replace this text with custom code or comments, and it will be preserved on regeneration
+1;
diff --git a/Debbugs/DB/Result/CorrespondentFullName.pm b/Debbugs/DB/Result/CorrespondentFullName.pm
new file mode 100644 (file)
index 0000000..a5be283
--- /dev/null
@@ -0,0 +1,126 @@
+use utf8;
+package Debbugs::DB::Result::CorrespondentFullName;
+
+# Created by DBIx::Class::Schema::Loader
+# DO NOT MODIFY THE FIRST PART OF THIS FILE
+
+=head1 NAME
+
+Debbugs::DB::Result::CorrespondentFullName - Full names of BTS correspondents
+
+=cut
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::Core';
+
+=head1 COMPONENTS LOADED
+
+=over 4
+
+=item * L<DBIx::Class::InflateColumn::DateTime>
+
+=item * L<DBIx::Class::TimeStamp>
+
+=back
+
+=cut
+
+__PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp");
+
+=head1 TABLE: C<correspondent_full_name>
+
+=cut
+
+__PACKAGE__->table("correspondent_full_name");
+
+=head1 ACCESSORS
+
+=head2 correspondent
+
+  data_type: 'integer'
+  is_foreign_key: 1
+  is_nullable: 0
+
+Correspondent ID (matches correspondent)
+
+=head2 full_name
+
+  data_type: 'text'
+  is_nullable: 0
+
+Correspondent full name (includes e-mail address)
+
+=head2 last_seen
+
+  data_type: 'timestamp'
+  default_value: current_timestamp
+  is_nullable: 0
+  original: {default_value => \"now()"}
+
+=cut
+
+__PACKAGE__->add_columns(
+  "correspondent",
+  { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
+  "full_name",
+  { data_type => "text", is_nullable => 0 },
+  "last_seen",
+  {
+    data_type     => "timestamp",
+    default_value => \"current_timestamp",
+    is_nullable   => 0,
+    original      => { default_value => \"now()" },
+  },
+);
+
+=head1 UNIQUE CONSTRAINTS
+
+=head2 C<correspondent_full_name_correspondent_full_name_idx>
+
+=over 4
+
+=item * L</correspondent>
+
+=item * L</full_name>
+
+=back
+
+=cut
+
+__PACKAGE__->add_unique_constraint(
+  "correspondent_full_name_correspondent_full_name_idx",
+  ["correspondent", "full_name"],
+);
+
+=head1 RELATIONS
+
+=head2 correspondent
+
+Type: belongs_to
+
+Related object: L<Debbugs::DB::Result::Correspondent>
+
+=cut
+
+__PACKAGE__->belongs_to(
+  "correspondent",
+  "Debbugs::DB::Result::Correspondent",
+  { id => "correspondent" },
+  { is_deferrable => 0, on_delete => "CASCADE", on_update => "CASCADE" },
+);
+
+
+# Created by DBIx::Class::Schema::Loader v0.07046 @ 2017-03-04 10:59:03
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:2Ac8mrDV2IsE/11YsYoqQQ
+
+sub sqlt_deploy_hook {
+    my ($self, $sqlt_table) = @_;
+    for my $idx (qw(full_name last_seen)) {
+       $sqlt_table->add_index(name => 'correspondent_full_name_idx_'.$idx,
+                              fields => [$idx]);
+    }
+}
+
+1;
diff --git a/Debbugs/DB/Result/Maintainer.pm b/Debbugs/DB/Result/Maintainer.pm
new file mode 100644 (file)
index 0000000..d8c04ec
--- /dev/null
@@ -0,0 +1,181 @@
+use utf8;
+package Debbugs::DB::Result::Maintainer;
+
+# Created by DBIx::Class::Schema::Loader
+# DO NOT MODIFY THE FIRST PART OF THIS FILE
+
+=head1 NAME
+
+Debbugs::DB::Result::Maintainer - Package maintainer names
+
+=cut
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::Core';
+
+=head1 COMPONENTS LOADED
+
+=over 4
+
+=item * L<DBIx::Class::InflateColumn::DateTime>
+
+=item * L<DBIx::Class::TimeStamp>
+
+=back
+
+=cut
+
+__PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp");
+
+=head1 TABLE: C<maintainer>
+
+=cut
+
+__PACKAGE__->table("maintainer");
+
+=head1 ACCESSORS
+
+=head2 id
+
+  data_type: 'integer'
+  is_auto_increment: 1
+  is_nullable: 0
+  sequence: 'maintainer_id_seq'
+
+Package maintainer id
+
+=head2 name
+
+  data_type: 'text'
+  is_nullable: 0
+
+Name of package maintainer
+
+=head2 correspondent
+
+  data_type: 'integer'
+  is_foreign_key: 1
+  is_nullable: 0
+
+Correspondent ID
+
+=head2 created
+
+  data_type: 'timestamp with time zone'
+  default_value: current_timestamp
+  is_nullable: 0
+  original: {default_value => \"now()"}
+
+Time maintainer record created
+
+=head2 modified
+
+  data_type: 'timestamp with time zone'
+  default_value: current_timestamp
+  is_nullable: 0
+  original: {default_value => \"now()"}
+
+Time maintainer record modified
+
+=cut
+
+__PACKAGE__->add_columns(
+  "id",
+  {
+    data_type         => "integer",
+    is_auto_increment => 1,
+    is_nullable       => 0,
+    sequence          => "maintainer_id_seq",
+  },
+  "name",
+  { data_type => "text", is_nullable => 0 },
+  "correspondent",
+  { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
+  "created",
+  {
+    data_type     => "timestamp with time zone",
+    default_value => \"current_timestamp",
+    is_nullable   => 0,
+    original      => { default_value => \"now()" },
+  },
+  "modified",
+  {
+    data_type     => "timestamp with time zone",
+    default_value => \"current_timestamp",
+    is_nullable   => 0,
+    original      => { default_value => \"now()" },
+  },
+);
+
+=head1 PRIMARY KEY
+
+=over 4
+
+=item * L</id>
+
+=back
+
+=cut
+
+__PACKAGE__->set_primary_key("id");
+
+=head1 UNIQUE CONSTRAINTS
+
+=head2 C<maintainer_name_idx>
+
+=over 4
+
+=item * L</name>
+
+=back
+
+=cut
+
+__PACKAGE__->add_unique_constraint("maintainer_name_idx", ["name"]);
+
+=head1 RELATIONS
+
+=head2 correspondent
+
+Type: belongs_to
+
+Related object: L<Debbugs::DB::Result::Correspondent>
+
+=cut
+
+__PACKAGE__->belongs_to(
+  "correspondent",
+  "Debbugs::DB::Result::Correspondent",
+  { id => "correspondent" },
+  { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" },
+);
+
+=head2 src_vers
+
+Type: has_many
+
+Related object: L<Debbugs::DB::Result::SrcVer>
+
+=cut
+
+__PACKAGE__->has_many(
+  "src_vers",
+  "Debbugs::DB::Result::SrcVer",
+  { "foreign.maintainer" => "self.id" },
+  { cascade_copy => 0, cascade_delete => 0 },
+);
+
+
+# Created by DBIx::Class::Schema::Loader v0.07042 @ 2014-11-30 21:56:51
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:rkpgeXltH2wiC1Us7FIijw
+
+sub sqlt_deploy_hook {
+    my ($self, $sqlt_table) = @_;
+    $sqlt_table->add_index(name => 'maintainer_idx_correspondent',
+                          fields => [qw(correspondent)],
+                         );
+}
+
+1;
diff --git a/Debbugs/DB/Result/Message.pm b/Debbugs/DB/Result/Message.pm
new file mode 100644 (file)
index 0000000..cd42f48
--- /dev/null
@@ -0,0 +1,255 @@
+use utf8;
+package Debbugs::DB::Result::Message;
+
+# Created by DBIx::Class::Schema::Loader
+# DO NOT MODIFY THE FIRST PART OF THIS FILE
+
+=head1 NAME
+
+Debbugs::DB::Result::Message - Messages sent to bugs
+
+=cut
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::Core';
+
+=head1 COMPONENTS LOADED
+
+=over 4
+
+=item * L<DBIx::Class::InflateColumn::DateTime>
+
+=item * L<DBIx::Class::TimeStamp>
+
+=back
+
+=cut
+
+__PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp");
+
+=head1 TABLE: C<message>
+
+=cut
+
+__PACKAGE__->table("message");
+
+=head1 ACCESSORS
+
+=head2 id
+
+  data_type: 'integer'
+  is_auto_increment: 1
+  is_nullable: 0
+  sequence: 'message_id_seq'
+
+Message id
+
+=head2 msgid
+
+  data_type: 'text'
+  default_value: (empty string)
+  is_nullable: 0
+
+Message id header
+
+=head2 from_complete
+
+  data_type: 'text'
+  default_value: (empty string)
+  is_nullable: 0
+
+Complete from header of message
+
+=head2 to_complete
+
+  data_type: 'text'
+  default_value: (empty string)
+  is_nullable: 0
+
+Complete to header of message
+
+=head2 subject
+
+  data_type: 'text'
+  default_value: (empty string)
+  is_nullable: 0
+
+Subject of the message
+
+=head2 sent_date
+
+  data_type: 'timestamp with time zone'
+  is_nullable: 1
+
+Time/date message was sent (from Date header)
+
+=head2 refs
+
+  data_type: 'text'
+  default_value: (empty string)
+  is_nullable: 0
+
+Contents of References: header
+
+=head2 spam_score
+
+  data_type: 'double precision'
+  default_value: 0
+  is_nullable: 0
+
+Spam score from spamassassin
+
+=head2 is_spam
+
+  data_type: 'boolean'
+  default_value: false
+  is_nullable: 0
+
+True if this message was spam and should not be shown
+
+=cut
+
+__PACKAGE__->add_columns(
+  "id",
+  {
+    data_type         => "integer",
+    is_auto_increment => 1,
+    is_nullable       => 0,
+    sequence          => "message_id_seq",
+  },
+  "msgid",
+  { data_type => "text", default_value => "", is_nullable => 0 },
+  "from_complete",
+  { data_type => "text", default_value => "", is_nullable => 0 },
+  "to_complete",
+  { data_type => "text", default_value => "", is_nullable => 0 },
+  "subject",
+  { data_type => "text", default_value => "", is_nullable => 0 },
+  "sent_date",
+  { data_type => "timestamp with time zone", is_nullable => 1 },
+  "refs",
+  { data_type => "text", default_value => "", is_nullable => 0 },
+  "spam_score",
+  { data_type => "double precision", default_value => 0, is_nullable => 0 },
+  "is_spam",
+  { data_type => "boolean", default_value => \"false", is_nullable => 0 },
+);
+
+=head1 PRIMARY KEY
+
+=over 4
+
+=item * L</id>
+
+=back
+
+=cut
+
+__PACKAGE__->set_primary_key("id");
+
+=head1 UNIQUE CONSTRAINTS
+
+=head2 C<message_msgid_from_complete_to_complete_subject_idx>
+
+=over 4
+
+=item * L</msgid>
+
+=item * L</from_complete>
+
+=item * L</to_complete>
+
+=item * L</subject>
+
+=back
+
+=cut
+
+__PACKAGE__->add_unique_constraint(
+  "message_msgid_from_complete_to_complete_subject_idx",
+  ["msgid", "from_complete", "to_complete", "subject"],
+);
+
+=head1 RELATIONS
+
+=head2 bug_messages
+
+Type: has_many
+
+Related object: L<Debbugs::DB::Result::BugMessage>
+
+=cut
+
+__PACKAGE__->has_many(
+  "bug_messages",
+  "Debbugs::DB::Result::BugMessage",
+  { "foreign.message" => "self.id" },
+  { cascade_copy => 0, cascade_delete => 0 },
+);
+
+=head2 message_correspondents
+
+Type: has_many
+
+Related object: L<Debbugs::DB::Result::MessageCorrespondent>
+
+=cut
+
+__PACKAGE__->has_many(
+  "message_correspondents",
+  "Debbugs::DB::Result::MessageCorrespondent",
+  { "foreign.message" => "self.id" },
+  { cascade_copy => 0, cascade_delete => 0 },
+);
+
+=head2 message_refs_messages
+
+Type: has_many
+
+Related object: L<Debbugs::DB::Result::MessageRef>
+
+=cut
+
+__PACKAGE__->has_many(
+  "message_refs_messages",
+  "Debbugs::DB::Result::MessageRef",
+  { "foreign.message" => "self.id" },
+  { cascade_copy => 0, cascade_delete => 0 },
+);
+
+=head2 message_refs_refs
+
+Type: has_many
+
+Related object: L<Debbugs::DB::Result::MessageRef>
+
+=cut
+
+__PACKAGE__->has_many(
+  "message_refs_refs",
+  "Debbugs::DB::Result::MessageRef",
+  { "foreign.refs" => "self.id" },
+  { cascade_copy => 0, cascade_delete => 0 },
+);
+
+
+# Created by DBIx::Class::Schema::Loader v0.07046 @ 2017-03-07 19:03:32
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:n8U0vD9R8M5wFoeoLlIWeQ
+
+__PACKAGE__->many_to_many(bugs => 'bug_messages','bug');
+__PACKAGE__->many_to_many(correspondents => 'message_correspondents','correspondent');
+__PACKAGE__->many_to_many(references => 'message_refs_message','message');
+__PACKAGE__->many_to_many(referenced_by => 'message_refs_refs','message');
+
+
+sub sqlt_deploy_hook {
+    my ($self, $sqlt_table) = @_;
+    for my $idx (qw(msgid subject)) {
+       $sqlt_table->add_index(name => 'message_'.$idx.'_idx',
+                              fields => [$idx]);
+    }
+}
+
+1;
diff --git a/Debbugs/DB/Result/MessageCorrespondent.pm b/Debbugs/DB/Result/MessageCorrespondent.pm
new file mode 100644 (file)
index 0000000..ddc79d1
--- /dev/null
@@ -0,0 +1,150 @@
+use utf8;
+package Debbugs::DB::Result::MessageCorrespondent;
+
+# Created by DBIx::Class::Schema::Loader
+# DO NOT MODIFY THE FIRST PART OF THIS FILE
+
+=head1 NAME
+
+Debbugs::DB::Result::MessageCorrespondent - Linkage between correspondent and message
+
+=cut
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::Core';
+
+=head1 COMPONENTS LOADED
+
+=over 4
+
+=item * L<DBIx::Class::InflateColumn::DateTime>
+
+=item * L<DBIx::Class::TimeStamp>
+
+=back
+
+=cut
+
+__PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp");
+
+=head1 TABLE: C<message_correspondent>
+
+=cut
+
+__PACKAGE__->table("message_correspondent");
+
+=head1 ACCESSORS
+
+=head2 message
+
+  data_type: 'integer'
+  is_foreign_key: 1
+  is_nullable: 0
+
+Message id (matches message)
+
+=head2 correspondent
+
+  data_type: 'integer'
+  is_foreign_key: 1
+  is_nullable: 0
+
+Correspondent (matches correspondent)
+
+=head2 correspondent_type
+
+  data_type: 'enum'
+  default_value: 'to'
+  extra: {custom_type_name => "message_correspondent_type",list => ["to","from","envfrom","cc","recv"]}
+  is_nullable: 0
+
+Type of correspondent (to, from, envfrom, cc, etc.)
+
+=cut
+
+__PACKAGE__->add_columns(
+  "message",
+  { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
+  "correspondent",
+  { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
+  "correspondent_type",
+  {
+    data_type => "enum",
+    default_value => "to",
+    extra => {
+      custom_type_name => "message_correspondent_type",
+      list => ["to", "from", "envfrom", "cc", "recv"],
+    },
+    is_nullable => 0,
+  },
+);
+
+=head1 UNIQUE CONSTRAINTS
+
+=head2 C<message_correspondent_message_correspondent_correspondent_t_idx>
+
+=over 4
+
+=item * L</message>
+
+=item * L</correspondent>
+
+=item * L</correspondent_type>
+
+=back
+
+=cut
+
+__PACKAGE__->add_unique_constraint(
+  "message_correspondent_message_correspondent_correspondent_t_idx",
+  ["message", "correspondent", "correspondent_type"],
+);
+
+=head1 RELATIONS
+
+=head2 correspondent
+
+Type: belongs_to
+
+Related object: L<Debbugs::DB::Result::Correspondent>
+
+=cut
+
+__PACKAGE__->belongs_to(
+  "correspondent",
+  "Debbugs::DB::Result::Correspondent",
+  { id => "correspondent" },
+  { is_deferrable => 0, on_delete => "CASCADE", on_update => "CASCADE" },
+);
+
+=head2 message
+
+Type: belongs_to
+
+Related object: L<Debbugs::DB::Result::Message>
+
+=cut
+
+__PACKAGE__->belongs_to(
+  "message",
+  "Debbugs::DB::Result::Message",
+  { id => "message" },
+  { is_deferrable => 0, on_delete => "CASCADE", on_update => "CASCADE" },
+);
+
+
+# Created by DBIx::Class::Schema::Loader v0.07046 @ 2017-03-07 19:03:32
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:kIhya7skj4ZNM3DkC+gAPw
+
+
+sub sqlt_deploy_hook {
+    my ($self, $sqlt_table) = @_;
+    for my $idx (qw(correspondent message)) {
+       $sqlt_table->add_index(name => 'message_correspondent_idx'.$idx,
+                              fields => [$idx]);
+    }
+}
+
+1;
diff --git a/Debbugs/DB/Result/MessageRef.pm b/Debbugs/DB/Result/MessageRef.pm
new file mode 100644 (file)
index 0000000..98e2a2d
--- /dev/null
@@ -0,0 +1,145 @@
+use utf8;
+package Debbugs::DB::Result::MessageRef;
+
+# Created by DBIx::Class::Schema::Loader
+# DO NOT MODIFY THE FIRST PART OF THIS FILE
+
+=head1 NAME
+
+Debbugs::DB::Result::MessageRef - Message references
+
+=cut
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::Core';
+
+=head1 COMPONENTS LOADED
+
+=over 4
+
+=item * L<DBIx::Class::InflateColumn::DateTime>
+
+=item * L<DBIx::Class::TimeStamp>
+
+=back
+
+=cut
+
+__PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp");
+
+=head1 TABLE: C<message_refs>
+
+=cut
+
+__PACKAGE__->table("message_refs");
+
+=head1 ACCESSORS
+
+=head2 message
+
+  data_type: 'integer'
+  is_foreign_key: 1
+  is_nullable: 0
+
+Message id (matches message)
+
+=head2 refs
+
+  data_type: 'integer'
+  is_foreign_key: 1
+  is_nullable: 0
+
+Reference id (matches message)
+
+=head2 inferred
+
+  data_type: 'boolean'
+  default_value: false
+  is_nullable: 1
+
+TRUE if this message reference was reconstructed; primarily of use for messages which lack In-Reply-To: or References: headers
+
+=head2 primary_ref
+
+  data_type: 'boolean'
+  default_value: false
+  is_nullable: 1
+
+TRUE if this message->ref came from In-Reply-To: or similar.
+
+=cut
+
+__PACKAGE__->add_columns(
+  "message",
+  { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
+  "refs",
+  { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
+  "inferred",
+  { data_type => "boolean", default_value => \"false", is_nullable => 1 },
+  "primary_ref",
+  { data_type => "boolean", default_value => \"false", is_nullable => 1 },
+);
+
+=head1 UNIQUE CONSTRAINTS
+
+=head2 C<message_refs_message_refs_idx>
+
+=over 4
+
+=item * L</message>
+
+=item * L</refs>
+
+=back
+
+=cut
+
+__PACKAGE__->add_unique_constraint("message_refs_message_refs_idx", ["message", "refs"]);
+
+=head1 RELATIONS
+
+=head2 message
+
+Type: belongs_to
+
+Related object: L<Debbugs::DB::Result::Message>
+
+=cut
+
+__PACKAGE__->belongs_to(
+  "message",
+  "Debbugs::DB::Result::Message",
+  { id => "message" },
+  { is_deferrable => 0, on_delete => "CASCADE", on_update => "CASCADE" },
+);
+
+=head2 ref
+
+Type: belongs_to
+
+Related object: L<Debbugs::DB::Result::Message>
+
+=cut
+
+__PACKAGE__->belongs_to(
+  "ref",
+  "Debbugs::DB::Result::Message",
+  { id => "refs" },
+  { is_deferrable => 0, on_delete => "CASCADE", on_update => "CASCADE" },
+);
+
+
+# Created by DBIx::Class::Schema::Loader v0.07046 @ 2017-03-04 10:59:03
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:0YaAP/sB5N2Xr2rAFNK1lg
+
+sub sqlt_deploy_hook {
+    my ($self, $sqlt_table) = @_;
+    for my $idx (qw(refs message)) {
+       $sqlt_table->add_index(name => 'message_refs_idx_'.$idx,
+                              fields => [$idx]);
+    }
+}
+
+1;
diff --git a/Debbugs/DB/Result/Severity.pm b/Debbugs/DB/Result/Severity.pm
new file mode 100644 (file)
index 0000000..edea9a9
--- /dev/null
@@ -0,0 +1,154 @@
+use utf8;
+package Debbugs::DB::Result::Severity;
+
+# Created by DBIx::Class::Schema::Loader
+# DO NOT MODIFY THE FIRST PART OF THIS FILE
+
+=head1 NAME
+
+Debbugs::DB::Result::Severity - Bug severity
+
+=cut
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::Core';
+
+=head1 COMPONENTS LOADED
+
+=over 4
+
+=item * L<DBIx::Class::InflateColumn::DateTime>
+
+=item * L<DBIx::Class::TimeStamp>
+
+=back
+
+=cut
+
+__PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp");
+
+=head1 TABLE: C<severity>
+
+=cut
+
+__PACKAGE__->table("severity");
+
+=head1 ACCESSORS
+
+=head2 id
+
+  data_type: 'integer'
+  is_auto_increment: 1
+  is_nullable: 0
+  sequence: 'severity_id_seq'
+
+Severity id
+
+=head2 severity
+
+  data_type: 'text'
+  is_nullable: 0
+
+Severity name
+
+=head2 ordering
+
+  data_type: 'integer'
+  default_value: 5
+  is_nullable: 0
+
+Severity ordering (more severe severities have higher numbers)
+
+=head2 strong
+
+  data_type: 'boolean'
+  default_value: false
+  is_nullable: 1
+
+True if severity is a strong severity
+
+=head2 obsolete
+
+  data_type: 'boolean'
+  default_value: false
+  is_nullable: 1
+
+Whether a severity level is obsolete (should not be set on new bugs)
+
+=cut
+
+__PACKAGE__->add_columns(
+  "id",
+  {
+    data_type         => "integer",
+    is_auto_increment => 1,
+    is_nullable       => 0,
+    sequence          => "severity_id_seq",
+  },
+  "severity",
+  { data_type => "text", is_nullable => 0 },
+  "ordering",
+  { data_type => "integer", default_value => 5, is_nullable => 0 },
+  "strong",
+  { data_type => "boolean", default_value => \"false", is_nullable => 1 },
+  "obsolete",
+  { data_type => "boolean", default_value => \"false", is_nullable => 1 },
+);
+
+=head1 PRIMARY KEY
+
+=over 4
+
+=item * L</id>
+
+=back
+
+=cut
+
+__PACKAGE__->set_primary_key("id");
+
+=head1 UNIQUE CONSTRAINTS
+
+=head2 C<severity_severity_idx>
+
+=over 4
+
+=item * L</severity>
+
+=back
+
+=cut
+
+__PACKAGE__->add_unique_constraint("severity_severity_idx", ["severity"]);
+
+=head1 RELATIONS
+
+=head2 bugs
+
+Type: has_many
+
+Related object: L<Debbugs::DB::Result::Bug>
+
+=cut
+
+__PACKAGE__->has_many(
+  "bugs",
+  "Debbugs::DB::Result::Bug",
+  { "foreign.severity" => "self.id" },
+  { cascade_copy => 0, cascade_delete => 0 },
+);
+
+
+# Created by DBIx::Class::Schema::Loader v0.07042 @ 2014-11-30 21:56:51
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:nI4ZqWa6IW7LgWuG7S1Gog
+
+sub sqlt_deploy_hook {
+    my ($self, $sqlt_table) = @_;
+    $sqlt_table->add_index(name => 'severity_ordering_idx',
+                          fields => [qw(ordering)],
+                         );
+}
+
+1;
diff --git a/Debbugs/DB/Result/SrcAssociation.pm b/Debbugs/DB/Result/SrcAssociation.pm
new file mode 100644 (file)
index 0000000..01ac4bd
--- /dev/null
@@ -0,0 +1,179 @@
+use utf8;
+package Debbugs::DB::Result::SrcAssociation;
+
+# Created by DBIx::Class::Schema::Loader
+# DO NOT MODIFY THE FIRST PART OF THIS FILE
+
+=head1 NAME
+
+Debbugs::DB::Result::SrcAssociation - Source <-> suite associations
+
+=cut
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::Core';
+
+=head1 COMPONENTS LOADED
+
+=over 4
+
+=item * L<DBIx::Class::InflateColumn::DateTime>
+
+=item * L<DBIx::Class::TimeStamp>
+
+=back
+
+=cut
+
+__PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp");
+
+=head1 TABLE: C<src_associations>
+
+=cut
+
+__PACKAGE__->table("src_associations");
+
+=head1 ACCESSORS
+
+=head2 id
+
+  data_type: 'integer'
+  is_auto_increment: 1
+  is_nullable: 0
+  sequence: 'src_associations_id_seq'
+
+Source <-> suite association id
+
+=head2 suite
+
+  data_type: 'integer'
+  is_foreign_key: 1
+  is_nullable: 0
+
+Suite id (matches suite)
+
+=head2 source
+
+  data_type: 'integer'
+  is_foreign_key: 1
+  is_nullable: 0
+
+Source version id (matches src_ver)
+
+=head2 created
+
+  data_type: 'timestamp with time zone'
+  default_value: current_timestamp
+  is_nullable: 0
+  original: {default_value => \"now()"}
+
+Time this source package entered this suite
+
+=head2 modified
+
+  data_type: 'timestamp with time zone'
+  default_value: current_timestamp
+  is_nullable: 0
+  original: {default_value => \"now()"}
+
+Time this entry was modified
+
+=cut
+
+__PACKAGE__->add_columns(
+  "id",
+  {
+    data_type         => "integer",
+    is_auto_increment => 1,
+    is_nullable       => 0,
+    sequence          => "src_associations_id_seq",
+  },
+  "suite",
+  { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
+  "source",
+  { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
+  "created",
+  {
+    data_type     => "timestamp with time zone",
+    default_value => \"current_timestamp",
+    is_nullable   => 0,
+    original      => { default_value => \"now()" },
+  },
+  "modified",
+  {
+    data_type     => "timestamp with time zone",
+    default_value => \"current_timestamp",
+    is_nullable   => 0,
+    original      => { default_value => \"now()" },
+  },
+);
+
+=head1 PRIMARY KEY
+
+=over 4
+
+=item * L</id>
+
+=back
+
+=cut
+
+__PACKAGE__->set_primary_key("id");
+
+=head1 UNIQUE CONSTRAINTS
+
+=head2 C<src_associations_source_suite>
+
+=over 4
+
+=item * L</source>
+
+=item * L</suite>
+
+=back
+
+=cut
+
+__PACKAGE__->add_unique_constraint("src_associations_source_suite", ["source", "suite"]);
+
+=head1 RELATIONS
+
+=head2 source
+
+Type: belongs_to
+
+Related object: L<Debbugs::DB::Result::SrcVer>
+
+=cut
+
+__PACKAGE__->belongs_to(
+  "source",
+  "Debbugs::DB::Result::SrcVer",
+  { id => "source" },
+  { is_deferrable => 0, on_delete => "CASCADE", on_update => "CASCADE" },
+);
+
+=head2 suite
+
+Type: belongs_to
+
+Related object: L<Debbugs::DB::Result::Suite>
+
+=cut
+
+__PACKAGE__->belongs_to(
+  "suite",
+  "Debbugs::DB::Result::Suite",
+  { id => "suite" },
+  { is_deferrable => 0, on_delete => "CASCADE", on_update => "CASCADE" },
+);
+
+
+# Created by DBIx::Class::Schema::Loader v0.07045 @ 2016-11-24 08:52:49
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:B3gOeYD0JxOUtV92mBocZQ
+
+
+# You can replace this text with custom code or comments, and it will be preserved on regeneration
+1;
diff --git a/Debbugs/DB/Result/SrcPkg.pm b/Debbugs/DB/Result/SrcPkg.pm
new file mode 100644 (file)
index 0000000..fc6b2e1
--- /dev/null
@@ -0,0 +1,272 @@
+use utf8;
+package Debbugs::DB::Result::SrcPkg;
+
+# Created by DBIx::Class::Schema::Loader
+# DO NOT MODIFY THE FIRST PART OF THIS FILE
+
+=head1 NAME
+
+Debbugs::DB::Result::SrcPkg - Source packages
+
+=cut
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::Core';
+
+=head1 COMPONENTS LOADED
+
+=over 4
+
+=item * L<DBIx::Class::InflateColumn::DateTime>
+
+=item * L<DBIx::Class::TimeStamp>
+
+=back
+
+=cut
+
+__PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp");
+
+=head1 TABLE: C<src_pkg>
+
+=cut
+
+__PACKAGE__->table("src_pkg");
+
+=head1 ACCESSORS
+
+=head2 id
+
+  data_type: 'integer'
+  is_auto_increment: 1
+  is_nullable: 0
+  sequence: 'src_pkg_id_seq'
+
+Source package id
+
+=head2 pkg
+
+  data_type: 'text'
+  is_nullable: 0
+
+Source package name
+
+=head2 pseduopkg
+
+  data_type: 'boolean'
+  default_value: false
+  is_nullable: 0
+
+=head2 alias_of
+
+  data_type: 'integer'
+  is_foreign_key: 1
+  is_nullable: 1
+
+Source package id which this source package is an alias of
+
+=head2 creation
+
+  data_type: 'timestamp with time zone'
+  default_value: current_timestamp
+  is_nullable: 0
+  original: {default_value => \"now()"}
+
+=head2 disabled
+
+  data_type: 'timestamp with time zone'
+  default_value: infinity
+  is_nullable: 0
+
+=head2 last_modified
+
+  data_type: 'timestamp with time zone'
+  default_value: current_timestamp
+  is_nullable: 0
+  original: {default_value => \"now()"}
+
+=head2 obsolete
+
+  data_type: 'boolean'
+  default_value: false
+  is_nullable: 0
+
+=cut
+
+__PACKAGE__->add_columns(
+  "id",
+  {
+    data_type         => "integer",
+    is_auto_increment => 1,
+    is_nullable       => 0,
+    sequence          => "src_pkg_id_seq",
+  },
+  "pkg",
+  { data_type => "text", is_nullable => 0 },
+  "pseduopkg",
+  { data_type => "boolean", default_value => \"false", is_nullable => 0 },
+  "alias_of",
+  { data_type => "integer", is_foreign_key => 1, is_nullable => 1 },
+  "creation",
+  {
+    data_type     => "timestamp with time zone",
+    default_value => \"current_timestamp",
+    is_nullable   => 0,
+    original      => { default_value => \"now()" },
+  },
+  "disabled",
+  {
+    data_type     => "timestamp with time zone",
+    default_value => "infinity",
+    is_nullable   => 0,
+  },
+  "last_modified",
+  {
+    data_type     => "timestamp with time zone",
+    default_value => \"current_timestamp",
+    is_nullable   => 0,
+    original      => { default_value => \"now()" },
+  },
+  "obsolete",
+  { data_type => "boolean", default_value => \"false", is_nullable => 0 },
+);
+
+=head1 PRIMARY KEY
+
+=over 4
+
+=item * L</id>
+
+=back
+
+=cut
+
+__PACKAGE__->set_primary_key("id");
+
+=head1 UNIQUE CONSTRAINTS
+
+=head2 C<src_pkg_pkg_disabled>
+
+=over 4
+
+=item * L</pkg>
+
+=item * L</disabled>
+
+=back
+
+=cut
+
+__PACKAGE__->add_unique_constraint("src_pkg_pkg_disabled", ["pkg", "disabled"]);
+
+=head1 RELATIONS
+
+=head2 alias_of
+
+Type: belongs_to
+
+Related object: L<Debbugs::DB::Result::SrcPkg>
+
+=cut
+
+__PACKAGE__->belongs_to(
+  "alias_of",
+  "Debbugs::DB::Result::SrcPkg",
+  { id => "alias_of" },
+  {
+    is_deferrable => 0,
+    join_type     => "LEFT",
+    on_delete     => "CASCADE",
+    on_update     => "CASCADE",
+  },
+);
+
+=head2 bug_affects_srcpackages
+
+Type: has_many
+
+Related object: L<Debbugs::DB::Result::BugAffectsSrcpackage>
+
+=cut
+
+__PACKAGE__->has_many(
+  "bug_affects_srcpackages",
+  "Debbugs::DB::Result::BugAffectsSrcpackage",
+  { "foreign.src_pkg" => "self.id" },
+  { cascade_copy => 0, cascade_delete => 0 },
+);
+
+=head2 bug_srcpackages
+
+Type: has_many
+
+Related object: L<Debbugs::DB::Result::BugSrcpackage>
+
+=cut
+
+__PACKAGE__->has_many(
+  "bug_srcpackages",
+  "Debbugs::DB::Result::BugSrcpackage",
+  { "foreign.src_pkg" => "self.id" },
+  { cascade_copy => 0, cascade_delete => 0 },
+);
+
+=head2 bug_vers
+
+Type: has_many
+
+Related object: L<Debbugs::DB::Result::BugVer>
+
+=cut
+
+__PACKAGE__->has_many(
+  "bug_vers",
+  "Debbugs::DB::Result::BugVer",
+  { "foreign.src_pkg" => "self.id" },
+  { cascade_copy => 0, cascade_delete => 0 },
+);
+
+=head2 src_pkgs
+
+Type: has_many
+
+Related object: L<Debbugs::DB::Result::SrcPkg>
+
+=cut
+
+__PACKAGE__->has_many(
+  "src_pkgs",
+  "Debbugs::DB::Result::SrcPkg",
+  { "foreign.alias_of" => "self.id" },
+  { cascade_copy => 0, cascade_delete => 0 },
+);
+
+=head2 src_vers
+
+Type: has_many
+
+Related object: L<Debbugs::DB::Result::SrcVer>
+
+=cut
+
+__PACKAGE__->has_many(
+  "src_vers",
+  "Debbugs::DB::Result::SrcVer",
+  { "foreign.src_pkg" => "self.id" },
+  { cascade_copy => 0, cascade_delete => 0 },
+);
+
+
+# Created by DBIx::Class::Schema::Loader v0.07046 @ 2017-03-04 10:59:03
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:j8LGu4eUfNUNxM/jkHUG2A
+
+
+sub sqlt_deploy_hook {
+    my ($self, $sqlt_table) = @_;
+    $sqlt_table->add_index(name => 'src_pkg_pkg',
+                          fields => 'pkg',
+                         );
+}
+1;
diff --git a/Debbugs/DB/Result/SrcVer.pm b/Debbugs/DB/Result/SrcVer.pm
new file mode 100644 (file)
index 0000000..79c39f1
--- /dev/null
@@ -0,0 +1,267 @@
+use utf8;
+package Debbugs::DB::Result::SrcVer;
+
+# Created by DBIx::Class::Schema::Loader
+# DO NOT MODIFY THE FIRST PART OF THIS FILE
+
+=head1 NAME
+
+Debbugs::DB::Result::SrcVer - Source Package versions
+
+=cut
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::Core';
+
+=head1 COMPONENTS LOADED
+
+=over 4
+
+=item * L<DBIx::Class::InflateColumn::DateTime>
+
+=item * L<DBIx::Class::TimeStamp>
+
+=back
+
+=cut
+
+__PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp");
+
+=head1 TABLE: C<src_ver>
+
+=cut
+
+__PACKAGE__->table("src_ver");
+
+=head1 ACCESSORS
+
+=head2 id
+
+  data_type: 'integer'
+  is_auto_increment: 1
+  is_nullable: 0
+  sequence: 'src_ver_id_seq'
+
+Source package version id
+
+=head2 src_pkg
+
+  data_type: 'integer'
+  is_foreign_key: 1
+  is_nullable: 0
+
+Source package id (matches src_pkg table)
+
+=head2 ver
+
+  data_type: 'debversion'
+  is_nullable: 0
+
+Version of the source package
+
+=head2 maintainer
+
+  data_type: 'integer'
+  is_foreign_key: 1
+  is_nullable: 1
+
+Maintainer id (matches maintainer table)
+
+=head2 upload_date
+
+  data_type: 'timestamp with time zone'
+  default_value: current_timestamp
+  is_nullable: 0
+  original: {default_value => \"now()"}
+
+Date this version of the source package was uploaded
+
+=head2 based_on
+
+  data_type: 'integer'
+  is_foreign_key: 1
+  is_nullable: 1
+
+Source package version this version is based on
+
+=cut
+
+__PACKAGE__->add_columns(
+  "id",
+  {
+    data_type         => "integer",
+    is_auto_increment => 1,
+    is_nullable       => 0,
+    sequence          => "src_ver_id_seq",
+  },
+  "src_pkg",
+  { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
+  "ver",
+  { data_type => "debversion", is_nullable => 0 },
+  "maintainer",
+  { data_type => "integer", is_foreign_key => 1, is_nullable => 1 },
+  "upload_date",
+  {
+    data_type     => "timestamp with time zone",
+    default_value => \"current_timestamp",
+    is_nullable   => 0,
+    original      => { default_value => \"now()" },
+  },
+  "based_on",
+  { data_type => "integer", is_foreign_key => 1, is_nullable => 1 },
+);
+
+=head1 PRIMARY KEY
+
+=over 4
+
+=item * L</id>
+
+=back
+
+=cut
+
+__PACKAGE__->set_primary_key("id");
+
+=head1 UNIQUE CONSTRAINTS
+
+=head2 C<src_ver_src_pkg_id_ver>
+
+=over 4
+
+=item * L</src_pkg>
+
+=item * L</ver>
+
+=back
+
+=cut
+
+__PACKAGE__->add_unique_constraint("src_ver_src_pkg_id_ver", ["src_pkg", "ver"]);
+
+=head1 RELATIONS
+
+=head2 based_on
+
+Type: belongs_to
+
+Related object: L<Debbugs::DB::Result::SrcVer>
+
+=cut
+
+__PACKAGE__->belongs_to(
+  "based_on",
+  "Debbugs::DB::Result::SrcVer",
+  { id => "based_on" },
+  {
+    is_deferrable => 0,
+    join_type     => "LEFT",
+    on_delete     => "CASCADE",
+    on_update     => "CASCADE",
+  },
+);
+
+=head2 bin_vers
+
+Type: has_many
+
+Related object: L<Debbugs::DB::Result::BinVer>
+
+=cut
+
+__PACKAGE__->has_many(
+  "bin_vers",
+  "Debbugs::DB::Result::BinVer",
+  { "foreign.src_ver" => "self.id" },
+  { cascade_copy => 0, cascade_delete => 0 },
+);
+
+=head2 bug_vers
+
+Type: has_many
+
+Related object: L<Debbugs::DB::Result::BugVer>
+
+=cut
+
+__PACKAGE__->has_many(
+  "bug_vers",
+  "Debbugs::DB::Result::BugVer",
+  { "foreign.src_ver" => "self.id" },
+  { cascade_copy => 0, cascade_delete => 0 },
+);
+
+=head2 maintainer
+
+Type: belongs_to
+
+Related object: L<Debbugs::DB::Result::Maintainer>
+
+=cut
+
+__PACKAGE__->belongs_to(
+  "maintainer",
+  "Debbugs::DB::Result::Maintainer",
+  { id => "maintainer" },
+  {
+    is_deferrable => 0,
+    join_type     => "LEFT",
+    on_delete     => "SET NULL",
+    on_update     => "CASCADE",
+  },
+);
+
+=head2 src_associations
+
+Type: has_many
+
+Related object: L<Debbugs::DB::Result::SrcAssociation>
+
+=cut
+
+__PACKAGE__->has_many(
+  "src_associations",
+  "Debbugs::DB::Result::SrcAssociation",
+  { "foreign.source" => "self.id" },
+  { cascade_copy => 0, cascade_delete => 0 },
+);
+
+=head2 src_pkg
+
+Type: belongs_to
+
+Related object: L<Debbugs::DB::Result::SrcPkg>
+
+=cut
+
+__PACKAGE__->belongs_to(
+  "src_pkg",
+  "Debbugs::DB::Result::SrcPkg",
+  { id => "src_pkg" },
+  { is_deferrable => 0, on_delete => "CASCADE", on_update => "CASCADE" },
+);
+
+=head2 src_vers
+
+Type: has_many
+
+Related object: L<Debbugs::DB::Result::SrcVer>
+
+=cut
+
+__PACKAGE__->has_many(
+  "src_vers",
+  "Debbugs::DB::Result::SrcVer",
+  { "foreign.based_on" => "self.id" },
+  { cascade_copy => 0, cascade_delete => 0 },
+);
+
+
+# Created by DBIx::Class::Schema::Loader v0.07042 @ 2014-11-30 21:56:51
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:gY5LidUaQeuJ5AnN06CfKQ
+
+
+# You can replace this text with custom code or comments, and it will be preserved on regeneration
+1;
diff --git a/Debbugs/DB/Result/Suite.pm b/Debbugs/DB/Result/Suite.pm
new file mode 100644 (file)
index 0000000..37c875c
--- /dev/null
@@ -0,0 +1,201 @@
+use utf8;
+package Debbugs::DB::Result::Suite;
+
+# Created by DBIx::Class::Schema::Loader
+# DO NOT MODIFY THE FIRST PART OF THIS FILE
+
+=head1 NAME
+
+Debbugs::DB::Result::Suite - Debian Release Suite (stable, testing, etc.)
+
+=cut
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::Core';
+
+=head1 COMPONENTS LOADED
+
+=over 4
+
+=item * L<DBIx::Class::InflateColumn::DateTime>
+
+=item * L<DBIx::Class::TimeStamp>
+
+=back
+
+=cut
+
+__PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp");
+
+=head1 TABLE: C<suite>
+
+=cut
+
+__PACKAGE__->table("suite");
+
+=head1 ACCESSORS
+
+=head2 id
+
+  data_type: 'integer'
+  is_auto_increment: 1
+  is_nullable: 0
+  sequence: 'suite_id_seq'
+
+Suite id
+
+=head2 codename
+
+  data_type: 'text'
+  is_nullable: 0
+
+Suite codename (sid, squeeze, etc.)
+
+=head2 suite_name
+
+  data_type: 'text'
+  is_nullable: 1
+
+Suite name (testing, stable, etc.)
+
+=head2 version
+
+  data_type: 'text'
+  is_nullable: 1
+
+Suite version; NULL if there is no appropriate version
+
+=head2 active
+
+  data_type: 'boolean'
+  default_value: true
+  is_nullable: 1
+
+TRUE if the suite is still accepting uploads
+
+=cut
+
+__PACKAGE__->add_columns(
+  "id",
+  {
+    data_type         => "integer",
+    is_auto_increment => 1,
+    is_nullable       => 0,
+    sequence          => "suite_id_seq",
+  },
+  "codename",
+  { data_type => "text", is_nullable => 0 },
+  "suite_name",
+  { data_type => "text", is_nullable => 1 },
+  "version",
+  { data_type => "text", is_nullable => 1 },
+  "active",
+  { data_type => "boolean", default_value => \"true", is_nullable => 1 },
+);
+
+=head1 PRIMARY KEY
+
+=over 4
+
+=item * L</id>
+
+=back
+
+=cut
+
+__PACKAGE__->set_primary_key("id");
+
+=head1 UNIQUE CONSTRAINTS
+
+=head2 C<suite_idx_codename>
+
+=over 4
+
+=item * L</codename>
+
+=back
+
+=cut
+
+__PACKAGE__->add_unique_constraint("suite_idx_codename", ["codename"]);
+
+=head2 C<suite_idx_version>
+
+=over 4
+
+=item * L</version>
+
+=back
+
+=cut
+
+__PACKAGE__->add_unique_constraint("suite_idx_version", ["version"]);
+
+=head2 C<suite_suite_name_key>
+
+=over 4
+
+=item * L</suite_name>
+
+=back
+
+=cut
+
+__PACKAGE__->add_unique_constraint("suite_suite_name_key", ["suite_name"]);
+
+=head1 RELATIONS
+
+=head2 bin_associations
+
+Type: has_many
+
+Related object: L<Debbugs::DB::Result::BinAssociation>
+
+=cut
+
+__PACKAGE__->has_many(
+  "bin_associations",
+  "Debbugs::DB::Result::BinAssociation",
+  { "foreign.suite" => "self.id" },
+  { cascade_copy => 0, cascade_delete => 0 },
+);
+
+=head2 bug_status_caches
+
+Type: has_many
+
+Related object: L<Debbugs::DB::Result::BugStatusCache>
+
+=cut
+
+__PACKAGE__->has_many(
+  "bug_status_caches",
+  "Debbugs::DB::Result::BugStatusCache",
+  { "foreign.suite" => "self.id" },
+  { cascade_copy => 0, cascade_delete => 0 },
+);
+
+=head2 src_associations
+
+Type: has_many
+
+Related object: L<Debbugs::DB::Result::SrcAssociation>
+
+=cut
+
+__PACKAGE__->has_many(
+  "src_associations",
+  "Debbugs::DB::Result::SrcAssociation",
+  { "foreign.suite" => "self.id" },
+  { cascade_copy => 0, cascade_delete => 0 },
+);
+
+
+# Created by DBIx::Class::Schema::Loader v0.07045 @ 2016-11-24 08:52:49
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:nXoQCYZhM9cFgC1x+RY9rA
+
+
+# You can replace this text with custom code or comments, and it will be preserved on regeneration
+1;
diff --git a/Debbugs/DB/Result/Tag.pm b/Debbugs/DB/Result/Tag.pm
new file mode 100644 (file)
index 0000000..c8d5397
--- /dev/null
@@ -0,0 +1,129 @@
+use utf8;
+package Debbugs::DB::Result::Tag;
+
+# Created by DBIx::Class::Schema::Loader
+# DO NOT MODIFY THE FIRST PART OF THIS FILE
+
+=head1 NAME
+
+Debbugs::DB::Result::Tag - Bug tags
+
+=cut
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::Core';
+
+=head1 COMPONENTS LOADED
+
+=over 4
+
+=item * L<DBIx::Class::InflateColumn::DateTime>
+
+=item * L<DBIx::Class::TimeStamp>
+
+=back
+
+=cut
+
+__PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp");
+
+=head1 TABLE: C<tag>
+
+=cut
+
+__PACKAGE__->table("tag");
+
+=head1 ACCESSORS
+
+=head2 id
+
+  data_type: 'integer'
+  is_auto_increment: 1
+  is_nullable: 0
+  sequence: 'tag_id_seq'
+
+Tag id
+
+=head2 tag
+
+  data_type: 'text'
+  is_nullable: 0
+
+Tag name
+
+=head2 obsolete
+
+  data_type: 'boolean'
+  default_value: false
+  is_nullable: 1
+
+Whether a tag is obsolete (should not be set on new bugs)
+
+=cut
+
+__PACKAGE__->add_columns(
+  "id",
+  {
+    data_type         => "integer",
+    is_auto_increment => 1,
+    is_nullable       => 0,
+    sequence          => "tag_id_seq",
+  },
+  "tag",
+  { data_type => "text", is_nullable => 0 },
+  "obsolete",
+  { data_type => "boolean", default_value => \"false", is_nullable => 1 },
+);
+
+=head1 PRIMARY KEY
+
+=over 4
+
+=item * L</id>
+
+=back
+
+=cut
+
+__PACKAGE__->set_primary_key("id");
+
+=head1 UNIQUE CONSTRAINTS
+
+=head2 C<tag_tag_key>
+
+=over 4
+
+=item * L</tag>
+
+=back
+
+=cut
+
+__PACKAGE__->add_unique_constraint("tag_tag_key", ["tag"]);
+
+=head1 RELATIONS
+
+=head2 bug_tags
+
+Type: has_many
+
+Related object: L<Debbugs::DB::Result::BugTag>
+
+=cut
+
+__PACKAGE__->has_many(
+  "bug_tags",
+  "Debbugs::DB::Result::BugTag",
+  { "foreign.tag" => "self.id" },
+  { cascade_copy => 0, cascade_delete => 0 },
+);
+
+
+# Created by DBIx::Class::Schema::Loader v0.07042 @ 2014-11-30 21:56:51
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:HH2aKSj4xl+co6qffSdrrQ
+
+
+# You can replace this text with custom code or comments, and it will be preserved on regeneration
+1;
diff --git a/Debbugs/DB/Result/UserTag.pm b/Debbugs/DB/Result/UserTag.pm
new file mode 100644 (file)
index 0000000..0883a2e
--- /dev/null
@@ -0,0 +1,151 @@
+use utf8;
+package Debbugs::DB::Result::UserTag;
+
+# Created by DBIx::Class::Schema::Loader
+# DO NOT MODIFY THE FIRST PART OF THIS FILE
+
+=head1 NAME
+
+Debbugs::DB::Result::UserTag - User bug tags
+
+=cut
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::Core';
+
+=head1 COMPONENTS LOADED
+
+=over 4
+
+=item * L<DBIx::Class::InflateColumn::DateTime>
+
+=item * L<DBIx::Class::TimeStamp>
+
+=back
+
+=cut
+
+__PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp");
+
+=head1 TABLE: C<user_tag>
+
+=cut
+
+__PACKAGE__->table("user_tag");
+
+=head1 ACCESSORS
+
+=head2 id
+
+  data_type: 'integer'
+  is_auto_increment: 1
+  is_nullable: 0
+  sequence: 'user_tag_id_seq'
+
+User bug tag id
+
+=head2 tag
+
+  data_type: 'text'
+  is_nullable: 0
+
+User bug tag name
+
+=head2 correspondent
+
+  data_type: 'integer'
+  is_foreign_key: 1
+  is_nullable: 0
+
+User bug tag correspondent
+
+=cut
+
+__PACKAGE__->add_columns(
+  "id",
+  {
+    data_type         => "integer",
+    is_auto_increment => 1,
+    is_nullable       => 0,
+    sequence          => "user_tag_id_seq",
+  },
+  "tag",
+  { data_type => "text", is_nullable => 0 },
+  "correspondent",
+  { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
+);
+
+=head1 PRIMARY KEY
+
+=over 4
+
+=item * L</id>
+
+=back
+
+=cut
+
+__PACKAGE__->set_primary_key("id");
+
+=head1 UNIQUE CONSTRAINTS
+
+=head2 C<user_tag_tag_correspondent>
+
+=over 4
+
+=item * L</tag>
+
+=item * L</correspondent>
+
+=back
+
+=cut
+
+__PACKAGE__->add_unique_constraint("user_tag_tag_correspondent", ["tag", "correspondent"]);
+
+=head1 RELATIONS
+
+=head2 bug_user_tags
+
+Type: has_many
+
+Related object: L<Debbugs::DB::Result::BugUserTag>
+
+=cut
+
+__PACKAGE__->has_many(
+  "bug_user_tags",
+  "Debbugs::DB::Result::BugUserTag",
+  { "foreign.user_tag" => "self.id" },
+  { cascade_copy => 0, cascade_delete => 0 },
+);
+
+=head2 correspondent
+
+Type: belongs_to
+
+Related object: L<Debbugs::DB::Result::Correspondent>
+
+=cut
+
+__PACKAGE__->belongs_to(
+  "correspondent",
+  "Debbugs::DB::Result::Correspondent",
+  { id => "correspondent" },
+  { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" },
+);
+
+
+# Created by DBIx::Class::Schema::Loader v0.07045 @ 2016-09-24 14:51:07
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:ZPmTBeTue62dG2NdQdPrQg
+
+sub sqlt_deploy_hook {
+    my ($self, $sqlt_table) = @_;
+    $sqlt_table->add_index(name => 'user_tag_correspondent',
+                          fields => [qw(correspondent)],
+                         );
+}
+
+1;
diff --git a/Debbugs/DB/ResultSet/Arch.pm b/Debbugs/DB/ResultSet/Arch.pm
new file mode 100644 (file)
index 0000000..572ed0a
--- /dev/null
@@ -0,0 +1,55 @@
+# This module is part of debbugs, and is released
+# under the terms of the GPL version 2, or any later version. See the
+# file README and COPYING for more information.
+# Copyright 2016 by Don Armstrong <don@donarmstrong.com>.
+use utf8;
+package Debbugs::DB::ResultSet::Arch;
+
+=head1 NAME
+
+Debbugs::DB::ResultSet::Arch - Architecture result set operations
+
+=head1 SYNOPSIS
+
+
+
+=head1 DESCRIPTION
+
+
+
+=cut
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::ResultSet';
+
+# required for hash slices
+use v5.20;
+
+sub get_archs {
+    my ($self,@archs) = @_;
+    my %archs;
+    for my $a ($self->result_source->schema->resultset('Arch')->
+              search(undef,
+                    {result_class => 'DBIx::Class::ResultClass::HashRefInflator',
+                     columns => [qw[id arch]],
+                    })->all()) {
+       $archs{$a->{arch}} = $a->{id};
+    }
+    for my $a (grep {not exists $archs{$_}} @archs) {
+       $archs{$a} =
+           $self->result_source->schema->resultset('Arch')->
+           find_or_create({arch => $a},
+                         {columns => [qw[id arch]],
+                         }
+                         )->id;
+    }
+
+    return {%archs{@archs}};
+}
+
+
+1;
+
+__END__
diff --git a/Debbugs/DB/ResultSet/BinAssociation.pm b/Debbugs/DB/ResultSet/BinAssociation.pm
new file mode 100644 (file)
index 0000000..5756199
--- /dev/null
@@ -0,0 +1,48 @@
+# This module is part of debbugs, and is released
+# under the terms of the GPL version 2, or any later version. See the
+# file README and COPYING for more information.
+# Copyright 2017 by Don Armstrong <don@donarmstrong.com>.
+use utf8;
+package Debbugs::DB::ResultSet::BinAssociation;
+
+=head1 NAME
+
+Debbugs::DB::ResultSet::BinAssociation - Binary/Suite Associations
+
+=head1 SYNOPSIS
+
+
+
+=head1 DESCRIPTION
+
+
+
+=cut
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::ResultSet';
+
+use Debbugs::DB::Util qw(select_one);
+
+
+sub insert_suite_bin_ver_association {
+    my ($self,$suite_id,$bin_ver_id) = @_;
+    return $self->result_source->schema->storage->
+       dbh_do(sub {
+                  my ($s,$dbh,$s_id,$bv_id) = @_;
+                  return select_one($dbh,<<'SQL',$s_id,$bv_id);
+INSERT INTO bin_associations (suite,bin)
+   VALUES (?,?) ON CONFLICT (suite,bin) DO
+    UPDATE SET modified = NOW()
+   RETURNING id;
+SQL
+              },
+              $suite_id,$bin_ver_id
+             );
+}
+
+1;
+
+__END__
diff --git a/Debbugs/DB/ResultSet/BinPkg.pm b/Debbugs/DB/ResultSet/BinPkg.pm
new file mode 100644 (file)
index 0000000..b89cb40
--- /dev/null
@@ -0,0 +1,66 @@
+# This module is part of debbugs, and is released
+# under the terms of the GPL version 2, or any later version. See the
+# file README and COPYING for more information.
+# Copyright 2017 by Don Armstrong <don@donarmstrong.com>.
+use utf8;
+package Debbugs::DB::ResultSet::BinPkg;
+
+=head1 NAME
+
+Debbugs::DB::ResultSet::BinPkg - Source Package
+
+=head1 SYNOPSIS
+
+
+
+=head1 DESCRIPTION
+
+
+
+=cut
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::ResultSet';
+
+use Debbugs::DB::Util qw(select_one);
+
+sub bin_pkg_and_ver_in_suite {
+    my ($self,$suite) = @_;
+    $suite = $self->result_source->schema->
+       resultset('Suite')->get_suite_id($suite);
+    return
+       $self->search_rs({'bin_associations.suite' => $suite,
+                        },
+                       {join => {bin_vers => ['bin_associations','arch']},
+                        result_class => 'DBIx::Class::ResultClass::HashRefInflator',
+                        columns => [qw(me.pkg  bin_vers.ver arch.arch bin_associations.id)]
+                       },
+                       )->all;
+}
+
+
+sub get_bin_pkg_id {
+    my ($self,$pkg) = @_;
+    return $self->result_source->schema->storage->
+       dbh_do(sub {
+                  my ($s,$dbh,$bin_pkg) = @_;
+                  return select_one($dbh,<<'SQL',$bin_pkg,$bin_pkg);
+WITH ins AS (
+INSERT INTO bin_pkg (pkg)
+VALUES (?) ON CONFLICT (pkg) DO NOTHING RETURNING id
+)
+SELECT id FROM ins
+UNION ALL
+SELECT id FROM bin_pkg where pkg = ?
+LIMIT 1;
+SQL
+              },
+              $pkg
+             );
+}
+
+1;
+
+__END__
diff --git a/Debbugs/DB/ResultSet/BinVer.pm b/Debbugs/DB/ResultSet/BinVer.pm
new file mode 100644 (file)
index 0000000..fcd8b59
--- /dev/null
@@ -0,0 +1,56 @@
+# This module is part of debbugs, and is released
+# under the terms of the GPL version 2, or any later version. See the
+# file README and COPYING for more information.
+# Copyright 2017 by Don Armstrong <don@donarmstrong.com>.
+use utf8;
+package Debbugs::DB::ResultSet::BinVer;
+
+=head1 NAME
+
+Debbugs::DB::ResultSet::BinVer - Source Version association
+
+=head1 SYNOPSIS
+
+
+
+=head1 DESCRIPTION
+
+
+
+=cut
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::ResultSet';
+
+use Debbugs::DB::Util qw(select_one);
+
+
+sub get_bin_ver_id {
+    my ($self,$bin_pkg_id,$bin_ver,$arch_id,$src_ver_id) = @_;
+    return $self->result_source->schema->storage->
+       dbh_do(sub {
+                  my ($s,$dbh,$bp_id,$bv,$a_id,$sv_id) = @_;
+                  return select_one($dbh,<<'SQL',
+WITH ins AS (
+INSERT INTO bin_ver (bin_pkg,src_ver,arch,ver)
+VALUES (?,?,?,?) ON CONFLICT (bin_pkg,arch,ver) DO NOTHING RETURNING id
+)
+SELECT id FROM ins
+UNION ALL
+SELECT id FROM bin_ver WHERE bin_pkg = ? AND arch = ? AND ver = ?
+LIMIT 1;
+SQL
+                                    $bp_id,$sv_id,
+                                    $a_id,$bv,
+                                    $bp_id,$a_id,
+                                    $bv);
+              },
+              $bin_pkg_id,$bin_ver,$arch_id,$src_ver_id
+             );
+}
+
+1;
+
+__END__
diff --git a/Debbugs/DB/ResultSet/Bug.pm b/Debbugs/DB/ResultSet/Bug.pm
new file mode 100644 (file)
index 0000000..503fe7e
--- /dev/null
@@ -0,0 +1,93 @@
+# This module is part of debbugs, and is released
+# under the terms of the GPL version 2, or any later version. See the
+# file README and COPYING for more information.
+# Copyright 2017 by Don Armstrong <don@donarmstrong.com>.
+use utf8;
+package Debbugs::DB::ResultSet::Bug;
+
+=head1 NAME
+
+Debbugs::DB::ResultSet::Bug - Bug result set operations
+
+=head1 SYNOPSIS
+
+
+
+=head1 DESCRIPTION
+
+
+
+=cut
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::ResultSet';
+__PACKAGE__->load_components('Helper::ResultSet');
+
+use Debbugs::DB::Util qw(select_one);
+
+use List::MoreUtils qw(natatime);
+
+
+=over
+
+=item quick_insert_bugs
+
+     $s->result_set('Bug')->quick_insert_bugs(@bugs);
+
+Quickly insert a set of bugs (without any useful information, like subject,
+etc). This should probably only be called when inserting bugs in the database
+for first time.
+
+=cut
+
+
+sub quick_insert_bugs {
+    my ($self,@bugs) = @_;
+
+    my $it = natatime 2000, @bugs;
+
+    while (my @b = $it->()) {
+       $self->result_source->schema->
+           txn_do(sub{
+                      for my $b (@b) {
+                          $self->quick_insert_bug($b);
+                      }
+                  });
+    }
+}
+
+=item quick_insert_bug
+
+     $s->result_set('Bug')->quick_insert_bug($bug);
+
+Quickly insert a single bug (called by quick_insert_bugs). You should probably
+actually be calling C<Debbugs::DB::Load::load_bug> instead of this function.
+
+=cut
+
+sub quick_insert_bug {
+    my ($self,$bug) = @_;
+    return $self->result_source->schema->storage->
+       dbh_do(sub {
+                  my ($s,$dbh,$b) = @_;
+                  select_one($dbh,<<'SQL',$b);
+INSERT INTO bug (id,subject,severity) VALUES (?,'',1)
+ON CONFLICT (id) DO NOTHING RETURNING id;
+SQL
+              },
+              $bug
+             );
+
+}
+
+
+=back
+
+=cut
+
+
+1;
+
+__END__
diff --git a/Debbugs/DB/ResultSet/BugStatusCache.pm b/Debbugs/DB/ResultSet/BugStatusCache.pm
new file mode 100644 (file)
index 0000000..278d0e6
--- /dev/null
@@ -0,0 +1,75 @@
+# This module is part of debbugs, and is released
+# under the terms of the GPL version 2, or any later version. See the
+# file README and COPYING for more information.
+# Copyright 2017 by Don Armstrong <don@donarmstrong.com>.
+use utf8;
+package Debbugs::DB::ResultSet::BugStatusCache;
+
+=head1 NAME
+
+Debbugs::DB::ResultSet::BugStatusCache - Bug result set operations
+
+=head1 SYNOPSIS
+
+
+
+=head1 DESCRIPTION
+
+
+
+=cut
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::ResultSet';
+__PACKAGE__->load_components('Helper::ResultSet');
+
+use Debbugs::DB::Util qw(select_one);
+
+use List::MoreUtils qw(natatime);
+
+
+=over
+
+=item update_bug_status
+
+       $s->resultset('BugStatusCache')->
+           update_bug_status($bug->id,
+                             $suite->{id},
+                             undef,
+                             $presence,
+                             );
+
+Update the status information for a particular bug at a particular suite
+
+=cut
+
+sub update_bug_status {
+    my ($self,@args) = @_;
+    return $self->result_source->schema->storage->
+       dbh_do(sub {
+                  my ($s,$dbh,$bug,$suite,$arch,$status,$modified,$asof) = @_;
+                  select_one($dbh,<<'SQL',$bug,$suite,$arch,$status,$status);
+INSERT INTO bug_status_cache AS bsc
+(bug,suite,arch,status,modified,asof)
+VALUES (?,?,?,?,NOW(),NOW())
+ON CONFLICT (bug,COALESCE(suite,0),COALESCE(arch,0)) DO
+UPDATE
+ SET asof=NOW(),modified=CASE WHEN bsc.status=? THEN bsc.modified ELSE NOW() END
+RETURNING status;
+SQL
+              },
+           @args
+             );
+}
+
+
+=back
+
+=cut
+
+
+1;
+
+__END__
diff --git a/Debbugs/DB/ResultSet/Correspondent.pm b/Debbugs/DB/ResultSet/Correspondent.pm
new file mode 100644 (file)
index 0000000..d722a5f
--- /dev/null
@@ -0,0 +1,92 @@
+# This module is part of debbugs, and is released
+# under the terms of the GPL version 2, or any later version. See the
+# file README and COPYING for more information.
+# Copyright 2017 by Don Armstrong <don@donarmstrong.com>.
+use utf8;
+package Debbugs::DB::ResultSet::Correspondent;
+
+=head1 NAME
+
+Debbugs::DB::ResultSet::Correspondent - Correspondent table actions
+
+=head1 SYNOPSIS
+
+
+
+=head1 DESCRIPTION
+
+
+
+=cut
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::ResultSet';
+
+use Debbugs::DB::Util qw(select_one);
+
+use Debbugs::Common qw(getparsedaddrs);
+use Debbugs::DB::Util qw(select_one);
+use Scalar::Util qw(blessed);
+
+sub get_correspondent_id {
+    my ($self,$addr) = @_;
+    my $full_name;
+    if (blessed($addr)) {
+       $full_name = $addr->phrase();
+       $addr = $addr->address();
+    } elsif ($addr =~ /</) {
+       $addr = getparsedaddrs($addr);
+       $full_name = $addr->phrase();
+       $addr = $addr->address();
+    }
+    if (defined $full_name) {
+       $full_name =~ s/^\"|\"$//g;
+       $full_name =~ s/^\s+|\s+$//g;
+    }
+    my $rs =
+       $self->
+       search({addr => $addr},
+             {result_class => 'DBIx::Class::ResultClass::HashRefInflator',
+             }
+             )->first();
+    if (defined $rs) {
+       return $rs->{id};
+    }
+    return $self->result_source->schema->storage->
+       dbh_do(sub {
+                  my ($s,$dbh,$addr,$full_name) = @_;
+                  my $ci = select_one($dbh,<<'SQL',$addr,$addr);
+WITH ins AS (
+INSERT INTO correspondent (addr) VALUES (?)
+ ON CONFLICT (addr) DO NOTHING RETURNING id
+)
+SELECT id FROM ins
+UNION ALL
+SELECT id FROM correspondent WHERE addr = ?
+LIMIT 1;
+SQL
+                  if (defined $full_name) {
+                      select_one($dbh,<<'SQL',$ci,$full_name);
+WITH ins AS (
+INSERT INTO correspondent_full_name (correspondent,full_name)
+   VALUES (?,?) ON CONFLICT (correspondent,full_name) DO NOTHING RETURNING 1
+) SELECT 1 FROM ins
+UNION ALL
+SELECT 1;
+SQL
+                  }
+                  return $ci;
+},
+              $addr,
+              $full_name
+             );
+
+}
+
+
+
+1;
+
+__END__
diff --git a/Debbugs/DB/ResultSet/Maintainer.pm b/Debbugs/DB/ResultSet/Maintainer.pm
new file mode 100644 (file)
index 0000000..7c889f3
--- /dev/null
@@ -0,0 +1,117 @@
+# This module is part of debbugs, and is released
+# under the terms of the GPL version 2, or any later version. See the
+# file README and COPYING for more information.
+# Copyright 2016 by Don Armstrong <don@donarmstrong.com>.
+use utf8;
+package Debbugs::DB::ResultSet::Maintainer;
+
+=head1 NAME
+
+Debbugs::DB::ResultSet::Maintainer - Package maintainer result set operations
+
+=head1 SYNOPSIS
+
+
+
+=head1 DESCRIPTION
+
+
+
+=cut
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::ResultSet';
+
+use Debbugs::DB::Util qw(select_one);
+
+
+=over
+
+=item get_maintainers 
+
+     $s->resultset('Maintainers')->get_maintainers();
+
+     $s->resultset('Maintainers')->get_maintainers(@maints);
+
+Retrieve a HASHREF of all maintainers with the maintainer name as the key and
+the id of the database as the value. If given an optional list of maintainers,
+adds those maintainers to the database if they do not already exist in the
+database.
+
+=cut
+sub get_maintainers {
+    my ($self,@maints) = @_;
+    my %maints;
+    for my $m ($self->result_source->schema->resultset('Maintainer')->
+              search(undef,
+                    {result_class => 'DBIx::Class::ResultClass::HashRefInflator',
+                     columns => [qw[id name] ]
+                    })->all()) {
+       $maints{$m->{name}} = $m->{id};
+    }
+    my @maint_names = grep {not exists $maints{$_}} @maints;
+    my @maint_ids = $self->result_source->schema->
+       txn_do(sub {
+                  my @ids;
+                  for my $name (@_) {
+                      push @ids,
+                          $self->result_source->schema->
+                          resultset('Maintainer')->get_maintainer_id($name);
+                  }
+                  return @ids;
+              },@maint_names);
+    @maints{@maint_names} = @maint_ids;
+    return \%maints;
+}
+
+=item get_maintainer_id
+
+     $s->resultset('Maintainer')->get_maintainer_id('Foo Bar <baz@example.com>')
+
+Given a maintainer name returns the maintainer id, possibly inserting the
+maintainer (and correspondent) if either do not exist in the database.
+
+
+=cut
+
+sub get_maintainer_id {
+    my ($self,$maint) = @_;
+    my $rs =
+       $self->
+       search({name => $maint},
+             {result_class => 'DBIx::Class::ResultClass::HashRefInflator',
+             }
+             )->first();
+    if (defined $rs) {
+       return $rs->{id};
+    }
+    my $ci =
+       $self->result_source->schema->resultset('Correspondent')->
+       get_correspondent_id($maint);
+    return $self->result_source->schema->storage->
+       dbh_do(sub {
+                  my ($s,$dbh,$maint,$ci) = @_;
+                  return select_one($dbh,<<'SQL',$maint,$ci,$maint);
+WITH ins AS (
+INSERT INTO maintainer (name,correspondent) VALUES (?,?)
+ON CONFLICT (name) DO NOTHING RETURNING id
+)
+SELECT id FROM ins
+UNION ALL
+SELECT id FROM maintainer WHERE name = ?
+LIMIT 1;
+SQL
+              },
+              $maint,$ci
+             );
+}
+
+=back
+
+=cut
+
+1;
+
+__END__
diff --git a/Debbugs/DB/ResultSet/Message.pm b/Debbugs/DB/ResultSet/Message.pm
new file mode 100644 (file)
index 0000000..08509ce
--- /dev/null
@@ -0,0 +1,56 @@
+# This module is part of debbugs, and is released
+# under the terms of the GPL version 2, or any later version. See the
+# file README and COPYING for more information.
+# Copyright 2017 by Don Armstrong <don@donarmstrong.com>.
+use utf8;
+package Debbugs::DB::ResultSet::Message;
+
+=head1 NAME
+
+Debbugs::DB::ResultSet::Message - Message table actions
+
+=head1 SYNOPSIS
+
+
+
+=head1 DESCRIPTION
+
+
+
+=cut
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::ResultSet';
+
+use Debbugs::DB::Util qw(select_one);
+
+sub get_message_id {
+    my ($self,$msg_id,$from,$to,$subject) = @_;
+    return $self->result_source->schema->storage->
+       dbh_do(sub {
+                  my ($dbh,$msg_id,$from,$to,$subject) = @_;
+                  my $mi = select_one($dbh,<<'SQL',@_[1..$#_],@_[1..$#_]);
+WITH ins AS (
+INSERT INTO message (msgid,from_complete,to_complete,subject) VALUES (?,?,?,?)
+ ON CONFLICT (msgid,from_complete,to_complete,subject) DO NOTHING RETURNING id
+)
+SELECT id FROM ins
+UNION ALL
+SELECT id FROM correspondent WHERE msgid=? AND from_complete = ?
+AND to_complete = ? AND subject = ?
+LIMIT 1;
+SQL
+                  return $mi;
+},
+              @_[1..$#_]
+             );
+
+}
+
+
+
+1;
+
+__END__
diff --git a/Debbugs/DB/ResultSet/SrcAssociation.pm b/Debbugs/DB/ResultSet/SrcAssociation.pm
new file mode 100644 (file)
index 0000000..047c54d
--- /dev/null
@@ -0,0 +1,48 @@
+# This module is part of debbugs, and is released
+# under the terms of the GPL version 2, or any later version. See the
+# file README and COPYING for more information.
+# Copyright 2017 by Don Armstrong <don@donarmstrong.com>.
+use utf8;
+package Debbugs::DB::ResultSet::SrcAssociation;
+
+=head1 NAME
+
+Debbugs::DB::ResultSet::SrcAssociation - Source/Suite Associations
+
+=head1 SYNOPSIS
+
+
+
+=head1 DESCRIPTION
+
+
+
+=cut
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::ResultSet';
+
+use Debbugs::DB::Util qw(select_one);
+
+
+sub insert_suite_src_ver_association {
+    my ($self,$suite_id,$src_ver_id) = @_;
+    return $self->result_source->schema->storage->
+       dbh_do(sub {
+                  my ($s,$dbh,$suite_id,$src_ver_id) = @_;
+                  return select_one($dbh,<<'SQL',$suite_id,$src_ver_id);
+INSERT INTO src_associations (suite,source)
+   VALUES (?,?) ON CONFLICT (suite,source) DO
+     UPDATE SET modified = NOW()
+RETURNING id;
+SQL
+              },
+              $suite_id,$src_ver_id
+             );
+}
+
+1;
+
+__END__
diff --git a/Debbugs/DB/ResultSet/SrcPkg.pm b/Debbugs/DB/ResultSet/SrcPkg.pm
new file mode 100644 (file)
index 0000000..c9db9a4
--- /dev/null
@@ -0,0 +1,82 @@
+# This module is part of debbugs, and is released
+# under the terms of the GPL version 2, or any later version. See the
+# file README and COPYING for more information.
+# Copyright 2017 by Don Armstrong <don@donarmstrong.com>.
+use utf8;
+package Debbugs::DB::ResultSet::SrcPkg;
+
+=head1 NAME
+
+Debbugs::DB::ResultSet::SrcPkg - Source Package
+
+=head1 SYNOPSIS
+
+
+
+=head1 DESCRIPTION
+
+
+
+=cut
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::ResultSet';
+
+use Debbugs::DB::Util qw(select_one);
+
+sub src_pkg_and_ver_in_suite {
+    my ($self,$suite) = @_;
+    if (ref($suite)) {
+       if (ref($suite) eq 'HASH') {
+           $suite = $suite->{id}
+       } else {
+          $suite = $suite->id();
+       }
+    } else {
+       if ($suite !~ /^\d+$/) {
+           $suite = $self->result_source->schema->
+               resultset('Suite')->
+               search_rs({codename => $suite},
+                        {result_class => 'DBIx::Class::ResultClass::HashRefInflator',
+                        })->first();
+           if (defined $suite) {
+               $suite = $suite->{id};
+           }
+       }
+    }
+    return
+       $self->search_rs({'src_associations.suite' => $suite,
+                        },
+                       {join => {src_vers => 'src_associations'},
+                        result_class => 'DBIx::Class::ResultClass::HashRefInflator',
+                        columns => [qw(me.pkg src_vers.ver src_associations.id)]
+                       },
+                       )->all;
+}
+
+
+sub get_src_pkg_id {
+    my ($self,$source) = @_;
+    return $self->result_source->schema->storage->
+       dbh_do(sub {
+                  my ($s,$dbh,$source) = @_;
+                  return select_one($dbh,<<'SQL',$source,$source);
+WITH ins AS (
+INSERT INTO src_pkg (pkg)
+   VALUES (?) ON CONFLICT (pkg,disabled) DO NOTHING RETURNING id
+)
+SELECT id FROM ins
+UNION ALL
+SELECT id FROM src_pkg where pkg = ? AND disabled = 'infinity'::timestamptz
+LIMIT 1;
+SQL
+              },
+              $source
+             );
+}
+
+1;
+
+__END__
diff --git a/Debbugs/DB/ResultSet/SrcVer.pm b/Debbugs/DB/ResultSet/SrcVer.pm
new file mode 100644 (file)
index 0000000..254816c
--- /dev/null
@@ -0,0 +1,50 @@
+# This module is part of debbugs, and is released
+# under the terms of the GPL version 2, or any later version. See the
+# file README and COPYING for more information.
+# Copyright 2017 by Don Armstrong <don@donarmstrong.com>.
+use utf8;
+package Debbugs::DB::ResultSet::SrcVer;
+
+=head1 NAME
+
+Debbugs::DB::ResultSet::SrcVer - Source Version association
+
+=head1 SYNOPSIS
+
+
+
+=head1 DESCRIPTION
+
+
+
+=cut
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::ResultSet';
+
+use Debbugs::DB::Util qw(select_one);
+
+
+sub get_src_ver_id {
+    my ($self,$src_pkg_id,$src_ver,$maint_id) = @_;
+    return $self->result_source->schema->storage->
+       dbh_do(sub {
+                  my ($s,$dbh,$src_pkg_id,$src_ver,$maint_id) = @_;
+                  return select_one($dbh,<<'SQL',
+INSERT INTO src_ver (src_pkg,ver,maintainer)
+   VALUES (?,?,?) ON CONFLICT (src_pkg,ver) DO
+     UPDATE SET maintainer = ?
+   RETURNING id;
+SQL
+                                    $src_pkg_id,$src_ver,
+                                    $maint_id,$maint_id);
+              },
+              $src_pkg_id,$src_ver,$maint_id
+             );
+}
+
+1;
+
+__END__
diff --git a/Debbugs/DB/ResultSet/Suite.pm b/Debbugs/DB/ResultSet/Suite.pm
new file mode 100644 (file)
index 0000000..c920080
--- /dev/null
@@ -0,0 +1,53 @@
+# This module is part of debbugs, and is released
+# under the terms of the GPL version 2, or any later version. See the
+# file README and COPYING for more information.
+# Copyright 2017 by Don Armstrong <don@donarmstrong.com>.
+use utf8;
+package Debbugs::DB::ResultSet::Suite;
+
+=head1 NAME
+
+Debbugs::DB::ResultSet::Suite - Suite table actions
+
+=head1 SYNOPSIS
+
+
+
+=head1 DESCRIPTION
+
+
+
+=cut
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::ResultSet';
+
+sub get_suite_id {
+    my ($self,$suite) = @_;
+    if (ref($suite)) {
+       if (ref($suite) eq 'HASH') {
+           $suite = $suite->{id}
+       } else {
+           $suite = $suite->id();
+       }
+    }
+    else {
+       if ($suite !~ /^\d+$/) {
+           $suite = $self->result_source->schema->
+               resultset('Suite')->
+               search_rs({codename => $suite},
+                        {result_class => 'DBIx::Class::ResultClass::HashRefInflator',
+                        })->first();
+           if (defined $suite) {
+               $suite = $suite->{id};
+           }
+       }
+    }
+    return $suite;
+}
+
+1;
+
+__END__
diff --git a/Debbugs/DB/Util.pm b/Debbugs/DB/Util.pm
new file mode 100644 (file)
index 0000000..d241f33
--- /dev/null
@@ -0,0 +1,96 @@
+# This module is part of debbugs, and is released
+# under the terms of the GPL version 2, or any later version. See the
+# file README and COPYING for more information.
+# Copyright 2017 by Don Armstrong <don@donarmstrong.com>.
+
+package Debbugs::DB::Util;
+
+=head1 NAME
+
+Debbugs::DB::Util -- Utility routines for the database
+
+=head1 SYNOPSIS
+
+
+=head1 DESCRIPTION
+
+
+=head1 BUGS
+
+None known.
+
+=cut
+
+use warnings;
+use strict;
+use vars qw($VERSION $DEBUG %EXPORT_TAGS @EXPORT_OK @EXPORT);
+use base qw(Exporter);
+
+BEGIN{
+     ($VERSION) = q$Revision$ =~ /^Revision:\s+([^\s+])/;
+     $DEBUG = 0 unless defined $DEBUG;
+
+     @EXPORT = ();
+     %EXPORT_TAGS = (select => [qw(select_one)],
+                    execute => [qw(prepare_execute)]
+                   );
+     @EXPORT_OK = ();
+     Exporter::export_ok_tags(keys %EXPORT_TAGS);
+     $EXPORT_TAGS{all} = [@EXPORT_OK];
+}
+
+=head2 select
+
+Routines for select requests
+
+=over
+
+=item select_one
+
+       select_one($dbh,$sql,@bind_vals)
+
+Returns the first column from the first row returned from a select statement
+
+=cut
+
+sub select_one {
+    my ($dbh,$sql,@bind_vals) = @_;
+    my $sth = $dbh->
+        prepare_cached($sql,
+                      {dbi_dummy => __FILE__.__LINE__ })
+        or die "Unable to prepare statement: $sql";
+    $sth->execute(@bind_vals) or
+        die "Unable to select one: ".$dbh->errstr();
+    my $results = $sth->fetchall_arrayref([0]);
+    $sth->finish();
+    return (ref($results) and ref($results->[0]))?$results->[0][0]:undef;
+}
+
+=item prepare_execute
+
+       prepare_execute($dbh,$sql,@bind_vals)
+
+Prepares and executes a statement
+
+=cut
+
+sub prepare_execute {
+    my ($dbh,$sql,@bind_vals) = @_;
+    my $sth = $dbh->
+        prepare_cached($sql,
+                      {dbi_dummy => __FILE__.__LINE__ })
+        or die "Unable to prepare statement: $sql";
+    $sth->execute(@bind_vals) or
+        die "Unable to execute statement: ".$dbh->errstr();
+    $sth->finish();
+}
+
+
+=back
+
+=cut
+
+1;
+
+
+__END__
diff --git a/Debbugs/DBase.pm b/Debbugs/DBase.pm
deleted file mode 100644 (file)
index 5df78b0..0000000
+++ /dev/null
@@ -1,289 +0,0 @@
-# TODO: Implement 'stale' checks, so that there is no need to explicitly
-#      write out a record, before closing.
-
-package Debbugs::DBase;  # assumes Some/Module.pm
-
-use strict;
-
-BEGIN {
-       use Exporter   ();
-       use vars       qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
-
-       # set the version for version checking
-       $VERSION     = 1.00;
-
-       @ISA         = qw(Exporter);
-       @EXPORT      = qw();
-       %EXPORT_TAGS = ( );     # eg: TAG => [ qw!name1 name2! ],
-
-       # your exported package globals go here,
-       # as well as any optionally exported functions
-       @EXPORT_OK   = qw();
-}
-
-use vars      @EXPORT_OK;
-use Fcntl ':flock';
-use Debbugs::Config;
-use Debbugs::Email;
-use Debbugs::Common;
-use Debbugs::DBase::Log;
-use Debbugs::DBase::Log::Html;
-use Debbugs::DBase::Log::Message;
-use Debbugs::DBase::Log::Mail;
-
-use FileHandle;
-use File::Basename qw(&dirname);
-use File::Path;
-
-my $OpenedRecord = 0;
-my $OpenedLog = 0;
-my $FileHandle;
-my $LogfileHandle = new FileHandle;
-
-sub ParseVersion1Record
-{
-    my @data = @_;
-    my @fields = ( "originator", "date", "subject", "msgid", "package",
-               "keywords", "done", "forwarded", "mergedwith", "severity" );
-    my $i = 0;
-    my $tag;
-    my (%record, %btags);
-
-    print "D2: (DBase) Record Fields:\n" if $Globals{ 'debug' } > 1;
-    foreach my $line ( @data )
-    {
-       chop( $line );
-       $tag = $fields[$i];
-       $record{ $tag } = $line;
-       print "\t $tag = $line\n" if $Globals{ 'debug' } > 1;
-       $i++;
-       $btags{ "BUG_$tag" } = $line;
-    }
-    return ( \%record, \%btags );
-}
-
-sub ParseVersion2Record
-{
-    # I envision the next round of records being totally different in
-    # meaning.  In order to maintain compatability, version tagging will be
-    # implemented in the next go around and different versions will be sent
-    # off to different functions to be parsed and interpreted into a format
-    # that the rest of the system will understand.  All data will be saved
-    # in whatever 'new" format exists.  The difference will be a "Version: x"
-    # at the top of the file.
-
-    print "No version 2 records are understood at this time\n";
-    exit 1;
-}
-
-sub ReadRecord
-{
-    my ($recordnum, $with_log, $new) = (shift, shift, shift);
-    my @data;
-    my $record;
-    my $btags;
-
-    #Open Status File
-    print "V: Reading status $recordnum\n" if $Globals{ 'verbose' };
-    if( $OpenedRecord != $recordnum )
-    {
-       if( defined( $FileHandle ) )
-       {
-           print "D1: Closing status $recordnum\n" if $Globals{ 'debug' };
-           $OpenedRecord = 0;
-           close $FileHandle;
-           $FileHandle = undef;
-       }
-       print "D1: Opening status $recordnum\n" if $Globals{ 'debug' };
-       $FileHandle = &OpenFile( ["db", "archive"], $recordnum, ".status", "status", $new );
-       if( !defined( $FileHandle ) ) { return undef; }
-    }
-    else { print "D1: Reusing status $recordnum\n" if $Globals{ 'debug' }; }
-
-    #Lock status file
-    print "D1: Locking status $recordnum\n" if $Globals{ 'debug' };
-    flock( $FileHandle, LOCK_EX ) || &fail( "Unable to lock record $recordnum\n" );
-
-    #Read in status file contents
-    print "D1: Loading status $recordnum\n" if $Globals{ 'debug' };
-    seek( $FileHandle, 0, 0 );
-    @data = <$FileHandle>;
-
-    #Parse Status File Contents
-    if ( scalar( @data ) =~ /Version: (\d*)/ )
-    {
-       if ( $1 == 2 )
-       { &ParseVersion2Record( @data ); }
-       else
-       { &fail( "Unknown record version: $1\n"); }
-    }
-    else { ($record, $btags) = &ParseVersion1Record( @data ); }
-    if( $with_log )
-    {
-       #DO READ IN LOG RECORD DATA STUFF
-    }
-    return ($record, $btags);
-}
-
-sub WriteRecord
-{
-    my ($recordnum, %record) = @_;
-    my @fields = ( "originator", "date", "subject", "msgid", "package",
-               "keywords", "done", "forwarded", "mergedwith", "severity" );
-
-    #Open Status File
-    print "V: Writing status $recordnum\n" if $Globals{ 'verbose' };
-    if( $OpenedRecord != $recordnum )
-    {
-       if( defined( $FileHandle ) )
-       {
-           print "D1: Closing status $recordnum\n" if $Globals{ 'debug' };
-           $OpenedRecord = 0;
-           close $FileHandle;
-           $FileHandle = undef;
-       }
-       print "D1: Opening status $recordnum\n" if $Globals{ 'debug' };
-       $FileHandle = &OpenFile( ["db", "archive"], $recordnum, ".status", "status", "old" );
-       if( !defined( $FileHandle ) ) { return undef; }
-    }
-    else { print "D1: Reusing status $recordnum\n" if $Globals{ 'debug' }; }
-
-    #Lock status file
-    print "D1: Locking status $recordnum\n" if $Globals{ 'debug' };
-    flock( $FileHandle, LOCK_EX ) || &fail( "Unable to lock record $recordnum\n" );
-
-    #Read in status file contents
-    print "D1: Saving status $recordnum\n" if $Globals{ 'debug' };
-    seek( $FileHandle, 0, 0 );
-    for( my $i = 0; $i < $#fields; $i++ )
-    {
-       if ( defined( $record{ $fields[$i] } ) )
-       { print $FileHandle $record{ $fields[$i] } . "\n"; }
-       else { print $FileHandle "\n"; }
-    }
-}
-
-sub GetFileName
-{
-    my ($prePaths, $stub, $postPath, $desc, $new) = (shift, shift, shift, shift, shift);
-    my $path;
-    foreach my $prePath (@$prePaths) {
-       $path = "/" . $prePath . "/" . $stub . $postPath;
-       print "V: Opening $desc $stub\n" if $Globals{ 'verbose' };
-       print "D2: (DBase) trying $path\n" if $Globals{ 'debug' } > 1;
-       if( ! -r $Globals{ "work-dir" } . $path ) {
-           $path = "/" . $prePath . "/" . &NameToPathHash($stub) . $postPath;
-           print "D2: (DBase) trying $path\n" if $Globals{ 'debug' } > 1;
-           if( ! -r $Globals{ "work-dir" } . $path ) {
-               next if( !$new =~ "new" );
-           }
-       }
-       if( -r $Globals{ "work-dir" } . $path ) {
-           return $path;
-       }
-       if( ( ! -r $Globals{ "work-dir" } . $path ) && defined($new) && $new =~ "new") {
-           my $dir = dirname( $path );
-           if ( ! -d $Globals{ "work-dir" } . $dir ) {
-               mkpath($Globals{ "work-dir" } . $dir);
-           }
-           return $path;
-       }
-    }
-    return undef;
-}
-
-sub OpenFile
-{
-    my ($prePaths, $stub, $postPath, $desc, $new) = (shift, shift, shift, shift, shift);
-    my $fileName = GetFileName($prePaths, $stub, $postPath, $desc, $new);
-    my $handle = new FileHandle;
-    open( $handle, $Globals{ "work-dir" } . $fileName ) && return $handle;
-    return undef;
-}
-
-sub OpenLogfile
-{
-    my $record = $_[0];
-    if ( $record ne $OpenedLog )
-    {
-       $LogfileHandle = OpenFile(["db", "archive"], $record, ".log", "log");
-       $OpenedLog = $record;
-    }
-}
-
-sub ReadLogfile
-{
-    my $record = $_[0];
-    if ( $record eq $OpenedLog )
-    {
-       seek( $LogfileHandle, 0, 0 );
-       my $log = new Debbugs::DBase::Log;
-       $log->Load($LogfileHandle);
-    }
-}
-
-sub CloseLogfile
-{
-    print "V: Closing log $OpenedLog\n" if $Globals{ 'verbose' };
-    close $LogfileHandle;
-    $OpenedLog = 0;
-}
-sub GetBugList
-{
-# TODO: This is ugly, but the easiest for me to implement.
-#      If you have a better way, then please send a patch.
-#
-    my $dir = new FileHandle;
-
-    my $prefix;
-    my $paths = shift;
-    my @paths;
-    if ( !defined($paths) ) {
-       @paths = ("db");
-    } else {
-       @paths = @$paths;
-    }
-    my @ret;
-    my $path;
-    foreach $path (@paths) {
-       $prefix = $Globals{ "work-dir" } . "/" . $path . "/";
-       opendir $dir, $prefix;
-       my @files = readdir($dir);
-       closedir $dir;
-       foreach (grep { /\d*\d\d.status/ } @files) {
-           next if ( ! -s $prefix . "/" . $_ );
-           s/.status$//;
-           push @ret, $_;
-#          print "$_ -> $_\n";
-       }
-       foreach (grep { /^[s0-9]$/ } @files) {
-           my $_1 = $_;
-           opendir $dir, $prefix . $_1;
-           my @files = grep { /^\d$/ } readdir($dir);
-           closedir $dir;
-           foreach (@files) {
-               my $_2 = $_;
-               opendir $dir, "$prefix$_1/$_2";
-               my @files = grep { /^\d$/ } readdir($dir);
-               close $dir;
-               foreach (@files) {
-                   my $_3 = $_;
-                   opendir $dir, "$prefix$_1/$_2/$_3";
-                   my @files = grep { /\d*\d\d.status/ } readdir($dir);
-                   close $dir;
-                   foreach (@files) {
-                       next if ( ! -s "$prefix$_1/$_2/$_3/$_" );
-                       s/.status$//;
-                       push @ret, $_;
-#                      print "$_ -> $_1/$_2/$_3/$_\n";
-                   }
-               }
-           }
-       }
-    }
-    return @ret;
-}
-
-1;
-
-END { }       # module clean-up code here (global destructor)
diff --git a/Debbugs/DBase/Log.pm b/Debbugs/DBase/Log.pm
deleted file mode 100644 (file)
index 3e493b7..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-# TODO: Implement 'stale' checks, so that there is no need to explicitly
-#      write out a record, before closing.
-
-package Debbugs::DBase::Log;
-
-use strict;
-                               
-sub new
-{
-    my $self  = {};
-#    $self->{LOG}    = new FileHandle;
-#    $self->{AGE}    = undef;
-#    $self->{PEERS}  = [];
-    $self->{log}       = [];
-    bless ($self);
-    return $self;
-}
-my %logClass = ();
-my %logType = ();
-sub Register
-{
-   my ($char, $type, $class) = (shift, shift, shift);
-   $logClass{ $char } = $class;
-   $logType{ $char } = $type;
-
-}
-
-sub Load
-{
-    my ($self, $handle) = (shift, shift);
-    foreach (keys %$self) {
-print "key=$_\n";
-}
-    while (<$handle>) {
-       chomp;
-       my ($char, $class, $type) = ($_, $logClass{ $_ }, $logType{ $_ });
-       my $msg = "";
-       while (<$handle>) {
-           chomp;
-           if ( $_ eq "\3" ) {
-               last;
-           } else {
-               $msg .= "$_\n";
-           }
-       }
-       if( defined($class) ) {
-           print "found handler $type for $char\n";
-           my $log = $class->new($msg);
-
-           my @log = $self->{log};
-           push @log, ($log);
-       } else {
-           print "undefined handler for $char\n";
-       }
-    }
-}
-
-BEGIN {
-        use Exporter   ();
-        use vars       qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
-
-        # set the version for version checking
-        $VERSION     = 1.00;
-
-        @ISA         = qw(Exporter);
-        @EXPORT      = qw(new);
-        %EXPORT_TAGS = ( );     # eg: TAG => [ qw!name1 name2! ],
-
-        # your exported package globals go here,
-        # as well as any optionally exported functions
-        @EXPORT_OK   = qw();
-
-}
-
-1;
diff --git a/Debbugs/DBase/Log/Html.pm b/Debbugs/DBase/Log/Html.pm
deleted file mode 100644 (file)
index b0eca6b..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-# TODO: Implement 'stale' checks, so that there is no need to explicitly
-#      write out a record, before closing.
-
-package Debbugs::DBase::Log::Html;
-
-use strict;
-
-BEGIN {
-       Debbugs::DBase::Log::Register("\6", "Html", "Debbugs::DBase::Log::Html");
-}
-
-
-sub new
-{
-    my $self  = {};
-    $self->{TYPE}      = "Html";
-    $self->{MSG}       = shift;
-    bless ($self);
-    return $self;
-}
-
-END { }       # module clean-up code here (global destructor)
-
-
-1;
diff --git a/Debbugs/DBase/Log/Mail.pm b/Debbugs/DBase/Log/Mail.pm
deleted file mode 100644 (file)
index 9d23c77..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-# TODO: Implement 'stale' checks, so that there is no need to explicitly
-#      write out a record, before closing.
-
-package Debbugs::DBase::Log::Mail;
-use Debbugs::DBase::LogEntry;
-use Exporter;
-
-use strict;
-BEGIN {
-       use vars        qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
-       @ISA = ( "Debbugs::DBase::LogEntry" );
-       Debbugs::DBase::Log::Register("\2", "Mail", "Debbugs::DBase::Log::Mail");
-}
-
-
-sub new
-{
-    my $proto = shift;
-    my $class = ref($proto) || $proto;
-    my $self  = {};
-    $self->{TYPE}      = "Html";
-    $self->{MSG}       = shift;
-    bless ($self, $class);
-    return $self;
-}
-
-END { }       # module clean-up code here (global destructor)
-
-
-1;
diff --git a/Debbugs/DBase/Log/Message.pm b/Debbugs/DBase/Log/Message.pm
deleted file mode 100644 (file)
index ceebb12..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-# TODO: Implement 'stale' checks, so that there is no need to explicitly
-#      write out a record, before closing.
-
-package Debbugs::DBase::Log::Message;
-
-use strict;
-
-BEGIN {
-       Debbugs::DBase::Log::Register("\7", "Message", "Debbugs::DBase::Log::Message");
-}
-
-
-sub new
-{
-    my $self  = {};
-    $self->{TYPE}      = "Message";
-    $self->{MSG}       = shift;
-    bless ($self);
-    return $self;
-}
-
-END { }       # module clean-up code here (global destructor)
-
-
-1;
diff --git a/Debbugs/DBase/LogEntry.pm b/Debbugs/DBase/LogEntry.pm
deleted file mode 100644 (file)
index c9ec852..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-# TODO: Implement 'stale' checks, so that there is no need to explicitly
-#      write out a record, before closing.
-
-package Debbugs::DBase::LogEntry;
-
-use strict;
-                               
-sub new
-{
-    my $self  = {};
-#    $self->{LOG}    = new FileHandle;
-#    $self->{AGE}    = undef;
-#    $self->{PEERS}  = [];
-    $self->{log}       = [];
-    $self->{Load}      = &Load;
-    bless ($self);
-    return $self;
-}
-my %logClass = ();
-my %logType = ();
-
-sub Load
-{
-    my ($self, $handle) = (shift, shift);
-    foreach (keys %$self) {
-print "key=$_\n";
-}
-    while (<$handle>) {
-       chomp;
-       my ($char, $class, $type) = ($_, $logClass{ $_ }, $logType{ $_ });
-       my $msg = "";
-       while (<$handle>) {
-           chomp;
-           if ( $_ eq "\3" ) {
-               last;
-           } else {
-               $msg .= "$_\n";
-           }
-       }
-       if( defined($class) ) {
-           print "found handler $type for $char\n";
-           my $log = $class->new($msg);
-
-           my @log = $self->{log};
-           push @log, ($log);
-       } else {
-           print "undefined handler for $char\n";
-       }
-    }
-}
-
-BEGIN {
-        use Exporter   ();
-        use vars       qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
-
-        # set the version for version checking
-        $VERSION     = 1.00;
-
-        @ISA         = qw(Exporter);
-        @EXPORT      = qw(new);
-        %EXPORT_TAGS = ( );     # eg: TAG => [ qw!name1 name2! ],
-
-        # your exported package globals go here,
-        # as well as any optionally exported functions
-        @EXPORT_OK   = qw();
-
-}
-
-1;
diff --git a/Debbugs/Email.pm b/Debbugs/Email.pm
deleted file mode 100644 (file)
index 980b5fb..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-package Debbugs::Email;
-
-use strict;
-
-BEGIN {
-       use Exporter   ();
-       use vars       qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
-
-       # set the version for version checking
-       $VERSION     = 1.00;
-
-       @ISA         = qw(Exporter);
-       @EXPORT      = qw( %GTags );
-       %EXPORT_TAGS = ( );     # eg: TAG => [ qw!name1 name2! ],
-
-       # your exported package globals go here,
-       # as well as any optionally exported functions
-       @EXPORT_OK   = qw( %GTags );
-}
-
-use vars @EXPORT_OK;
-use Debbugs::Config qw(%Globals);
-
-# initialize package globals, first exported ones
-%GTags= ( );
-
-#############################################################################
-#  Initialize Global Tags
-#############################################################################
-sub InitEmailTags
-{   my @config = @_;
-       
-    print "V: Initializing Email Tags\n" if $Globals{ 'verbose' };
-    for( my $i=0; $i<=$#config; $i++)
-    {  $_ = $config[$i];
-       chop $_;
-       next unless length $_;
-       next if /^#/;
-       if ( /^GTAG\s*[:=]\s*(\S)+\s*[:=]\s*([^#]*)/i )
-       {   $GTags{ $1 } = $2;
-           print "D2: (email) GTag $1=$GTags{$1}\n" if $Globals{ 'debug' } > 1;
-       }
-    }
-}
-
-#############################################################################
-#  Load File with Tags
-#############################################################################
-sub LoadEmail
-{   my $emailfile = $_[0];
-    my @email;
-
-    open( LETTER, $emailfile ) or &::fail( "Unable to open $emailfile: $!" );
-    @email = <LETTER>;
-    close LETTER;
-    &ProcessTags( \@email, \%GTags, "GTAG" );
-    return @email;
-}
-#############################################################################
-#  Process Tags
-#############################################################################
-sub ProcessTags
-{   my ($email, $tagsin, $marker) = @_;
-    my %tags=%$tagsin;
-    my $tag;
-
-    print "V: Processing Template Mail\n" if $Globals{ 'verbose' };
-    foreach my $line ( @$email )
-    {  while( $line =~ /\%$marker\_(\S*)\%/s )
-       {   if( defined( $tags{ $1 } ) ) { $tag = $tags{ $1 }; }
-           else { $tag = "(missed tag $1)"; }
-           $line =~ s/\%$marker\_(\S*)\%/$tag/;
-       }
-    }
-    1;
-}
-
-END { }       # module clean-up code here (global destructor)
-1;
index 2531a6d5c22e017d3dcc8db9ba07e9029825a2fd..d824d9a996d1b3fdce8fae13954fb28d7614e55c 100644 (file)
@@ -249,6 +249,7 @@ sub read_record
     my $record = {};
 
     while (defined (my $line = <$logfh>)) {
+        $record->{start} = $logfh->tell() if not defined $record->{start};
        chomp $line;
        ++$this->{linenum};
        if (length($line) == 1 and exists $states{ord($line)}) {
index 1d8fcb57e2a3c633e8cf86d2bab484ca9c0e5f04..8644c359695db3a332346900c11e9a59e8f2bfff 100644 (file)
@@ -41,7 +41,9 @@ BEGIN {
 
     @EXPORT = ();
 
-    %EXPORT_TAGS = (mime => [qw(parse create_mime_message getmailbody)],
+    %EXPORT_TAGS = (mime => [qw(parse create_mime_message getmailbody),
+                            qw(parse_to_mime_entity),
+                           ],
                    rfc1522 => [qw(decode_rfc1522 encode_rfc1522)],
                   );
     @EXPORT_OK=();
@@ -88,6 +90,43 @@ sub getmailbody
     return undef;
 }
 
+=item parse_to_mime_entity
+
+     $entity = parse_to_mime_entity($record);
+
+Returns a MIME::Entity from a record (from Debbugs::Log), a filehandle, or a
+scalar mail message. Will die upon failure.
+
+Intermediate parsing results will be output under a temporary directory which
+should be cleaned up upon process exit.
+
+=cut
+
+sub parse_to_mime_entity {
+    my ($record) = @_;
+    my $parser = MIME::Parser->new();
+    my $entity;
+    # this will be cleaned up once we exit
+    my $tempdir = File::Temp->newdir();
+    $parser->output_dir($tempdir->dirname());
+    if (ref($record) eq 'HASH') {
+       if ($record->{inner_file}) {
+           $entity = $parser->parse($record->{fh}) or
+               die "Unable to parse entity";
+       } else {
+           $entity = $parser->parse_data($record->{text}) or
+               die "Unable to parse entity";
+       }
+    } elsif (ref($record)) {
+       $entity = $parser->parse($record) or
+           die "Unable to parse entity";
+    } else {
+       $entity = $parser->parse_data($record) or
+           die "Unable to parse entity";
+    }
+    return $entity;
+}
+
 sub parse
 {
     # header and decoded body respectively
index 6980315f06afef7b160d6ea47af695c1dc5bc2eb..877466f91d2b4ce7f64c489546b0c34b79344a74 100644 (file)
@@ -187,12 +187,15 @@ sub binary_to_source{
                                         cache => {type => HASHREF,
                                                   default => {},
                                                  },
+                                        schema => {type => OBJECT,
+                                                   optional => 1,
+                                                  },
                                        },
                             );
 
     # TODO: This gets hit a lot, especially from buggyversion() - probably
     # need an extra cache for speed here.
-    return () unless defined $gBinarySourceMap;
+    return () unless defined $gBinarySourceMap or defined $param{schema};
 
     if ($param{scalar_only} or not wantarray) {
        $param{source_only} = 1;
@@ -204,6 +207,59 @@ sub binary_to_source{
     my @versions = grep {defined $_} make_list(exists $param{version}?$param{version}:[]);
     my @archs = grep {defined $_} make_list(exists $param{arch}?$param{arch}:[]);
     return () unless @binaries;
+
+    # any src:foo is source package foo with unspecified version
+    @source = map {/^src:(.+)$/?
+                      [$1,'']:()} @binaries;
+    @binaries = grep {$_ !~ /^src:/} @binaries;
+    if ($param{schema}) {
+       if ($param{source_only}) {
+           @source = map {$_->[0]} @source;
+           my $src_rs = $param{schema}->resultset('SrcPkg')->
+               search_rs({'binpkg.pkg' => [@binaries],
+                          @versions?('bin_vers.ver'    => [@versions]):(),
+                          @archs?('arch.arch' => [@archs]):(),
+                         },
+                        {join => {'src_vers'=>
+                                 {'bin_vers'=> ['arch','bin_pkg']}
+                                 },
+                         distinct => 1,
+                        },
+                        );
+           push @source,
+               map {$_->pkg} $src_rs->all;
+           if ($param{scalar_only}) {
+               return join(',',@source);
+           }
+           return @source;
+
+       }
+       my $src_rs = $param{schema}->resultset('SrcVer')->
+           search_rs({'bin_pkg.pkg' => [@binaries],
+                      @versions?('bin_vers.ver' => [@versions]):(),
+                      @archs?('arch.arch' => [@archs]):(),
+                     },
+                    {join => ['src_pkg',
+                             {'bin_vers' => ['arch','binpkg']},
+                             ],
+                     distinct => 1,
+                    },
+                    );
+       push @source,
+           map {[$_->get_column('src_pkg.pkg'),
+                 $_->get_column('src_ver.ver'),
+                ]} $src_rs->all;
+       if (not @source and not @versions and not @archs) {
+           $src_rs = $param{schema}->resultset('SrcPkg')->
+               search_rs({pkg => [@binaries]},
+                        {distinct => 1},
+                        );
+           push @source,
+               map {[$_->pkg,
+                    ]} $src_rs->all;
+       }
+       return @source;
+    }
     my $cache_key = join("\1",
                         join("\0",@binaries),
                         join("\0",@versions),
@@ -214,10 +270,6 @@ sub binary_to_source{
            @{$param{cache}{$cache_key}};
     }
     for my $binary (@binaries) {
-       if ($binary =~ m/^src:(.+)$/) {
-           push @source,[$1,''];
-           next;
-       }
        if (not tied %_binarytosource) {
            tie %_binarytosource, MLDBM => $config{binary_source_map}, O_RDONLY or
                die "Unable to open $config{binary_source_map} for reading";
index 4b8d82e828f06687595ea11a45164a4bb907401d..62cba343dce6183553b59ec8fe4976b69a0d10bc 100644 (file)
@@ -191,6 +191,7 @@ sub read_bug{
     my $status;
     my $log;
     my $location;
+    my $report;
     if (not defined $param{summary}) {
         my $lref;
         ($lref,$location) = @param{qw(bug location)};
@@ -200,13 +201,16 @@ sub read_bug{
         }
         $status = getbugcomponent($lref, 'summary', $location);
         $log    = getbugcomponent($lref, 'log'    , $location);
+        $report    = getbugcomponent($lref, 'report'    , $location);
         return undef unless defined $status;
         return undef if not -e $status;
     }
     else {
         $status = $param{summary};
         $log = $status;
+        $report = $status;
         $log =~ s/\.summary$/.log/;
+        $report =~ s/\.summary$/.report/;
         ($location) = $status =~ m/(db-h|db|archive)/;
          ($param{bug}) = $status =~ m/(\d+)\.summary$/;
     }
@@ -277,7 +281,12 @@ sub read_bug{
     my $status_modified = (stat($status))[9];
     # Add log last modified time
     $data{log_modified} = (stat($log))[9] // (stat("${log}.gz"))[9];
+    my $report_modified = (stat($report))[9] // $data{log_modified};
     $data{last_modified} = max($status_modified,$data{log_modified});
+    # if the date isn't set (ancient bug), use the smallest of any of the modified
+    if (not defined $data{date} or not length($data{date})) {
+        $data{date} = min($report_modified,$status_modified,$data{log_modified});
+    }
     $data{location} = $location;
     $data{archived} = (defined($location) and ($location eq 'archive'))?1:0;
     $data{bug_num} = $param{bug};
@@ -314,23 +323,42 @@ our $ditch_empty = sub{
     return grep {length $_} map {split $splitter} @t;
 };
 
-my $ditch_empty_space = sub {return &{$ditch_empty}(' ',@_)};
+our $sort_and_unique = sub {
+    my @v;
+    my %u;
+    my $all_numeric = 1;
+    for my $v (@_) {
+        if ($all_numeric and $v =~ /\D/) {
+            $all_numeric = 0;
+        }
+        next if exists $u{$v};
+        $u{$v} = 1;
+        push @v, $v;
+    }
+    if ($all_numeric) {
+        return sort {$a <=> $b} @v;
+    } else {
+        return sort @v;
+    }
+};
+
+my $ditch_space_unique_and_sort = sub {return &{$sort_and_unique}(&{$ditch_empty}(' ',@_))};
 my %split_fields =
     (package        => \&splitpackages,
      affects        => \&splitpackages,
      # Ideally we won't have to split source, but because some consumers of
      # get_bug_status cannot handle arrayref, we will split it here.
      source         => \&splitpackages,
-     blocks         => $ditch_empty_space,
-     blockedby      => $ditch_empty_space,
+     blocks         => $ditch_space_unique_and_sort,
+     blockedby      => $ditch_space_unique_and_sort,
      # this isn't strictly correct, but we'll split both of them for
      # the time being until we ditch all use of keywords everywhere
      # from the code
-     keywords       => $ditch_empty_space,
-     tags           => $ditch_empty_space,
-     found_versions => $ditch_empty_space,
-     fixed_versions => $ditch_empty_space,
-     mergedwith     => $ditch_empty_space,
+     keywords       => $ditch_space_unique_and_sort,
+     tags           => $ditch_space_unique_and_sort,
+     found_versions => $ditch_space_unique_and_sort,
+     fixed_versions => $ditch_space_unique_and_sort,
+     mergedwith     => $ditch_space_unique_and_sort,
     );
 
 sub split_status_fields {
diff --git a/README_sql.md b/README_sql.md
new file mode 100644 (file)
index 0000000..43e7314
--- /dev/null
@@ -0,0 +1,42 @@
+# Bringing up SQL for Debbugs
+
+## Creation of database
+
+Debbugs needs a postgresql database (≥ 9.4) with the debversion
+extension installed. `apt-get install postgresql-9.5
+postgreql-9.5-debversion` to install those two packages.
+
+Then create a database and enable the debversion extension:
+
+    echo 'create database debbugs' | psql;
+    echo 'create extension debversion' | psql debbugs;
+    
+Debbugs also expects to be able to connect to databases using
+a
+[postgresql service definition](https://www.postgresql.org/docs/current/static/libpq-pgservice.html) which
+defines the host, port, database, and any other connection information
+which is needed. The default service is 'debbugs', but this can be
+configured using `/etc/debbugs/config` or the `--service` option to
+most commands. The most simplistic `~/.pg_service.conf` looks like this:
+
+    [debbugs]
+     host=localhost
+     database=debbugs
+
+## Insert database schema
+
+To create the database schema, run `debbugs-installsql
+--service=debbugs --install` (replacing debbugs with whatever the
+appropriate service is.) The `debbugs-installsql` command also has an
+`--upgrade` option which can be used to upgrade the schema between
+schema revisions.
+
+## Populate database initially
+
+1. Insert configuration `debbugs-loadsql configuration`
+2. Add suites `debbugs-loadsql suites --ftpdist /srv/ftp.debian.org/dists`
+3. Add packages `debbugs-loadsql packages --progress --ftpdist /srv/ftp.debian.org/dists`
+4. Add bugs `debbugs-loadsql bugs --progress --preload`
+5. Add bug logs `debbugs-loadsql logs --progress`
+6. Add maintainers `debbugs-loadsql maintainers`
+
diff --git a/bin/debbugs-installsql b/bin/debbugs-installsql
new file mode 100755 (executable)
index 0000000..892aef4
--- /dev/null
@@ -0,0 +1,165 @@
+#!/usr/bin/perl
+# debbugs-installsql installs the SQL database using DBIx::Class::DeploymentHandler
+# and is released under the terms of the GNU GPL version 3, or any
+# later version, at your option. See the file README and COPYING for
+# more information.
+# Copyright 2013-2014 by Don Armstrong <don@donarmstrong.com>.
+
+
+use warnings;
+use strict;
+
+use Getopt::Long;
+use Pod::Usage;
+
+=head1 NAME
+
+debbugs-installsql - installs the SQL database using DBIx::Class::DeploymentHandler
+
+=head1 SYNOPSIS
+
+debbugs-installsql [ --upgrade | --install ]
+
+ Options:
+  --service postgresql service to connect to
+  --sysconfdir postgresql system configuration directory
+  --deployment-dir SQL deployment directory
+  --debug, -d debugging level (Default 0)
+  --help, -h display this help
+  --man, -m display manual
+
+=head1 OPTIONS
+
+=over
+
+=item B<--service>
+
+Postgresl service to connect to (defaults to debbugs)
+
+=item B<--sysconfdir>
+
+Postgresql sysconf dir. May also be set using the PGSYSCONFDIR
+environmental variable (which this option overrides).
+
+=item B<--deployment-dir>
+
+Deployment directory (defaults to /usr/share/debbugs/sqldeployment)
+
+=item B<--debug, -d>
+
+Debug verbosity. (Default 0)
+
+=item B<--help, -h>
+
+Display brief usage information.
+
+=item B<--man, -m>
+
+Display this manual.
+
+=back
+
+=head1 EXAMPLES
+
+debbugs-installsql
+
+=cut
+
+
+use vars qw($DEBUG);
+
+use Debbugs::DB;
+use Debbugs::DB::Util qw(prepare_execute);
+use aliased 'DBIx::Class::DeploymentHandler' => 'DH';
+
+my %options = (debug           => 0,
+              help            => 0,
+              man             => 0,
+               developer_prepare => 0,
+               overwrite_deployment => 0,
+               service         => 'debbugs',
+               deployment_dir  => '/usr/share/debbugs/sqldeployment',
+              );
+
+GetOptions(\%options,
+           'service|s=s',
+           'sysconfdir|c=s',
+           'install',
+           'install_version_storage|install-version-storage',
+           'upgrade',
+           'current_version|current-version',
+           'developer_prepare|developer-prepare',
+           'overwrite_deployment|overwrite-deployment|force_overwrite|force-overwrite',
+           'deployment_dir|deployment-dir=s',
+          'debug|d+','help|h|?','man|m');
+
+pod2usage() if $options{help};
+pod2usage({verbose=>2}) if $options{man};
+
+$DEBUG = $options{debug};
+
+my @USAGE_ERRORS;
+
+my @exclusive_options = qw(install upgrade current_version install_version_storage);
+if (1 < grep {exists $options{$_}} @exclusive_options) {
+      push @USAGE_ERRORS,"You must only give one of the ".
+          join(', ',map {s/_/-/g; "--".$_} @exclusive_options).
+          " options";
+}
+if (not grep {exists $options{$_}} @exclusive_options) {
+    $options{current_version} = 1;
+}
+
+pod2usage(join("\n",@USAGE_ERRORS)) if @USAGE_ERRORS;
+
+if (exists $options{sysconfdir}) {
+    if (not defined $options{sysconfdir} or not length $options{sysconfdir}) {
+       delete $ENV{PGSYSCONFDIR};
+    } else {
+       $ENV{PGSYSCONFDIR} = $options{sysconfdir};
+    }
+}
+
+
+my $schema = Debbugs::DB->connect('dbi:Pg:service='.$options{service}) or
+    die "Unable to connect to database";
+
+
+my $dh = DH->new({schema => $schema,
+                  force_overwrite => $options{overwrite_deployment},
+                  script_directory => $options{deployment_dir},
+                  databases => 'PostgreSQL',
+                 sql_translator_args => {producer_args=> {postgres_version => 9}},
+                 });
+
+if ($options{current_version}) {
+    print "The current database version is: ".$dh->database_version."\n";
+    exit 0;
+} elsif ($options{install}) {
+    $dh->prepare_install if $options{developer_prepare};
+    $dh->install unless $options{developer_prepare};
+    ## this is lame, but because the current release of DeploymentHandler does
+    ## not support WHERE or quoted indexes properly (fixed in git), we create
+    ## these indexes manually here.
+    $schema->storage->
+       dbh_do(sub{my ($s,$dbh) = @_;
+                  prepare_execute($dbh,<<SQL);
+CREATE UNIQUE INDEX bug_status_cache_bug_col_suite_col_arch_idx ON
+ bug_status_cache(bug,COALESCE(suite,0),COALESCE(arch,0));
+CREATE UNIQUE INDEX bug_status_cache_bug_suite_idx ON
+ bug_status_cache(bug,suite) WHERE arch is NULL;
+CREATE UNIQUE INDEX bug_status_cache_bug_idx ON
+ bug_status_cache(bug) WHERE arch is NULL AND suite IS NULL;
+SQL
+                  });
+} elsif ($options{upgrade}) {
+    $dh->prepare_deploy if $options{developer_prepare};
+    $dh->prepare_upgrade() if $options{developer_prepare};
+    $dh->upgrade unless $options{developer_prepare};
+} elsif ($options{install_version_storage}) {
+    $dh->prepare_version_storage_install if $options{developer_prepare};
+    $dh->install_version_storage unless $options{developer_prepare};
+}
+
+
+__END__
diff --git a/bin/debbugs-loadsql b/bin/debbugs-loadsql
new file mode 100755 (executable)
index 0000000..f343c97
--- /dev/null
@@ -0,0 +1,761 @@
+#! /usr/bin/perl
+# debbugs-loadsql is part of debbugs, and is released
+# under the terms of the GPL version 2, or any later version, at your
+# option. See the file README and COPYING for more information.
+# Copyright 2012 by Don Armstrong <don@donarmstrong.com>.
+
+
+use warnings;
+use strict;
+
+use Getopt::Long qw(:config no_ignore_case);
+use Pod::Usage;
+
+=head1 NAME
+
+debbugs-loadsql -- load debbugs sql database
+
+=head1 SYNOPSIS
+
+debbugs-loadsql [options] [subcommand]
+
+ Subcommands:
+  bugs help versions configuration
+  suites logs packages debinfo
+ Options:
+  --quick, -q only load changed things
+  --progress Show progress bar
+  --service, -s service name
+  --sysconfdir, -c postgresql service config dir
+  --spool-dir debbugs spool directory
+  --debug, -d debugging level (Default 0)
+  --help, -h display this help
+  --man, -m display manual
+
+=head1 SUBCOMMANDS
+
+=head2 help
+
+Display this manual
+
+=head2 bugs
+
+Add bugs (subject, number, etc) to the database
+
+   --preload create all bugs first, then add information
+
+=head2 versions
+
+Add version descendant information (which version is based on which version) to
+the database
+
+=head2 maintainers
+
+Add source maintainers to the BTS
+
+=head2 configuration
+
+Add debbugs configuration information (tags, severity, etc)
+
+=head2 suites
+
+Add suite information from ftp distribution
+
+  --ftpdists location of FTP mirror
+
+=head2 logs
+
+Add bug logs
+
+=head2 packages
+
+Add package information from the ftp archive
+
+  --ftpdists location of FTP mirror
+  --suites Suite to operate on
+
+=head2 debinfo
+
+Add package information from a debinfo file
+
+  --null -0 names of debinfo files are null separated
+
+=head1 OPTIONS
+
+=over
+
+=item B<--quick, -q>
+
+Only load changed bugs
+
+=item B<--progress>
+
+Show progress bar (requires Term::ProgressBar)
+
+=item B<--service,-s>
+
+Postgreql service to use; defaults to debbugs
+
+=item B<--sysconfdir,-c>
+
+System configuration directory to use; if not set, defaults to the
+postgresql default. [Operates by setting PGSYSCONFDIR]
+
+=item B<--spool-dir>
+
+Debbugs spool directory; defaults to the value configured in the
+debbugs configuration file.
+
+=item B<--verbose>
+
+Output more information about what is happening. Probably not useful
+if you also set --progress.
+
+=item B<--debug, -d>
+
+Debug verbosity.
+
+=item B<--help, -h>
+
+Display brief useage information.
+
+=item B<--man, -m>
+
+Display this manual.
+
+=back
+
+
+=cut
+
+
+use vars qw($DEBUG);
+
+use Debbugs::Common (qw(checkpid lockpid get_hashname getparsedaddrs getbugcomponent make_list getsourcemaintainers),
+                    qw(hash_slice open_compressed_file),);
+use Debbugs::Config qw(:config);
+use Debbugs::Status qw(read_bug split_status_fields);
+use Debbugs::Log;
+use Debbugs::DB;
+use Debbugs::DB::Load qw(:load_bug :load_package :load_suite);
+use DateTime;
+use File::stat;
+use File::Basename;
+use File::Spec;
+use IO::Dir;
+use IO::File;
+use IO::Uncompress::AnyUncompress;
+use Encode qw(decode_utf8);
+use List::MoreUtils qw(natatime);
+
+my %options =
+    (debug           => 0,
+     help            => 0,
+     man             => 0,
+     verbose         => 0,
+     quiet           => 0,
+     quick           => 0,
+     service         => $config{debbugs_db},
+     progress        => 0,
+    );
+
+Getopt::Long::Configure('pass_through');
+GetOptions(\%options,
+           'quick|q',
+           'service|s=s',
+           'sysconfdir|c=s',
+           'progress!',
+           'spool_dir|spool-dir=s',
+           'verbose|v+',
+           'quiet+',
+           'debug|d+','help|h|?','man|m');
+Getopt::Long::Configure('default');
+
+pod2usage() if $options{help};
+pod2usage({verbose=>2}) if $options{man};
+
+$DEBUG = $options{debug};
+
+my %subcommands =
+    ('bugs' => {function => \&add_bugs,
+               arguments => {'preload' => 0},
+               },
+     'versions' => {function => \&add_versions,
+                   },
+     'debinfo' => {function => \&add_debinfo,
+                   arguments => {'0|null' => 0},
+                  },
+     'maintainers' => {function => \&add_maintainers,
+                      },
+     'configuration' => {function => \&add_configuration,
+                        },
+     'suites' => {function => \&add_suite,
+                 arguments => {'ftpdists=s' => 1,
+                              },
+                 },
+     'logs' => {function => \&add_logs,
+               },
+     'packages' => {function => \&add_packages,
+                   arguments => {'ftpdists=s' => 1,
+                                 'suites=s@' => 0,
+                                },
+                  },
+     'help' => {function => sub {pod2usage({verbose => 2});}}
+    );
+
+my @USAGE_ERRORS;
+$options{verbose} = $options{verbose} - $options{quiet};
+
+if ($options{progress}) {
+    eval "use Term::ProgressBar";
+    push @USAGE_ERRORS, "You asked for a progress bar, but Term::ProgressBar isn't installed" if $@;
+}
+
+
+pod2usage(join("\n",@USAGE_ERRORS)) if @USAGE_ERRORS;
+
+if (exists $options{sysconfdir}) {
+    if (not defined $options{sysconfdir} or not length $options{sysconfdir}) {
+        delete $ENV{PGSYSCONFDIR};
+    } else {
+        $ENV{PGSYSCONFDIR} = $options{sysconfdir};
+    }
+}
+
+if (exists $options{spool_dir} and defined $options{spool_dir}) {
+    $config{spool_dir} = $options{spool_dir};
+}
+
+my $prog_bar;
+if ($options{progress}) {
+    $prog_bar = eval "Term::ProgressBar->new({count => 1,ETA=>q(linear)})";
+    warn "Unable to initialize progress bar: $@" if not $prog_bar;
+}
+
+
+my ($subcommand) = shift @ARGV;
+if (not defined $subcommand) {
+    $subcommand = 'help';
+    print STDERR "You must provide a subcommand; displaying usage.\n";
+    pod2usage();
+} elsif (not exists $subcommands{$subcommand}) {
+    print STDERR "$subcommand is not a valid subcommand; displaying usage.\n";
+    pod2usage();
+}
+
+binmode(STDOUT,':encoding(UTF-8)');
+binmode(STDERR,':encoding(UTF-8)');
+
+my $opts =
+    handle_subcommand_arguments(\@ARGV,$subcommands{$subcommand}{arguments});
+$subcommands{$subcommand}{function}->(\%options,$opts,$prog_bar,\%config,\@ARGV);
+
+sub add_bugs {
+    my ($options,$opts,$p,$config,$argv) = @_;
+    chdir($config->{spool_dir}) or
+        die "chdir $config->{spool_dir} failed: $!";
+
+    my $verbose = $options->{debug};
+
+    my $initialdir = "db-h";
+
+    if (defined $argv->[0] and $argv->[0] eq "archive") {
+        $initialdir = "archive";
+    }
+    my $s = db_connect($options);
+
+
+    my $time = 0;
+    my $start_time = time;
+    my %tags;
+    my %severities;
+    my %queue;
+
+    if ($opts->{preload}) {
+       my @bugs;
+       walk_bugs([(@{$argv}?@{$argv} : $initialdir)],
+                 undef,
+                 'summary',
+                 undef,
+                 sub {
+                   push @bugs,@_;
+                 },
+                 10000
+                );
+       $s->resultset('Bug')->quick_insert_bugs(@bugs);
+    }
+    walk_bugs([(@{$argv}?@{$argv} : $initialdir)],
+              $p,
+              'summary',
+              $verbose,
+              sub {
+               my @bugs = @_;
+               my @bugs_to_update;
+               if ($options{quick}) {
+                 for my $bug (@bugs) {
+                   my $stat = stat(getbugcomponent($bug,'summary',$initialdir));
+                   if (not defined $stat) {
+                      print STDERR "Unable to stat $bug $!\n";
+                      next;
+                   }
+                   my $rs = $s->resultset('Bug')->search({id=>$bug})->single();
+                   next if defined $rs and $stat->mtime <= $rs->last_modified()->epoch();
+                   push @bugs_to_update, $bug;
+                  }
+               } else {
+                 @bugs_to_update = @bugs;
+               }
+               eval {
+                 $s->txn_do(sub {
+                              for my $bug (@bugs_to_update) {
+                                load_bug(db => $s,
+                                         bug => $bug,
+                                         tags => \%tags,
+                                         severities => \%severities,
+                                         queue => \%queue);
+                              }
+                            });
+               };
+               if ($@) {
+                 die "failure while trying to load bug: $@";
+               }
+              },
+             50
+             );
+    handle_load_bug_queue(db => $s,
+                          queue => \%queue);
+}
+
+sub add_versions {
+    my ($options,$opts,$p,$config,$argv) = @_;
+
+    my $s = db_connect($options);
+
+    my @files = @{$argv};
+    $p->target(scalar @files) if $p;
+    for my $file (@files) {
+        my $fh = IO::File->new($file,'r') or
+            die "Unable to open $file for reading: $!";
+        my @versions;
+        my %src_pkgs;
+        while (<$fh>) {
+            chomp;
+            next unless length $_;
+            if (/(\w[-+0-9a-z.]+) \(([^\(\) \t]+)\)/) {
+                push @versions, [$1,$2];
+            }
+        }
+        close($fh);
+        my $ancestor_sv;
+        for my $i (reverse 0..($#versions)) {
+            my $sp;
+            if (not defined $src_pkgs{$versions[$i][0]}) {
+                $src_pkgs{$versions[$i][0]} =
+                    $s->resultset('SrcPkg')->
+                   get_src_pkg_id($versions[$i][0]);
+            }
+            $sp = $src_pkgs{$versions[$i][0]};
+            # There's probably something wrong if the source package
+            # doesn't exist, but we'll skip it for now
+            last if not defined $sp;
+            my $sv = $s->resultset('SrcVer')->find({src_pkg=>$sp,
+                                                    ver => $versions[$i][1],
+                                                   });
+           last if not defined $sv;
+            if (defined $ancestor_sv and defined $sv and not defined $sv->based_on()) {
+                $sv->update({based_on => $ancestor_sv})
+            }
+            $ancestor_sv = $sv->id();
+        }
+        $p->update() if $p;
+    }
+    $p->remove() if $p;
+}
+
+sub add_debinfo {
+    my ($options,$opts,$p,$config,$argv) = @_;
+
+    my @files = @{$argv};
+    if (not @files) {
+       {
+          local $/ = "\n";
+           local $/ = "\0" if $opts->{0};
+           while (<STDIN>) {
+              s/\n$// unless $opts->{0};
+              s/\0$// if $opts->{0};
+               push @files, $_;
+           }
+       }
+    }
+    return unless @files;
+    my $s = db_connect($options);
+    $p->target(scalar @files) if $p;
+    my $it = natatime 100, @files;
+    while (my @v = $it->()) {
+       my %cache;
+       my @debinfos;
+       for my $file (@v) {
+           my $fh = IO::File->new($file,'r') or
+               die "Unable to open $file for reading: $!";
+           my $f_stat = stat($file);
+           my $ct_date = DateTime->from_epoch(epoch => $f_stat->ctime);
+           while (<$fh>) {
+               chomp;
+               next unless length $_;
+               my ($binname, $binver, $binarch, $srcname, $srcver) = split;
+               # if $srcver is not defined, this is probably a broken
+               # .debinfo file [they were causing #686106, see commit
+               # 49c85ab8 in dak.] Basically, $binarch didn't get put into
+               # the file, so we'll fudge it from the filename.
+               if (not defined $srcver) {
+                   ($srcname,$srcver) = ($binarch,$srcname);
+                   ($binarch) = $file =~ /_([^\.]+)\.debinfo/;
+               }
+               if (not defined $srcver) {
+                   print STDERR "malformed debinfo (no srcver): $file\n";
+                   next;
+               }
+               push @debinfos,
+                   [$binname,$binver,$binarch,$srcname,$srcver,$ct_date];
+           }
+       }
+       $s->txn_do(
+           sub {
+               for my $di (@debinfos) {
+                   Debbugs::DB::Load::load_debinfo($s,@{$di}[0..5],\%cache);
+               }
+           });
+       $p->update($p->last_update()+@v) if $p;
+    }
+    $p->remove() if $p;
+}
+
+sub add_maintainers {
+    my ($options,$opts,$p,$config,$argv) = @_;
+
+    my $s = db_connect($options);
+    my $maintainers = getsourcemaintainers();
+    $p->target(2) if $p;
+    ## get all of the maintainers, and add the missing ones
+    my $maints = $s->resultset('Maintainer')->
+       get_maintainers(values %{$maintainers});
+    $p->update();
+    my @svs = $s->resultset('SrcVer')->
+       search({maintainer => undef
+              },
+             {join => 'src_pkg',
+              group_by => 'me.src_pkg, src_pkg.pkg',
+              result_class => 'DBIx::Class::ResultClass::HashRefInflator',
+              columns => [qw(me.src_pkg src_pkg.pkg)],
+             }
+             )->all();
+    $p->target(2+@svs) if $p;
+    $p->update() if $p;
+    for my $sv (@svs) {
+       if (exists $maintainers->{$sv->{src_pkg}{pkg}}) {
+           my $pkg = $sv->{src_pkg}{pkg};
+           my $maint = $maints->
+              {$maintainers->{$pkg}};
+           $s->txn_do(sub {$s->resultset('SrcVer')->
+                               search({maintainer => undef,
+                                       'src_pkg.pkg' => $pkg
+                                      },
+                                     {join => 'src_pkg'}
+                                     )->update({maintainer => $maint})
+                                 });
+       }
+       $p->update() if $p;
+    }
+    $p->remove() if $p;
+}
+
+sub add_configuration {
+    my ($options,$opts,$p,$config,$argv) = @_;
+
+    my $s = db_connect($options);
+
+    # tags
+    # add all tags
+    my %tags;
+    for my $tag (@{$config{tags}}) {
+       $tags{$tag} = 1;
+       $s->resultset('Tag')->find_or_create({tag => $tag});
+    }
+    # mark obsolete tags
+    for my $tag ($s->resultset('Tag')->search_rs()->all()) {
+       next if exists $tags{$tag->tag};
+       $tag->obsolete(1);
+       $tag->update;
+    }
+
+    # severities
+    my %sev_names;
+    my $order = -1;
+    for my $sev_name (($config{default_severity},@{$config{severity_list}})) {
+        # add all severitites
+        my $sev = $s->resultset('Severity')->find_or_create({severity => $sev_name});
+        # mark strong severities
+        if (grep {$_ eq $sev_name} @{$config{strong_severities}}) {
+            $sev->strong(1);
+        }
+        $sev->ordering($order);
+        $sev->update();
+        $order++;
+        $sev_names{$sev_name} = 1;
+    }
+    # mark obsolete severities
+    for my $sev ($s->resultset('Severity')->search_rs()->all()) {
+        next if exists $sev_names{$sev->severity()};
+        $sev->obsolete(1);
+        $sev->update();
+    }
+}
+
+sub add_suite {
+    my ($options,$opts,$p,$config,$argv) = @_;
+    # suites
+
+    my $s = db_connect($options);
+    my $dist_dir = IO::Dir->new($opts->{ftpdists});
+    my @dist_names =
+       grep { $_ !~ /^\./ and
+              -d $opts->{ftpdists}.'/'.$_ and
+              not -l $opts->{ftpdists}.'/'.$_
+          } $dist_dir->read;
+    while (my $dist = shift @dist_names) {
+       my $dist_dir = $opts->{ftpdists}.'/'.$dist;
+       my ($dist_info,$package_files) =
+           read_release_file($dist_dir.'/Release');
+       load_suite($s,$dist_info);
+    }
+}
+
+sub add_logs {
+    my ($options,$opts,$p,$config,$argv) = @_;
+
+    chdir($config->{spool_dir}) or
+        die "chdir $config->{spool_dir} failed: $!";
+
+    my $verbose = $options->{debug};
+
+    my $initialdir = "db-h";
+
+    if (defined $argv->[0] and $argv->[0] eq "archive") {
+        $initialdir = "archive";
+    }
+    my $s = db_connect($options);
+
+
+    my $time = 0;
+    my $start_time = time;
+
+    walk_bugs([(@{$argv}?@{$argv} : $initialdir)],
+              $p,
+              'log',
+              $verbose,
+              sub {
+                  my $bug = shift;
+                 my $stat = stat(getbugcomponent($bug,'log',$initialdir));
+                  if (not defined $stat) {
+                      print STDERR "Unable to stat $bug $!\n";
+                      next;
+                  }
+                  if ($options{quick}) {
+                      my $rs = $s->resultset('Bug')->
+                         search({id=>$bug})->single();
+                      return if defined $rs and
+                         $stat->mtime <= $rs->last_modified()->epoch();
+                  }
+                  eval {
+                      load_bug_log(db => $s,
+                                   bug => $bug);
+                  };
+                  if ($@) {
+                      die "failure while trying to load bug log $bug\n$@";
+                  }
+              });
+}
+
+sub add_packages {
+    my ($options,$opts,$p,$config,$argv) = @_;
+
+    my $dist_dir = IO::Dir->new($opts->{ftpdists});
+    my @dist_names =
+       grep { $_ !~ /^\./ and
+              -d $opts->{ftpdists}.'/'.$_ and
+              not -l $opts->{ftpdists}.'/'.$_
+          } $dist_dir->read;
+    my %s_p;
+    while (my $dist = shift @dist_names) {
+       my $dist_dir = $opts->{ftpdists}.'/'.$dist;
+       my ($dist_info,$package_files) =
+           read_release_file($dist_dir.'/Release');
+       $s_p{$dist_info->{Codename}} = $package_files;
+    }
+    my $tot = 0;
+    for my $suite (keys %s_p) {
+       for my $component (keys %{$s_p{$suite}}) {
+           $tot += scalar keys %{$s_p{$suite}{$component}};
+       }
+    }
+    $p->target($tot) if $p;
+    my $i = 0;
+    my $avg_pkgs = 0;
+    my $tot_suites = scalar keys %s_p;
+    my $done_suites=0;
+    my $completed_pkgs=0;
+    # parse packages files
+    for my $suite (keys %s_p) {
+       my @pkgs;
+       for my $component (keys %{$s_p{$suite}}) {
+           my @archs = keys %{$s_p{$suite}{$component}};
+           if (grep {$_ eq 'source'} @archs) {
+               @archs = ('source',grep {$_ ne 'source'} @archs);
+           }
+           for my $arch (@archs) {
+               my $pfh =  open_compressed_file($s_p{$suite}{$component}{$arch}) or
+                   die "Unable to open $s_p{$suite}{$component}{$arch} for reading: $!";
+               local $_;
+               local $/ = '';  # paragraph mode
+               while (<$pfh>) {
+                   my %pkg;
+                   for my $field (qw(Package Maintainer Version Source)) {
+                       /^\Q$field\E: (.*)/m;
+                       $pkg{$field} = $1;
+                   }
+                   next unless defined $pkg{Package} and
+                       defined $pkg{Version};
+                   push @pkgs,[$arch,$component,\%pkg];
+               }
+           }
+       }
+       my $s = db_connect($options);
+       if ($avg_pkgs==0) {
+           $avg_pkgs = @pkgs;
+       }
+        $p->target($avg_pkgs*($tot_suites-$done_suites-1)+
+                  $completed_pkgs+@pkgs) if $p;
+       load_packages($s,
+                     $suite,
+                     \@pkgs,
+                     $p);
+       $avg_pkgs=($avg_pkgs*$done_suites + @pkgs)/($done_suites+1);
+       $completed_pkgs += @pkgs;
+       $done_suites++;
+    }
+    $p->remove() if $p;
+}
+
+sub handle_subcommand_arguments {
+    my ($argv,$args) = @_;
+    my $subopt = {};
+    Getopt::Long::GetOptionsFromArray($argv,
+                              $subopt,
+                              keys %{$args},
+                             );
+    my @usage_errors;
+    for my $arg  (keys %{$args}) {
+        next unless $args->{$arg};
+        my $r_arg = $arg; # real argument name
+        $r_arg =~ s/[=\|].+//g;
+        if (not defined $subopt->{$r_arg}) {
+            push @usage_errors, "You must give a $r_arg option";
+        }
+    }
+    pod2usage(join("\n",@usage_errors)) if @usage_errors;
+    return $subopt;
+}
+
+sub get_lock{
+    my ($subcommand,$config,$options) = @_;
+    if (not lockpid($config->{spool_dir}.'/lock/debbugs-loadsql-$subcommand')) {
+        if ($options->{quick}) {
+            # If this is a quick run, just exit
+            print STDERR "Another debbugs-loadsql is running; stopping\n" if $options->{verbose};
+            exit 0;
+        }
+        print STDERR "Another debbugs-loadsql is running; stopping\n";
+        exit 1;
+    }
+}
+
+sub db_connect {
+    my ($options) = @_;
+    # connect to the database; figure out how to handle errors
+    # properly here.
+    my $s = Debbugs::DB->connect($options->{service}) or
+        die "Unable to connect to database: ";
+}
+
+sub read_release_file {
+    my ($file) = @_;
+    # parse release
+    my $rfh =  open_compressed_file($file) or
+       die "Unable to open $file for reading: $!";
+    my %dist_info;
+    my $in_sha1;
+    my %p_f;
+    while (<$rfh>) {
+       chomp;
+       if (s/^(\S+):\s*//) {
+           if ($1 eq 'SHA1'or $1 eq 'SHA256') {
+               $in_sha1 = 1;
+               next;
+           }
+           $dist_info{$1} = $_;
+       } elsif ($in_sha1) {
+           s/^\s//;
+           my ($sha,$size,$f) = split /\s+/,$_;
+           next unless $f =~ /(?:Packages|Sources)(?:\.gz|\.xz)$/;
+           next unless $f =~ m{^([^/]+)/([^/]+)/([^/]+)$};
+           my ($component,$arch,$package_source) = ($1,$2,$3);
+           $arch =~ s/binary-//;
+           next if exists $p_f{$component}{$arch};
+           $p_f{$component}{$arch} = File::Spec->catfile(dirname($file),$f);
+       }
+    }
+    return (\%dist_info,\%p_f);
+}
+
+sub walk_bugs {
+    my ($dirs,$p,$what,$verbose,$sub,$n) = @_;
+    my @dirs = @{$dirs};
+    my $tot_dirs = @dirs;
+    my $done_dirs = 0;
+    my $avg_subfiles = 0;
+    my $completed_files = 0;
+    $n //= 1;
+    while (my $dir = shift @dirs) {
+        printf "Doing dir %s ...\n", $dir if $verbose;
+
+        opendir(DIR, "$dir/.") or die "opendir $dir: $!";
+        my @subdirs = readdir(DIR);
+        closedir(DIR);
+
+        my @list = map { m/^(\d+)\.$what$/?($1):() } @subdirs;
+        $tot_dirs -= @dirs;
+        push @dirs, map { m/^(\d+)$/ && -d "$dir/$1"?("$dir/$1"):() } @subdirs;
+        $tot_dirs += @dirs;
+        if ($avg_subfiles == 0) {
+            $avg_subfiles = @list;
+        }
+
+        $p->target($avg_subfiles*($tot_dirs-$done_dirs)+$completed_files+@list) if $p;
+        $avg_subfiles = ($avg_subfiles * $done_dirs + @list) / ($done_dirs+1);
+        $done_dirs += 1;
+
+       my $it = natatime $n,@list;
+       while (my @bugs = $it->()) {
+         $sub->(@bugs);
+         $completed_files += scalar @bugs;
+         $p->update($completed_files) if $p;
+         print "Up to $completed_files bugs...\n"
+           if ($completed_files % 100 == 0 && $verbose);
+        }
+    }
+    $p->remove() if $p;
+}
+
+
+
+__END__
diff --git a/bin/debbugs-loadsql-debinfo b/bin/debbugs-loadsql-debinfo
new file mode 100755 (executable)
index 0000000..98b2d29
--- /dev/null
@@ -0,0 +1,156 @@
+#! /usr/bin/perl
+# debbugs-loadsql-debinfo is part of debbugs, and is released
+# under the terms of the GPL version 2, or any later version, at your
+# option. See the file README and COPYING for more information.
+# Copyright 2012 by Don Armstrong <don@donarmstrong.com>.
+
+
+use warnings;
+use strict;
+
+use Getopt::Long qw(:config no_ignore_case);
+use Pod::Usage;
+
+=head1 NAME
+
+debbugs-loadsql-debinfo -- load debbugs sql versions database
+
+=head1 SYNOPSIS
+
+debbugs-loadsql-debinfo [options]
+
+ Options:
+  --service, -s service name
+  --sysconfdir, -c postgresql service config dir
+  --debug, -d debugging level (Default 0)
+  --help, -h display this help
+  --man, -m display manual
+
+=head1 OPTIONS
+
+=over
+
+=item B<--quick, -q>
+
+Only load changed bugs
+
+=item B<--service,-s>
+
+Postgreql service to use; defaults to debbugs
+
+=item B<--sysconfdir,-c>
+
+System configuration directory to use; if not set, defaults to the
+postgresql default. [Operates by setting PGSYSCONFDIR]
+
+=item B<--debug, -d>
+
+Debug verbosity.
+
+=item B<--help, -h>
+
+Display brief useage information.
+
+=item B<--man, -m>
+
+Display this manual.
+
+=back
+
+
+=cut
+
+
+use vars qw($DEBUG);
+
+use Debbugs::Common qw(checkpid lockpid get_hashname getparsedaddrs getbugcomponent make_list);
+use Debbugs::Config qw(:config);
+use Debbugs::Status qw(read_bug split_status_fields);
+use Debbugs::Log;
+use Debbugs::DB;
+use DateTime;
+use File::stat;
+
+
+my %options = (debug           => 0,
+              help            => 0,
+              man             => 0,
+              verbose         => 0,
+              quiet           => 0,
+              quick           => 0,
+              service         => 'debbugs',
+             );
+
+
+GetOptions(\%options,
+          'quick|q',
+          'service|s',
+          'sysconfdir|c',
+          'debug|d+','help|h|?','man|m');
+
+pod2usage() if $options{help};
+pod2usage({verbose=>2}) if $options{man};
+
+$DEBUG = $options{debug};
+
+my @USAGE_ERRORS;
+$options{verbose} = $options{verbose} - $options{quiet};
+
+pod2usage(join("\n",@USAGE_ERRORS)) if @USAGE_ERRORS;
+
+if (exists $options{sysconfdir}) {
+    if (not defined $options{sysconfdir} or not length $options{sysconfdir}) {
+       delete $ENV{PGSYSCONFDIR};
+    } else {
+       $ENV{PGSYSCONFDIR} = $options{sysconfdir};
+    }
+}
+
+my $verbose = $options{debug};
+
+my $initialdir = "db-h";
+
+# connect to the database; figure out how to handle errors properly
+# here.
+my $s = Debbugs::DB->connect('dbi:Pg:service='.$options{service}) or
+    die "Unable to connect to database: ";
+
+my @files = @ARGV;
+
+my %arch;
+for my $file (@files) {
+    my $fh = IO::File->new($file,'r') or
+       die "Unable to open $file for reading: $!";
+    while (<$fh>) {
+       chomp;
+       next unless length $_;
+       my ($binname, $binver, $binarch, $srcname, $srcver) = split;
+       # if $srcver is not defined, this is probably a broken
+       # .debinfo file [they were causing #686106, see commit
+       # 49c85ab8 in dak.] Basically, $binarch didn't get put into
+       # the file, so we'll fudge it from the filename.
+       if (not defined $srcver) {
+           ($srcname,$srcver) = ($binarch,$srcname);
+           ($binarch) = $file =~ /_([^\.]+)\.debinfo/;
+       }
+       my $sp = $s->resultset('SrcPkg')->find_or_create({pkg => $srcname});
+       my $sv = $s->resultset('SrcVer')->find_or_create({src_pkg_id=>$sp->id(),
+                                                         ver => $srcver});
+        my $arch;
+        if (defined $arch{$binarch}) {
+            $arch = $arch{$binarch};
+        } else {
+            $arch = $s->resultset('Arch')->find_or_create({arch => $binarch});
+            $arch{$binarch} = $arch;
+        }
+       my $bp = $s->resultset('BinPkg')->find_or_create({pkg => $binname});
+       $s->resultset('BinVer')->find_or_create({bin_pkg_id => $bp->id(),
+                                                src_ver_id => $sv->id(),
+                                                arch_id    => $arch->id(),
+                                                ver        => $binver,
+                                               });
+    }
+}
+
+
+__END__
diff --git a/bin/debbugs-loadsql-versions b/bin/debbugs-loadsql-versions
new file mode 100755 (executable)
index 0000000..44d1a8b
--- /dev/null
@@ -0,0 +1,153 @@
+#! /usr/bin/perl
+# debbugs-loadsql-versions is part of debbugs, and is released
+# under the terms of the GPL version 2, or any later version, at your
+# option. See the file README and COPYING for more information.
+# Copyright 2012 by Don Armstrong <don@donarmstrong.com>.
+
+
+use warnings;
+use strict;
+
+use Getopt::Long qw(:config no_ignore_case);
+use Pod::Usage;
+
+=head1 NAME
+
+debbugs-loadsql-versions -- load debbugs sql versions database
+
+=head1 SYNOPSIS
+
+debbugs-loadsql-versions [options]
+
+ Options:
+  --service, -s service name
+  --sysconfdir, -c postgresql service config dir
+  --debug, -d debugging level (Default 0)
+  --help, -h display this help
+  --man, -m display manual
+
+=head1 OPTIONS
+
+=over
+
+=item B<--quick, -q>
+
+Only load changed bugs
+
+=item B<--service,-s>
+
+Postgreql service to use; defaults to debbugs
+
+=item B<--sysconfdir,-c>
+
+System configuration directory to use; if not set, defaults to the
+postgresql default. [Operates by setting PGSYSCONFDIR]
+
+=item B<--debug, -d>
+
+Debug verbosity.
+
+=item B<--help, -h>
+
+Display brief useage information.
+
+=item B<--man, -m>
+
+Display this manual.
+
+=back
+
+
+=cut
+
+
+use vars qw($DEBUG);
+
+use Debbugs::Common qw(checkpid lockpid get_hashname getparsedaddrs getbugcomponent make_list);
+use Debbugs::Config qw(:config);
+use Debbugs::Status qw(read_bug split_status_fields);
+use Debbugs::Log;
+use Debbugs::DB;
+use DateTime;
+use File::stat;
+
+
+my %options = (debug           => 0,
+              help            => 0,
+              man             => 0,
+              verbose         => 0,
+              quiet           => 0,
+              quick           => 0,
+              service         => 'debbugs',
+             );
+
+
+GetOptions(\%options,
+          'quick|q',
+          'service|s',
+          'sysconfdir|c',
+          'spool_dir|spool-dir=s',
+          'debug|d+','help|h|?','man|m');
+
+pod2usage() if $options{help};
+pod2usage({verbose=>2}) if $options{man};
+
+$DEBUG = $options{debug};
+
+my @USAGE_ERRORS;
+$options{verbose} = $options{verbose} - $options{quiet};
+
+pod2usage(join("\n",@USAGE_ERRORS)) if @USAGE_ERRORS;
+
+if (exists $options{sysconfdir}) {
+    if (not defined $options{sysconfdir} or not length $options{sysconfdir}) {
+       delete $ENV{PGSYSCONFDIR};
+    } else {
+       $ENV{PGSYSCONFDIR} = $options{sysconfdir};
+    }
+}
+
+my $verbose = $options{debug};
+
+# connect to the database; figure out how to handle errors properly
+# here.
+my $s = Debbugs::DB->connect('dbi:Pg:service='.$options{service}) or
+    die "Unable to connect to database: ";
+
+my @files = @ARGV;
+for my $file (@files) {
+    my $fh = IO::File->new($file,'r') or
+       die "Unable to open $file for reading: $!";
+    my @versions;
+    my %src_pkgs;
+    while (<$fh>) {
+       chomp;
+       next unless length $_;
+       if (/(\w[-+0-9a-z.]+) \(([^\(\) \t]+)\)/) {
+           push @versions, [$1,$2];
+       }
+    }
+    close($fh);
+    my $ancestor_sv;
+    for my $i (reverse 0..($#versions)) {
+        my $sp;
+        if (not defined $src_pkgs{$versions[$i][0]}) {
+            $src_pkgs{$versions[$i][0]} =
+                $s->resultset('SrcPkg')->find({pkg => $versions[$i][0]});
+        }
+        $sp = $src_pkgs{$versions[$i][0]};
+        # There's probably something wrong if the source package
+        # doesn't exist, but we'll skip it for now
+       next unless defined $sp;
+       my $sv = $s->resultset('SrcVer')->find({src_pkg_id=>$sp->id(),
+                                               ver => $versions[$i][1],
+                                              });
+       if (defined $ancestor_sv and defined $sv and not defined $sv->based_on()) {
+           $sv->update({based_on => $ancestor_sv->id()})
+       }
+       $ancestor_sv = $sv;
+    }
+}
+
+
+__END__
diff --git a/bin/debbugs-updatesqlcache b/bin/debbugs-updatesqlcache
new file mode 100755 (executable)
index 0000000..057757b
--- /dev/null
@@ -0,0 +1,406 @@
+#! /usr/bin/perl
+# debbugs-updatesqlcache is part of debbugs, and is released
+# under the terms of the GPL version 2, or any later version, at your
+# option. See the file README and COPYING for more information.
+# Copyright 2016 by Don Armstrong <don@donarmstrong.com>.
+
+
+use warnings;
+use strict;
+
+use Getopt::Long qw(:config no_ignore_case);
+use Pod::Usage;
+
+=head1 NAME
+
+debbugs-updatesqlcache -- Update Debbugs SQL Cache
+
+=head1 SYNOPSIS
+
+debbugs-updatesqlcache [options]
+
+ Options:
+  --quick, -q only load changed bugs
+  --progress Show progress bar
+  --service, -s service name
+  --sysconfdir, -c postgresql service config dir
+  --spool-dir debbugs spool directory
+  --debug, -d debugging level (Default 0)
+  --help, -h display this help
+  --man, -m display manual
+
+=head1 SUBCOMMANDS
+
+=head2 help
+
+Display this manual
+
+=head2 update
+
+Update SQL cache
+
+=head1 OPTIONS
+
+=over
+
+=item B<--quick, -q>
+
+Only update things which may have changed
+
+=item B<--progress>
+
+Show progress bar (requires Term::ProgressBar)
+
+=item B<--service,-s>
+
+Postgreql service to use; defaults to debbugs
+
+=item B<--sysconfdir,-c>
+
+System configuration directory to use; if not set, defaults to the
+postgresql default. [Operates by setting PGSYSCONFDIR]
+
+=item B<--spool-dir>
+
+Debbugs spool directory; defaults to the value configured in the
+debbugs configuration file.
+
+=item B<--verbose>
+
+Output more information about what is happening. Probably not useful
+if you also set --progress.
+
+=item B<--debug, -d>
+
+Debug verbosity.
+
+=item B<--help, -h>
+
+Display brief useage information.
+
+=item B<--man, -m>
+
+Display this manual.
+
+=back
+
+
+=cut
+
+
+use vars qw($DEBUG);
+
+use Debbugs::Common qw(checkpid lockpid get_hashname getparsedaddrs getbugcomponent make_list getsourcemaintainers);
+use Debbugs::Config qw(:config);
+use Debbugs::Status qw(bug_presence read_bug);
+use Debbugs::DB;
+use DateTime;
+use File::stat;
+use List::MoreUtils qw(natatime uniq);
+use POSIX qw(ceil);
+
+my %options =
+    (debug           => 0,
+     help            => 0,
+     man             => 0,
+     verbose         => 0,
+     quiet           => 0,
+     quick           => 0,
+     archived        => 0,
+     service         => $config{debbugs_db},
+     progress        => 0,
+    );
+
+Getopt::Long::Configure('pass_through');
+GetOptions(\%options,
+           'quick|q!',
+           'service|s=s',
+           'sysconfdir|c=s',
+           'progress!',
+          'archived+',
+           'spool_dir|spool-dir=s',
+           'verbose|v+',
+           'quiet+',
+           'debug|d+','help|h|?','man|m');
+Getopt::Long::Configure('default');
+
+pod2usage() if $options{help};
+pod2usage({verbose=>2}) if $options{man};
+
+$DEBUG = $options{debug};
+
+my %subcommands =
+    ('update' => {function => \&update_cache,
+                 arguments => {'suites|suite=s@' => 0,
+                              },
+               },
+     'help' => {function => sub {pod2usage({verbose => 2});}}
+    );
+
+my @USAGE_ERRORS;
+$options{verbose} = $options{verbose} - $options{quiet};
+
+if ($options{progress}) {
+    eval "use Term::ProgressBar";
+    push @USAGE_ERRORS, "You asked for a progress bar, but Term::ProgressBar isn't installed" if $@;
+}
+
+
+pod2usage(join("\n",@USAGE_ERRORS)) if @USAGE_ERRORS;
+
+if (exists $options{sysconfdir}) {
+    if (not defined $options{sysconfdir} or not length $options{sysconfdir}) {
+        delete $ENV{PGSYSCONFDIR};
+    } else {
+        $ENV{PGSYSCONFDIR} = $options{sysconfdir};
+    }
+}
+
+if (exists $options{spool_dir} and defined $options{spool_dir}) {
+    $config{spool_dir} = $options{spool_dir};
+}
+
+my $prog_bar;
+if ($options{progress}) {
+    $prog_bar = eval "Term::ProgressBar->new({count => 1,ETA=>q(linear)})";
+    warn "Unable to initialize progress bar: $@" if not $prog_bar;
+}
+
+
+my ($subcommand) = shift @ARGV;
+if (not defined $subcommand) {
+    $subcommand = 'help';
+    print STDERR "You must provide a subcommand; displaying usage.\n";
+    pod2usage();
+} elsif (not exists $subcommands{$subcommand}) {
+    print STDERR "$subcommand is not a valid subcommand; displaying usage.\n";
+    pod2usage();
+}
+
+my $opts =
+    handle_subcommand_arguments(\@ARGV,$subcommands{$subcommand}{arguments});
+$subcommands{$subcommand}{function}->(\%options,$opts,$prog_bar,\%config,\@ARGV);
+
+sub update_cache {
+    my ($options,$opts,$p,$config,$argv) = @_;
+
+    my $verbose = $options->{debug};
+    # select bugs to update
+
+    # basically, if this is a quick run, we want any bug which has
+    # been modified or any bug which belongs to a package which has a
+    # new version; otherwise, walk every bug
+    my $s = db_connect($options);
+
+    # get all of the possible architectures that we might care about
+    # select distinct s.codename,a.arch from bin_associations ba join bin_ver bv on ba.bin=bv.id join suite s on ba.suite=s.id join arch a on bv.arch=a.id;
+
+    my @suites;
+    if (exists $opts->{suites}) {
+       @suites =
+           $s->resultset('Suite')->
+           search_rs({active => 1,
+                      -or => {codename => [make_list($opts->{suites})],
+                              suite_name => [make_list($opts->{suites})],
+                             },
+                     },
+                    {result_class => 'DBIx::Class::ResultClass::HashRefInflator'}
+                    )->all();
+     } else {
+       @suites = 
+           $s->resultset('Suite')->
+           search_rs({active => 1,
+                     },
+                    {result_class => 'DBIx::Class::ResultClass::HashRefInflator'}
+                    )->all();
+    }
+    my @bugs;
+    my $bugs;
+    if ($options->{quick}) {
+       # identify the last time that we ran this query
+       my $last_query_time =
+           $s->resultset('BugStatusCache')->
+           search_rs(undef,
+                    {rows => 1,
+                     order_by => { -desc => 'asof' },
+                     columns => [qw(asof)],
+                    }
+                    )->first();
+       my $dtf = $s->storage->datetime_parser;
+       if (defined $last_query_time) {
+           $last_query_time = $last_query_time->asof();
+       } else {
+           $last_query_time = DateTime->from_epoch(0);
+       }
+        # select last status update
+       $last_query_time = $dtf->format_datetime($last_query_time);
+       # select all bugs which are in packages which have had a binary
+       # association modified
+       push @bugs,
+           map {$_->{bug_binpackages}{bug}}
+           $s->resultset('BinAssociation')->
+           search_rs({'me.modified' => {'>=',$last_query_time},
+                     },
+                    {columns => [qw(bug_binpackages.bug)],
+                     join => {bin =>
+                             {bin_pkg =>
+                              'bug_binpackages'
+                             }},
+                     result_class => 'DBIx::Class::ResultClass::HashRefInflator',
+                    },
+                    )->all();
+       # or a source association modified
+       push @bugs,
+           map {$_->{bug_srcpackages}{bug}}
+           $s->resultset('SrcAssociation')->
+           search_rs({'me.modified' => {'>=',$last_query_time},
+                     },
+                    {columns => [qw(bug_srcpackages.bug)],
+                     join => {source =>
+                             {src_pkg =>
+                              'bug_srcpackages'
+                             }},
+                     result_class => 'DBIx::Class::ResultClass::HashRefInflator',
+                    },
+                    )->all();
+       # or bugs which have been modified since we last ran
+       push @bugs,
+           map {$_->{id}}
+           $s->resultset('Bug')->
+           search_rs({-or => {'me.log_modified' => {'>=',$last_query_time},
+                              'me.last_modified' => {'>=',$last_query_time},
+                             },
+                      archived => ! $options->{archived},
+                     },
+                    {columns => [qw(id)],
+                     result_class => 'DBIx::Class::ResultClass::HashRefInflator',
+                    },
+                    )->all();
+       @bugs = uniq(@bugs);
+
+    } else {
+       ## or just select all of them
+       push @bugs,
+           map {$_->{id}}
+           $s->resultset('Bug')->
+           search_rs({archived => ! $options->{archived}},
+                    {columns => [qw(id)],
+                     result_class => 'DBIx::Class::ResultClass::HashRefInflator',
+                    },
+                    )->all();
+    }
+    my $update_bug =
+       sub {
+           my @b = @_;
+           for my $bug (@b) {
+               my $status = read_bug(bug => $bug);
+               next unless defined $status;
+               for my $suite (@suites) {
+                   my $presence =
+                       bug_presence(bug => $bug,
+                                    status => $status,
+                                    dist => $suite->{suite_name},
+                                   );
+                   $s->resultset('BugStatusCache')->
+                       update_bug_status($bug,
+                                         $suite->{id},
+                                         undef,
+                                         $presence,
+                                        );
+               }
+           }
+       };
+    my $it = natatime 500,@bugs;
+    my $page = 0;
+    my $last_page = ceil(@bugs / 500);
+    $p->target($last_page) if defined $p;
+    while (my @b_sub = $it->()) {
+       $s->txn_do($update_bug,
+                  @b_sub);
+       $page++;
+       $p->update($page) if defined $p;
+    }
+    $p->remove() if $p;
+}
+
+
+sub handle_subcommand_arguments {
+    my ($argv,$args) = @_;
+    my $subopt = {};
+    Getopt::Long::GetOptionsFromArray($argv,
+                              $subopt,
+                              keys %{$args},
+                             );
+    my @usage_errors;
+    for my $arg  (keys %{$args}) {
+        next unless $args->{$arg};
+        my $r_arg = $arg; # real argument name
+        $r_arg =~ s/[=\|].+//g;
+        if (not defined $subopt->{$r_arg}) {
+            push @usage_errors, "You must give a $r_arg option";
+        }
+    }
+    pod2usage(join("\n",@usage_errors)) if @usage_errors;
+    return $subopt;
+}
+
+sub get_lock{
+    my ($subcommand,$config,$options) = @_;
+    if (not lockpid($config->{spool_dir}.'/lock/debbugs-updatesqlcache-$subcommand')) {
+        if ($options->{quick}) {
+            # If this is a quick run, just exit
+            print STDERR "Another debbugs-updatesqlcache is running; stopping\n" if $options->{verbose};
+            exit 0;
+        }
+        print STDERR "Another debbugs-updatesqlcache is running; stopping\n";
+        exit 1;
+    }
+}
+
+sub db_connect {
+    my ($options) = @_;
+    # connect to the database; figure out how to handle errors
+    # properly here.
+    my $s = Debbugs::DB->connect('dbi:Pg:service='.$options->{service}) or
+        die "Unable to connect to database: ";
+}
+
+sub walk_bugs {
+    my ($dirs,$p,$what,$verbose,$sub) = @_;
+    my @dirs = @{$dirs};
+    my $tot_dirs = @dirs;
+    my $done_dirs = 0;
+    my $avg_subfiles = 0;
+    my $completed_files = 0;
+    while (my $dir = shift @dirs) {
+        printf "Doing dir %s ...\n", $dir if $verbose;
+
+        opendir(DIR, "$dir/.") or die "opendir $dir: $!";
+        my @subdirs = readdir(DIR);
+        closedir(DIR);
+
+        my @list = map { m/^(\d+)\.$what$/?($1):() } @subdirs;
+        $tot_dirs -= @dirs;
+        push @dirs, map { m/^(\d+)$/ && -d "$dir/$1"?("$dir/$1"):() } @subdirs;
+        $tot_dirs += @dirs;
+        if ($avg_subfiles == 0) {
+            $avg_subfiles = @list;
+        }
+
+        $p->target($avg_subfiles*($tot_dirs-$done_dirs)+$completed_files+@list) if $p;
+        $avg_subfiles = ($avg_subfiles * $done_dirs + @list) / ($done_dirs+1);
+        $done_dirs += 1;
+
+        for my $bug (@list) {
+            $completed_files++;
+            $p->update($completed_files) if $p;
+            print "Up to $completed_files bugs...\n" if ($completed_files % 100 == 0 && $verbose);
+            $sub->($bug);
+        }
+    }
+    $p->remove() if $p;
+}
+
+
+
+__END__
index 36ebfcc4033320d2495e62bd2eaf44479736210d..097852d898e53d14becbc29ee907473c8a2fa655 100644 (file)
@@ -13,8 +13,9 @@ Build-Depends-Indep: libparams-validate-perl,
  libhttp-server-simple-perl, libtest-www-mechanize-perl,
  libmail-rfc822-address-perl, libsafe-hole-perl, libuser-perl,
  libconfig-simple-perl, libtest-pod-perl, liblist-allutils-perl,
-# used by Debbugs::Libravatar and libravatar.cgi
  libfile-libmagic-perl, libgravatar-url-perl, libwww-perl, imagemagick,
+ libdbix-class-perl, libdatetime-format-pg-perl,
+ libdatetime-format-mail-perl,
  libtext-template-perl, graphviz, libtext-iconv-perl, libnet-server-perl
 Homepage: http://wiki.debian.org/Teams/Debbugs
 
@@ -41,14 +42,16 @@ Description: bug tracking system based on the active Debian BTS
 Package: libdebbugs-perl
 Architecture: all
 Depends:
- ${misc:Depends},
- ${perl:Depends}, libmailtools-perl, ed, libmime-tools-perl,
+ ${misc:Depends}, ${perl:Depends}, libmailtools-perl, ed, libmime-tools-perl,
  libio-stringy-perl, libmldbm-perl, liburi-perl, libsoap-lite-perl,
  libcgi-simple-perl, libparams-validate-perl, libtext-template-perl,
  libsafe-hole-perl, libmail-rfc822-address-perl, liblist-moreutils-perl,
  libtext-template-perl,
-# used by Debbugs::Libravatar and libravatar.cgi
- libfile-libmagic-perl, libgravatar-url-perl, libwww-perl, imagemagick
+ # used by Debbugs::Libravatar and libravatar.cgi
+ libfile-libmagic-perl,
+ libgravatar-url-perl, libwww-perl, imagemagick,
+ # used by the database
+ libdatetime-format-mail-perl, libdbix-class-perl, libdatetime-format-pg-perl
 Section: perl
 Description: modules used by the active Debian BTS
  Debian has a bug tracking system which files details of bugs reported by
diff --git a/sql/PostgreSQL/deploy/1/001-auto-__VERSION.sql b/sql/PostgreSQL/deploy/1/001-auto-__VERSION.sql
new file mode 100644 (file)
index 0000000..ba0884e
--- /dev/null
@@ -0,0 +1,18 @@
+-- 
+-- Created by SQL::Translator::Producer::PostgreSQL
+-- Created on Wed Aug  6 14:09:26 2014
+-- 
+;
+--
+-- Table: dbix_class_deploymenthandler_versions.
+--
+CREATE TABLE "dbix_class_deploymenthandler_versions" (
+  "id" serial NOT NULL,
+  "version" character varying(50) NOT NULL,
+  "ddl" text,
+  "upgrade_sql" text,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "dbix_class_deploymenthandler_versions_version" UNIQUE ("version")
+);
+
+;
diff --git a/sql/PostgreSQL/deploy/1/001-auto.sql b/sql/PostgreSQL/deploy/1/001-auto.sql
new file mode 100644 (file)
index 0000000..0de4b8b
--- /dev/null
@@ -0,0 +1,602 @@
+-- 
+-- Created by SQL::Translator::Producer::PostgreSQL
+-- Created on Wed Aug  6 14:09:26 2014
+-- 
+;
+--
+-- Table: arch.
+--
+CREATE TABLE "arch" (
+  "id" serial NOT NULL,
+  "arch" text NOT NULL,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "arch_arch_key" UNIQUE ("arch")
+);
+
+;
+--
+-- Table: bin_pkg.
+--
+CREATE TABLE "bin_pkg" (
+  "id" serial NOT NULL,
+  "pkg" text NOT NULL,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "bin_pkg_pkg_key" UNIQUE ("pkg")
+);
+
+;
+--
+-- Table: binary_versions.
+--
+CREATE TABLE "binary_versions" (
+  "src_pkg" text,
+  "src_ver" debversion,
+  "bin_pkg" text,
+  "arch" text,
+  "bin_ver" debversion,
+  "src_ver_based_on" debversion,
+  "src_pkg_based_on" text
+);
+
+;
+--
+-- Table: bug_package.
+--
+CREATE TABLE "bug_package" (
+  "bug" integer,
+  "pkg_id" integer,
+  "pkg_type" text,
+  "package" text
+);
+
+;
+--
+-- Table: column_comments.
+--
+CREATE TABLE "column_comments" (
+  "table_name" text NOT NULL,
+  "column_name" text NOT NULL,
+  "comment_text" text NOT NULL,
+  CONSTRAINT "column_comments_table_name_column_name_idx" UNIQUE ("table_name", "column_name")
+);
+
+;
+--
+-- Table: correspondent.
+--
+CREATE TABLE "correspondent" (
+  "id" serial NOT NULL,
+  "addr" text NOT NULL,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "correspondent_addr_idx" UNIQUE ("addr")
+);
+
+;
+--
+-- Table: message.
+--
+CREATE TABLE "message" (
+  "id" serial NOT NULL,
+  "msgid" text,
+  "from_complete" text,
+  "from_addr" text,
+  "to_complete" text,
+  "to_addr" text,
+  "subject" text DEFAULT '' NOT NULL,
+  "sent_date" timestamp with time zone,
+  "refs" text DEFAULT '' NOT NULL,
+  "spam_score" double precision,
+  "is_spam" boolean DEFAULT false,
+  PRIMARY KEY ("id")
+);
+
+;
+--
+-- Table: severity.
+--
+CREATE TABLE "severity" (
+  "id" serial NOT NULL,
+  "severity" text NOT NULL,
+  "ordering" integer DEFAULT 5 NOT NULL,
+  "strong" boolean DEFAULT false,
+  "obsolete" boolean DEFAULT false,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "severity_severity_idx" UNIQUE ("severity")
+);
+
+;
+--
+-- Table: src_pkg.
+--
+CREATE TABLE "src_pkg" (
+  "id" serial NOT NULL,
+  "pkg" text NOT NULL,
+  "pseduopkg" boolean DEFAULT false,
+  "alias_of" integer,
+  "creation" timestamp with time zone DEFAULT current_timestamp,
+  "disabled" timestamp with time zone,
+  "last_modified" timestamp with time zone DEFAULT current_timestamp,
+  "obsolete" boolean DEFAULT false,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "src_pkg_pkg_disabled" UNIQUE ("pkg", "disabled")
+);
+CREATE INDEX "src_pkg_idx_alias_of" on "src_pkg" ("alias_of");
+
+;
+--
+-- Table: suite.
+--
+CREATE TABLE "suite" (
+  "id" serial NOT NULL,
+  "suite_name" text NOT NULL,
+  "version" text,
+  "codename" text,
+  "active" boolean DEFAULT true,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "suite_suite_name_key" UNIQUE ("suite_name")
+);
+
+;
+--
+-- Table: table_comments.
+--
+CREATE TABLE "table_comments" (
+  "table_name" text NOT NULL,
+  "comment_text" text NOT NULL,
+  CONSTRAINT "table_comments_table_name_key" UNIQUE ("table_name")
+);
+
+;
+--
+-- Table: tag.
+--
+CREATE TABLE "tag" (
+  "id" serial NOT NULL,
+  "tag" text NOT NULL,
+  "obsolete" boolean DEFAULT false,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "tag_tag_key" UNIQUE ("tag")
+);
+
+;
+--
+-- Table: correspondent_full_name.
+--
+CREATE TABLE "correspondent_full_name" (
+  "id" serial NOT NULL,
+  "correspondent" integer NOT NULL,
+  "full_name" text NOT NULL,
+  "last_seen" timestamp DEFAULT current_timestamp NOT NULL,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "correspondent_full_name_correspondent_full_name_idx" UNIQUE ("correspondent", "full_name")
+);
+CREATE INDEX "correspondent_full_name_idx_correspondent" on "correspondent_full_name" ("correspondent");
+
+;
+--
+-- Table: maintainer.
+--
+CREATE TABLE "maintainer" (
+  "id" serial NOT NULL,
+  "name" text NOT NULL,
+  "correspondent" integer NOT NULL,
+  "created" timestamp with time zone DEFAULT current_timestamp NOT NULL,
+  "modified" timestamp with time zone DEFAULT current_timestamp NOT NULL,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "maintainer_name_idx" UNIQUE ("name")
+);
+CREATE INDEX "maintainer_idx_correspondent" on "maintainer" ("correspondent");
+
+;
+--
+-- Table: message_refs.
+--
+CREATE TABLE "message_refs" (
+  "id" serial NOT NULL,
+  "message" integer NOT NULL,
+  "refs" integer NOT NULL,
+  "inferred" boolean DEFAULT false,
+  "primary_ref" boolean DEFAULT false,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "message_refs_message_refs_idx" UNIQUE ("message", "refs")
+);
+CREATE INDEX "message_refs_idx_message" on "message_refs" ("message");
+CREATE INDEX "message_refs_idx_refs" on "message_refs" ("refs");
+
+;
+--
+-- Table: bug.
+--
+CREATE TABLE "bug" (
+  "id" integer NOT NULL,
+  "creation" timestamp with time zone DEFAULT current_timestamp NOT NULL,
+  "log_modified" timestamp with time zone DEFAULT current_timestamp NOT NULL,
+  "last_modified" timestamp with time zone DEFAULT current_timestamp NOT NULL,
+  "archived" boolean DEFAULT false NOT NULL,
+  "unarchived" timestamp with time zone,
+  "forwarded" text DEFAULT '' NOT NULL,
+  "summary" text DEFAULT '' NOT NULL,
+  "outlook" text DEFAULT '' NOT NULL,
+  "subject" text NOT NULL,
+  "severity" integer NOT NULL,
+  "done" integer,
+  "done_full" text DEFAULT '' NOT NULL,
+  "owner" integer,
+  "owner_full" text DEFAULT '' NOT NULL,
+  "submitter" integer,
+  "submitter_full" text DEFAULT '' NOT NULL,
+  "unknown_packages" text DEFAULT '' NOT NULL,
+  PRIMARY KEY ("id")
+);
+CREATE INDEX "bug_idx_done" on "bug" ("done");
+CREATE INDEX "bug_idx_owner" on "bug" ("owner");
+CREATE INDEX "bug_idx_severity" on "bug" ("severity");
+CREATE INDEX "bug_idx_submitter" on "bug" ("submitter");
+
+;
+--
+-- Table: message_correspondent.
+--
+CREATE TABLE "message_correspondent" (
+  "id" serial NOT NULL,
+  "message" integer NOT NULL,
+  "correspondent" integer NOT NULL,
+  "correspondent_type" character varying DEFAULT 'to' NOT NULL,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "message_correspondent_message_correspondent_correspondent_t_idx" UNIQUE ("message", "correspondent", "correspondent_type")
+);
+CREATE INDEX "message_correspondent_idx_correspondent" on "message_correspondent" ("correspondent");
+CREATE INDEX "message_correspondent_idx_message" on "message_correspondent" ("message");
+
+;
+--
+-- Table: bug_blocks.
+--
+CREATE TABLE "bug_blocks" (
+  "id" serial NOT NULL,
+  "bug" integer NOT NULL,
+  "blocks" integer NOT NULL,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "bug_blocks_bug_id_blocks_idx" UNIQUE ("bug", "blocks")
+);
+CREATE INDEX "bug_blocks_idx_blocks" on "bug_blocks" ("blocks");
+CREATE INDEX "bug_blocks_idx_bug" on "bug_blocks" ("bug");
+
+;
+--
+-- Table: bug_merged.
+--
+CREATE TABLE "bug_merged" (
+  "id" serial NOT NULL,
+  "bug" integer NOT NULL,
+  "merged" integer NOT NULL,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "bug_merged_bug_id_merged_idx" UNIQUE ("bug", "merged")
+);
+CREATE INDEX "bug_merged_idx_bug" on "bug_merged" ("bug");
+CREATE INDEX "bug_merged_idx_merged" on "bug_merged" ("merged");
+
+;
+--
+-- Table: src_ver.
+--
+CREATE TABLE "src_ver" (
+  "id" serial NOT NULL,
+  "src_pkg" integer NOT NULL,
+  "ver" debversion NOT NULL,
+  "maintainer" integer,
+  "upload_date" timestamp with time zone DEFAULT current_timestamp NOT NULL,
+  "based_on" integer,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "src_ver_src_pkg_id_ver" UNIQUE ("src_pkg", "ver")
+);
+CREATE INDEX "src_ver_idx_based_on" on "src_ver" ("based_on");
+CREATE INDEX "src_ver_idx_maintainer" on "src_ver" ("maintainer");
+CREATE INDEX "src_ver_idx_src_pkg" on "src_ver" ("src_pkg");
+
+;
+--
+-- Table: bug_binpackage.
+--
+CREATE TABLE "bug_binpackage" (
+  "id" serial NOT NULL,
+  "bug" integer NOT NULL,
+  "bin_pkg" integer NOT NULL,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "bug_binpackage_id_pkg" UNIQUE ("bug", "bin_pkg")
+);
+CREATE INDEX "bug_binpackage_idx_bin_pkg" on "bug_binpackage" ("bin_pkg");
+CREATE INDEX "bug_binpackage_idx_bug" on "bug_binpackage" ("bug");
+
+;
+--
+-- Table: bug_message.
+--
+CREATE TABLE "bug_message" (
+  "id" serial NOT NULL,
+  "bug" integer NOT NULL,
+  "message" integer NOT NULL,
+  "message_number" integer NOT NULL,
+  "bug_log_offset" integer,
+  "offset_valid" timestamp with time zone,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "bug_message_bug_message_idx" UNIQUE ("bug", "message")
+);
+CREATE INDEX "bug_message_idx_bug" on "bug_message" ("bug");
+CREATE INDEX "bug_message_idx_message" on "bug_message" ("message");
+
+;
+--
+-- Table: bug_srcpackage.
+--
+CREATE TABLE "bug_srcpackage" (
+  "id" serial NOT NULL,
+  "bug" integer NOT NULL,
+  "src_pkg" integer NOT NULL,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "bug_srcpackage_id_pkg" UNIQUE ("bug", "src_pkg")
+);
+CREATE INDEX "bug_srcpackage_idx_bug" on "bug_srcpackage" ("bug");
+CREATE INDEX "bug_srcpackage_idx_src_pkg" on "bug_srcpackage" ("src_pkg");
+
+;
+--
+-- Table: bug_tag.
+--
+CREATE TABLE "bug_tag" (
+  "id" serial NOT NULL,
+  "bug" integer NOT NULL,
+  "tag" integer NOT NULL,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "bug_tag_bug_tag" UNIQUE ("bug", "tag")
+);
+CREATE INDEX "bug_tag_idx_bug" on "bug_tag" ("bug");
+CREATE INDEX "bug_tag_idx_tag" on "bug_tag" ("tag");
+
+;
+--
+-- Table: bug_status_cache.
+--
+CREATE TABLE "bug_status_cache" (
+  "id" serial NOT NULL,
+  "bug" integer NOT NULL,
+  "suite" integer,
+  "arch" integer,
+  "status" character varying NOT NULL,
+  "modified" timestamp with time zone DEFAULT current_timestamp NOT NULL,
+  "asof" timestamp with time zone DEFAULT current_timestamp NOT NULL,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "bug_status_cache_bug_suite_arch_idx" UNIQUE ("bug", "suite", "arch")
+);
+CREATE INDEX "bug_status_cache_idx_arch" on "bug_status_cache" ("arch");
+CREATE INDEX "bug_status_cache_idx_bug" on "bug_status_cache" ("bug");
+CREATE INDEX "bug_status_cache_idx_suite" on "bug_status_cache" ("suite");
+
+;
+--
+-- Table: src_associations.
+--
+CREATE TABLE "src_associations" (
+  "id" serial NOT NULL,
+  "suite" integer NOT NULL,
+  "source" integer NOT NULL,
+  "created" timestamp with time zone DEFAULT current_timestamp NOT NULL,
+  "modified" timestamp with time zone DEFAULT current_timestamp NOT NULL,
+  PRIMARY KEY ("id")
+);
+CREATE INDEX "src_associations_idx_source" on "src_associations" ("source");
+CREATE INDEX "src_associations_idx_suite" on "src_associations" ("suite");
+
+;
+--
+-- Table: bin_ver.
+--
+CREATE TABLE "bin_ver" (
+  "id" serial NOT NULL,
+  "bin_pkg" integer NOT NULL,
+  "src_ver" integer NOT NULL,
+  "arch" integer NOT NULL,
+  "ver" debversion NOT NULL,
+  PRIMARY KEY ("id")
+);
+CREATE INDEX "bin_ver_idx_arch" on "bin_ver" ("arch");
+CREATE INDEX "bin_ver_idx_bin_pkg" on "bin_ver" ("bin_pkg");
+CREATE INDEX "bin_ver_idx_src_ver" on "bin_ver" ("src_ver");
+
+;
+--
+-- Table: bug_ver.
+--
+CREATE TABLE "bug_ver" (
+  "id" serial NOT NULL,
+  "bug" integer NOT NULL,
+  "ver_string" text,
+  "src_pkg" integer,
+  "src_ver" integer,
+  "found" boolean DEFAULT true NOT NULL,
+  "creation" timestamp with time zone DEFAULT current_timestamp NOT NULL,
+  "last_modified" timestamp with time zone DEFAULT current_timestamp NOT NULL,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "bug_ver_bug_ver_string_found_idx" UNIQUE ("bug", "ver_string", "found")
+);
+CREATE INDEX "bug_ver_idx_bug" on "bug_ver" ("bug");
+CREATE INDEX "bug_ver_idx_src_pkg" on "bug_ver" ("src_pkg");
+CREATE INDEX "bug_ver_idx_src_ver" on "bug_ver" ("src_ver");
+
+;
+--
+-- Table: bin_associations.
+--
+CREATE TABLE "bin_associations" (
+  "id" serial NOT NULL,
+  "suite" integer NOT NULL,
+  "bin" integer NOT NULL,
+  "created" timestamp with time zone DEFAULT current_timestamp NOT NULL,
+  "modified" timestamp with time zone DEFAULT current_timestamp NOT NULL,
+  PRIMARY KEY ("id")
+);
+CREATE INDEX "bin_associations_idx_bin" on "bin_associations" ("bin");
+CREATE INDEX "bin_associations_idx_suite" on "bin_associations" ("suite");
+
+;
+--
+-- Foreign Key Definitions
+--
+
+;
+ALTER TABLE "src_pkg" ADD CONSTRAINT "src_pkg_fk_alias_of" FOREIGN KEY ("alias_of")
+  REFERENCES "src_pkg" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "correspondent_full_name" ADD CONSTRAINT "correspondent_full_name_fk_correspondent" FOREIGN KEY ("correspondent")
+  REFERENCES "correspondent" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "maintainer" ADD CONSTRAINT "maintainer_fk_correspondent" FOREIGN KEY ("correspondent")
+  REFERENCES "correspondent" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
+
+;
+ALTER TABLE "message_refs" ADD CONSTRAINT "message_refs_fk_message" FOREIGN KEY ("message")
+  REFERENCES "message" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "message_refs" ADD CONSTRAINT "message_refs_fk_refs" FOREIGN KEY ("refs")
+  REFERENCES "message" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "bug" ADD CONSTRAINT "bug_fk_done" FOREIGN KEY ("done")
+  REFERENCES "correspondent" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
+
+;
+ALTER TABLE "bug" ADD CONSTRAINT "bug_fk_owner" FOREIGN KEY ("owner")
+  REFERENCES "correspondent" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
+
+;
+ALTER TABLE "bug" ADD CONSTRAINT "bug_fk_severity" FOREIGN KEY ("severity")
+  REFERENCES "severity" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
+
+;
+ALTER TABLE "bug" ADD CONSTRAINT "bug_fk_submitter" FOREIGN KEY ("submitter")
+  REFERENCES "correspondent" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
+
+;
+ALTER TABLE "message_correspondent" ADD CONSTRAINT "message_correspondent_fk_correspondent" FOREIGN KEY ("correspondent")
+  REFERENCES "correspondent" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "message_correspondent" ADD CONSTRAINT "message_correspondent_fk_message" FOREIGN KEY ("message")
+  REFERENCES "message" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "bug_blocks" ADD CONSTRAINT "bug_blocks_fk_blocks" FOREIGN KEY ("blocks")
+  REFERENCES "bug" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
+
+;
+ALTER TABLE "bug_blocks" ADD CONSTRAINT "bug_blocks_fk_bug" FOREIGN KEY ("bug")
+  REFERENCES "bug" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
+
+;
+ALTER TABLE "bug_merged" ADD CONSTRAINT "bug_merged_fk_bug" FOREIGN KEY ("bug")
+  REFERENCES "bug" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
+
+;
+ALTER TABLE "bug_merged" ADD CONSTRAINT "bug_merged_fk_merged" FOREIGN KEY ("merged")
+  REFERENCES "bug" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
+
+;
+ALTER TABLE "src_ver" ADD CONSTRAINT "src_ver_fk_based_on" FOREIGN KEY ("based_on")
+  REFERENCES "src_ver" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "src_ver" ADD CONSTRAINT "src_ver_fk_maintainer" FOREIGN KEY ("maintainer")
+  REFERENCES "maintainer" ("id") ON DELETE SET NULL ON UPDATE CASCADE;
+
+;
+ALTER TABLE "src_ver" ADD CONSTRAINT "src_ver_fk_src_pkg" FOREIGN KEY ("src_pkg")
+  REFERENCES "src_pkg" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "bug_binpackage" ADD CONSTRAINT "bug_binpackage_fk_bin_pkg" FOREIGN KEY ("bin_pkg")
+  REFERENCES "bin_pkg" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
+
+;
+ALTER TABLE "bug_binpackage" ADD CONSTRAINT "bug_binpackage_fk_bug" FOREIGN KEY ("bug")
+  REFERENCES "bug" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
+
+;
+ALTER TABLE "bug_message" ADD CONSTRAINT "bug_message_fk_bug" FOREIGN KEY ("bug")
+  REFERENCES "bug" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "bug_message" ADD CONSTRAINT "bug_message_fk_message" FOREIGN KEY ("message")
+  REFERENCES "message" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "bug_srcpackage" ADD CONSTRAINT "bug_srcpackage_fk_bug" FOREIGN KEY ("bug")
+  REFERENCES "bug" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
+
+;
+ALTER TABLE "bug_srcpackage" ADD CONSTRAINT "bug_srcpackage_fk_src_pkg" FOREIGN KEY ("src_pkg")
+  REFERENCES "src_pkg" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "bug_tag" ADD CONSTRAINT "bug_tag_fk_bug" FOREIGN KEY ("bug")
+  REFERENCES "bug" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
+
+;
+ALTER TABLE "bug_tag" ADD CONSTRAINT "bug_tag_fk_tag" FOREIGN KEY ("tag")
+  REFERENCES "tag" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
+
+;
+ALTER TABLE "bug_status_cache" ADD CONSTRAINT "bug_status_cache_fk_arch" FOREIGN KEY ("arch")
+  REFERENCES "arch" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "bug_status_cache" ADD CONSTRAINT "bug_status_cache_fk_bug" FOREIGN KEY ("bug")
+  REFERENCES "bug" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "bug_status_cache" ADD CONSTRAINT "bug_status_cache_fk_suite" FOREIGN KEY ("suite")
+  REFERENCES "suite" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "src_associations" ADD CONSTRAINT "src_associations_fk_source" FOREIGN KEY ("source")
+  REFERENCES "src_ver" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "src_associations" ADD CONSTRAINT "src_associations_fk_suite" FOREIGN KEY ("suite")
+  REFERENCES "suite" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "bin_ver" ADD CONSTRAINT "bin_ver_fk_arch" FOREIGN KEY ("arch")
+  REFERENCES "arch" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "bin_ver" ADD CONSTRAINT "bin_ver_fk_bin_pkg" FOREIGN KEY ("bin_pkg")
+  REFERENCES "bin_pkg" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "bin_ver" ADD CONSTRAINT "bin_ver_fk_src_ver" FOREIGN KEY ("src_ver")
+  REFERENCES "src_ver" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "bug_ver" ADD CONSTRAINT "bug_ver_fk_bug" FOREIGN KEY ("bug")
+  REFERENCES "bug" ("id") ON DELETE RESTRICT ON UPDATE CASCADE;
+
+;
+ALTER TABLE "bug_ver" ADD CONSTRAINT "bug_ver_fk_src_pkg" FOREIGN KEY ("src_pkg")
+  REFERENCES "src_pkg" ("id") ON DELETE SET NULL ON UPDATE CASCADE;
+
+;
+ALTER TABLE "bug_ver" ADD CONSTRAINT "bug_ver_fk_src_ver" FOREIGN KEY ("src_ver")
+  REFERENCES "src_ver" ("id") ON DELETE SET NULL ON UPDATE CASCADE;
+
+;
+ALTER TABLE "bin_associations" ADD CONSTRAINT "bin_associations_fk_bin" FOREIGN KEY ("bin")
+  REFERENCES "bin_ver" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "bin_associations" ADD CONSTRAINT "bin_associations_fk_suite" FOREIGN KEY ("suite")
+  REFERENCES "suite" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
diff --git a/sql/PostgreSQL/deploy/5/001-auto.sql b/sql/PostgreSQL/deploy/5/001-auto.sql
new file mode 100644 (file)
index 0000000..3300ac9
--- /dev/null
@@ -0,0 +1,669 @@
+-- 
+-- Created by SQL::Translator::Producer::PostgreSQL
+-- Created on Thu Apr 13 11:40:05 2017
+-- 
+;
+--
+-- Table: arch
+--
+CREATE TABLE "arch" (
+  "id" serial NOT NULL,
+  "arch" text NOT NULL,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "arch_arch_key" UNIQUE ("arch")
+);
+
+;
+--
+-- Table: bin_pkg
+--
+CREATE TABLE "bin_pkg" (
+  "id" serial NOT NULL,
+  "pkg" text NOT NULL,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "bin_pkg_pkg_key" UNIQUE ("pkg")
+);
+
+;
+--
+-- Table: column_comments
+--
+CREATE TABLE "column_comments" (
+  "table_name" text NOT NULL,
+  "column_name" text NOT NULL,
+  "comment_text" text NOT NULL,
+  CONSTRAINT "column_comments_table_name_column_name_idx" UNIQUE ("table_name", "column_name")
+);
+
+;
+--
+-- Table: correspondent
+--
+CREATE TABLE "correspondent" (
+  "id" serial NOT NULL,
+  "addr" text NOT NULL,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "correspondent_addr_idx" UNIQUE ("addr")
+);
+
+;
+--
+-- Table: message
+--
+CREATE TABLE "message" (
+  "id" serial NOT NULL,
+  "msgid" text DEFAULT '' NOT NULL,
+  "from_complete" text DEFAULT '' NOT NULL,
+  "to_complete" text DEFAULT '' NOT NULL,
+  "subject" text DEFAULT '' NOT NULL,
+  "sent_date" timestamp with time zone,
+  "refs" text DEFAULT '' NOT NULL,
+  "spam_score" double precision DEFAULT '0' NOT NULL,
+  "is_spam" boolean DEFAULT false NOT NULL,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "message_msgid_from_complete_to_complete_subject_idx" UNIQUE ("msgid", "from_complete", "to_complete", "subject")
+);
+
+;
+--
+-- Table: severity
+--
+CREATE TABLE "severity" (
+  "id" serial NOT NULL,
+  "severity" text NOT NULL,
+  "ordering" integer DEFAULT 5 NOT NULL,
+  "strong" boolean DEFAULT false,
+  "obsolete" boolean DEFAULT false,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "severity_severity_idx" UNIQUE ("severity")
+);
+
+;
+--
+-- Table: src_pkg
+--
+CREATE TABLE "src_pkg" (
+  "id" serial NOT NULL,
+  "pkg" text NOT NULL,
+  "pseduopkg" boolean DEFAULT false NOT NULL,
+  "alias_of" integer,
+  "creation" timestamp with time zone DEFAULT current_timestamp NOT NULL,
+  "disabled" timestamp with time zone DEFAULT 'infinity' NOT NULL,
+  "last_modified" timestamp with time zone DEFAULT current_timestamp NOT NULL,
+  "obsolete" boolean DEFAULT false NOT NULL,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "src_pkg_pkg_disabled" UNIQUE ("pkg", "disabled")
+);
+CREATE INDEX "src_pkg_idx_alias_of" on "src_pkg" ("alias_of");
+
+;
+--
+-- Table: suite
+--
+CREATE TABLE "suite" (
+  "id" serial NOT NULL,
+  "codename" text NOT NULL,
+  "suite_name" text,
+  "version" text,
+  "active" boolean DEFAULT true,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "suite_idx_codename" UNIQUE ("codename"),
+  CONSTRAINT "suite_idx_version" UNIQUE ("version"),
+  CONSTRAINT "suite_suite_name_key" UNIQUE ("suite_name")
+);
+
+;
+--
+-- Table: table_comments
+--
+CREATE TABLE "table_comments" (
+  "table_name" text NOT NULL,
+  "comment_text" text NOT NULL,
+  CONSTRAINT "table_comments_table_name_idx" UNIQUE ("table_name"),
+  CONSTRAINT "table_comments_table_name_key" UNIQUE ("table_name")
+);
+
+;
+--
+-- Table: tag
+--
+CREATE TABLE "tag" (
+  "id" serial NOT NULL,
+  "tag" text NOT NULL,
+  "obsolete" boolean DEFAULT false,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "tag_tag_key" UNIQUE ("tag")
+);
+
+;
+--
+-- Table: correspondent_full_name
+--
+CREATE TABLE "correspondent_full_name" (
+  "correspondent" integer NOT NULL,
+  "full_name" text NOT NULL,
+  "last_seen" timestamp DEFAULT current_timestamp NOT NULL,
+  CONSTRAINT "correspondent_full_name_correspondent_full_name_idx" UNIQUE ("correspondent", "full_name")
+);
+CREATE INDEX "correspondent_full_name_idx_correspondent" on "correspondent_full_name" ("correspondent");
+
+;
+--
+-- Table: maintainer
+--
+CREATE TABLE "maintainer" (
+  "id" serial NOT NULL,
+  "name" text NOT NULL,
+  "correspondent" integer NOT NULL,
+  "created" timestamp with time zone DEFAULT current_timestamp NOT NULL,
+  "modified" timestamp with time zone DEFAULT current_timestamp NOT NULL,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "maintainer_name_idx" UNIQUE ("name")
+);
+CREATE INDEX "maintainer_idx_correspondent" on "maintainer" ("correspondent");
+
+;
+--
+-- Table: message_refs
+--
+CREATE TABLE "message_refs" (
+  "message" integer NOT NULL,
+  "refs" integer NOT NULL,
+  "inferred" boolean DEFAULT false,
+  "primary_ref" boolean DEFAULT false,
+  CONSTRAINT "message_refs_message_refs_idx" UNIQUE ("message", "refs")
+);
+CREATE INDEX "message_refs_idx_message" on "message_refs" ("message");
+CREATE INDEX "message_refs_idx_refs" on "message_refs" ("refs");
+
+;
+--
+-- Table: user_tag
+--
+CREATE TABLE "user_tag" (
+  "id" serial NOT NULL,
+  "tag" text NOT NULL,
+  "correspondent" integer NOT NULL,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "user_tag_tag_correspondent" UNIQUE ("tag", "correspondent")
+);
+CREATE INDEX "user_tag_idx_correspondent" on "user_tag" ("correspondent");
+
+;
+--
+-- Table: bug
+--
+CREATE TABLE "bug" (
+  "id" integer NOT NULL,
+  "creation" timestamp with time zone DEFAULT current_timestamp NOT NULL,
+  "log_modified" timestamp with time zone DEFAULT current_timestamp NOT NULL,
+  "last_modified" timestamp with time zone DEFAULT current_timestamp NOT NULL,
+  "archived" boolean DEFAULT false NOT NULL,
+  "unarchived" timestamp with time zone,
+  "forwarded" text DEFAULT '' NOT NULL,
+  "summary" text DEFAULT '' NOT NULL,
+  "outlook" text DEFAULT '' NOT NULL,
+  "subject" text NOT NULL,
+  "severity" integer NOT NULL,
+  "done" integer,
+  "done_full" text DEFAULT '' NOT NULL,
+  "owner" integer,
+  "owner_full" text DEFAULT '' NOT NULL,
+  "submitter" integer,
+  "submitter_full" text DEFAULT '' NOT NULL,
+  "unknown_packages" text DEFAULT '' NOT NULL,
+  PRIMARY KEY ("id")
+);
+CREATE INDEX "bug_idx_done" on "bug" ("done");
+CREATE INDEX "bug_idx_owner" on "bug" ("owner");
+CREATE INDEX "bug_idx_severity" on "bug" ("severity");
+CREATE INDEX "bug_idx_submitter" on "bug" ("submitter");
+
+;
+--
+-- Table: message_correspondent
+--
+CREATE TABLE "message_correspondent" (
+  "message" integer NOT NULL,
+  "correspondent" integer NOT NULL,
+  "correspondent_type" character varying DEFAULT 'to' NOT NULL,
+  CONSTRAINT "message_correspondent_message_correspondent_correspondent_t_idx" UNIQUE ("message", "correspondent", "correspondent_type")
+);
+CREATE INDEX "message_correspondent_idx_correspondent" on "message_correspondent" ("correspondent");
+CREATE INDEX "message_correspondent_idx_message" on "message_correspondent" ("message");
+
+;
+--
+-- Table: bug_blocks
+--
+CREATE TABLE "bug_blocks" (
+  "id" serial NOT NULL,
+  "bug" integer NOT NULL,
+  "blocks" integer NOT NULL,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "bug_blocks_bug_id_blocks_idx" UNIQUE ("bug", "blocks")
+);
+CREATE INDEX "bug_blocks_idx_blocks" on "bug_blocks" ("blocks");
+CREATE INDEX "bug_blocks_idx_bug" on "bug_blocks" ("bug");
+
+;
+--
+-- Table: bug_merged
+--
+CREATE TABLE "bug_merged" (
+  "id" serial NOT NULL,
+  "bug" integer NOT NULL,
+  "merged" integer NOT NULL,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "bug_merged_bug_id_merged_idx" UNIQUE ("bug", "merged")
+);
+CREATE INDEX "bug_merged_idx_bug" on "bug_merged" ("bug");
+CREATE INDEX "bug_merged_idx_merged" on "bug_merged" ("merged");
+
+;
+--
+-- Table: src_ver
+--
+CREATE TABLE "src_ver" (
+  "id" serial NOT NULL,
+  "src_pkg" integer NOT NULL,
+  "ver" debversion NOT NULL,
+  "maintainer" integer,
+  "upload_date" timestamp with time zone DEFAULT current_timestamp NOT NULL,
+  "based_on" integer,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "src_ver_src_pkg_id_ver" UNIQUE ("src_pkg", "ver")
+);
+CREATE INDEX "src_ver_idx_based_on" on "src_ver" ("based_on");
+CREATE INDEX "src_ver_idx_maintainer" on "src_ver" ("maintainer");
+CREATE INDEX "src_ver_idx_src_pkg" on "src_ver" ("src_pkg");
+
+;
+--
+-- Table: bug_affects_binpackage
+--
+CREATE TABLE "bug_affects_binpackage" (
+  "bug" integer NOT NULL,
+  "bin_pkg" integer NOT NULL,
+  CONSTRAINT "bug_affects_binpackage_id_pkg" UNIQUE ("bug", "bin_pkg")
+);
+CREATE INDEX "bug_affects_binpackage_idx_bin_pkg" on "bug_affects_binpackage" ("bin_pkg");
+CREATE INDEX "bug_affects_binpackage_idx_bug" on "bug_affects_binpackage" ("bug");
+
+;
+--
+-- Table: bug_affects_srcpackage
+--
+CREATE TABLE "bug_affects_srcpackage" (
+  "bug" integer NOT NULL,
+  "src_pkg" integer NOT NULL,
+  CONSTRAINT "bug_affects_srcpackage_id_pkg" UNIQUE ("bug", "src_pkg")
+);
+CREATE INDEX "bug_affects_srcpackage_idx_bug" on "bug_affects_srcpackage" ("bug");
+CREATE INDEX "bug_affects_srcpackage_idx_src_pkg" on "bug_affects_srcpackage" ("src_pkg");
+
+;
+--
+-- Table: bug_binpackage
+--
+CREATE TABLE "bug_binpackage" (
+  "bug" integer NOT NULL,
+  "bin_pkg" integer NOT NULL,
+  CONSTRAINT "bug_binpackage_id_pkg" UNIQUE ("bug", "bin_pkg")
+);
+CREATE INDEX "bug_binpackage_idx_bin_pkg" on "bug_binpackage" ("bin_pkg");
+CREATE INDEX "bug_binpackage_idx_bug" on "bug_binpackage" ("bug");
+
+;
+--
+-- Table: bug_message
+--
+CREATE TABLE "bug_message" (
+  "bug" integer NOT NULL,
+  "message" integer NOT NULL,
+  "message_number" integer NOT NULL,
+  "bug_log_offset" integer,
+  "offset_valid" timestamp with time zone,
+  CONSTRAINT "bug_message_bug_message_idx" UNIQUE ("bug", "message")
+);
+CREATE INDEX "bug_message_idx_bug" on "bug_message" ("bug");
+CREATE INDEX "bug_message_idx_message" on "bug_message" ("message");
+
+;
+--
+-- Table: bug_srcpackage
+--
+CREATE TABLE "bug_srcpackage" (
+  "bug" integer NOT NULL,
+  "src_pkg" integer NOT NULL,
+  CONSTRAINT "bug_srcpackage_id_pkg" UNIQUE ("bug", "src_pkg")
+);
+CREATE INDEX "bug_srcpackage_idx_bug" on "bug_srcpackage" ("bug");
+CREATE INDEX "bug_srcpackage_idx_src_pkg" on "bug_srcpackage" ("src_pkg");
+
+;
+--
+-- Table: bug_tag
+--
+CREATE TABLE "bug_tag" (
+  "bug" integer NOT NULL,
+  "tag" integer NOT NULL,
+  CONSTRAINT "bug_tag_bug_tag" UNIQUE ("bug", "tag")
+);
+CREATE INDEX "bug_tag_idx_bug" on "bug_tag" ("bug");
+CREATE INDEX "bug_tag_idx_tag" on "bug_tag" ("tag");
+
+;
+--
+-- Table: bug_user_tag
+--
+CREATE TABLE "bug_user_tag" (
+  "bug" integer NOT NULL,
+  "user_tag" integer NOT NULL,
+  CONSTRAINT "bug_user_tag_bug_tag" UNIQUE ("bug", "user_tag")
+);
+CREATE INDEX "bug_user_tag_idx_bug" on "bug_user_tag" ("bug");
+CREATE INDEX "bug_user_tag_idx_user_tag" on "bug_user_tag" ("user_tag");
+
+;
+--
+-- Table: bug_status_cache
+--
+CREATE TABLE "bug_status_cache" (
+  "bug" integer NOT NULL,
+  "suite" integer,
+  "arch" integer,
+  "status" character varying NOT NULL,
+  "modified" timestamp with time zone DEFAULT current_timestamp NOT NULL,
+  "asof" timestamp with time zone DEFAULT current_timestamp NOT NULL,
+  CONSTRAINT "bug_status_cache_bug_suite_arch_idx" UNIQUE ("bug", "suite", "arch")
+);
+CREATE INDEX "bug_status_cache_idx_arch" on "bug_status_cache" ("arch");
+CREATE INDEX "bug_status_cache_idx_bug" on "bug_status_cache" ("bug");
+CREATE INDEX "bug_status_cache_idx_suite" on "bug_status_cache" ("suite");
+
+;
+--
+-- Table: src_associations
+--
+CREATE TABLE "src_associations" (
+  "id" serial NOT NULL,
+  "suite" integer NOT NULL,
+  "source" integer NOT NULL,
+  "created" timestamp with time zone DEFAULT current_timestamp NOT NULL,
+  "modified" timestamp with time zone DEFAULT current_timestamp NOT NULL,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "src_associations_source_suite" UNIQUE ("source", "suite")
+);
+CREATE INDEX "src_associations_idx_source" on "src_associations" ("source");
+CREATE INDEX "src_associations_idx_suite" on "src_associations" ("suite");
+
+;
+--
+-- Table: bin_ver
+--
+CREATE TABLE "bin_ver" (
+  "id" serial NOT NULL,
+  "bin_pkg" integer NOT NULL,
+  "src_ver" integer NOT NULL,
+  "arch" integer NOT NULL,
+  "ver" debversion NOT NULL,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "bin_ver_bin_pkg_id_arch_idx" UNIQUE ("bin_pkg", "arch", "ver")
+);
+CREATE INDEX "bin_ver_idx_arch" on "bin_ver" ("arch");
+CREATE INDEX "bin_ver_idx_bin_pkg" on "bin_ver" ("bin_pkg");
+CREATE INDEX "bin_ver_idx_src_ver" on "bin_ver" ("src_ver");
+
+;
+--
+-- Table: bug_ver
+--
+CREATE TABLE "bug_ver" (
+  "id" serial NOT NULL,
+  "bug" integer NOT NULL,
+  "ver_string" text,
+  "src_pkg" integer,
+  "src_ver" integer,
+  "found" boolean DEFAULT true NOT NULL,
+  "creation" timestamp with time zone DEFAULT current_timestamp NOT NULL,
+  "last_modified" timestamp with time zone DEFAULT current_timestamp NOT NULL,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "bug_ver_bug_ver_string_found_idx" UNIQUE ("bug", "ver_string", "found")
+);
+CREATE INDEX "bug_ver_idx_bug" on "bug_ver" ("bug");
+CREATE INDEX "bug_ver_idx_src_pkg" on "bug_ver" ("src_pkg");
+CREATE INDEX "bug_ver_idx_src_ver" on "bug_ver" ("src_ver");
+
+;
+--
+-- Table: bin_associations
+--
+CREATE TABLE "bin_associations" (
+  "id" serial NOT NULL,
+  "suite" integer NOT NULL,
+  "bin" integer NOT NULL,
+  "created" timestamp with time zone DEFAULT current_timestamp NOT NULL,
+  "modified" timestamp with time zone DEFAULT current_timestamp NOT NULL,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "bin_associations_bin_suite" UNIQUE ("bin", "suite")
+);
+CREATE INDEX "bin_associations_idx_bin" on "bin_associations" ("bin");
+CREATE INDEX "bin_associations_idx_suite" on "bin_associations" ("suite");
+
+;
+--
+-- View: "binary_versions"
+--
+CREATE VIEW "binary_versions" ( "src_pkg", "src_ver", "bin_pkg", "arch", "bin_ver", "src_ver_based_on", "src_pkg_based_on" ) AS
+    SELECT sp.pkg AS src_pkg, sv.ver AS src_ver, bp.pkg AS bin_pkg, a.arch AS arch, b.ver AS bin_ver,
+svb.ver AS src_ver_based_on, spb.pkg AS src_pkg_based_on
+FROM bin_ver b JOIN arch a ON b.arch = a.id
+                     JOIN bin_pkg bp ON b.bin_pkg  = bp.id
+               JOIN src_ver sv ON b.src_ver  = sv.id
+               JOIN src_pkg sp ON sv.src_pkg = sp.id
+               LEFT OUTER JOIN src_ver svb ON sv.based_on = svb.id
+               LEFT OUTER JOIN src_pkg spb ON spb.id = svb.src_pkg;
+
+;
+
+;
+--
+-- View: "bug_package"
+--
+CREATE VIEW "bug_package" ( "bug", "pkg_id", "pkg_type", "package" ) AS
+    SELECT b.bug,b.bin_pkg,'binary',bp.pkg FROM bug_binpackage b JOIN bin_pkg bp ON bp.id=b.bin_pkg UNION
+       SELECT s.bug,s.src_pkg,'source',sp.pkg FROM bug_srcpackage s JOIN src_pkg sp ON sp.id=s.src_pkg;
+
+;
+
+;
+--
+-- Foreign Key Definitions
+--
+
+;
+ALTER TABLE "src_pkg" ADD CONSTRAINT "src_pkg_fk_alias_of" FOREIGN KEY ("alias_of")
+  REFERENCES "src_pkg" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "correspondent_full_name" ADD CONSTRAINT "correspondent_full_name_fk_correspondent" FOREIGN KEY ("correspondent")
+  REFERENCES "correspondent" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "maintainer" ADD CONSTRAINT "maintainer_fk_correspondent" FOREIGN KEY ("correspondent")
+  REFERENCES "correspondent" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
+
+;
+ALTER TABLE "message_refs" ADD CONSTRAINT "message_refs_fk_message" FOREIGN KEY ("message")
+  REFERENCES "message" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "message_refs" ADD CONSTRAINT "message_refs_fk_refs" FOREIGN KEY ("refs")
+  REFERENCES "message" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "user_tag" ADD CONSTRAINT "user_tag_fk_correspondent" FOREIGN KEY ("correspondent")
+  REFERENCES "correspondent" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
+
+;
+ALTER TABLE "bug" ADD CONSTRAINT "bug_fk_done" FOREIGN KEY ("done")
+  REFERENCES "correspondent" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
+
+;
+ALTER TABLE "bug" ADD CONSTRAINT "bug_fk_owner" FOREIGN KEY ("owner")
+  REFERENCES "correspondent" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
+
+;
+ALTER TABLE "bug" ADD CONSTRAINT "bug_fk_severity" FOREIGN KEY ("severity")
+  REFERENCES "severity" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
+
+;
+ALTER TABLE "bug" ADD CONSTRAINT "bug_fk_submitter" FOREIGN KEY ("submitter")
+  REFERENCES "correspondent" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
+
+;
+ALTER TABLE "message_correspondent" ADD CONSTRAINT "message_correspondent_fk_correspondent" FOREIGN KEY ("correspondent")
+  REFERENCES "correspondent" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "message_correspondent" ADD CONSTRAINT "message_correspondent_fk_message" FOREIGN KEY ("message")
+  REFERENCES "message" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "bug_blocks" ADD CONSTRAINT "bug_blocks_fk_blocks" FOREIGN KEY ("blocks")
+  REFERENCES "bug" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
+
+;
+ALTER TABLE "bug_blocks" ADD CONSTRAINT "bug_blocks_fk_bug" FOREIGN KEY ("bug")
+  REFERENCES "bug" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
+
+;
+ALTER TABLE "bug_merged" ADD CONSTRAINT "bug_merged_fk_bug" FOREIGN KEY ("bug")
+  REFERENCES "bug" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
+
+;
+ALTER TABLE "bug_merged" ADD CONSTRAINT "bug_merged_fk_merged" FOREIGN KEY ("merged")
+  REFERENCES "bug" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
+
+;
+ALTER TABLE "src_ver" ADD CONSTRAINT "src_ver_fk_based_on" FOREIGN KEY ("based_on")
+  REFERENCES "src_ver" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "src_ver" ADD CONSTRAINT "src_ver_fk_maintainer" FOREIGN KEY ("maintainer")
+  REFERENCES "maintainer" ("id") ON DELETE SET NULL ON UPDATE CASCADE;
+
+;
+ALTER TABLE "src_ver" ADD CONSTRAINT "src_ver_fk_src_pkg" FOREIGN KEY ("src_pkg")
+  REFERENCES "src_pkg" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "bug_affects_binpackage" ADD CONSTRAINT "bug_affects_binpackage_fk_bin_pkg" FOREIGN KEY ("bin_pkg")
+  REFERENCES "bin_pkg" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "bug_affects_binpackage" ADD CONSTRAINT "bug_affects_binpackage_fk_bug" FOREIGN KEY ("bug")
+  REFERENCES "bug" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
+
+;
+ALTER TABLE "bug_affects_srcpackage" ADD CONSTRAINT "bug_affects_srcpackage_fk_bug" FOREIGN KEY ("bug")
+  REFERENCES "bug" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
+
+;
+ALTER TABLE "bug_affects_srcpackage" ADD CONSTRAINT "bug_affects_srcpackage_fk_src_pkg" FOREIGN KEY ("src_pkg")
+  REFERENCES "src_pkg" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "bug_binpackage" ADD CONSTRAINT "bug_binpackage_fk_bin_pkg" FOREIGN KEY ("bin_pkg")
+  REFERENCES "bin_pkg" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "bug_binpackage" ADD CONSTRAINT "bug_binpackage_fk_bug" FOREIGN KEY ("bug")
+  REFERENCES "bug" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
+
+;
+ALTER TABLE "bug_message" ADD CONSTRAINT "bug_message_fk_bug" FOREIGN KEY ("bug")
+  REFERENCES "bug" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "bug_message" ADD CONSTRAINT "bug_message_fk_message" FOREIGN KEY ("message")
+  REFERENCES "message" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "bug_srcpackage" ADD CONSTRAINT "bug_srcpackage_fk_bug" FOREIGN KEY ("bug")
+  REFERENCES "bug" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
+
+;
+ALTER TABLE "bug_srcpackage" ADD CONSTRAINT "bug_srcpackage_fk_src_pkg" FOREIGN KEY ("src_pkg")
+  REFERENCES "src_pkg" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "bug_tag" ADD CONSTRAINT "bug_tag_fk_bug" FOREIGN KEY ("bug")
+  REFERENCES "bug" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
+
+;
+ALTER TABLE "bug_tag" ADD CONSTRAINT "bug_tag_fk_tag" FOREIGN KEY ("tag")
+  REFERENCES "tag" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
+
+;
+ALTER TABLE "bug_user_tag" ADD CONSTRAINT "bug_user_tag_fk_bug" FOREIGN KEY ("bug")
+  REFERENCES "bug" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
+
+;
+ALTER TABLE "bug_user_tag" ADD CONSTRAINT "bug_user_tag_fk_user_tag" FOREIGN KEY ("user_tag")
+  REFERENCES "user_tag" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
+
+;
+ALTER TABLE "bug_status_cache" ADD CONSTRAINT "bug_status_cache_fk_arch" FOREIGN KEY ("arch")
+  REFERENCES "arch" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "bug_status_cache" ADD CONSTRAINT "bug_status_cache_fk_bug" FOREIGN KEY ("bug")
+  REFERENCES "bug" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "bug_status_cache" ADD CONSTRAINT "bug_status_cache_fk_suite" FOREIGN KEY ("suite")
+  REFERENCES "suite" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "src_associations" ADD CONSTRAINT "src_associations_fk_source" FOREIGN KEY ("source")
+  REFERENCES "src_ver" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "src_associations" ADD CONSTRAINT "src_associations_fk_suite" FOREIGN KEY ("suite")
+  REFERENCES "suite" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "bin_ver" ADD CONSTRAINT "bin_ver_fk_arch" FOREIGN KEY ("arch")
+  REFERENCES "arch" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "bin_ver" ADD CONSTRAINT "bin_ver_fk_bin_pkg" FOREIGN KEY ("bin_pkg")
+  REFERENCES "bin_pkg" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "bin_ver" ADD CONSTRAINT "bin_ver_fk_src_ver" FOREIGN KEY ("src_ver")
+  REFERENCES "src_ver" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "bug_ver" ADD CONSTRAINT "bug_ver_fk_bug" FOREIGN KEY ("bug")
+  REFERENCES "bug" ("id") ON DELETE RESTRICT ON UPDATE CASCADE;
+
+;
+ALTER TABLE "bug_ver" ADD CONSTRAINT "bug_ver_fk_src_pkg" FOREIGN KEY ("src_pkg")
+  REFERENCES "src_pkg" ("id") ON DELETE SET NULL ON UPDATE CASCADE;
+
+;
+ALTER TABLE "bug_ver" ADD CONSTRAINT "bug_ver_fk_src_ver" FOREIGN KEY ("src_ver")
+  REFERENCES "src_ver" ("id") ON DELETE SET NULL ON UPDATE CASCADE;
+
+;
+ALTER TABLE "bin_associations" ADD CONSTRAINT "bin_associations_fk_bin" FOREIGN KEY ("bin")
+  REFERENCES "bin_ver" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "bin_associations" ADD CONSTRAINT "bin_associations_fk_suite" FOREIGN KEY ("suite")
+  REFERENCES "suite" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
diff --git a/sql/PostgreSQL/deploy/6/001-auto.sql b/sql/PostgreSQL/deploy/6/001-auto.sql
new file mode 100644 (file)
index 0000000..3b4b122
--- /dev/null
@@ -0,0 +1,702 @@
+-- 
+-- Created by SQL::Translator::Producer::PostgreSQL
+-- Created on Sat Apr 15 20:14:22 2017
+-- 
+;
+--
+-- Table: arch
+--
+CREATE TABLE "arch" (
+  "id" serial NOT NULL,
+  "arch" text NOT NULL,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "arch_arch_key" UNIQUE ("arch")
+);
+
+;
+--
+-- Table: bin_pkg
+--
+CREATE TABLE "bin_pkg" (
+  "id" serial NOT NULL,
+  "pkg" text NOT NULL,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "bin_pkg_pkg_key" UNIQUE ("pkg")
+);
+
+;
+--
+-- Table: column_comments
+--
+CREATE TABLE "column_comments" (
+  "table_name" text NOT NULL,
+  "column_name" text NOT NULL,
+  "comment_text" text NOT NULL,
+  CONSTRAINT "column_comments_table_name_column_name_idx" UNIQUE ("table_name", "column_name")
+);
+
+;
+--
+-- Table: correspondent
+--
+CREATE TABLE "correspondent" (
+  "id" serial NOT NULL,
+  "addr" text NOT NULL,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "correspondent_addr_idx" UNIQUE ("addr")
+);
+
+;
+--
+-- Table: message
+--
+CREATE TABLE "message" (
+  "id" serial NOT NULL,
+  "msgid" text DEFAULT '' NOT NULL,
+  "from_complete" text DEFAULT '' NOT NULL,
+  "to_complete" text DEFAULT '' NOT NULL,
+  "subject" text DEFAULT '' NOT NULL,
+  "sent_date" timestamp with time zone,
+  "refs" text DEFAULT '' NOT NULL,
+  "spam_score" double precision DEFAULT '0' NOT NULL,
+  "is_spam" boolean DEFAULT false NOT NULL,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "message_msgid_from_complete_to_complete_subject_idx" UNIQUE ("msgid", "from_complete", "to_complete", "subject")
+);
+CREATE INDEX "message_msgid_idx" on "message" ("msgid");
+CREATE INDEX "message_subject_idx" on "message" ("subject");
+
+;
+--
+-- Table: severity
+--
+CREATE TABLE "severity" (
+  "id" serial NOT NULL,
+  "severity" text NOT NULL,
+  "ordering" integer DEFAULT 5 NOT NULL,
+  "strong" boolean DEFAULT false,
+  "obsolete" boolean DEFAULT false,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "severity_severity_idx" UNIQUE ("severity")
+);
+CREATE INDEX "severity_ordering_idx" on "severity" ("ordering");
+
+;
+--
+-- Table: src_pkg
+--
+CREATE TABLE "src_pkg" (
+  "id" serial NOT NULL,
+  "pkg" text NOT NULL,
+  "pseduopkg" boolean DEFAULT false NOT NULL,
+  "alias_of" integer,
+  "creation" timestamp with time zone DEFAULT current_timestamp NOT NULL,
+  "disabled" timestamp with time zone DEFAULT 'infinity' NOT NULL,
+  "last_modified" timestamp with time zone DEFAULT current_timestamp NOT NULL,
+  "obsolete" boolean DEFAULT false NOT NULL,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "src_pkg_pkg_disabled" UNIQUE ("pkg", "disabled")
+);
+CREATE INDEX "src_pkg_idx_alias_of" on "src_pkg" ("alias_of");
+CREATE INDEX "src_pkg_pkg" on "src_pkg" ("pkg");
+
+;
+--
+-- Table: suite
+--
+CREATE TABLE "suite" (
+  "id" serial NOT NULL,
+  "codename" text NOT NULL,
+  "suite_name" text,
+  "version" text,
+  "active" boolean DEFAULT true,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "suite_idx_codename" UNIQUE ("codename"),
+  CONSTRAINT "suite_idx_version" UNIQUE ("version"),
+  CONSTRAINT "suite_suite_name_key" UNIQUE ("suite_name")
+);
+
+;
+--
+-- Table: table_comments
+--
+CREATE TABLE "table_comments" (
+  "table_name" text NOT NULL,
+  "comment_text" text NOT NULL,
+  CONSTRAINT "table_comments_table_name_idx" UNIQUE ("table_name"),
+  CONSTRAINT "table_comments_table_name_key" UNIQUE ("table_name")
+);
+
+;
+--
+-- Table: tag
+--
+CREATE TABLE "tag" (
+  "id" serial NOT NULL,
+  "tag" text NOT NULL,
+  "obsolete" boolean DEFAULT false,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "tag_tag_key" UNIQUE ("tag")
+);
+
+;
+--
+-- Table: correspondent_full_name
+--
+CREATE TABLE "correspondent_full_name" (
+  "correspondent" integer NOT NULL,
+  "full_name" text NOT NULL,
+  "last_seen" timestamp DEFAULT current_timestamp NOT NULL,
+  CONSTRAINT "correspondent_full_name_correspondent_full_name_idx" UNIQUE ("correspondent", "full_name")
+);
+CREATE INDEX "correspondent_full_name_idx_correspondent" on "correspondent_full_name" ("correspondent");
+CREATE INDEX "correspondent_full_name_idx_full_name" on "correspondent_full_name" ("full_name");
+CREATE INDEX "correspondent_full_name_idx_last_seen" on "correspondent_full_name" ("last_seen");
+
+;
+--
+-- Table: maintainer
+--
+CREATE TABLE "maintainer" (
+  "id" serial NOT NULL,
+  "name" text NOT NULL,
+  "correspondent" integer NOT NULL,
+  "created" timestamp with time zone DEFAULT current_timestamp NOT NULL,
+  "modified" timestamp with time zone DEFAULT current_timestamp NOT NULL,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "maintainer_name_idx" UNIQUE ("name")
+);
+CREATE INDEX "maintainer_idx_correspondent" on "maintainer" ("correspondent");
+
+;
+--
+-- Table: message_refs
+--
+CREATE TABLE "message_refs" (
+  "message" integer NOT NULL,
+  "refs" integer NOT NULL,
+  "inferred" boolean DEFAULT false,
+  "primary_ref" boolean DEFAULT false,
+  CONSTRAINT "message_refs_message_refs_idx" UNIQUE ("message", "refs")
+);
+CREATE INDEX "message_refs_idx_message" on "message_refs" ("message");
+CREATE INDEX "message_refs_idx_refs" on "message_refs" ("refs");
+
+;
+--
+-- Table: user_tag
+--
+CREATE TABLE "user_tag" (
+  "id" serial NOT NULL,
+  "tag" text NOT NULL,
+  "correspondent" integer NOT NULL,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "user_tag_tag_correspondent" UNIQUE ("tag", "correspondent")
+);
+CREATE INDEX "user_tag_idx_correspondent" on "user_tag" ("correspondent");
+CREATE INDEX "user_tag_correspondent" on "user_tag" ("correspondent");
+
+;
+--
+-- Table: bug
+--
+CREATE TABLE "bug" (
+  "id" integer NOT NULL,
+  "creation" timestamp with time zone DEFAULT current_timestamp NOT NULL,
+  "log_modified" timestamp with time zone DEFAULT current_timestamp NOT NULL,
+  "last_modified" timestamp with time zone DEFAULT current_timestamp NOT NULL,
+  "archived" boolean DEFAULT false NOT NULL,
+  "unarchived" timestamp with time zone,
+  "forwarded" text DEFAULT '' NOT NULL,
+  "summary" text DEFAULT '' NOT NULL,
+  "outlook" text DEFAULT '' NOT NULL,
+  "subject" text NOT NULL,
+  "severity" integer NOT NULL,
+  "done" integer,
+  "done_full" text DEFAULT '' NOT NULL,
+  "owner" integer,
+  "owner_full" text DEFAULT '' NOT NULL,
+  "submitter" integer,
+  "submitter_full" text DEFAULT '' NOT NULL,
+  "unknown_packages" text DEFAULT '' NOT NULL,
+  PRIMARY KEY ("id")
+);
+CREATE INDEX "bug_idx_done" on "bug" ("done");
+CREATE INDEX "bug_idx_owner" on "bug" ("owner");
+CREATE INDEX "bug_idx_severity" on "bug" ("severity");
+CREATE INDEX "bug_idx_submitter" on "bug" ("submitter");
+CREATE INDEX "bug_idxowner" on "bug" ("owner");
+CREATE INDEX "bug_idxsubmitter" on "bug" ("submitter");
+CREATE INDEX "bug_idxdone" on "bug" ("done");
+CREATE INDEX "bug_idxforwarded" on "bug" ("forwarded");
+CREATE INDEX "bug_idxlast_modified" on "bug" ("last_modified");
+CREATE INDEX "bug_idxseverity" on "bug" ("severity");
+CREATE INDEX "bug_idxcreation" on "bug" ("creation");
+CREATE INDEX "bug_idxlog_modified" on "bug" ("log_modified");
+
+;
+--
+-- Table: message_correspondent
+--
+CREATE TABLE "message_correspondent" (
+  "message" integer NOT NULL,
+  "correspondent" integer NOT NULL,
+  "correspondent_type" character varying DEFAULT 'to' NOT NULL,
+  CONSTRAINT "message_correspondent_message_correspondent_correspondent_t_idx" UNIQUE ("message", "correspondent", "correspondent_type")
+);
+CREATE INDEX "message_correspondent_idx_correspondent" on "message_correspondent" ("correspondent");
+CREATE INDEX "message_correspondent_idx_message" on "message_correspondent" ("message");
+CREATE INDEX "message_correspondent_idxcorrespondent" on "message_correspondent" ("correspondent");
+CREATE INDEX "message_correspondent_idxmessage" on "message_correspondent" ("message");
+
+;
+--
+-- Table: bug_blocks
+--
+CREATE TABLE "bug_blocks" (
+  "id" serial NOT NULL,
+  "bug" integer NOT NULL,
+  "blocks" integer NOT NULL,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "bug_blocks_bug_id_blocks_idx" UNIQUE ("bug", "blocks")
+);
+CREATE INDEX "bug_blocks_idx_blocks" on "bug_blocks" ("blocks");
+CREATE INDEX "bug_blocks_idx_bug" on "bug_blocks" ("bug");
+CREATE INDEX "bug_blocks_bug_idx" on "bug_blocks" ("bug");
+CREATE INDEX "bug_blocks_blocks_idx" on "bug_blocks" ("blocks");
+
+;
+--
+-- Table: bug_merged
+--
+CREATE TABLE "bug_merged" (
+  "id" serial NOT NULL,
+  "bug" integer NOT NULL,
+  "merged" integer NOT NULL,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "bug_merged_bug_id_merged_idx" UNIQUE ("bug", "merged")
+);
+CREATE INDEX "bug_merged_idx_bug" on "bug_merged" ("bug");
+CREATE INDEX "bug_merged_idx_merged" on "bug_merged" ("merged");
+CREATE INDEX "bug_merged_bug_idx" on "bug_merged" ("bug");
+CREATE INDEX "bug_merged_merged_idx" on "bug_merged" ("merged");
+
+;
+--
+-- Table: src_ver
+--
+CREATE TABLE "src_ver" (
+  "id" serial NOT NULL,
+  "src_pkg" integer NOT NULL,
+  "ver" debversion NOT NULL,
+  "maintainer" integer,
+  "upload_date" timestamp with time zone DEFAULT current_timestamp NOT NULL,
+  "based_on" integer,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "src_ver_src_pkg_id_ver" UNIQUE ("src_pkg", "ver")
+);
+CREATE INDEX "src_ver_idx_based_on" on "src_ver" ("based_on");
+CREATE INDEX "src_ver_idx_maintainer" on "src_ver" ("maintainer");
+CREATE INDEX "src_ver_idx_src_pkg" on "src_ver" ("src_pkg");
+
+;
+--
+-- Table: bug_affects_binpackage
+--
+CREATE TABLE "bug_affects_binpackage" (
+  "bug" integer NOT NULL,
+  "bin_pkg" integer NOT NULL,
+  CONSTRAINT "bug_affects_binpackage_id_pkg" UNIQUE ("bug", "bin_pkg")
+);
+CREATE INDEX "bug_affects_binpackage_idx_bin_pkg" on "bug_affects_binpackage" ("bin_pkg");
+CREATE INDEX "bug_affects_binpackage_idx_bug" on "bug_affects_binpackage" ("bug");
+
+;
+--
+-- Table: bug_affects_srcpackage
+--
+CREATE TABLE "bug_affects_srcpackage" (
+  "bug" integer NOT NULL,
+  "src_pkg" integer NOT NULL,
+  CONSTRAINT "bug_affects_srcpackage_id_pkg" UNIQUE ("bug", "src_pkg")
+);
+CREATE INDEX "bug_affects_srcpackage_idx_bug" on "bug_affects_srcpackage" ("bug");
+CREATE INDEX "bug_affects_srcpackage_idx_src_pkg" on "bug_affects_srcpackage" ("src_pkg");
+
+;
+--
+-- Table: bug_binpackage
+--
+CREATE TABLE "bug_binpackage" (
+  "bug" integer NOT NULL,
+  "bin_pkg" integer NOT NULL,
+  CONSTRAINT "bug_binpackage_id_pkg" UNIQUE ("bug", "bin_pkg")
+);
+CREATE INDEX "bug_binpackage_idx_bin_pkg" on "bug_binpackage" ("bin_pkg");
+CREATE INDEX "bug_binpackage_idx_bug" on "bug_binpackage" ("bug");
+CREATE INDEX "bug_binpackage_bin_pkg_idx" on "bug_binpackage" ("bin_pkg");
+
+;
+--
+-- Table: bug_message
+--
+CREATE TABLE "bug_message" (
+  "bug" integer NOT NULL,
+  "message" integer NOT NULL,
+  "message_number" integer NOT NULL,
+  "bug_log_offset" integer,
+  "offset_valid" timestamp with time zone,
+  CONSTRAINT "bug_message_bug_message_idx" UNIQUE ("bug", "message")
+);
+CREATE INDEX "bug_message_idx_bug" on "bug_message" ("bug");
+CREATE INDEX "bug_message_idx_message" on "bug_message" ("message");
+CREATE INDEX "bug_message_idx_bug_message_number" on "bug_message" ("bug", "message_number");
+
+;
+--
+-- Table: bug_srcpackage
+--
+CREATE TABLE "bug_srcpackage" (
+  "bug" integer NOT NULL,
+  "src_pkg" integer NOT NULL,
+  CONSTRAINT "bug_srcpackage_id_pkg" UNIQUE ("bug", "src_pkg")
+);
+CREATE INDEX "bug_srcpackage_idx_bug" on "bug_srcpackage" ("bug");
+CREATE INDEX "bug_srcpackage_idx_src_pkg" on "bug_srcpackage" ("src_pkg");
+CREATE INDEX "bug_srcpackage_src_pkg_idx" on "bug_srcpackage" ("src_pkg");
+
+;
+--
+-- Table: bug_tag
+--
+CREATE TABLE "bug_tag" (
+  "bug" integer NOT NULL,
+  "tag" integer NOT NULL,
+  CONSTRAINT "bug_tag_bug_tag" UNIQUE ("bug", "tag")
+);
+CREATE INDEX "bug_tag_idx_bug" on "bug_tag" ("bug");
+CREATE INDEX "bug_tag_idx_tag" on "bug_tag" ("tag");
+CREATE INDEX "bug_tag_tag" on "bug_tag" ("tag");
+
+;
+--
+-- Table: bug_user_tag
+--
+CREATE TABLE "bug_user_tag" (
+  "bug" integer NOT NULL,
+  "user_tag" integer NOT NULL,
+  CONSTRAINT "bug_user_tag_bug_tag" UNIQUE ("bug", "user_tag")
+);
+CREATE INDEX "bug_user_tag_idx_bug" on "bug_user_tag" ("bug");
+CREATE INDEX "bug_user_tag_idx_user_tag" on "bug_user_tag" ("user_tag");
+CREATE INDEX "bug_user_tag_tag" on "bug_user_tag" ("user_tag");
+
+;
+--
+-- Table: bug_status_cache
+--
+CREATE TABLE "bug_status_cache" (
+  "bug" integer NOT NULL,
+  "suite" integer,
+  "arch" integer,
+  "status" character varying NOT NULL,
+  "modified" timestamp with time zone DEFAULT current_timestamp NOT NULL,
+  "asof" timestamp with time zone DEFAULT current_timestamp NOT NULL,
+  CONSTRAINT "bug_status_cache_bug_suite_arch_idx" UNIQUE ("bug", "suite", "arch")
+);
+CREATE INDEX "bug_status_cache_idx_arch" on "bug_status_cache" ("arch");
+CREATE INDEX "bug_status_cache_idx_bug" on "bug_status_cache" ("bug");
+CREATE INDEX "bug_status_cache_idx_suite" on "bug_status_cache" ("suite");
+
+;
+--
+-- Table: src_associations
+--
+CREATE TABLE "src_associations" (
+  "id" serial NOT NULL,
+  "suite" integer NOT NULL,
+  "source" integer NOT NULL,
+  "created" timestamp with time zone DEFAULT current_timestamp NOT NULL,
+  "modified" timestamp with time zone DEFAULT current_timestamp NOT NULL,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "src_associations_source_suite" UNIQUE ("source", "suite")
+);
+CREATE INDEX "src_associations_idx_source" on "src_associations" ("source");
+CREATE INDEX "src_associations_idx_suite" on "src_associations" ("suite");
+
+;
+--
+-- Table: bin_ver
+--
+CREATE TABLE "bin_ver" (
+  "id" serial NOT NULL,
+  "bin_pkg" integer NOT NULL,
+  "src_ver" integer NOT NULL,
+  "arch" integer NOT NULL,
+  "ver" debversion NOT NULL,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "bin_ver_bin_pkg_id_arch_idx" UNIQUE ("bin_pkg", "arch", "ver")
+);
+CREATE INDEX "bin_ver_idx_arch" on "bin_ver" ("arch");
+CREATE INDEX "bin_ver_idx_bin_pkg" on "bin_ver" ("bin_pkg");
+CREATE INDEX "bin_ver_idx_src_ver" on "bin_ver" ("src_ver");
+CREATE INDEX "bin_ver_ver_id_idx" on "bin_ver" ("ver");
+CREATE INDEX "bin_ver_bin_pkg_id_idx" on "bin_ver" ("bin_pkg");
+CREATE INDEX "bin_ver_src_ver_id_idx" on "bin_ver" ("src_ver");
+CREATE INDEX "bin_ver_src_ver_id_arch_idx" on "bin_ver" ("src_ver", "arch");
+
+;
+--
+-- Table: bug_ver
+--
+CREATE TABLE "bug_ver" (
+  "id" serial NOT NULL,
+  "bug" integer NOT NULL,
+  "ver_string" text,
+  "src_pkg" integer,
+  "src_ver" integer,
+  "found" boolean DEFAULT true NOT NULL,
+  "creation" timestamp with time zone DEFAULT current_timestamp NOT NULL,
+  "last_modified" timestamp with time zone DEFAULT current_timestamp NOT NULL,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "bug_ver_bug_ver_string_found_idx" UNIQUE ("bug", "ver_string", "found")
+);
+CREATE INDEX "bug_ver_idx_bug" on "bug_ver" ("bug");
+CREATE INDEX "bug_ver_idx_src_pkg" on "bug_ver" ("src_pkg");
+CREATE INDEX "bug_ver_idx_src_ver" on "bug_ver" ("src_ver");
+CREATE INDEX "bug_ver_src_pkg_id_idx" on "bug_ver" ("src_pkg");
+CREATE INDEX "bug_ver_src_ver_id_idx" on "bug_ver" ("src_ver");
+CREATE INDEX "bug_ver_src_pkg_id_src_ver_id_idx" on "bug_ver" ("src_pkg", "src_ver");
+
+;
+--
+-- Table: bin_associations
+--
+CREATE TABLE "bin_associations" (
+  "id" serial NOT NULL,
+  "suite" integer NOT NULL,
+  "bin" integer NOT NULL,
+  "created" timestamp with time zone DEFAULT current_timestamp NOT NULL,
+  "modified" timestamp with time zone DEFAULT current_timestamp NOT NULL,
+  PRIMARY KEY ("id"),
+  CONSTRAINT "bin_associations_bin_suite" UNIQUE ("bin", "suite")
+);
+CREATE INDEX "bin_associations_idx_bin" on "bin_associations" ("bin");
+CREATE INDEX "bin_associations_idx_suite" on "bin_associations" ("suite");
+
+;
+--
+-- View: "binary_versions"
+--
+CREATE VIEW "binary_versions" ( "src_pkg", "src_ver", "bin_pkg", "arch", "bin_ver", "src_ver_based_on", "src_pkg_based_on" ) AS
+    SELECT sp.pkg AS src_pkg, sv.ver AS src_ver, bp.pkg AS bin_pkg, a.arch AS arch, b.ver AS bin_ver,
+svb.ver AS src_ver_based_on, spb.pkg AS src_pkg_based_on
+FROM bin_ver b JOIN arch a ON b.arch = a.id
+                     JOIN bin_pkg bp ON b.bin_pkg  = bp.id
+               JOIN src_ver sv ON b.src_ver  = sv.id
+               JOIN src_pkg sp ON sv.src_pkg = sp.id
+               LEFT OUTER JOIN src_ver svb ON sv.based_on = svb.id
+               LEFT OUTER JOIN src_pkg spb ON spb.id = svb.src_pkg;
+
+;
+
+;
+--
+-- View: "bug_package"
+--
+CREATE VIEW "bug_package" ( "bug", "pkg_id", "pkg_type", "package" ) AS
+    SELECT b.bug,b.bin_pkg,'binary',bp.pkg FROM bug_binpackage b JOIN bin_pkg bp ON bp.id=b.bin_pkg UNION
+       SELECT s.bug,s.src_pkg,'source',sp.pkg FROM bug_srcpackage s JOIN src_pkg sp ON sp.id=s.src_pkg;
+
+;
+
+;
+--
+-- Foreign Key Definitions
+--
+
+;
+ALTER TABLE "src_pkg" ADD CONSTRAINT "src_pkg_fk_alias_of" FOREIGN KEY ("alias_of")
+  REFERENCES "src_pkg" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "correspondent_full_name" ADD CONSTRAINT "correspondent_full_name_fk_correspondent" FOREIGN KEY ("correspondent")
+  REFERENCES "correspondent" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "maintainer" ADD CONSTRAINT "maintainer_fk_correspondent" FOREIGN KEY ("correspondent")
+  REFERENCES "correspondent" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
+
+;
+ALTER TABLE "message_refs" ADD CONSTRAINT "message_refs_fk_message" FOREIGN KEY ("message")
+  REFERENCES "message" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "message_refs" ADD CONSTRAINT "message_refs_fk_refs" FOREIGN KEY ("refs")
+  REFERENCES "message" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "user_tag" ADD CONSTRAINT "user_tag_fk_correspondent" FOREIGN KEY ("correspondent")
+  REFERENCES "correspondent" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
+
+;
+ALTER TABLE "bug" ADD CONSTRAINT "bug_fk_done" FOREIGN KEY ("done")
+  REFERENCES "correspondent" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
+
+;
+ALTER TABLE "bug" ADD CONSTRAINT "bug_fk_owner" FOREIGN KEY ("owner")
+  REFERENCES "correspondent" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
+
+;
+ALTER TABLE "bug" ADD CONSTRAINT "bug_fk_severity" FOREIGN KEY ("severity")
+  REFERENCES "severity" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
+
+;
+ALTER TABLE "bug" ADD CONSTRAINT "bug_fk_submitter" FOREIGN KEY ("submitter")
+  REFERENCES "correspondent" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
+
+;
+ALTER TABLE "message_correspondent" ADD CONSTRAINT "message_correspondent_fk_correspondent" FOREIGN KEY ("correspondent")
+  REFERENCES "correspondent" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "message_correspondent" ADD CONSTRAINT "message_correspondent_fk_message" FOREIGN KEY ("message")
+  REFERENCES "message" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "bug_blocks" ADD CONSTRAINT "bug_blocks_fk_blocks" FOREIGN KEY ("blocks")
+  REFERENCES "bug" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
+
+;
+ALTER TABLE "bug_blocks" ADD CONSTRAINT "bug_blocks_fk_bug" FOREIGN KEY ("bug")
+  REFERENCES "bug" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
+
+;
+ALTER TABLE "bug_merged" ADD CONSTRAINT "bug_merged_fk_bug" FOREIGN KEY ("bug")
+  REFERENCES "bug" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
+
+;
+ALTER TABLE "bug_merged" ADD CONSTRAINT "bug_merged_fk_merged" FOREIGN KEY ("merged")
+  REFERENCES "bug" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
+
+;
+ALTER TABLE "src_ver" ADD CONSTRAINT "src_ver_fk_based_on" FOREIGN KEY ("based_on")
+  REFERENCES "src_ver" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "src_ver" ADD CONSTRAINT "src_ver_fk_maintainer" FOREIGN KEY ("maintainer")
+  REFERENCES "maintainer" ("id") ON DELETE SET NULL ON UPDATE CASCADE;
+
+;
+ALTER TABLE "src_ver" ADD CONSTRAINT "src_ver_fk_src_pkg" FOREIGN KEY ("src_pkg")
+  REFERENCES "src_pkg" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "bug_affects_binpackage" ADD CONSTRAINT "bug_affects_binpackage_fk_bin_pkg" FOREIGN KEY ("bin_pkg")
+  REFERENCES "bin_pkg" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "bug_affects_binpackage" ADD CONSTRAINT "bug_affects_binpackage_fk_bug" FOREIGN KEY ("bug")
+  REFERENCES "bug" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
+
+;
+ALTER TABLE "bug_affects_srcpackage" ADD CONSTRAINT "bug_affects_srcpackage_fk_bug" FOREIGN KEY ("bug")
+  REFERENCES "bug" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
+
+;
+ALTER TABLE "bug_affects_srcpackage" ADD CONSTRAINT "bug_affects_srcpackage_fk_src_pkg" FOREIGN KEY ("src_pkg")
+  REFERENCES "src_pkg" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "bug_binpackage" ADD CONSTRAINT "bug_binpackage_fk_bin_pkg" FOREIGN KEY ("bin_pkg")
+  REFERENCES "bin_pkg" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "bug_binpackage" ADD CONSTRAINT "bug_binpackage_fk_bug" FOREIGN KEY ("bug")
+  REFERENCES "bug" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
+
+;
+ALTER TABLE "bug_message" ADD CONSTRAINT "bug_message_fk_bug" FOREIGN KEY ("bug")
+  REFERENCES "bug" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "bug_message" ADD CONSTRAINT "bug_message_fk_message" FOREIGN KEY ("message")
+  REFERENCES "message" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "bug_srcpackage" ADD CONSTRAINT "bug_srcpackage_fk_bug" FOREIGN KEY ("bug")
+  REFERENCES "bug" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
+
+;
+ALTER TABLE "bug_srcpackage" ADD CONSTRAINT "bug_srcpackage_fk_src_pkg" FOREIGN KEY ("src_pkg")
+  REFERENCES "src_pkg" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "bug_tag" ADD CONSTRAINT "bug_tag_fk_bug" FOREIGN KEY ("bug")
+  REFERENCES "bug" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
+
+;
+ALTER TABLE "bug_tag" ADD CONSTRAINT "bug_tag_fk_tag" FOREIGN KEY ("tag")
+  REFERENCES "tag" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
+
+;
+ALTER TABLE "bug_user_tag" ADD CONSTRAINT "bug_user_tag_fk_bug" FOREIGN KEY ("bug")
+  REFERENCES "bug" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
+
+;
+ALTER TABLE "bug_user_tag" ADD CONSTRAINT "bug_user_tag_fk_user_tag" FOREIGN KEY ("user_tag")
+  REFERENCES "user_tag" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
+
+;
+ALTER TABLE "bug_status_cache" ADD CONSTRAINT "bug_status_cache_fk_arch" FOREIGN KEY ("arch")
+  REFERENCES "arch" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "bug_status_cache" ADD CONSTRAINT "bug_status_cache_fk_bug" FOREIGN KEY ("bug")
+  REFERENCES "bug" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "bug_status_cache" ADD CONSTRAINT "bug_status_cache_fk_suite" FOREIGN KEY ("suite")
+  REFERENCES "suite" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "src_associations" ADD CONSTRAINT "src_associations_fk_source" FOREIGN KEY ("source")
+  REFERENCES "src_ver" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "src_associations" ADD CONSTRAINT "src_associations_fk_suite" FOREIGN KEY ("suite")
+  REFERENCES "suite" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "bin_ver" ADD CONSTRAINT "bin_ver_fk_arch" FOREIGN KEY ("arch")
+  REFERENCES "arch" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "bin_ver" ADD CONSTRAINT "bin_ver_fk_bin_pkg" FOREIGN KEY ("bin_pkg")
+  REFERENCES "bin_pkg" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "bin_ver" ADD CONSTRAINT "bin_ver_fk_src_ver" FOREIGN KEY ("src_ver")
+  REFERENCES "src_ver" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "bug_ver" ADD CONSTRAINT "bug_ver_fk_bug" FOREIGN KEY ("bug")
+  REFERENCES "bug" ("id") ON DELETE RESTRICT ON UPDATE CASCADE;
+
+;
+ALTER TABLE "bug_ver" ADD CONSTRAINT "bug_ver_fk_src_pkg" FOREIGN KEY ("src_pkg")
+  REFERENCES "src_pkg" ("id") ON DELETE SET NULL ON UPDATE CASCADE;
+
+;
+ALTER TABLE "bug_ver" ADD CONSTRAINT "bug_ver_fk_src_ver" FOREIGN KEY ("src_ver")
+  REFERENCES "src_ver" ("id") ON DELETE SET NULL ON UPDATE CASCADE;
+
+;
+ALTER TABLE "bin_associations" ADD CONSTRAINT "bin_associations_fk_bin" FOREIGN KEY ("bin")
+  REFERENCES "bin_ver" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
+ALTER TABLE "bin_associations" ADD CONSTRAINT "bin_associations_fk_suite" FOREIGN KEY ("suite")
+  REFERENCES "suite" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+;
diff --git a/sql/PostgreSQL/upgrade/1-1/001-auto.sql b/sql/PostgreSQL/upgrade/1-1/001-auto.sql
new file mode 100644 (file)
index 0000000..6f388eb
--- /dev/null
@@ -0,0 +1,5 @@
+-- Convert schema 'sql/_source/deploy/1/001-auto.yml' to 'sql/_source/deploy/1/001-auto.yml':;
+
+;
+-- No differences found;
+
diff --git a/sql/PostgreSQL/upgrade/5-6/001-auto.sql b/sql/PostgreSQL/upgrade/5-6/001-auto.sql
new file mode 100644 (file)
index 0000000..0e6fe49
--- /dev/null
@@ -0,0 +1,51 @@
+-- Convert schema 'sql/_source/deploy/5/001-auto.yml' to 'sql/_source/deploy/6/001-auto.yml':;
+
+;
+BEGIN;
+
+;
+CREATE INDEX bin_ver_ver_id_idx on bin_ver (ver);
+
+;
+CREATE INDEX bin_ver_src_ver_id_arch_idx on bin_ver (src_ver, arch);
+
+;
+CREATE INDEX bug_idxforwarded on bug (forwarded);
+
+;
+CREATE INDEX bug_idxlast_modified on bug (last_modified);
+
+;
+CREATE INDEX bug_idxcreation on bug (creation);
+
+;
+CREATE INDEX bug_idxlog_modified on bug (log_modified);
+
+;
+CREATE INDEX bug_message_idx_bug_message_number on bug_message (bug, message_number);
+
+;
+CREATE INDEX bug_ver_src_pkg_id_src_ver_id_idx on bug_ver (src_pkg, src_ver);
+
+;
+CREATE INDEX correspondent_full_name_idx_full_name on correspondent_full_name (full_name);
+
+;
+CREATE INDEX correspondent_full_name_idx_last_seen on correspondent_full_name (last_seen);
+
+;
+CREATE INDEX message_msgid_idx on message (msgid);
+
+;
+CREATE INDEX message_subject_idx on message (subject);
+
+;
+CREATE INDEX severity_ordering_idx on severity (ordering);
+
+;
+CREATE INDEX src_pkg_pkg on src_pkg (pkg);
+
+;
+
+COMMIT;
+
diff --git a/sql/README.mdwn b/sql/README.mdwn
new file mode 100644 (file)
index 0000000..a5dc05e
--- /dev/null
@@ -0,0 +1,17 @@
+# Developer specific instructions #
+## Upgrading Schema ##
+
+To make changes to the database schema:
+
+1. Make whatever changes are appropriate to the SQL directly in the
+   debbugs_schema.sql file, and make corresponding changes to the
+   database (or dump the entire database and otherwise make the
+   changes).
+    + If you add non-unique indexes, you will need to add an sqlt_deploy_hook
+      (or edit an exist one) to add the index
+2. Run `./sql/dbicdump_command.sh` to update the DBIx::Class classes which are
+   under Debbugs::DB if you made changes to the database directly
+3. Increment the version of Debbugs::DB;
+
+Steps 1 and 2 can alternatively be performed by changing the
+DBIx::Class classes directly if that is desired.
diff --git a/sql/_source/deploy/1/001-auto-__VERSION.yml b/sql/_source/deploy/1/001-auto-__VERSION.yml
new file mode 100644 (file)
index 0000000..a803e96
--- /dev/null
@@ -0,0 +1,91 @@
+---
+schema:
+  procedures: {}
+  tables:
+    dbix_class_deploymenthandler_versions:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - version
+          match_type: ''
+          name: dbix_class_deploymenthandler_versions_version
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+      fields:
+        ddl:
+          data_type: text
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: ddl
+          order: 3
+          size:
+            - 0
+        id:
+          data_type: int
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+        upgrade_sql:
+          data_type: text
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: upgrade_sql
+          order: 4
+          size:
+            - 0
+        version:
+          data_type: varchar
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: version
+          order: 2
+          size:
+            - 50
+      indices: []
+      name: dbix_class_deploymenthandler_versions
+      options: []
+      order: 1
+  triggers: {}
+  views: {}
+translator:
+  add_drop_table: 0
+  filename: ~
+  no_comments: 0
+  parser_args:
+    sources:
+      - __VERSION
+  parser_type: SQL::Translator::Parser::DBIx::Class
+  producer_args: {}
+  producer_type: SQL::Translator::Producer::YAML
+  show_warnings: 0
+  trace: 0
+  version: 0.11018
diff --git a/sql/_source/deploy/1/001-auto.yml b/sql/_source/deploy/1/001-auto.yml
new file mode 100644 (file)
index 0000000..b130817
--- /dev/null
@@ -0,0 +1,3071 @@
+---
+schema:
+  procedures: {}
+  tables:
+    arch:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - arch
+          match_type: ''
+          name: arch_arch_key
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+      fields:
+        arch:
+          data_type: text
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: arch
+          order: 2
+          size:
+            - 0
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+      indices: []
+      name: arch
+      options: []
+      order: 1
+    bin_associations:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - bin
+          match_type: ''
+          name: bin_associations_fk_bin
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: bin_ver
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - suite
+          match_type: ''
+          name: bin_associations_fk_suite
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: suite
+          type: FOREIGN KEY
+      fields:
+        bin:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: bin
+          order: 3
+          size:
+            - 0
+        created:
+          data_type: timestamp with time zone
+          default_value: !!perl/ref
+            =: current_timestamp
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: created
+          order: 4
+          size:
+            - 0
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+        modified:
+          data_type: timestamp with time zone
+          default_value: !!perl/ref
+            =: current_timestamp
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: modified
+          order: 5
+          size:
+            - 0
+        suite:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: suite
+          order: 2
+          size:
+            - 0
+      indices:
+        - fields:
+            - bin
+          name: bin_associations_idx_bin
+          options: []
+          type: NORMAL
+        - fields:
+            - suite
+          name: bin_associations_idx_suite
+          options: []
+          type: NORMAL
+      name: bin_associations
+      options: []
+      order: 29
+    bin_pkg:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - pkg
+          match_type: ''
+          name: bin_pkg_pkg_key
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+      fields:
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+        pkg:
+          data_type: text
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: pkg
+          order: 2
+          size:
+            - 0
+      indices: []
+      name: bin_pkg
+      options: []
+      order: 2
+    bin_ver:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - arch
+          match_type: ''
+          name: bin_ver_fk_arch
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: arch
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - bin_pkg
+          match_type: ''
+          name: bin_ver_fk_bin_pkg
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: bin_pkg
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - src_ver
+          match_type: ''
+          name: bin_ver_fk_src_ver
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: src_ver
+          type: FOREIGN KEY
+      fields:
+        arch:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: arch
+          order: 4
+          size:
+            - 0
+        bin_pkg:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: bin_pkg
+          order: 2
+          size:
+            - 0
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+        src_ver:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: src_ver
+          order: 3
+          size:
+            - 0
+        ver:
+          data_type: debversion
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: ver
+          order: 5
+          size:
+            - 0
+      indices:
+        - fields:
+            - arch
+          name: bin_ver_idx_arch
+          options: []
+          type: NORMAL
+        - fields:
+            - bin_pkg
+          name: bin_ver_idx_bin_pkg
+          options: []
+          type: NORMAL
+        - fields:
+            - src_ver
+          name: bin_ver_idx_src_ver
+          options: []
+          type: NORMAL
+      name: bin_ver
+      options: []
+      order: 27
+    binary_versions:
+      constraints: []
+      fields:
+        arch:
+          data_type: text
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: arch
+          order: 4
+          size:
+            - 0
+        bin_pkg:
+          data_type: text
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: bin_pkg
+          order: 3
+          size:
+            - 0
+        bin_ver:
+          data_type: debversion
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: bin_ver
+          order: 5
+          size:
+            - 0
+        src_pkg:
+          data_type: text
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: src_pkg
+          order: 1
+          size:
+            - 0
+        src_pkg_based_on:
+          data_type: text
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: src_pkg_based_on
+          order: 7
+          size:
+            - 0
+        src_ver:
+          data_type: debversion
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: src_ver
+          order: 2
+          size:
+            - 0
+        src_ver_based_on:
+          data_type: debversion
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: src_ver_based_on
+          order: 6
+          size:
+            - 0
+      indices: []
+      name: binary_versions
+      options: []
+      order: 3
+    bug:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - done
+          match_type: ''
+          name: bug_fk_done
+          on_delete: NO ACTION
+          on_update: NO ACTION
+          options: []
+          reference_fields:
+            - id
+          reference_table: correspondent
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - owner
+          match_type: ''
+          name: bug_fk_owner
+          on_delete: NO ACTION
+          on_update: NO ACTION
+          options: []
+          reference_fields:
+            - id
+          reference_table: correspondent
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - severity
+          match_type: ''
+          name: bug_fk_severity
+          on_delete: NO ACTION
+          on_update: NO ACTION
+          options: []
+          reference_fields:
+            - id
+          reference_table: severity
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - submitter
+          match_type: ''
+          name: bug_fk_submitter
+          on_delete: NO ACTION
+          on_update: NO ACTION
+          options: []
+          reference_fields:
+            - id
+          reference_table: correspondent
+          type: FOREIGN KEY
+      fields:
+        archived:
+          data_type: boolean
+          default_value: !!perl/ref
+            =: false
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: archived
+          order: 5
+          size:
+            - 0
+        creation:
+          data_type: timestamp with time zone
+          default_value: !!perl/ref
+            =: current_timestamp
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: creation
+          order: 2
+          size:
+            - 0
+        done:
+          data_type: integer
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: done
+          order: 12
+          size:
+            - 0
+        done_full:
+          data_type: text
+          default_value: ''
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: done_full
+          order: 13
+          size:
+            - 0
+        forwarded:
+          data_type: text
+          default_value: ''
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: forwarded
+          order: 7
+          size:
+            - 0
+        id:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+        last_modified:
+          data_type: timestamp with time zone
+          default_value: !!perl/ref
+            =: current_timestamp
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: last_modified
+          order: 4
+          size:
+            - 0
+        log_modified:
+          data_type: timestamp with time zone
+          default_value: !!perl/ref
+            =: current_timestamp
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: log_modified
+          order: 3
+          size:
+            - 0
+        outlook:
+          data_type: text
+          default_value: ''
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: outlook
+          order: 9
+          size:
+            - 0
+        owner:
+          data_type: integer
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: owner
+          order: 14
+          size:
+            - 0
+        owner_full:
+          data_type: text
+          default_value: ''
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: owner_full
+          order: 15
+          size:
+            - 0
+        severity:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: severity
+          order: 11
+          size:
+            - 0
+        subject:
+          data_type: text
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: subject
+          order: 10
+          size:
+            - 0
+        submitter:
+          data_type: integer
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: submitter
+          order: 16
+          size:
+            - 0
+        submitter_full:
+          data_type: text
+          default_value: ''
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: submitter_full
+          order: 17
+          size:
+            - 0
+        summary:
+          data_type: text
+          default_value: ''
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: summary
+          order: 8
+          size:
+            - 0
+        unarchived:
+          data_type: timestamp with time zone
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: unarchived
+          order: 6
+          size:
+            - 0
+        unknown_packages:
+          data_type: text
+          default_value: ''
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: unknown_packages
+          order: 18
+          size:
+            - 0
+      indices:
+        - fields:
+            - done
+          name: bug_idx_done
+          options: []
+          type: NORMAL
+        - fields:
+            - owner
+          name: bug_idx_owner
+          options: []
+          type: NORMAL
+        - fields:
+            - severity
+          name: bug_idx_severity
+          options: []
+          type: NORMAL
+        - fields:
+            - submitter
+          name: bug_idx_submitter
+          options: []
+          type: NORMAL
+      name: bug
+      options: []
+      order: 16
+    bug_binpackage:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - bug
+            - bin_pkg
+          match_type: ''
+          name: bug_binpackage_id_pkg
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - bin_pkg
+          match_type: ''
+          name: bug_binpackage_fk_bin_pkg
+          on_delete: NO ACTION
+          on_update: NO ACTION
+          options: []
+          reference_fields:
+            - id
+          reference_table: bin_pkg
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - bug
+          match_type: ''
+          name: bug_binpackage_fk_bug
+          on_delete: NO ACTION
+          on_update: NO ACTION
+          options: []
+          reference_fields:
+            - id
+          reference_table: bug
+          type: FOREIGN KEY
+      fields:
+        bin_pkg:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: bin_pkg
+          order: 3
+          size:
+            - 0
+        bug:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: bug
+          order: 2
+          size:
+            - 0
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+      indices:
+        - fields:
+            - bin_pkg
+          name: bug_binpackage_idx_bin_pkg
+          options: []
+          type: NORMAL
+        - fields:
+            - bug
+          name: bug_binpackage_idx_bug
+          options: []
+          type: NORMAL
+      name: bug_binpackage
+      options: []
+      order: 21
+    bug_blocks:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - bug
+            - blocks
+          match_type: ''
+          name: bug_blocks_bug_id_blocks_idx
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - blocks
+          match_type: ''
+          name: bug_blocks_fk_blocks
+          on_delete: NO ACTION
+          on_update: NO ACTION
+          options: []
+          reference_fields:
+            - id
+          reference_table: bug
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - bug
+          match_type: ''
+          name: bug_blocks_fk_bug
+          on_delete: NO ACTION
+          on_update: NO ACTION
+          options: []
+          reference_fields:
+            - id
+          reference_table: bug
+          type: FOREIGN KEY
+      fields:
+        blocks:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: blocks
+          order: 3
+          size:
+            - 0
+        bug:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: bug
+          order: 2
+          size:
+            - 0
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+      indices:
+        - fields:
+            - blocks
+          name: bug_blocks_idx_blocks
+          options: []
+          type: NORMAL
+        - fields:
+            - bug
+          name: bug_blocks_idx_bug
+          options: []
+          type: NORMAL
+      name: bug_blocks
+      options: []
+      order: 18
+    bug_merged:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - bug
+            - merged
+          match_type: ''
+          name: bug_merged_bug_id_merged_idx
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - bug
+          match_type: ''
+          name: bug_merged_fk_bug
+          on_delete: NO ACTION
+          on_update: NO ACTION
+          options: []
+          reference_fields:
+            - id
+          reference_table: bug
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - merged
+          match_type: ''
+          name: bug_merged_fk_merged
+          on_delete: NO ACTION
+          on_update: NO ACTION
+          options: []
+          reference_fields:
+            - id
+          reference_table: bug
+          type: FOREIGN KEY
+      fields:
+        bug:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: bug
+          order: 2
+          size:
+            - 0
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+        merged:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: merged
+          order: 3
+          size:
+            - 0
+      indices:
+        - fields:
+            - bug
+          name: bug_merged_idx_bug
+          options: []
+          type: NORMAL
+        - fields:
+            - merged
+          name: bug_merged_idx_merged
+          options: []
+          type: NORMAL
+      name: bug_merged
+      options: []
+      order: 19
+    bug_message:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - bug
+            - message
+          match_type: ''
+          name: bug_message_bug_message_idx
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - bug
+          match_type: ''
+          name: bug_message_fk_bug
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: bug
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - message
+          match_type: ''
+          name: bug_message_fk_message
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: message
+          type: FOREIGN KEY
+      fields:
+        bug:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: bug
+          order: 2
+          size:
+            - 0
+        bug_log_offset:
+          data_type: integer
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: bug_log_offset
+          order: 5
+          size:
+            - 0
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+        message:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: message
+          order: 3
+          size:
+            - 0
+        message_number:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: message_number
+          order: 4
+          size:
+            - 0
+        offset_valid:
+          data_type: timestamp with time zone
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: offset_valid
+          order: 6
+          size:
+            - 0
+      indices:
+        - fields:
+            - bug
+          name: bug_message_idx_bug
+          options: []
+          type: NORMAL
+        - fields:
+            - message
+          name: bug_message_idx_message
+          options: []
+          type: NORMAL
+      name: bug_message
+      options: []
+      order: 22
+    bug_package:
+      constraints: []
+      fields:
+        bug:
+          data_type: integer
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: bug
+          order: 1
+          size:
+            - 0
+        package:
+          data_type: text
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: package
+          order: 4
+          size:
+            - 0
+        pkg_id:
+          data_type: integer
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: pkg_id
+          order: 2
+          size:
+            - 0
+        pkg_type:
+          data_type: text
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: pkg_type
+          order: 3
+          size:
+            - 0
+      indices: []
+      name: bug_package
+      options: []
+      order: 4
+    bug_srcpackage:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - bug
+            - src_pkg
+          match_type: ''
+          name: bug_srcpackage_id_pkg
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - bug
+          match_type: ''
+          name: bug_srcpackage_fk_bug
+          on_delete: NO ACTION
+          on_update: NO ACTION
+          options: []
+          reference_fields:
+            - id
+          reference_table: bug
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - src_pkg
+          match_type: ''
+          name: bug_srcpackage_fk_src_pkg
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: src_pkg
+          type: FOREIGN KEY
+      fields:
+        bug:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: bug
+          order: 2
+          size:
+            - 0
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+        src_pkg:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: src_pkg
+          order: 3
+          size:
+            - 0
+      indices:
+        - fields:
+            - bug
+          name: bug_srcpackage_idx_bug
+          options: []
+          type: NORMAL
+        - fields:
+            - src_pkg
+          name: bug_srcpackage_idx_src_pkg
+          options: []
+          type: NORMAL
+      name: bug_srcpackage
+      options: []
+      order: 23
+    bug_status_cache:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - bug
+            - suite
+            - arch
+          match_type: ''
+          name: bug_status_cache_bug_suite_arch_idx
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - arch
+          match_type: ''
+          name: bug_status_cache_fk_arch
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: arch
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - bug
+          match_type: ''
+          name: bug_status_cache_fk_bug
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: bug
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - suite
+          match_type: ''
+          name: bug_status_cache_fk_suite
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: suite
+          type: FOREIGN KEY
+      fields:
+        arch:
+          data_type: integer
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 1
+          name: arch
+          order: 4
+          size:
+            - 0
+        asof:
+          data_type: timestamp with time zone
+          default_value: !!perl/ref
+            =: current_timestamp
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: asof
+          order: 7
+          size:
+            - 0
+        bug:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: bug
+          order: 2
+          size:
+            - 0
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+        modified:
+          data_type: timestamp with time zone
+          default_value: !!perl/ref
+            =: current_timestamp
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: modified
+          order: 6
+          size:
+            - 0
+        status:
+          data_type: enum
+          default_value: ~
+          extra:
+            custom_type_name: bug_status_type
+            list:
+              - pending
+              - forwarded
+              - pending-fixed
+              - fixed
+              - absent
+              - done
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: status
+          order: 5
+          size:
+            - 0
+        suite:
+          data_type: integer
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 1
+          name: suite
+          order: 3
+          size:
+            - 0
+      indices:
+        - fields:
+            - arch
+          name: bug_status_cache_idx_arch
+          options: []
+          type: NORMAL
+        - fields:
+            - bug
+          name: bug_status_cache_idx_bug
+          options: []
+          type: NORMAL
+        - fields:
+            - suite
+          name: bug_status_cache_idx_suite
+          options: []
+          type: NORMAL
+      name: bug_status_cache
+      options: []
+      order: 25
+    bug_tag:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - bug
+            - tag
+          match_type: ''
+          name: bug_tag_bug_tag
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - bug
+          match_type: ''
+          name: bug_tag_fk_bug
+          on_delete: NO ACTION
+          on_update: NO ACTION
+          options: []
+          reference_fields:
+            - id
+          reference_table: bug
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - tag
+          match_type: ''
+          name: bug_tag_fk_tag
+          on_delete: NO ACTION
+          on_update: NO ACTION
+          options: []
+          reference_fields:
+            - id
+          reference_table: tag
+          type: FOREIGN KEY
+      fields:
+        bug:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: bug
+          order: 2
+          size:
+            - 0
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+        tag:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: tag
+          order: 3
+          size:
+            - 0
+      indices:
+        - fields:
+            - bug
+          name: bug_tag_idx_bug
+          options: []
+          type: NORMAL
+        - fields:
+            - tag
+          name: bug_tag_idx_tag
+          options: []
+          type: NORMAL
+      name: bug_tag
+      options: []
+      order: 24
+    bug_ver:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - bug
+            - ver_string
+            - found
+          match_type: ''
+          name: bug_ver_bug_ver_string_found_idx
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - bug
+          match_type: ''
+          name: bug_ver_fk_bug
+          on_delete: RESTRICT
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: bug
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - src_pkg
+          match_type: ''
+          name: bug_ver_fk_src_pkg
+          on_delete: SET NULL
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: src_pkg
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - src_ver
+          match_type: ''
+          name: bug_ver_fk_src_ver
+          on_delete: SET NULL
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: src_ver
+          type: FOREIGN KEY
+      fields:
+        bug:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: bug
+          order: 2
+          size:
+            - 0
+        creation:
+          data_type: timestamp with time zone
+          default_value: !!perl/ref
+            =: current_timestamp
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: creation
+          order: 7
+          size:
+            - 0
+        found:
+          data_type: boolean
+          default_value: !!perl/ref
+            =: true
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: found
+          order: 6
+          size:
+            - 0
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+        last_modified:
+          data_type: timestamp with time zone
+          default_value: !!perl/ref
+            =: current_timestamp
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: last_modified
+          order: 8
+          size:
+            - 0
+        src_pkg:
+          data_type: integer
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: src_pkg
+          order: 4
+          size:
+            - 0
+        src_ver:
+          data_type: integer
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: src_ver
+          order: 5
+          size:
+            - 0
+        ver_string:
+          data_type: text
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 1
+          name: ver_string
+          order: 3
+          size:
+            - 0
+      indices:
+        - fields:
+            - bug
+          name: bug_ver_idx_bug
+          options: []
+          type: NORMAL
+        - fields:
+            - src_pkg
+          name: bug_ver_idx_src_pkg
+          options: []
+          type: NORMAL
+        - fields:
+            - src_ver
+          name: bug_ver_idx_src_ver
+          options: []
+          type: NORMAL
+      name: bug_ver
+      options: []
+      order: 28
+    column_comments:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - table_name
+            - column_name
+          match_type: ''
+          name: column_comments_table_name_column_name_idx
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+      fields:
+        column_name:
+          data_type: text
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: column_name
+          order: 2
+          size:
+            - 0
+        comment_text:
+          data_type: text
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: comment_text
+          order: 3
+          size:
+            - 0
+        table_name:
+          data_type: text
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: table_name
+          order: 1
+          size:
+            - 0
+      indices: []
+      name: column_comments
+      options: []
+      order: 5
+    correspondent:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - addr
+          match_type: ''
+          name: correspondent_addr_idx
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+      fields:
+        addr:
+          data_type: text
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: addr
+          order: 2
+          size:
+            - 0
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+      indices: []
+      name: correspondent
+      options: []
+      order: 6
+    correspondent_full_name:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - correspondent
+            - full_name
+          match_type: ''
+          name: correspondent_full_name_correspondent_full_name_idx
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - correspondent
+          match_type: ''
+          name: correspondent_full_name_fk_correspondent
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: correspondent
+          type: FOREIGN KEY
+      fields:
+        correspondent:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: correspondent
+          order: 2
+          size:
+            - 0
+        full_name:
+          data_type: text
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: full_name
+          order: 3
+          size:
+            - 0
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+        last_seen:
+          data_type: timestamp
+          default_value: !!perl/ref
+            =: current_timestamp
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: last_seen
+          order: 4
+          size:
+            - 0
+      indices:
+        - fields:
+            - correspondent
+          name: correspondent_full_name_idx_correspondent
+          options: []
+          type: NORMAL
+      name: correspondent_full_name
+      options: []
+      order: 13
+    maintainer:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - name
+          match_type: ''
+          name: maintainer_name_idx
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - correspondent
+          match_type: ''
+          name: maintainer_fk_correspondent
+          on_delete: NO ACTION
+          on_update: NO ACTION
+          options: []
+          reference_fields:
+            - id
+          reference_table: correspondent
+          type: FOREIGN KEY
+      fields:
+        correspondent:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: correspondent
+          order: 3
+          size:
+            - 0
+        created:
+          data_type: timestamp with time zone
+          default_value: !!perl/ref
+            =: current_timestamp
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: created
+          order: 4
+          size:
+            - 0
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+        modified:
+          data_type: timestamp with time zone
+          default_value: !!perl/ref
+            =: current_timestamp
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: modified
+          order: 5
+          size:
+            - 0
+        name:
+          data_type: text
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: name
+          order: 2
+          size:
+            - 0
+      indices:
+        - fields:
+            - correspondent
+          name: maintainer_idx_correspondent
+          options: []
+          type: NORMAL
+      name: maintainer
+      options: []
+      order: 14
+    message:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+      fields:
+        from_addr:
+          data_type: text
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: from_addr
+          order: 4
+          size:
+            - 0
+        from_complete:
+          data_type: text
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: from_complete
+          order: 3
+          size:
+            - 0
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+        is_spam:
+          data_type: boolean
+          default_value: !!perl/ref
+            =: false
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: is_spam
+          order: 11
+          size:
+            - 0
+        msgid:
+          data_type: text
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: msgid
+          order: 2
+          size:
+            - 0
+        refs:
+          data_type: text
+          default_value: ''
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: refs
+          order: 9
+          size:
+            - 0
+        sent_date:
+          data_type: timestamp with time zone
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: sent_date
+          order: 8
+          size:
+            - 0
+        spam_score:
+          data_type: double precision
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: spam_score
+          order: 10
+          size:
+            - 0
+        subject:
+          data_type: text
+          default_value: ''
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: subject
+          order: 7
+          size:
+            - 0
+        to_addr:
+          data_type: text
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: to_addr
+          order: 6
+          size:
+            - 0
+        to_complete:
+          data_type: text
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: to_complete
+          order: 5
+          size:
+            - 0
+      indices: []
+      name: message
+      options: []
+      order: 7
+    message_correspondent:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - message
+            - correspondent
+            - correspondent_type
+          match_type: ''
+          name: message_correspondent_message_correspondent_correspondent_t_idx
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - correspondent
+          match_type: ''
+          name: message_correspondent_fk_correspondent
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: correspondent
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - message
+          match_type: ''
+          name: message_correspondent_fk_message
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: message
+          type: FOREIGN KEY
+      fields:
+        correspondent:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: correspondent
+          order: 3
+          size:
+            - 0
+        correspondent_type:
+          data_type: enum
+          default_value: to
+          extra:
+            custom_type_name: message_correspondent_type
+            list:
+              - to
+              - from
+              - envfrom
+              - cc
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: correspondent_type
+          order: 4
+          size:
+            - 0
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+        message:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: message
+          order: 2
+          size:
+            - 0
+      indices:
+        - fields:
+            - correspondent
+          name: message_correspondent_idx_correspondent
+          options: []
+          type: NORMAL
+        - fields:
+            - message
+          name: message_correspondent_idx_message
+          options: []
+          type: NORMAL
+      name: message_correspondent
+      options: []
+      order: 17
+    message_refs:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - message
+            - refs
+          match_type: ''
+          name: message_refs_message_refs_idx
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - message
+          match_type: ''
+          name: message_refs_fk_message
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: message
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - refs
+          match_type: ''
+          name: message_refs_fk_refs
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: message
+          type: FOREIGN KEY
+      fields:
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+        inferred:
+          data_type: boolean
+          default_value: !!perl/ref
+            =: false
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: inferred
+          order: 4
+          size:
+            - 0
+        message:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: message
+          order: 2
+          size:
+            - 0
+        primary_ref:
+          data_type: boolean
+          default_value: !!perl/ref
+            =: false
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: primary_ref
+          order: 5
+          size:
+            - 0
+        refs:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: refs
+          order: 3
+          size:
+            - 0
+      indices:
+        - fields:
+            - message
+          name: message_refs_idx_message
+          options: []
+          type: NORMAL
+        - fields:
+            - refs
+          name: message_refs_idx_refs
+          options: []
+          type: NORMAL
+      name: message_refs
+      options: []
+      order: 15
+    severity:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - severity
+          match_type: ''
+          name: severity_severity_idx
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+      fields:
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+        obsolete:
+          data_type: boolean
+          default_value: !!perl/ref
+            =: false
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: obsolete
+          order: 5
+          size:
+            - 0
+        ordering:
+          data_type: integer
+          default_value: 5
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: ordering
+          order: 3
+          size:
+            - 0
+        severity:
+          data_type: text
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: severity
+          order: 2
+          size:
+            - 0
+        strong:
+          data_type: boolean
+          default_value: !!perl/ref
+            =: false
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: strong
+          order: 4
+          size:
+            - 0
+      indices: []
+      name: severity
+      options: []
+      order: 8
+    src_associations:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - source
+          match_type: ''
+          name: src_associations_fk_source
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: src_ver
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - suite
+          match_type: ''
+          name: src_associations_fk_suite
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: suite
+          type: FOREIGN KEY
+      fields:
+        created:
+          data_type: timestamp with time zone
+          default_value: !!perl/ref
+            =: current_timestamp
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: created
+          order: 4
+          size:
+            - 0
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+        modified:
+          data_type: timestamp with time zone
+          default_value: !!perl/ref
+            =: current_timestamp
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: modified
+          order: 5
+          size:
+            - 0
+        source:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: source
+          order: 3
+          size:
+            - 0
+        suite:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: suite
+          order: 2
+          size:
+            - 0
+      indices:
+        - fields:
+            - source
+          name: src_associations_idx_source
+          options: []
+          type: NORMAL
+        - fields:
+            - suite
+          name: src_associations_idx_suite
+          options: []
+          type: NORMAL
+      name: src_associations
+      options: []
+      order: 26
+    src_pkg:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - pkg
+            - disabled
+          match_type: ''
+          name: src_pkg_pkg_disabled
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - alias_of
+          match_type: ''
+          name: src_pkg_fk_alias_of
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: src_pkg
+          type: FOREIGN KEY
+      fields:
+        alias_of:
+          data_type: integer
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: alias_of
+          order: 4
+          size:
+            - 0
+        creation:
+          data_type: timestamp with time zone
+          default_value: !!perl/ref
+            =: current_timestamp
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: creation
+          order: 5
+          size:
+            - 0
+        disabled:
+          data_type: timestamp with time zone
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 1
+          name: disabled
+          order: 6
+          size:
+            - 0
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+        last_modified:
+          data_type: timestamp with time zone
+          default_value: !!perl/ref
+            =: current_timestamp
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: last_modified
+          order: 7
+          size:
+            - 0
+        obsolete:
+          data_type: boolean
+          default_value: !!perl/ref
+            =: false
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: obsolete
+          order: 8
+          size:
+            - 0
+        pkg:
+          data_type: text
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: pkg
+          order: 2
+          size:
+            - 0
+        pseduopkg:
+          data_type: boolean
+          default_value: !!perl/ref
+            =: false
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: pseduopkg
+          order: 3
+          size:
+            - 0
+      indices:
+        - fields:
+            - alias_of
+          name: src_pkg_idx_alias_of
+          options: []
+          type: NORMAL
+      name: src_pkg
+      options: []
+      order: 9
+    src_ver:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - src_pkg
+            - ver
+          match_type: ''
+          name: src_ver_src_pkg_id_ver
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - based_on
+          match_type: ''
+          name: src_ver_fk_based_on
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: src_ver
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - maintainer
+          match_type: ''
+          name: src_ver_fk_maintainer
+          on_delete: SET NULL
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: maintainer
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - src_pkg
+          match_type: ''
+          name: src_ver_fk_src_pkg
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: src_pkg
+          type: FOREIGN KEY
+      fields:
+        based_on:
+          data_type: integer
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: based_on
+          order: 6
+          size:
+            - 0
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+        maintainer:
+          data_type: integer
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: maintainer
+          order: 4
+          size:
+            - 0
+        src_pkg:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: src_pkg
+          order: 2
+          size:
+            - 0
+        upload_date:
+          data_type: timestamp with time zone
+          default_value: !!perl/ref
+            =: current_timestamp
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: upload_date
+          order: 5
+          size:
+            - 0
+        ver:
+          data_type: debversion
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: ver
+          order: 3
+          size:
+            - 0
+      indices:
+        - fields:
+            - based_on
+          name: src_ver_idx_based_on
+          options: []
+          type: NORMAL
+        - fields:
+            - maintainer
+          name: src_ver_idx_maintainer
+          options: []
+          type: NORMAL
+        - fields:
+            - src_pkg
+          name: src_ver_idx_src_pkg
+          options: []
+          type: NORMAL
+      name: src_ver
+      options: []
+      order: 20
+    suite:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - suite_name
+          match_type: ''
+          name: suite_suite_name_key
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+      fields:
+        active:
+          data_type: boolean
+          default_value: !!perl/ref
+            =: true
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: active
+          order: 5
+          size:
+            - 0
+        codename:
+          data_type: text
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: codename
+          order: 4
+          size:
+            - 0
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+        suite_name:
+          data_type: text
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: suite_name
+          order: 2
+          size:
+            - 0
+        version:
+          data_type: text
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: version
+          order: 3
+          size:
+            - 0
+      indices: []
+      name: suite
+      options: []
+      order: 10
+    table_comments:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - table_name
+          match_type: ''
+          name: table_comments_table_name_key
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+      fields:
+        comment_text:
+          data_type: text
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: comment_text
+          order: 2
+          size:
+            - 0
+        table_name:
+          data_type: text
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: table_name
+          order: 1
+          size:
+            - 0
+      indices: []
+      name: table_comments
+      options: []
+      order: 11
+    tag:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - tag
+          match_type: ''
+          name: tag_tag_key
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+      fields:
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+        obsolete:
+          data_type: boolean
+          default_value: !!perl/ref
+            =: false
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: obsolete
+          order: 3
+          size:
+            - 0
+        tag:
+          data_type: text
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: tag
+          order: 2
+          size:
+            - 0
+      indices: []
+      name: tag
+      options: []
+      order: 12
+  triggers: {}
+  views: {}
+translator:
+  add_drop_table: 0
+  filename: ~
+  no_comments: 0
+  parser_args:
+    sources:
+      - Arch
+      - BinAssociation
+      - BinPkg
+      - BinVer
+      - BinaryVersion
+      - Bug
+      - BugBinpackage
+      - BugBlock
+      - BugMerged
+      - BugMessage
+      - BugPackage
+      - BugSrcpackage
+      - BugStatusCache
+      - BugTag
+      - BugVer
+      - ColumnComment
+      - Correspondent
+      - CorrespondentFullName
+      - Maintainer
+      - Message
+      - MessageCorrespondent
+      - MessageRef
+      - Severity
+      - SrcAssociation
+      - SrcPkg
+      - SrcVer
+      - Suite
+      - TableComment
+      - Tag
+  parser_type: SQL::Translator::Parser::DBIx::Class
+  producer_args: {}
+  producer_type: SQL::Translator::Producer::YAML
+  show_warnings: 0
+  trace: 0
+  version: 0.11018
diff --git a/sql/_source/deploy/5/001-auto.yml b/sql/_source/deploy/5/001-auto.yml
new file mode 100644 (file)
index 0000000..ebf57cf
--- /dev/null
@@ -0,0 +1,3179 @@
+---
+schema:
+  procedures: {}
+  tables:
+    arch:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - arch
+          match_type: ''
+          name: arch_arch_key
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+      fields:
+        arch:
+          data_type: text
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: arch
+          order: 2
+          size:
+            - 0
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+      indices: []
+      name: arch
+      options: []
+      order: 1
+    bin_associations:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - bin
+            - suite
+          match_type: ''
+          name: bin_associations_bin_suite
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - bin
+          match_type: ''
+          name: bin_associations_fk_bin
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: bin_ver
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - suite
+          match_type: ''
+          name: bin_associations_fk_suite
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: suite
+          type: FOREIGN KEY
+      fields:
+        bin:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: bin
+          order: 3
+          size:
+            - 0
+        created:
+          data_type: timestamp with time zone
+          default_value: !!perl/ref
+            =: current_timestamp
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: created
+          order: 4
+          size:
+            - 0
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+        modified:
+          data_type: timestamp with time zone
+          default_value: !!perl/ref
+            =: current_timestamp
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: modified
+          order: 5
+          size:
+            - 0
+        suite:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: suite
+          order: 2
+          size:
+            - 0
+      indices:
+        - fields:
+            - bin
+          name: bin_associations_idx_bin
+          options: []
+          type: NORMAL
+        - fields:
+            - suite
+          name: bin_associations_idx_suite
+          options: []
+          type: NORMAL
+      name: bin_associations
+      options: []
+      order: 31
+    bin_pkg:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - pkg
+          match_type: ''
+          name: bin_pkg_pkg_key
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+      fields:
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+        pkg:
+          data_type: text
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: pkg
+          order: 2
+          size:
+            - 0
+      indices: []
+      name: bin_pkg
+      options: []
+      order: 2
+    bin_ver:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - bin_pkg
+            - arch
+            - ver
+          match_type: ''
+          name: bin_ver_bin_pkg_id_arch_idx
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - arch
+          match_type: ''
+          name: bin_ver_fk_arch
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: arch
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - bin_pkg
+          match_type: ''
+          name: bin_ver_fk_bin_pkg
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: bin_pkg
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - src_ver
+          match_type: ''
+          name: bin_ver_fk_src_ver
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: src_ver
+          type: FOREIGN KEY
+      fields:
+        arch:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: arch
+          order: 4
+          size:
+            - 0
+        bin_pkg:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: bin_pkg
+          order: 2
+          size:
+            - 0
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+        src_ver:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: src_ver
+          order: 3
+          size:
+            - 0
+        ver:
+          data_type: debversion
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: ver
+          order: 5
+          size:
+            - 0
+      indices:
+        - fields:
+            - arch
+          name: bin_ver_idx_arch
+          options: []
+          type: NORMAL
+        - fields:
+            - bin_pkg
+          name: bin_ver_idx_bin_pkg
+          options: []
+          type: NORMAL
+        - fields:
+            - src_ver
+          name: bin_ver_idx_src_ver
+          options: []
+          type: NORMAL
+      name: bin_ver
+      options: []
+      order: 29
+    bug:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - done
+          match_type: ''
+          name: bug_fk_done
+          on_delete: NO ACTION
+          on_update: NO ACTION
+          options: []
+          reference_fields:
+            - id
+          reference_table: correspondent
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - owner
+          match_type: ''
+          name: bug_fk_owner
+          on_delete: NO ACTION
+          on_update: NO ACTION
+          options: []
+          reference_fields:
+            - id
+          reference_table: correspondent
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - severity
+          match_type: ''
+          name: bug_fk_severity
+          on_delete: NO ACTION
+          on_update: NO ACTION
+          options: []
+          reference_fields:
+            - id
+          reference_table: severity
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - submitter
+          match_type: ''
+          name: bug_fk_submitter
+          on_delete: NO ACTION
+          on_update: NO ACTION
+          options: []
+          reference_fields:
+            - id
+          reference_table: correspondent
+          type: FOREIGN KEY
+      fields:
+        archived:
+          data_type: boolean
+          default_value: !!perl/ref
+            =: false
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: archived
+          order: 5
+          size:
+            - 0
+        creation:
+          data_type: timestamp with time zone
+          default_value: !!perl/ref
+            =: current_timestamp
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: creation
+          order: 2
+          size:
+            - 0
+        done:
+          data_type: integer
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: done
+          order: 12
+          size:
+            - 0
+        done_full:
+          data_type: text
+          default_value: ''
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: done_full
+          order: 13
+          size:
+            - 0
+        forwarded:
+          data_type: text
+          default_value: ''
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: forwarded
+          order: 7
+          size:
+            - 0
+        id:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+        last_modified:
+          data_type: timestamp with time zone
+          default_value: !!perl/ref
+            =: current_timestamp
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: last_modified
+          order: 4
+          size:
+            - 0
+        log_modified:
+          data_type: timestamp with time zone
+          default_value: !!perl/ref
+            =: current_timestamp
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: log_modified
+          order: 3
+          size:
+            - 0
+        outlook:
+          data_type: text
+          default_value: ''
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: outlook
+          order: 9
+          size:
+            - 0
+        owner:
+          data_type: integer
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: owner
+          order: 14
+          size:
+            - 0
+        owner_full:
+          data_type: text
+          default_value: ''
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: owner_full
+          order: 15
+          size:
+            - 0
+        severity:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: severity
+          order: 11
+          size:
+            - 0
+        subject:
+          data_type: text
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: subject
+          order: 10
+          size:
+            - 0
+        submitter:
+          data_type: integer
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: submitter
+          order: 16
+          size:
+            - 0
+        submitter_full:
+          data_type: text
+          default_value: ''
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: submitter_full
+          order: 17
+          size:
+            - 0
+        summary:
+          data_type: text
+          default_value: ''
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: summary
+          order: 8
+          size:
+            - 0
+        unarchived:
+          data_type: timestamp with time zone
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: unarchived
+          order: 6
+          size:
+            - 0
+        unknown_packages:
+          data_type: text
+          default_value: ''
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: unknown_packages
+          order: 18
+          size:
+            - 0
+      indices:
+        - fields:
+            - done
+          name: bug_idx_done
+          options: []
+          type: NORMAL
+        - fields:
+            - owner
+          name: bug_idx_owner
+          options: []
+          type: NORMAL
+        - fields:
+            - severity
+          name: bug_idx_severity
+          options: []
+          type: NORMAL
+        - fields:
+            - submitter
+          name: bug_idx_submitter
+          options: []
+          type: NORMAL
+      name: bug
+      options: []
+      order: 15
+    bug_affects_binpackage:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - bug
+            - bin_pkg
+          match_type: ''
+          name: bug_affects_binpackage_id_pkg
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - bin_pkg
+          match_type: ''
+          name: bug_affects_binpackage_fk_bin_pkg
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: bin_pkg
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - bug
+          match_type: ''
+          name: bug_affects_binpackage_fk_bug
+          on_delete: NO ACTION
+          on_update: NO ACTION
+          options: []
+          reference_fields:
+            - id
+          reference_table: bug
+          type: FOREIGN KEY
+      fields:
+        bin_pkg:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: bin_pkg
+          order: 2
+          size:
+            - 0
+        bug:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: bug
+          order: 1
+          size:
+            - 0
+      indices:
+        - fields:
+            - bin_pkg
+          name: bug_affects_binpackage_idx_bin_pkg
+          options: []
+          type: NORMAL
+        - fields:
+            - bug
+          name: bug_affects_binpackage_idx_bug
+          options: []
+          type: NORMAL
+      name: bug_affects_binpackage
+      options: []
+      order: 20
+    bug_affects_srcpackage:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - bug
+            - src_pkg
+          match_type: ''
+          name: bug_affects_srcpackage_id_pkg
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - bug
+          match_type: ''
+          name: bug_affects_srcpackage_fk_bug
+          on_delete: NO ACTION
+          on_update: NO ACTION
+          options: []
+          reference_fields:
+            - id
+          reference_table: bug
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - src_pkg
+          match_type: ''
+          name: bug_affects_srcpackage_fk_src_pkg
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: src_pkg
+          type: FOREIGN KEY
+      fields:
+        bug:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: bug
+          order: 1
+          size:
+            - 0
+        src_pkg:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: src_pkg
+          order: 2
+          size:
+            - 0
+      indices:
+        - fields:
+            - bug
+          name: bug_affects_srcpackage_idx_bug
+          options: []
+          type: NORMAL
+        - fields:
+            - src_pkg
+          name: bug_affects_srcpackage_idx_src_pkg
+          options: []
+          type: NORMAL
+      name: bug_affects_srcpackage
+      options: []
+      order: 21
+    bug_binpackage:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - bug
+            - bin_pkg
+          match_type: ''
+          name: bug_binpackage_id_pkg
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - bin_pkg
+          match_type: ''
+          name: bug_binpackage_fk_bin_pkg
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: bin_pkg
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - bug
+          match_type: ''
+          name: bug_binpackage_fk_bug
+          on_delete: NO ACTION
+          on_update: NO ACTION
+          options: []
+          reference_fields:
+            - id
+          reference_table: bug
+          type: FOREIGN KEY
+      fields:
+        bin_pkg:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: bin_pkg
+          order: 2
+          size:
+            - 0
+        bug:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: bug
+          order: 1
+          size:
+            - 0
+      indices:
+        - fields:
+            - bin_pkg
+          name: bug_binpackage_idx_bin_pkg
+          options: []
+          type: NORMAL
+        - fields:
+            - bug
+          name: bug_binpackage_idx_bug
+          options: []
+          type: NORMAL
+      name: bug_binpackage
+      options: []
+      order: 22
+    bug_blocks:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - bug
+            - blocks
+          match_type: ''
+          name: bug_blocks_bug_id_blocks_idx
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - blocks
+          match_type: ''
+          name: bug_blocks_fk_blocks
+          on_delete: NO ACTION
+          on_update: NO ACTION
+          options: []
+          reference_fields:
+            - id
+          reference_table: bug
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - bug
+          match_type: ''
+          name: bug_blocks_fk_bug
+          on_delete: NO ACTION
+          on_update: NO ACTION
+          options: []
+          reference_fields:
+            - id
+          reference_table: bug
+          type: FOREIGN KEY
+      fields:
+        blocks:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: blocks
+          order: 3
+          size:
+            - 0
+        bug:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: bug
+          order: 2
+          size:
+            - 0
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+      indices:
+        - fields:
+            - blocks
+          name: bug_blocks_idx_blocks
+          options: []
+          type: NORMAL
+        - fields:
+            - bug
+          name: bug_blocks_idx_bug
+          options: []
+          type: NORMAL
+      name: bug_blocks
+      options: []
+      order: 17
+    bug_merged:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - bug
+            - merged
+          match_type: ''
+          name: bug_merged_bug_id_merged_idx
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - bug
+          match_type: ''
+          name: bug_merged_fk_bug
+          on_delete: NO ACTION
+          on_update: NO ACTION
+          options: []
+          reference_fields:
+            - id
+          reference_table: bug
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - merged
+          match_type: ''
+          name: bug_merged_fk_merged
+          on_delete: NO ACTION
+          on_update: NO ACTION
+          options: []
+          reference_fields:
+            - id
+          reference_table: bug
+          type: FOREIGN KEY
+      fields:
+        bug:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: bug
+          order: 2
+          size:
+            - 0
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+        merged:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: merged
+          order: 3
+          size:
+            - 0
+      indices:
+        - fields:
+            - bug
+          name: bug_merged_idx_bug
+          options: []
+          type: NORMAL
+        - fields:
+            - merged
+          name: bug_merged_idx_merged
+          options: []
+          type: NORMAL
+      name: bug_merged
+      options: []
+      order: 18
+    bug_message:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - bug
+            - message
+          match_type: ''
+          name: bug_message_bug_message_idx
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - bug
+          match_type: ''
+          name: bug_message_fk_bug
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: bug
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - message
+          match_type: ''
+          name: bug_message_fk_message
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: message
+          type: FOREIGN KEY
+      fields:
+        bug:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: bug
+          order: 1
+          size:
+            - 0
+        bug_log_offset:
+          data_type: integer
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: bug_log_offset
+          order: 4
+          size:
+            - 0
+        message:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: message
+          order: 2
+          size:
+            - 0
+        message_number:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: message_number
+          order: 3
+          size:
+            - 0
+        offset_valid:
+          data_type: timestamp with time zone
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: offset_valid
+          order: 5
+          size:
+            - 0
+      indices:
+        - fields:
+            - bug
+          name: bug_message_idx_bug
+          options: []
+          type: NORMAL
+        - fields:
+            - message
+          name: bug_message_idx_message
+          options: []
+          type: NORMAL
+      name: bug_message
+      options: []
+      order: 23
+    bug_srcpackage:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - bug
+            - src_pkg
+          match_type: ''
+          name: bug_srcpackage_id_pkg
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - bug
+          match_type: ''
+          name: bug_srcpackage_fk_bug
+          on_delete: NO ACTION
+          on_update: NO ACTION
+          options: []
+          reference_fields:
+            - id
+          reference_table: bug
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - src_pkg
+          match_type: ''
+          name: bug_srcpackage_fk_src_pkg
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: src_pkg
+          type: FOREIGN KEY
+      fields:
+        bug:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: bug
+          order: 1
+          size:
+            - 0
+        src_pkg:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: src_pkg
+          order: 2
+          size:
+            - 0
+      indices:
+        - fields:
+            - bug
+          name: bug_srcpackage_idx_bug
+          options: []
+          type: NORMAL
+        - fields:
+            - src_pkg
+          name: bug_srcpackage_idx_src_pkg
+          options: []
+          type: NORMAL
+      name: bug_srcpackage
+      options: []
+      order: 24
+    bug_status_cache:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - bug
+            - suite
+            - arch
+          match_type: ''
+          name: bug_status_cache_bug_suite_arch_idx
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - arch
+          match_type: ''
+          name: bug_status_cache_fk_arch
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: arch
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - bug
+          match_type: ''
+          name: bug_status_cache_fk_bug
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: bug
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - suite
+          match_type: ''
+          name: bug_status_cache_fk_suite
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: suite
+          type: FOREIGN KEY
+      fields:
+        arch:
+          data_type: integer
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 1
+          name: arch
+          order: 3
+          size:
+            - 0
+        asof:
+          data_type: timestamp with time zone
+          default_value: !!perl/ref
+            =: current_timestamp
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: asof
+          order: 6
+          size:
+            - 0
+        bug:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: bug
+          order: 1
+          size:
+            - 0
+        modified:
+          data_type: timestamp with time zone
+          default_value: !!perl/ref
+            =: current_timestamp
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: modified
+          order: 5
+          size:
+            - 0
+        status:
+          data_type: enum
+          default_value: ~
+          extra:
+            custom_type_name: bug_status_type
+            list:
+              - pending
+              - forwarded
+              - pending-fixed
+              - fixed
+              - absent
+              - done
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: status
+          order: 4
+          size:
+            - 0
+        suite:
+          data_type: integer
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 1
+          name: suite
+          order: 2
+          size:
+            - 0
+      indices:
+        - fields:
+            - arch
+          name: bug_status_cache_idx_arch
+          options: []
+          type: NORMAL
+        - fields:
+            - bug
+          name: bug_status_cache_idx_bug
+          options: []
+          type: NORMAL
+        - fields:
+            - suite
+          name: bug_status_cache_idx_suite
+          options: []
+          type: NORMAL
+      name: bug_status_cache
+      options: []
+      order: 27
+    bug_tag:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - bug
+            - tag
+          match_type: ''
+          name: bug_tag_bug_tag
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - bug
+          match_type: ''
+          name: bug_tag_fk_bug
+          on_delete: NO ACTION
+          on_update: NO ACTION
+          options: []
+          reference_fields:
+            - id
+          reference_table: bug
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - tag
+          match_type: ''
+          name: bug_tag_fk_tag
+          on_delete: NO ACTION
+          on_update: NO ACTION
+          options: []
+          reference_fields:
+            - id
+          reference_table: tag
+          type: FOREIGN KEY
+      fields:
+        bug:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: bug
+          order: 1
+          size:
+            - 0
+        tag:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: tag
+          order: 2
+          size:
+            - 0
+      indices:
+        - fields:
+            - bug
+          name: bug_tag_idx_bug
+          options: []
+          type: NORMAL
+        - fields:
+            - tag
+          name: bug_tag_idx_tag
+          options: []
+          type: NORMAL
+      name: bug_tag
+      options: []
+      order: 25
+    bug_user_tag:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - bug
+            - user_tag
+          match_type: ''
+          name: bug_user_tag_bug_tag
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - bug
+          match_type: ''
+          name: bug_user_tag_fk_bug
+          on_delete: NO ACTION
+          on_update: NO ACTION
+          options: []
+          reference_fields:
+            - id
+          reference_table: bug
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - user_tag
+          match_type: ''
+          name: bug_user_tag_fk_user_tag
+          on_delete: NO ACTION
+          on_update: NO ACTION
+          options: []
+          reference_fields:
+            - id
+          reference_table: user_tag
+          type: FOREIGN KEY
+      fields:
+        bug:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: bug
+          order: 1
+          size:
+            - 0
+        user_tag:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: user_tag
+          order: 2
+          size:
+            - 0
+      indices:
+        - fields:
+            - bug
+          name: bug_user_tag_idx_bug
+          options: []
+          type: NORMAL
+        - fields:
+            - user_tag
+          name: bug_user_tag_idx_user_tag
+          options: []
+          type: NORMAL
+      name: bug_user_tag
+      options: []
+      order: 26
+    bug_ver:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - bug
+            - ver_string
+            - found
+          match_type: ''
+          name: bug_ver_bug_ver_string_found_idx
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - bug
+          match_type: ''
+          name: bug_ver_fk_bug
+          on_delete: RESTRICT
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: bug
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - src_pkg
+          match_type: ''
+          name: bug_ver_fk_src_pkg
+          on_delete: SET NULL
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: src_pkg
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - src_ver
+          match_type: ''
+          name: bug_ver_fk_src_ver
+          on_delete: SET NULL
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: src_ver
+          type: FOREIGN KEY
+      fields:
+        bug:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: bug
+          order: 2
+          size:
+            - 0
+        creation:
+          data_type: timestamp with time zone
+          default_value: !!perl/ref
+            =: current_timestamp
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: creation
+          order: 7
+          size:
+            - 0
+        found:
+          data_type: boolean
+          default_value: !!perl/ref
+            =: true
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: found
+          order: 6
+          size:
+            - 0
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+        last_modified:
+          data_type: timestamp with time zone
+          default_value: !!perl/ref
+            =: current_timestamp
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: last_modified
+          order: 8
+          size:
+            - 0
+        src_pkg:
+          data_type: integer
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: src_pkg
+          order: 4
+          size:
+            - 0
+        src_ver:
+          data_type: integer
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: src_ver
+          order: 5
+          size:
+            - 0
+        ver_string:
+          data_type: text
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 1
+          name: ver_string
+          order: 3
+          size:
+            - 0
+      indices:
+        - fields:
+            - bug
+          name: bug_ver_idx_bug
+          options: []
+          type: NORMAL
+        - fields:
+            - src_pkg
+          name: bug_ver_idx_src_pkg
+          options: []
+          type: NORMAL
+        - fields:
+            - src_ver
+          name: bug_ver_idx_src_ver
+          options: []
+          type: NORMAL
+      name: bug_ver
+      options: []
+      order: 30
+    column_comments:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - table_name
+            - column_name
+          match_type: ''
+          name: column_comments_table_name_column_name_idx
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+      fields:
+        column_name:
+          data_type: text
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: column_name
+          order: 2
+          size:
+            - 0
+        comment_text:
+          data_type: text
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: comment_text
+          order: 3
+          size:
+            - 0
+        table_name:
+          data_type: text
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: table_name
+          order: 1
+          size:
+            - 0
+      indices: []
+      name: column_comments
+      options: []
+      order: 3
+    correspondent:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - addr
+          match_type: ''
+          name: correspondent_addr_idx
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+      fields:
+        addr:
+          data_type: text
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: addr
+          order: 2
+          size:
+            - 0
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+      indices: []
+      name: correspondent
+      options: []
+      order: 4
+    correspondent_full_name:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - correspondent
+            - full_name
+          match_type: ''
+          name: correspondent_full_name_correspondent_full_name_idx
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - correspondent
+          match_type: ''
+          name: correspondent_full_name_fk_correspondent
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: correspondent
+          type: FOREIGN KEY
+      fields:
+        correspondent:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: correspondent
+          order: 1
+          size:
+            - 0
+        full_name:
+          data_type: text
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: full_name
+          order: 2
+          size:
+            - 0
+        last_seen:
+          data_type: timestamp
+          default_value: !!perl/ref
+            =: current_timestamp
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: last_seen
+          order: 3
+          size:
+            - 0
+      indices:
+        - fields:
+            - correspondent
+          name: correspondent_full_name_idx_correspondent
+          options: []
+          type: NORMAL
+      name: correspondent_full_name
+      options: []
+      order: 11
+    maintainer:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - name
+          match_type: ''
+          name: maintainer_name_idx
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - correspondent
+          match_type: ''
+          name: maintainer_fk_correspondent
+          on_delete: NO ACTION
+          on_update: NO ACTION
+          options: []
+          reference_fields:
+            - id
+          reference_table: correspondent
+          type: FOREIGN KEY
+      fields:
+        correspondent:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: correspondent
+          order: 3
+          size:
+            - 0
+        created:
+          data_type: timestamp with time zone
+          default_value: !!perl/ref
+            =: current_timestamp
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: created
+          order: 4
+          size:
+            - 0
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+        modified:
+          data_type: timestamp with time zone
+          default_value: !!perl/ref
+            =: current_timestamp
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: modified
+          order: 5
+          size:
+            - 0
+        name:
+          data_type: text
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: name
+          order: 2
+          size:
+            - 0
+      indices:
+        - fields:
+            - correspondent
+          name: maintainer_idx_correspondent
+          options: []
+          type: NORMAL
+      name: maintainer
+      options: []
+      order: 12
+    message:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - msgid
+            - from_complete
+            - to_complete
+            - subject
+          match_type: ''
+          name: message_msgid_from_complete_to_complete_subject_idx
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+      fields:
+        from_complete:
+          data_type: text
+          default_value: ''
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: from_complete
+          order: 3
+          size:
+            - 0
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+        is_spam:
+          data_type: boolean
+          default_value: !!perl/ref
+            =: false
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: is_spam
+          order: 9
+          size:
+            - 0
+        msgid:
+          data_type: text
+          default_value: ''
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: msgid
+          order: 2
+          size:
+            - 0
+        refs:
+          data_type: text
+          default_value: ''
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: refs
+          order: 7
+          size:
+            - 0
+        sent_date:
+          data_type: timestamp with time zone
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: sent_date
+          order: 6
+          size:
+            - 0
+        spam_score:
+          data_type: double precision
+          default_value: 0
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: spam_score
+          order: 8
+          size:
+            - 0
+        subject:
+          data_type: text
+          default_value: ''
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: subject
+          order: 5
+          size:
+            - 0
+        to_complete:
+          data_type: text
+          default_value: ''
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: to_complete
+          order: 4
+          size:
+            - 0
+      indices: []
+      name: message
+      options: []
+      order: 5
+    message_correspondent:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - message
+            - correspondent
+            - correspondent_type
+          match_type: ''
+          name: message_correspondent_message_correspondent_correspondent_t_idx
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - correspondent
+          match_type: ''
+          name: message_correspondent_fk_correspondent
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: correspondent
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - message
+          match_type: ''
+          name: message_correspondent_fk_message
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: message
+          type: FOREIGN KEY
+      fields:
+        correspondent:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: correspondent
+          order: 2
+          size:
+            - 0
+        correspondent_type:
+          data_type: enum
+          default_value: to
+          extra:
+            custom_type_name: message_correspondent_type
+            list:
+              - to
+              - from
+              - envfrom
+              - cc
+              - recv
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: correspondent_type
+          order: 3
+          size:
+            - 0
+        message:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: message
+          order: 1
+          size:
+            - 0
+      indices:
+        - fields:
+            - correspondent
+          name: message_correspondent_idx_correspondent
+          options: []
+          type: NORMAL
+        - fields:
+            - message
+          name: message_correspondent_idx_message
+          options: []
+          type: NORMAL
+      name: message_correspondent
+      options: []
+      order: 16
+    message_refs:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - message
+            - refs
+          match_type: ''
+          name: message_refs_message_refs_idx
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - message
+          match_type: ''
+          name: message_refs_fk_message
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: message
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - refs
+          match_type: ''
+          name: message_refs_fk_refs
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: message
+          type: FOREIGN KEY
+      fields:
+        inferred:
+          data_type: boolean
+          default_value: !!perl/ref
+            =: false
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: inferred
+          order: 3
+          size:
+            - 0
+        message:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: message
+          order: 1
+          size:
+            - 0
+        primary_ref:
+          data_type: boolean
+          default_value: !!perl/ref
+            =: false
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: primary_ref
+          order: 4
+          size:
+            - 0
+        refs:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: refs
+          order: 2
+          size:
+            - 0
+      indices:
+        - fields:
+            - message
+          name: message_refs_idx_message
+          options: []
+          type: NORMAL
+        - fields:
+            - refs
+          name: message_refs_idx_refs
+          options: []
+          type: NORMAL
+      name: message_refs
+      options: []
+      order: 13
+    severity:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - severity
+          match_type: ''
+          name: severity_severity_idx
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+      fields:
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+        obsolete:
+          data_type: boolean
+          default_value: !!perl/ref
+            =: false
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: obsolete
+          order: 5
+          size:
+            - 0
+        ordering:
+          data_type: integer
+          default_value: 5
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: ordering
+          order: 3
+          size:
+            - 0
+        severity:
+          data_type: text
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: severity
+          order: 2
+          size:
+            - 0
+        strong:
+          data_type: boolean
+          default_value: !!perl/ref
+            =: false
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: strong
+          order: 4
+          size:
+            - 0
+      indices: []
+      name: severity
+      options: []
+      order: 6
+    src_associations:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - source
+            - suite
+          match_type: ''
+          name: src_associations_source_suite
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - source
+          match_type: ''
+          name: src_associations_fk_source
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: src_ver
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - suite
+          match_type: ''
+          name: src_associations_fk_suite
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: suite
+          type: FOREIGN KEY
+      fields:
+        created:
+          data_type: timestamp with time zone
+          default_value: !!perl/ref
+            =: current_timestamp
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: created
+          order: 4
+          size:
+            - 0
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+        modified:
+          data_type: timestamp with time zone
+          default_value: !!perl/ref
+            =: current_timestamp
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: modified
+          order: 5
+          size:
+            - 0
+        source:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: source
+          order: 3
+          size:
+            - 0
+        suite:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: suite
+          order: 2
+          size:
+            - 0
+      indices:
+        - fields:
+            - source
+          name: src_associations_idx_source
+          options: []
+          type: NORMAL
+        - fields:
+            - suite
+          name: src_associations_idx_suite
+          options: []
+          type: NORMAL
+      name: src_associations
+      options: []
+      order: 28
+    src_pkg:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - pkg
+            - disabled
+          match_type: ''
+          name: src_pkg_pkg_disabled
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - alias_of
+          match_type: ''
+          name: src_pkg_fk_alias_of
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: src_pkg
+          type: FOREIGN KEY
+      fields:
+        alias_of:
+          data_type: integer
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: alias_of
+          order: 4
+          size:
+            - 0
+        creation:
+          data_type: timestamp with time zone
+          default_value: !!perl/ref
+            =: current_timestamp
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: creation
+          order: 5
+          size:
+            - 0
+        disabled:
+          data_type: timestamp with time zone
+          default_value: infinity
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: disabled
+          order: 6
+          size:
+            - 0
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+        last_modified:
+          data_type: timestamp with time zone
+          default_value: !!perl/ref
+            =: current_timestamp
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: last_modified
+          order: 7
+          size:
+            - 0
+        obsolete:
+          data_type: boolean
+          default_value: !!perl/ref
+            =: false
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: obsolete
+          order: 8
+          size:
+            - 0
+        pkg:
+          data_type: text
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: pkg
+          order: 2
+          size:
+            - 0
+        pseduopkg:
+          data_type: boolean
+          default_value: !!perl/ref
+            =: false
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: pseduopkg
+          order: 3
+          size:
+            - 0
+      indices:
+        - fields:
+            - alias_of
+          name: src_pkg_idx_alias_of
+          options: []
+          type: NORMAL
+      name: src_pkg
+      options: []
+      order: 7
+    src_ver:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - src_pkg
+            - ver
+          match_type: ''
+          name: src_ver_src_pkg_id_ver
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - based_on
+          match_type: ''
+          name: src_ver_fk_based_on
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: src_ver
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - maintainer
+          match_type: ''
+          name: src_ver_fk_maintainer
+          on_delete: SET NULL
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: maintainer
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - src_pkg
+          match_type: ''
+          name: src_ver_fk_src_pkg
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: src_pkg
+          type: FOREIGN KEY
+      fields:
+        based_on:
+          data_type: integer
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: based_on
+          order: 6
+          size:
+            - 0
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+        maintainer:
+          data_type: integer
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: maintainer
+          order: 4
+          size:
+            - 0
+        src_pkg:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: src_pkg
+          order: 2
+          size:
+            - 0
+        upload_date:
+          data_type: timestamp with time zone
+          default_value: !!perl/ref
+            =: current_timestamp
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: upload_date
+          order: 5
+          size:
+            - 0
+        ver:
+          data_type: debversion
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: ver
+          order: 3
+          size:
+            - 0
+      indices:
+        - fields:
+            - based_on
+          name: src_ver_idx_based_on
+          options: []
+          type: NORMAL
+        - fields:
+            - maintainer
+          name: src_ver_idx_maintainer
+          options: []
+          type: NORMAL
+        - fields:
+            - src_pkg
+          name: src_ver_idx_src_pkg
+          options: []
+          type: NORMAL
+      name: src_ver
+      options: []
+      order: 19
+    suite:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - codename
+          match_type: ''
+          name: suite_idx_codename
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 1
+          expression: ''
+          fields:
+            - version
+          match_type: ''
+          name: suite_idx_version
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 1
+          expression: ''
+          fields:
+            - suite_name
+          match_type: ''
+          name: suite_suite_name_key
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+      fields:
+        active:
+          data_type: boolean
+          default_value: !!perl/ref
+            =: true
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: active
+          order: 5
+          size:
+            - 0
+        codename:
+          data_type: text
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: codename
+          order: 2
+          size:
+            - 0
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+        suite_name:
+          data_type: text
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 1
+          name: suite_name
+          order: 3
+          size:
+            - 0
+        version:
+          data_type: text
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 1
+          name: version
+          order: 4
+          size:
+            - 0
+      indices: []
+      name: suite
+      options: []
+      order: 8
+    table_comments:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - table_name
+          match_type: ''
+          name: table_comments_table_name_idx
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 1
+          expression: ''
+          fields:
+            - table_name
+          match_type: ''
+          name: table_comments_table_name_key
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+      fields:
+        comment_text:
+          data_type: text
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: comment_text
+          order: 2
+          size:
+            - 0
+        table_name:
+          data_type: text
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: table_name
+          order: 1
+          size:
+            - 0
+      indices: []
+      name: table_comments
+      options: []
+      order: 9
+    tag:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - tag
+          match_type: ''
+          name: tag_tag_key
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+      fields:
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+        obsolete:
+          data_type: boolean
+          default_value: !!perl/ref
+            =: false
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: obsolete
+          order: 3
+          size:
+            - 0
+        tag:
+          data_type: text
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: tag
+          order: 2
+          size:
+            - 0
+      indices: []
+      name: tag
+      options: []
+      order: 10
+    user_tag:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - tag
+            - correspondent
+          match_type: ''
+          name: user_tag_tag_correspondent
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - correspondent
+          match_type: ''
+          name: user_tag_fk_correspondent
+          on_delete: NO ACTION
+          on_update: NO ACTION
+          options: []
+          reference_fields:
+            - id
+          reference_table: correspondent
+          type: FOREIGN KEY
+      fields:
+        correspondent:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: correspondent
+          order: 3
+          size:
+            - 0
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+        tag:
+          data_type: text
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: tag
+          order: 2
+          size:
+            - 0
+      indices:
+        - fields:
+            - correspondent
+          name: user_tag_idx_correspondent
+          options: []
+          type: NORMAL
+      name: user_tag
+      options: []
+      order: 14
+  triggers: {}
+  views:
+    binary_versions:
+      fields:
+        - src_pkg
+        - src_ver
+        - bin_pkg
+        - arch
+        - bin_ver
+        - src_ver_based_on
+        - src_pkg_based_on
+      name: binary_versions
+      order: 1
+      sql: |
+        SELECT sp.pkg AS src_pkg, sv.ver AS src_ver, bp.pkg AS bin_pkg, a.arch AS arch, b.ver AS bin_ver,
+        svb.ver AS src_ver_based_on, spb.pkg AS src_pkg_based_on
+        FROM bin_ver b JOIN arch a ON b.arch = a.id
+                             JOIN bin_pkg bp ON b.bin_pkg  = bp.id
+                       JOIN src_ver sv ON b.src_ver  = sv.id
+                       JOIN src_pkg sp ON sv.src_pkg = sp.id
+                       LEFT OUTER JOIN src_ver svb ON sv.based_on = svb.id
+                       LEFT OUTER JOIN src_pkg spb ON spb.id = svb.src_pkg;
+    bug_package:
+      fields:
+        - bug
+        - pkg_id
+        - pkg_type
+        - package
+      name: bug_package
+      order: 2
+      sql: |
+        SELECT b.bug,b.bin_pkg,'binary',bp.pkg FROM bug_binpackage b JOIN bin_pkg bp ON bp.id=b.bin_pkg UNION
+               SELECT s.bug,s.src_pkg,'source',sp.pkg FROM bug_srcpackage s JOIN src_pkg sp ON sp.id=s.src_pkg;
+translator:
+  add_drop_table: 0
+  filename: ~
+  no_comments: 0
+  parser_args:
+    sources:
+      - Arch
+      - BinAssociation
+      - BinPkg
+      - BinVer
+      - BinaryVersion
+      - Bug
+      - BugAffectsBinpackage
+      - BugAffectsSrcpackage
+      - BugBinpackage
+      - BugBlock
+      - BugMerged
+      - BugMessage
+      - BugPackage
+      - BugSrcpackage
+      - BugStatusCache
+      - BugTag
+      - BugUserTag
+      - BugVer
+      - ColumnComment
+      - Correspondent
+      - CorrespondentFullName
+      - Maintainer
+      - Message
+      - MessageCorrespondent
+      - MessageRef
+      - Severity
+      - SrcAssociation
+      - SrcPkg
+      - SrcVer
+      - Suite
+      - TableComment
+      - Tag
+      - UserTag
+  parser_type: SQL::Translator::Parser::DBIx::Class
+  producer_args: {}
+  producer_type: SQL::Translator::Producer::YAML
+  show_warnings: 0
+  trace: 0
+  version: 0.11021
diff --git a/sql/_source/deploy/6/001-auto.yml b/sql/_source/deploy/6/001-auto.yml
new file mode 100644 (file)
index 0000000..a480db4
--- /dev/null
@@ -0,0 +1,3347 @@
+---
+schema:
+  procedures: {}
+  tables:
+    arch:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - arch
+          match_type: ''
+          name: arch_arch_key
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+      fields:
+        arch:
+          data_type: text
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: arch
+          order: 2
+          size:
+            - 0
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+      indices: []
+      name: arch
+      options: []
+      order: 1
+    bin_associations:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - bin
+            - suite
+          match_type: ''
+          name: bin_associations_bin_suite
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - bin
+          match_type: ''
+          name: bin_associations_fk_bin
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: bin_ver
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - suite
+          match_type: ''
+          name: bin_associations_fk_suite
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: suite
+          type: FOREIGN KEY
+      fields:
+        bin:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: bin
+          order: 3
+          size:
+            - 0
+        created:
+          data_type: timestamp with time zone
+          default_value: !!perl/ref
+            =: current_timestamp
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: created
+          order: 4
+          size:
+            - 0
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+        modified:
+          data_type: timestamp with time zone
+          default_value: !!perl/ref
+            =: current_timestamp
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: modified
+          order: 5
+          size:
+            - 0
+        suite:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: suite
+          order: 2
+          size:
+            - 0
+      indices:
+        - fields:
+            - bin
+          name: bin_associations_idx_bin
+          options: []
+          type: NORMAL
+        - fields:
+            - suite
+          name: bin_associations_idx_suite
+          options: []
+          type: NORMAL
+      name: bin_associations
+      options: []
+      order: 31
+    bin_pkg:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - pkg
+          match_type: ''
+          name: bin_pkg_pkg_key
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+      fields:
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+        pkg:
+          data_type: text
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: pkg
+          order: 2
+          size:
+            - 0
+      indices: []
+      name: bin_pkg
+      options: []
+      order: 2
+    bin_ver:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - bin_pkg
+            - arch
+            - ver
+          match_type: ''
+          name: bin_ver_bin_pkg_id_arch_idx
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - arch
+          match_type: ''
+          name: bin_ver_fk_arch
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: arch
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - bin_pkg
+          match_type: ''
+          name: bin_ver_fk_bin_pkg
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: bin_pkg
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - src_ver
+          match_type: ''
+          name: bin_ver_fk_src_ver
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: src_ver
+          type: FOREIGN KEY
+      fields:
+        arch:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: arch
+          order: 4
+          size:
+            - 0
+        bin_pkg:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: bin_pkg
+          order: 2
+          size:
+            - 0
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+        src_ver:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: src_ver
+          order: 3
+          size:
+            - 0
+        ver:
+          data_type: debversion
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: ver
+          order: 5
+          size:
+            - 0
+      indices:
+        - fields:
+            - arch
+          name: bin_ver_idx_arch
+          options: []
+          type: NORMAL
+        - fields:
+            - bin_pkg
+          name: bin_ver_idx_bin_pkg
+          options: []
+          type: NORMAL
+        - fields:
+            - src_ver
+          name: bin_ver_idx_src_ver
+          options: []
+          type: NORMAL
+        - fields:
+            - ver
+          name: bin_ver_ver_id_idx
+          options: []
+          type: NORMAL
+        - fields:
+            - bin_pkg
+          name: bin_ver_bin_pkg_id_idx
+          options: []
+          type: NORMAL
+        - fields:
+            - src_ver
+          name: bin_ver_src_ver_id_idx
+          options: []
+          type: NORMAL
+        - fields:
+            - src_ver
+            - arch
+          name: bin_ver_src_ver_id_arch_idx
+          options: []
+          type: NORMAL
+      name: bin_ver
+      options: []
+      order: 29
+    bug:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - done
+          match_type: ''
+          name: bug_fk_done
+          on_delete: NO ACTION
+          on_update: NO ACTION
+          options: []
+          reference_fields:
+            - id
+          reference_table: correspondent
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - owner
+          match_type: ''
+          name: bug_fk_owner
+          on_delete: NO ACTION
+          on_update: NO ACTION
+          options: []
+          reference_fields:
+            - id
+          reference_table: correspondent
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - severity
+          match_type: ''
+          name: bug_fk_severity
+          on_delete: NO ACTION
+          on_update: NO ACTION
+          options: []
+          reference_fields:
+            - id
+          reference_table: severity
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - submitter
+          match_type: ''
+          name: bug_fk_submitter
+          on_delete: NO ACTION
+          on_update: NO ACTION
+          options: []
+          reference_fields:
+            - id
+          reference_table: correspondent
+          type: FOREIGN KEY
+      fields:
+        archived:
+          data_type: boolean
+          default_value: !!perl/ref
+            =: false
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: archived
+          order: 5
+          size:
+            - 0
+        creation:
+          data_type: timestamp with time zone
+          default_value: !!perl/ref
+            =: current_timestamp
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: creation
+          order: 2
+          size:
+            - 0
+        done:
+          data_type: integer
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: done
+          order: 12
+          size:
+            - 0
+        done_full:
+          data_type: text
+          default_value: ''
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: done_full
+          order: 13
+          size:
+            - 0
+        forwarded:
+          data_type: text
+          default_value: ''
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: forwarded
+          order: 7
+          size:
+            - 0
+        id:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+        last_modified:
+          data_type: timestamp with time zone
+          default_value: !!perl/ref
+            =: current_timestamp
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: last_modified
+          order: 4
+          size:
+            - 0
+        log_modified:
+          data_type: timestamp with time zone
+          default_value: !!perl/ref
+            =: current_timestamp
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: log_modified
+          order: 3
+          size:
+            - 0
+        outlook:
+          data_type: text
+          default_value: ''
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: outlook
+          order: 9
+          size:
+            - 0
+        owner:
+          data_type: integer
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: owner
+          order: 14
+          size:
+            - 0
+        owner_full:
+          data_type: text
+          default_value: ''
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: owner_full
+          order: 15
+          size:
+            - 0
+        severity:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: severity
+          order: 11
+          size:
+            - 0
+        subject:
+          data_type: text
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: subject
+          order: 10
+          size:
+            - 0
+        submitter:
+          data_type: integer
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: submitter
+          order: 16
+          size:
+            - 0
+        submitter_full:
+          data_type: text
+          default_value: ''
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: submitter_full
+          order: 17
+          size:
+            - 0
+        summary:
+          data_type: text
+          default_value: ''
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: summary
+          order: 8
+          size:
+            - 0
+        unarchived:
+          data_type: timestamp with time zone
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: unarchived
+          order: 6
+          size:
+            - 0
+        unknown_packages:
+          data_type: text
+          default_value: ''
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: unknown_packages
+          order: 18
+          size:
+            - 0
+      indices:
+        - fields:
+            - done
+          name: bug_idx_done
+          options: []
+          type: NORMAL
+        - fields:
+            - owner
+          name: bug_idx_owner
+          options: []
+          type: NORMAL
+        - fields:
+            - severity
+          name: bug_idx_severity
+          options: []
+          type: NORMAL
+        - fields:
+            - submitter
+          name: bug_idx_submitter
+          options: []
+          type: NORMAL
+        - fields:
+            - owner
+          name: bug_idxowner
+          options: []
+          type: NORMAL
+        - fields:
+            - submitter
+          name: bug_idxsubmitter
+          options: []
+          type: NORMAL
+        - fields:
+            - done
+          name: bug_idxdone
+          options: []
+          type: NORMAL
+        - fields:
+            - forwarded
+          name: bug_idxforwarded
+          options: []
+          type: NORMAL
+        - fields:
+            - last_modified
+          name: bug_idxlast_modified
+          options: []
+          type: NORMAL
+        - fields:
+            - severity
+          name: bug_idxseverity
+          options: []
+          type: NORMAL
+        - fields:
+            - creation
+          name: bug_idxcreation
+          options: []
+          type: NORMAL
+        - fields:
+            - log_modified
+          name: bug_idxlog_modified
+          options: []
+          type: NORMAL
+      name: bug
+      options: []
+      order: 15
+    bug_affects_binpackage:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - bug
+            - bin_pkg
+          match_type: ''
+          name: bug_affects_binpackage_id_pkg
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - bin_pkg
+          match_type: ''
+          name: bug_affects_binpackage_fk_bin_pkg
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: bin_pkg
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - bug
+          match_type: ''
+          name: bug_affects_binpackage_fk_bug
+          on_delete: NO ACTION
+          on_update: NO ACTION
+          options: []
+          reference_fields:
+            - id
+          reference_table: bug
+          type: FOREIGN KEY
+      fields:
+        bin_pkg:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: bin_pkg
+          order: 2
+          size:
+            - 0
+        bug:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: bug
+          order: 1
+          size:
+            - 0
+      indices:
+        - fields:
+            - bin_pkg
+          name: bug_affects_binpackage_idx_bin_pkg
+          options: []
+          type: NORMAL
+        - fields:
+            - bug
+          name: bug_affects_binpackage_idx_bug
+          options: []
+          type: NORMAL
+      name: bug_affects_binpackage
+      options: []
+      order: 20
+    bug_affects_srcpackage:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - bug
+            - src_pkg
+          match_type: ''
+          name: bug_affects_srcpackage_id_pkg
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - bug
+          match_type: ''
+          name: bug_affects_srcpackage_fk_bug
+          on_delete: NO ACTION
+          on_update: NO ACTION
+          options: []
+          reference_fields:
+            - id
+          reference_table: bug
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - src_pkg
+          match_type: ''
+          name: bug_affects_srcpackage_fk_src_pkg
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: src_pkg
+          type: FOREIGN KEY
+      fields:
+        bug:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: bug
+          order: 1
+          size:
+            - 0
+        src_pkg:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: src_pkg
+          order: 2
+          size:
+            - 0
+      indices:
+        - fields:
+            - bug
+          name: bug_affects_srcpackage_idx_bug
+          options: []
+          type: NORMAL
+        - fields:
+            - src_pkg
+          name: bug_affects_srcpackage_idx_src_pkg
+          options: []
+          type: NORMAL
+      name: bug_affects_srcpackage
+      options: []
+      order: 21
+    bug_binpackage:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - bug
+            - bin_pkg
+          match_type: ''
+          name: bug_binpackage_id_pkg
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - bin_pkg
+          match_type: ''
+          name: bug_binpackage_fk_bin_pkg
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: bin_pkg
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - bug
+          match_type: ''
+          name: bug_binpackage_fk_bug
+          on_delete: NO ACTION
+          on_update: NO ACTION
+          options: []
+          reference_fields:
+            - id
+          reference_table: bug
+          type: FOREIGN KEY
+      fields:
+        bin_pkg:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: bin_pkg
+          order: 2
+          size:
+            - 0
+        bug:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: bug
+          order: 1
+          size:
+            - 0
+      indices:
+        - fields:
+            - bin_pkg
+          name: bug_binpackage_idx_bin_pkg
+          options: []
+          type: NORMAL
+        - fields:
+            - bug
+          name: bug_binpackage_idx_bug
+          options: []
+          type: NORMAL
+        - fields:
+            - bin_pkg
+          name: bug_binpackage_bin_pkg_idx
+          options: []
+          type: NORMAL
+      name: bug_binpackage
+      options: []
+      order: 22
+    bug_blocks:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - bug
+            - blocks
+          match_type: ''
+          name: bug_blocks_bug_id_blocks_idx
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - blocks
+          match_type: ''
+          name: bug_blocks_fk_blocks
+          on_delete: NO ACTION
+          on_update: NO ACTION
+          options: []
+          reference_fields:
+            - id
+          reference_table: bug
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - bug
+          match_type: ''
+          name: bug_blocks_fk_bug
+          on_delete: NO ACTION
+          on_update: NO ACTION
+          options: []
+          reference_fields:
+            - id
+          reference_table: bug
+          type: FOREIGN KEY
+      fields:
+        blocks:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: blocks
+          order: 3
+          size:
+            - 0
+        bug:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: bug
+          order: 2
+          size:
+            - 0
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+      indices:
+        - fields:
+            - blocks
+          name: bug_blocks_idx_blocks
+          options: []
+          type: NORMAL
+        - fields:
+            - bug
+          name: bug_blocks_idx_bug
+          options: []
+          type: NORMAL
+        - fields:
+            - bug
+          name: bug_blocks_bug_idx
+          options: []
+          type: NORMAL
+        - fields:
+            - blocks
+          name: bug_blocks_blocks_idx
+          options: []
+          type: NORMAL
+      name: bug_blocks
+      options: []
+      order: 17
+    bug_merged:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - bug
+            - merged
+          match_type: ''
+          name: bug_merged_bug_id_merged_idx
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - bug
+          match_type: ''
+          name: bug_merged_fk_bug
+          on_delete: NO ACTION
+          on_update: NO ACTION
+          options: []
+          reference_fields:
+            - id
+          reference_table: bug
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - merged
+          match_type: ''
+          name: bug_merged_fk_merged
+          on_delete: NO ACTION
+          on_update: NO ACTION
+          options: []
+          reference_fields:
+            - id
+          reference_table: bug
+          type: FOREIGN KEY
+      fields:
+        bug:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: bug
+          order: 2
+          size:
+            - 0
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+        merged:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: merged
+          order: 3
+          size:
+            - 0
+      indices:
+        - fields:
+            - bug
+          name: bug_merged_idx_bug
+          options: []
+          type: NORMAL
+        - fields:
+            - merged
+          name: bug_merged_idx_merged
+          options: []
+          type: NORMAL
+        - fields:
+            - bug
+          name: bug_merged_bug_idx
+          options: []
+          type: NORMAL
+        - fields:
+            - merged
+          name: bug_merged_merged_idx
+          options: []
+          type: NORMAL
+      name: bug_merged
+      options: []
+      order: 18
+    bug_message:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - bug
+            - message
+          match_type: ''
+          name: bug_message_bug_message_idx
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - bug
+          match_type: ''
+          name: bug_message_fk_bug
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: bug
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - message
+          match_type: ''
+          name: bug_message_fk_message
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: message
+          type: FOREIGN KEY
+      fields:
+        bug:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: bug
+          order: 1
+          size:
+            - 0
+        bug_log_offset:
+          data_type: integer
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: bug_log_offset
+          order: 4
+          size:
+            - 0
+        message:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: message
+          order: 2
+          size:
+            - 0
+        message_number:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: message_number
+          order: 3
+          size:
+            - 0
+        offset_valid:
+          data_type: timestamp with time zone
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: offset_valid
+          order: 5
+          size:
+            - 0
+      indices:
+        - fields:
+            - bug
+          name: bug_message_idx_bug
+          options: []
+          type: NORMAL
+        - fields:
+            - message
+          name: bug_message_idx_message
+          options: []
+          type: NORMAL
+        - fields:
+            - bug
+            - message_number
+          name: bug_message_idx_bug_message_number
+          options: []
+          type: NORMAL
+      name: bug_message
+      options: []
+      order: 23
+    bug_srcpackage:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - bug
+            - src_pkg
+          match_type: ''
+          name: bug_srcpackage_id_pkg
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - bug
+          match_type: ''
+          name: bug_srcpackage_fk_bug
+          on_delete: NO ACTION
+          on_update: NO ACTION
+          options: []
+          reference_fields:
+            - id
+          reference_table: bug
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - src_pkg
+          match_type: ''
+          name: bug_srcpackage_fk_src_pkg
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: src_pkg
+          type: FOREIGN KEY
+      fields:
+        bug:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: bug
+          order: 1
+          size:
+            - 0
+        src_pkg:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: src_pkg
+          order: 2
+          size:
+            - 0
+      indices:
+        - fields:
+            - bug
+          name: bug_srcpackage_idx_bug
+          options: []
+          type: NORMAL
+        - fields:
+            - src_pkg
+          name: bug_srcpackage_idx_src_pkg
+          options: []
+          type: NORMAL
+        - fields:
+            - src_pkg
+          name: bug_srcpackage_src_pkg_idx
+          options: []
+          type: NORMAL
+      name: bug_srcpackage
+      options: []
+      order: 24
+    bug_status_cache:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - bug
+            - suite
+            - arch
+          match_type: ''
+          name: bug_status_cache_bug_suite_arch_idx
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - arch
+          match_type: ''
+          name: bug_status_cache_fk_arch
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: arch
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - bug
+          match_type: ''
+          name: bug_status_cache_fk_bug
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: bug
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - suite
+          match_type: ''
+          name: bug_status_cache_fk_suite
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: suite
+          type: FOREIGN KEY
+      fields:
+        arch:
+          data_type: integer
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 1
+          name: arch
+          order: 3
+          size:
+            - 0
+        asof:
+          data_type: timestamp with time zone
+          default_value: !!perl/ref
+            =: current_timestamp
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: asof
+          order: 6
+          size:
+            - 0
+        bug:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: bug
+          order: 1
+          size:
+            - 0
+        modified:
+          data_type: timestamp with time zone
+          default_value: !!perl/ref
+            =: current_timestamp
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: modified
+          order: 5
+          size:
+            - 0
+        status:
+          data_type: enum
+          default_value: ~
+          extra:
+            custom_type_name: bug_status_type
+            list:
+              - pending
+              - forwarded
+              - pending-fixed
+              - fixed
+              - absent
+              - done
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: status
+          order: 4
+          size:
+            - 0
+        suite:
+          data_type: integer
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 1
+          name: suite
+          order: 2
+          size:
+            - 0
+      indices:
+        - fields:
+            - arch
+          name: bug_status_cache_idx_arch
+          options: []
+          type: NORMAL
+        - fields:
+            - bug
+          name: bug_status_cache_idx_bug
+          options: []
+          type: NORMAL
+        - fields:
+            - suite
+          name: bug_status_cache_idx_suite
+          options: []
+          type: NORMAL
+      name: bug_status_cache
+      options: []
+      order: 27
+    bug_tag:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - bug
+            - tag
+          match_type: ''
+          name: bug_tag_bug_tag
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - bug
+          match_type: ''
+          name: bug_tag_fk_bug
+          on_delete: NO ACTION
+          on_update: NO ACTION
+          options: []
+          reference_fields:
+            - id
+          reference_table: bug
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - tag
+          match_type: ''
+          name: bug_tag_fk_tag
+          on_delete: NO ACTION
+          on_update: NO ACTION
+          options: []
+          reference_fields:
+            - id
+          reference_table: tag
+          type: FOREIGN KEY
+      fields:
+        bug:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: bug
+          order: 1
+          size:
+            - 0
+        tag:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: tag
+          order: 2
+          size:
+            - 0
+      indices:
+        - fields:
+            - bug
+          name: bug_tag_idx_bug
+          options: []
+          type: NORMAL
+        - fields:
+            - tag
+          name: bug_tag_idx_tag
+          options: []
+          type: NORMAL
+        - fields:
+            - tag
+          name: bug_tag_tag
+          options: []
+          type: NORMAL
+      name: bug_tag
+      options: []
+      order: 25
+    bug_user_tag:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - bug
+            - user_tag
+          match_type: ''
+          name: bug_user_tag_bug_tag
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - bug
+          match_type: ''
+          name: bug_user_tag_fk_bug
+          on_delete: NO ACTION
+          on_update: NO ACTION
+          options: []
+          reference_fields:
+            - id
+          reference_table: bug
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - user_tag
+          match_type: ''
+          name: bug_user_tag_fk_user_tag
+          on_delete: NO ACTION
+          on_update: NO ACTION
+          options: []
+          reference_fields:
+            - id
+          reference_table: user_tag
+          type: FOREIGN KEY
+      fields:
+        bug:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: bug
+          order: 1
+          size:
+            - 0
+        user_tag:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: user_tag
+          order: 2
+          size:
+            - 0
+      indices:
+        - fields:
+            - bug
+          name: bug_user_tag_idx_bug
+          options: []
+          type: NORMAL
+        - fields:
+            - user_tag
+          name: bug_user_tag_idx_user_tag
+          options: []
+          type: NORMAL
+        - fields:
+            - user_tag
+          name: bug_user_tag_tag
+          options: []
+          type: NORMAL
+      name: bug_user_tag
+      options: []
+      order: 26
+    bug_ver:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - bug
+            - ver_string
+            - found
+          match_type: ''
+          name: bug_ver_bug_ver_string_found_idx
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - bug
+          match_type: ''
+          name: bug_ver_fk_bug
+          on_delete: RESTRICT
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: bug
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - src_pkg
+          match_type: ''
+          name: bug_ver_fk_src_pkg
+          on_delete: SET NULL
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: src_pkg
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - src_ver
+          match_type: ''
+          name: bug_ver_fk_src_ver
+          on_delete: SET NULL
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: src_ver
+          type: FOREIGN KEY
+      fields:
+        bug:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: bug
+          order: 2
+          size:
+            - 0
+        creation:
+          data_type: timestamp with time zone
+          default_value: !!perl/ref
+            =: current_timestamp
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: creation
+          order: 7
+          size:
+            - 0
+        found:
+          data_type: boolean
+          default_value: !!perl/ref
+            =: true
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: found
+          order: 6
+          size:
+            - 0
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+        last_modified:
+          data_type: timestamp with time zone
+          default_value: !!perl/ref
+            =: current_timestamp
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: last_modified
+          order: 8
+          size:
+            - 0
+        src_pkg:
+          data_type: integer
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: src_pkg
+          order: 4
+          size:
+            - 0
+        src_ver:
+          data_type: integer
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: src_ver
+          order: 5
+          size:
+            - 0
+        ver_string:
+          data_type: text
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 1
+          name: ver_string
+          order: 3
+          size:
+            - 0
+      indices:
+        - fields:
+            - bug
+          name: bug_ver_idx_bug
+          options: []
+          type: NORMAL
+        - fields:
+            - src_pkg
+          name: bug_ver_idx_src_pkg
+          options: []
+          type: NORMAL
+        - fields:
+            - src_ver
+          name: bug_ver_idx_src_ver
+          options: []
+          type: NORMAL
+        - fields:
+            - src_pkg
+          name: bug_ver_src_pkg_id_idx
+          options: []
+          type: NORMAL
+        - fields:
+            - src_ver
+          name: bug_ver_src_ver_id_idx
+          options: []
+          type: NORMAL
+        - fields:
+            - src_pkg
+            - src_ver
+          name: bug_ver_src_pkg_id_src_ver_id_idx
+          options: []
+          type: NORMAL
+      name: bug_ver
+      options: []
+      order: 30
+    column_comments:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - table_name
+            - column_name
+          match_type: ''
+          name: column_comments_table_name_column_name_idx
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+      fields:
+        column_name:
+          data_type: text
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: column_name
+          order: 2
+          size:
+            - 0
+        comment_text:
+          data_type: text
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: comment_text
+          order: 3
+          size:
+            - 0
+        table_name:
+          data_type: text
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: table_name
+          order: 1
+          size:
+            - 0
+      indices: []
+      name: column_comments
+      options: []
+      order: 3
+    correspondent:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - addr
+          match_type: ''
+          name: correspondent_addr_idx
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+      fields:
+        addr:
+          data_type: text
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: addr
+          order: 2
+          size:
+            - 0
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+      indices: []
+      name: correspondent
+      options: []
+      order: 4
+    correspondent_full_name:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - correspondent
+            - full_name
+          match_type: ''
+          name: correspondent_full_name_correspondent_full_name_idx
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - correspondent
+          match_type: ''
+          name: correspondent_full_name_fk_correspondent
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: correspondent
+          type: FOREIGN KEY
+      fields:
+        correspondent:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: correspondent
+          order: 1
+          size:
+            - 0
+        full_name:
+          data_type: text
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: full_name
+          order: 2
+          size:
+            - 0
+        last_seen:
+          data_type: timestamp
+          default_value: !!perl/ref
+            =: current_timestamp
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: last_seen
+          order: 3
+          size:
+            - 0
+      indices:
+        - fields:
+            - correspondent
+          name: correspondent_full_name_idx_correspondent
+          options: []
+          type: NORMAL
+        - fields:
+            - full_name
+          name: correspondent_full_name_idx_full_name
+          options: []
+          type: NORMAL
+        - fields:
+            - last_seen
+          name: correspondent_full_name_idx_last_seen
+          options: []
+          type: NORMAL
+      name: correspondent_full_name
+      options: []
+      order: 11
+    maintainer:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - name
+          match_type: ''
+          name: maintainer_name_idx
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - correspondent
+          match_type: ''
+          name: maintainer_fk_correspondent
+          on_delete: NO ACTION
+          on_update: NO ACTION
+          options: []
+          reference_fields:
+            - id
+          reference_table: correspondent
+          type: FOREIGN KEY
+      fields:
+        correspondent:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: correspondent
+          order: 3
+          size:
+            - 0
+        created:
+          data_type: timestamp with time zone
+          default_value: !!perl/ref
+            =: current_timestamp
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: created
+          order: 4
+          size:
+            - 0
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+        modified:
+          data_type: timestamp with time zone
+          default_value: !!perl/ref
+            =: current_timestamp
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: modified
+          order: 5
+          size:
+            - 0
+        name:
+          data_type: text
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: name
+          order: 2
+          size:
+            - 0
+      indices:
+        - fields:
+            - correspondent
+          name: maintainer_idx_correspondent
+          options: []
+          type: NORMAL
+      name: maintainer
+      options: []
+      order: 12
+    message:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - msgid
+            - from_complete
+            - to_complete
+            - subject
+          match_type: ''
+          name: message_msgid_from_complete_to_complete_subject_idx
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+      fields:
+        from_complete:
+          data_type: text
+          default_value: ''
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: from_complete
+          order: 3
+          size:
+            - 0
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+        is_spam:
+          data_type: boolean
+          default_value: !!perl/ref
+            =: false
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: is_spam
+          order: 9
+          size:
+            - 0
+        msgid:
+          data_type: text
+          default_value: ''
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: msgid
+          order: 2
+          size:
+            - 0
+        refs:
+          data_type: text
+          default_value: ''
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: refs
+          order: 7
+          size:
+            - 0
+        sent_date:
+          data_type: timestamp with time zone
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: sent_date
+          order: 6
+          size:
+            - 0
+        spam_score:
+          data_type: double precision
+          default_value: 0
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: spam_score
+          order: 8
+          size:
+            - 0
+        subject:
+          data_type: text
+          default_value: ''
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: subject
+          order: 5
+          size:
+            - 0
+        to_complete:
+          data_type: text
+          default_value: ''
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: to_complete
+          order: 4
+          size:
+            - 0
+      indices:
+        - fields:
+            - msgid
+          name: message_msgid_idx
+          options: []
+          type: NORMAL
+        - fields:
+            - subject
+          name: message_subject_idx
+          options: []
+          type: NORMAL
+      name: message
+      options: []
+      order: 5
+    message_correspondent:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - message
+            - correspondent
+            - correspondent_type
+          match_type: ''
+          name: message_correspondent_message_correspondent_correspondent_t_idx
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - correspondent
+          match_type: ''
+          name: message_correspondent_fk_correspondent
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: correspondent
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - message
+          match_type: ''
+          name: message_correspondent_fk_message
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: message
+          type: FOREIGN KEY
+      fields:
+        correspondent:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: correspondent
+          order: 2
+          size:
+            - 0
+        correspondent_type:
+          data_type: enum
+          default_value: to
+          extra:
+            custom_type_name: message_correspondent_type
+            list:
+              - to
+              - from
+              - envfrom
+              - cc
+              - recv
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: correspondent_type
+          order: 3
+          size:
+            - 0
+        message:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: message
+          order: 1
+          size:
+            - 0
+      indices:
+        - fields:
+            - correspondent
+          name: message_correspondent_idx_correspondent
+          options: []
+          type: NORMAL
+        - fields:
+            - message
+          name: message_correspondent_idx_message
+          options: []
+          type: NORMAL
+        - fields:
+            - correspondent
+          name: message_correspondent_idxcorrespondent
+          options: []
+          type: NORMAL
+        - fields:
+            - message
+          name: message_correspondent_idxmessage
+          options: []
+          type: NORMAL
+      name: message_correspondent
+      options: []
+      order: 16
+    message_refs:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - message
+            - refs
+          match_type: ''
+          name: message_refs_message_refs_idx
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - message
+          match_type: ''
+          name: message_refs_fk_message
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: message
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - refs
+          match_type: ''
+          name: message_refs_fk_refs
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: message
+          type: FOREIGN KEY
+      fields:
+        inferred:
+          data_type: boolean
+          default_value: !!perl/ref
+            =: false
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: inferred
+          order: 3
+          size:
+            - 0
+        message:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: message
+          order: 1
+          size:
+            - 0
+        primary_ref:
+          data_type: boolean
+          default_value: !!perl/ref
+            =: false
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: primary_ref
+          order: 4
+          size:
+            - 0
+        refs:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: refs
+          order: 2
+          size:
+            - 0
+      indices:
+        - fields:
+            - message
+          name: message_refs_idx_message
+          options: []
+          type: NORMAL
+        - fields:
+            - refs
+          name: message_refs_idx_refs
+          options: []
+          type: NORMAL
+      name: message_refs
+      options: []
+      order: 13
+    severity:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - severity
+          match_type: ''
+          name: severity_severity_idx
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+      fields:
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+        obsolete:
+          data_type: boolean
+          default_value: !!perl/ref
+            =: false
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: obsolete
+          order: 5
+          size:
+            - 0
+        ordering:
+          data_type: integer
+          default_value: 5
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: ordering
+          order: 3
+          size:
+            - 0
+        severity:
+          data_type: text
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: severity
+          order: 2
+          size:
+            - 0
+        strong:
+          data_type: boolean
+          default_value: !!perl/ref
+            =: false
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: strong
+          order: 4
+          size:
+            - 0
+      indices:
+        - fields:
+            - ordering
+          name: severity_ordering_idx
+          options: []
+          type: NORMAL
+      name: severity
+      options: []
+      order: 6
+    src_associations:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - source
+            - suite
+          match_type: ''
+          name: src_associations_source_suite
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - source
+          match_type: ''
+          name: src_associations_fk_source
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: src_ver
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - suite
+          match_type: ''
+          name: src_associations_fk_suite
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: suite
+          type: FOREIGN KEY
+      fields:
+        created:
+          data_type: timestamp with time zone
+          default_value: !!perl/ref
+            =: current_timestamp
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: created
+          order: 4
+          size:
+            - 0
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+        modified:
+          data_type: timestamp with time zone
+          default_value: !!perl/ref
+            =: current_timestamp
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: modified
+          order: 5
+          size:
+            - 0
+        source:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: source
+          order: 3
+          size:
+            - 0
+        suite:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: suite
+          order: 2
+          size:
+            - 0
+      indices:
+        - fields:
+            - source
+          name: src_associations_idx_source
+          options: []
+          type: NORMAL
+        - fields:
+            - suite
+          name: src_associations_idx_suite
+          options: []
+          type: NORMAL
+      name: src_associations
+      options: []
+      order: 28
+    src_pkg:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - pkg
+            - disabled
+          match_type: ''
+          name: src_pkg_pkg_disabled
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - alias_of
+          match_type: ''
+          name: src_pkg_fk_alias_of
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: src_pkg
+          type: FOREIGN KEY
+      fields:
+        alias_of:
+          data_type: integer
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: alias_of
+          order: 4
+          size:
+            - 0
+        creation:
+          data_type: timestamp with time zone
+          default_value: !!perl/ref
+            =: current_timestamp
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: creation
+          order: 5
+          size:
+            - 0
+        disabled:
+          data_type: timestamp with time zone
+          default_value: infinity
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: disabled
+          order: 6
+          size:
+            - 0
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+        last_modified:
+          data_type: timestamp with time zone
+          default_value: !!perl/ref
+            =: current_timestamp
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: last_modified
+          order: 7
+          size:
+            - 0
+        obsolete:
+          data_type: boolean
+          default_value: !!perl/ref
+            =: false
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: obsolete
+          order: 8
+          size:
+            - 0
+        pkg:
+          data_type: text
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: pkg
+          order: 2
+          size:
+            - 0
+        pseduopkg:
+          data_type: boolean
+          default_value: !!perl/ref
+            =: false
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: pseduopkg
+          order: 3
+          size:
+            - 0
+      indices:
+        - fields:
+            - alias_of
+          name: src_pkg_idx_alias_of
+          options: []
+          type: NORMAL
+        - fields:
+            - pkg
+          name: src_pkg_pkg
+          options: []
+          type: NORMAL
+      name: src_pkg
+      options: []
+      order: 7
+    src_ver:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - src_pkg
+            - ver
+          match_type: ''
+          name: src_ver_src_pkg_id_ver
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - based_on
+          match_type: ''
+          name: src_ver_fk_based_on
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: src_ver
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - maintainer
+          match_type: ''
+          name: src_ver_fk_maintainer
+          on_delete: SET NULL
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: maintainer
+          type: FOREIGN KEY
+        - deferrable: 0
+          expression: ''
+          fields:
+            - src_pkg
+          match_type: ''
+          name: src_ver_fk_src_pkg
+          on_delete: CASCADE
+          on_update: CASCADE
+          options: []
+          reference_fields:
+            - id
+          reference_table: src_pkg
+          type: FOREIGN KEY
+      fields:
+        based_on:
+          data_type: integer
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: based_on
+          order: 6
+          size:
+            - 0
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+        maintainer:
+          data_type: integer
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: maintainer
+          order: 4
+          size:
+            - 0
+        src_pkg:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: src_pkg
+          order: 2
+          size:
+            - 0
+        upload_date:
+          data_type: timestamp with time zone
+          default_value: !!perl/ref
+            =: current_timestamp
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: upload_date
+          order: 5
+          size:
+            - 0
+        ver:
+          data_type: debversion
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: ver
+          order: 3
+          size:
+            - 0
+      indices:
+        - fields:
+            - based_on
+          name: src_ver_idx_based_on
+          options: []
+          type: NORMAL
+        - fields:
+            - maintainer
+          name: src_ver_idx_maintainer
+          options: []
+          type: NORMAL
+        - fields:
+            - src_pkg
+          name: src_ver_idx_src_pkg
+          options: []
+          type: NORMAL
+      name: src_ver
+      options: []
+      order: 19
+    suite:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - codename
+          match_type: ''
+          name: suite_idx_codename
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 1
+          expression: ''
+          fields:
+            - version
+          match_type: ''
+          name: suite_idx_version
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 1
+          expression: ''
+          fields:
+            - suite_name
+          match_type: ''
+          name: suite_suite_name_key
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+      fields:
+        active:
+          data_type: boolean
+          default_value: !!perl/ref
+            =: true
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: active
+          order: 5
+          size:
+            - 0
+        codename:
+          data_type: text
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: codename
+          order: 2
+          size:
+            - 0
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+        suite_name:
+          data_type: text
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 1
+          name: suite_name
+          order: 3
+          size:
+            - 0
+        version:
+          data_type: text
+          default_value: ~
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 1
+          name: version
+          order: 4
+          size:
+            - 0
+      indices: []
+      name: suite
+      options: []
+      order: 8
+    table_comments:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - table_name
+          match_type: ''
+          name: table_comments_table_name_idx
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 1
+          expression: ''
+          fields:
+            - table_name
+          match_type: ''
+          name: table_comments_table_name_key
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+      fields:
+        comment_text:
+          data_type: text
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 0
+          name: comment_text
+          order: 2
+          size:
+            - 0
+        table_name:
+          data_type: text
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: table_name
+          order: 1
+          size:
+            - 0
+      indices: []
+      name: table_comments
+      options: []
+      order: 9
+    tag:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - tag
+          match_type: ''
+          name: tag_tag_key
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+      fields:
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+        obsolete:
+          data_type: boolean
+          default_value: !!perl/ref
+            =: false
+          is_nullable: 1
+          is_primary_key: 0
+          is_unique: 0
+          name: obsolete
+          order: 3
+          size:
+            - 0
+        tag:
+          data_type: text
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: tag
+          order: 2
+          size:
+            - 0
+      indices: []
+      name: tag
+      options: []
+      order: 10
+    user_tag:
+      constraints:
+        - deferrable: 1
+          expression: ''
+          fields:
+            - id
+          match_type: ''
+          name: ''
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: PRIMARY KEY
+        - deferrable: 1
+          expression: ''
+          fields:
+            - tag
+            - correspondent
+          match_type: ''
+          name: user_tag_tag_correspondent
+          on_delete: ''
+          on_update: ''
+          options: []
+          reference_fields: []
+          reference_table: ''
+          type: UNIQUE
+        - deferrable: 0
+          expression: ''
+          fields:
+            - correspondent
+          match_type: ''
+          name: user_tag_fk_correspondent
+          on_delete: NO ACTION
+          on_update: NO ACTION
+          options: []
+          reference_fields:
+            - id
+          reference_table: correspondent
+          type: FOREIGN KEY
+      fields:
+        correspondent:
+          data_type: integer
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: correspondent
+          order: 3
+          size:
+            - 0
+        id:
+          data_type: integer
+          default_value: ~
+          is_auto_increment: 1
+          is_nullable: 0
+          is_primary_key: 1
+          is_unique: 0
+          name: id
+          order: 1
+          size:
+            - 0
+        tag:
+          data_type: text
+          default_value: ~
+          is_nullable: 0
+          is_primary_key: 0
+          is_unique: 1
+          name: tag
+          order: 2
+          size:
+            - 0
+      indices:
+        - fields:
+            - correspondent
+          name: user_tag_idx_correspondent
+          options: []
+          type: NORMAL
+        - fields:
+            - correspondent
+          name: user_tag_correspondent
+          options: []
+          type: NORMAL
+      name: user_tag
+      options: []
+      order: 14
+  triggers: {}
+  views:
+    binary_versions:
+      fields:
+        - src_pkg
+        - src_ver
+        - bin_pkg
+        - arch
+        - bin_ver
+        - src_ver_based_on
+        - src_pkg_based_on
+      name: binary_versions
+      order: 1
+      sql: |
+        SELECT sp.pkg AS src_pkg, sv.ver AS src_ver, bp.pkg AS bin_pkg, a.arch AS arch, b.ver AS bin_ver,
+        svb.ver AS src_ver_based_on, spb.pkg AS src_pkg_based_on
+        FROM bin_ver b JOIN arch a ON b.arch = a.id
+                             JOIN bin_pkg bp ON b.bin_pkg  = bp.id
+                       JOIN src_ver sv ON b.src_ver  = sv.id
+                       JOIN src_pkg sp ON sv.src_pkg = sp.id
+                       LEFT OUTER JOIN src_ver svb ON sv.based_on = svb.id
+                       LEFT OUTER JOIN src_pkg spb ON spb.id = svb.src_pkg;
+    bug_package:
+      fields:
+        - bug
+        - pkg_id
+        - pkg_type
+        - package
+      name: bug_package
+      order: 2
+      sql: |
+        SELECT b.bug,b.bin_pkg,'binary',bp.pkg FROM bug_binpackage b JOIN bin_pkg bp ON bp.id=b.bin_pkg UNION
+               SELECT s.bug,s.src_pkg,'source',sp.pkg FROM bug_srcpackage s JOIN src_pkg sp ON sp.id=s.src_pkg;
+translator:
+  add_drop_table: 0
+  filename: ~
+  no_comments: 0
+  parser_args:
+    sources:
+      - Arch
+      - BinAssociation
+      - BinPkg
+      - BinVer
+      - BinaryVersion
+      - Bug
+      - BugAffectsBinpackage
+      - BugAffectsSrcpackage
+      - BugBinpackage
+      - BugBlock
+      - BugMerged
+      - BugMessage
+      - BugPackage
+      - BugSrcpackage
+      - BugStatusCache
+      - BugTag
+      - BugUserTag
+      - BugVer
+      - ColumnComment
+      - Correspondent
+      - CorrespondentFullName
+      - Maintainer
+      - Message
+      - MessageCorrespondent
+      - MessageRef
+      - Severity
+      - SrcAssociation
+      - SrcPkg
+      - SrcVer
+      - Suite
+      - TableComment
+      - Tag
+      - UserTag
+  parser_type: SQL::Translator::Parser::DBIx::Class
+  producer_args: {}
+  producer_type: SQL::Translator::Producer::YAML
+  show_warnings: 0
+  trace: 0
+  version: 0.11021
diff --git a/sql/dbicdump.conf b/sql/dbicdump.conf
new file mode 100644 (file)
index 0000000..02460b6
--- /dev/null
@@ -0,0 +1,12 @@
+schema_class Debbugs::DB::Schema
+
+lib .
+
+<connect_info>
+    dsn     dbi:Pg:service=debbugs
+</connect_info>
+
+<loader_options>
+    components  InflateColumn::DateTime
+    components  TimeStamp
+</loader_options>
\ No newline at end of file
diff --git a/sql/dbicdump_command.sh b/sql/dbicdump_command.sh
new file mode 100755 (executable)
index 0000000..c957f8f
--- /dev/null
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+if [ -z "$DEBBUGS_SERVICE" ]; then
+    DEBBUGS_SERVICE="debbugs";
+fi;
+
+if ! [ -d "sql" ] || ! [ -d "Debbugs" ]; then 
+    echo "In the wrong directory"
+    exit 1;
+fi;
+
+dbicdump -I. -o dump_directory=. \
+    -o components='["InflateColumn::DateTime","TimeStamp"]' \
+    -o preserve_case=1 \
+    -o skip_load_external=1 \
+    -o exclude='qr/^dbix_class_deploymenthandler_versions$/' \
+    Debbugs::DB dbi:Pg:service=$DEBBUGS_SERVICE '' '';
+
diff --git a/sql/debbugs_schema.sql b/sql/debbugs_schema.sql
new file mode 100644 (file)
index 0000000..f2a420d
--- /dev/null
@@ -0,0 +1,548 @@
+
+DROP TABLE bug_status_cache CASCADE;
+DROP VIEW bug_package CASCADE;
+DROP VIEW binary_versions CASCADE;
+DROP TABLE bug_tag CASCADE;
+DROP TABLE tag CASCADE;
+DROP TABLE bug_user_tag CASCADE;
+DROP TABLE user_tag CASCADE;
+DROP TABLE severity CASCADE;
+DROP TABLE bug CASCADE;
+DROP TABLE src_pkg CASCADE;
+DROP TABLE bug_ver CASCADE;
+DROP TABLE src_ver CASCADE;
+DROP TABLE arch CASCADE;
+DROP TABLE bin_ver CASCADE;
+DROP TABLE bin_pkg CASCADE;
+DROP TABLE bug_blocks CASCADE;
+DROP TABLE bug_merged CASCADE;
+DROP TABLE bug_srcpackage CASCADE;
+DROP TABLE bug_binpackage CASCADE;
+DROP TABLE bug_affects_binpackage CASCADE;
+DROP TABLE bug_affects_srcpackage CASCADE;
+DROP TABLE suite CASCADE;
+DROP TABLE bin_associations CASCADE;
+DROP TABLE src_associations CASCADE;
+DROP TABLE maintainer CASCADE;
+DROP TABLE bug_message CASCADE;
+DROP TABLE message_correspondent CASCADE;
+DROP TABLE correspondent_full_name CASCADE;
+DROP TABLE correspondent CASCADE;
+DROP TABLE message_refs CASCADE;
+DROP TABLE message CASCADE;
+DROP TYPE message_correspondent_type CASCADE;
+DROP TABLE table_comments CASCADE;
+DROP TABLE column_comments CASCADE;
+DROP TYPE bug_status_type CASCADE;
+
+-- the following two tables are used to provide documentation about
+-- the tables and columns for DBIx::Class::Schema::Loader
+CREATE TABLE table_comments (
+       table_name TEXT NOT NULL,
+       comment_text TEXT NOT NULL
+);
+CREATE UNIQUE INDEX table_comments_table_name_idx ON table_comments(table_name);
+CREATE TABLE column_comments (
+       table_name TEXT  NOT NULL,
+       column_name TEXT  NOT NULL,
+       comment_text TEXT NOT NULL
+);
+CREATE UNIQUE INDEX column_comments_table_name_column_name_idx ON column_comments(table_name,column_name);
+
+
+CREATE TABLE correspondent (
+       id SERIAL PRIMARY KEY,
+       addr TEXT NOT NULL
+);
+CREATE UNIQUE INDEX correspondent_addr_idx ON correspondent(addr);
+INSERT INTO table_comments VALUES ('correspondent','Individual who has corresponded with the BTS');
+INSERT INTO column_comments VALUES ('correspondent','id','Correspondent ID');
+INSERT INTO column_comments VALUES ('correspondent','addr','Correspondent address');
+
+CREATE TABLE maintainer (
+       id SERIAL PRIMARY KEY,
+       name TEXT NOT NULL,
+       correspondent INT NOT NULL REFERENCES correspondent(id),
+       created TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL,
+       modified TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL
+);
+CREATE UNIQUE INDEX maintainer_name_idx ON maintainer(name);
+CREATE INDEX maintainer_idx_correspondent ON maintainer(correspondent);
+INSERT INTO table_comments  VALUES ('maintainer','Package maintainer names');
+INSERT INTO column_comments VALUES ('maintainer','id','Package maintainer id');
+INSERT INTO column_comments VALUES ('maintainer','name','Name of package maintainer');
+INSERT INTO column_comments VALUES ('maintainer','correspondent','Correspondent ID');
+INSERT INTO column_comments VALUES ('maintainer','created','Time maintainer record created');
+INSERT INTO column_comments VALUES ('maintainer','modified','Time maintainer record modified');
+
+
+CREATE TABLE severity (
+       id SERIAL PRIMARY KEY,
+       severity TEXT NOT NULL,
+       ordering INT NOT NULL DEFAULT 5,
+       strong BOOLEAN DEFAULT FALSE,
+       obsolete BOOLEAN DEFAULT FALSE
+);
+CREATE UNIQUE INDEX severity_severity_idx ON severity(severity);
+CREATE INDEX severity_ordering_idx ON severity(ordering);
+INSERT INTO table_comments VALUES ('severity','Bug severity');
+INSERT INTO column_comments VALUES ('severity','id','Severity id');
+INSERT INTO column_comments VALUES ('severity','severity','Severity name');
+INSERT INTO column_comments VALUES ('severity','ordering','Severity ordering (more severe severities have higher numbers)');
+INSERT INTO column_comments VALUES ('severity','strong','True if severity is a strong severity');
+INSERT INTO column_comments VALUES ('severity','obsolete','Whether a severity level is obsolete (should not be set on new bugs)');
+
+-- bugs table
+CREATE TABLE bug (
+       id INTEGER NOT NULL PRIMARY KEY,
+       creation TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
+       log_modified TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
+       last_modified TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
+       archived BOOLEAN NOT NULL DEFAULT FALSE,
+       unarchived TIMESTAMP WITH TIME ZONE,
+       forwarded TEXT NOT NULL DEFAULT '',
+       summary TEXT NOT NULL DEFAULT '',
+       outlook TEXT NOT NULL DEFAULT '',
+       subject TEXT NOT NULL,
+       severity INT NOT NULL REFERENCES severity(id),
+       done INT REFERENCES correspondent(id),
+       done_full TEXT NOT NULL DEFAULT '',
+       owner INT REFERENCES correspondent(id),
+       owner_full TEXT NOT NULL DEFAULT '',
+       -- submitter would ideally be NOT NULL, but there are some ancient bugs which do not have submitters
+       submitter INT REFERENCES correspondent(id),
+       submitter_full TEXT NOT NULL DEFAULT '',
+       unknown_packages TEXT NOT NULL DEfAULT ''
+);
+CREATE INDEX bug_idx_owner ON bug(owner);
+CREATE INDEX bug_idx_submitter ON bug(submitter);
+CREATE INDEX bug_idx_done ON bug(done);
+CREATE INDEX bug_idx_forwarded ON bug(forwarded);
+CREATE INDEX bug_idx_last_modified ON bug(last_modified);
+CREATE INDEX bug_idx_severity ON bug(severity);
+CREATE INDEX bug_idx_creation ON bug(creation);
+CREATE INDEX bug_idx_log_modified ON bug(log_modified);
+
+INSERT INTO table_comments VALUES ('bug','Bugs');
+INSERT INTO column_comments VALUES ('bug','id','Bug number');
+INSERT INTO column_comments VALUES ('bug','creation','Time bug created');
+INSERT INTO column_comments VALUES ('bug','log_modified','Time bug log was last modified');
+INSERT INTO column_comments VALUES ('bug','last_modified','Time bug status was last modified');
+INSERT INTO column_comments VALUES ('bug','archived','True if bug has been archived');
+INSERT INTO column_comments VALUES ('bug','unarchived','Time bug was last unarchived; null if bug has never been unarchived');
+INSERT INTO column_comments VALUES ('bug','forwarded','Where bug has been forwarded to; empty if it has not been forwarded');
+INSERT INTO column_comments VALUES ('bug','summary','Summary of the bug; empty if it has no summary');
+INSERT INTO column_comments VALUES ('bug','outlook','Outlook of the bug; empty if it has no outlook');
+INSERT INTO column_comments VALUES ('bug','subject','Subject of the bug');
+INSERT INTO column_comments VALUES ('bug','done','Individual who did the -done; empty if it has never been -done');
+INSERT INTO column_comments VALUES ('bug','owner','Individual who owns this bug; empty if no one owns it');
+INSERT INTO column_comments VALUES ('bug','submitter','Individual who submitted this bug; empty if there is no submitter');
+INSERT INTO column_comments VALUES ('bug','unknown_packages','Package name if the package is not known');
+
+
+
+CREATE TABLE bug_blocks (
+       id SERIAL PRIMARY KEY,
+       bug INT NOT NULL REFERENCES bug,
+       blocks INT NOT NULL REFERENCES bug,
+       CONSTRAINT bug_doesnt_block_itself CHECK (bug <> blocks)
+);
+CREATE UNIQUE INDEX bug_blocks_bug_id_blocks_idx ON bug_blocks(bug,blocks);
+CREATE INDEX bug_blocks_bug_id_idx ON bug_blocks(bug);
+CREATE INDEX bug_blocks_blocks_idx ON bug_blocks(blocks);
+INSERT INTO table_comments VALUES ('bug_blocks','Bugs which block other bugs');
+INSERT INTO column_comments VALUES ('bug_blocks','bug','Bug number');
+INSERT INTO column_comments VALUES ('bug_blocks','blocks','Bug number which is blocked by bug');
+
+
+CREATE TABLE bug_merged (
+       id SERIAL PRIMARY KEY,
+       bug INT NOT NULL REFERENCES bug,
+       merged INT NOT NULL REFERENCES bug,
+       CONSTRAINT bug_doesnt_merged_itself CHECK (bug <> merged)
+);
+CREATE UNIQUE INDEX bug_merged_bug_id_merged_idx ON bug_merged(bug,merged);
+CREATE INDEX bug_merged_bug_id_idx ON bug_merged(bug);
+CREATE INDEX bug_merged_merged_idx ON bug_merged(merged);
+INSERT INTO table_comments  VALUES ('bug_merged','Bugs which are merged with other bugs');
+INSERT INTO column_comments VALUES ('bug_merged','bug','Bug number');
+INSERT INTO column_comments VALUES ('bug_merged','merged','Bug number which is merged with bug');
+
+CREATE TABLE src_pkg (
+       id SERIAL PRIMARY KEY,
+       pkg TEXT NOT NULL,
+       pseduopkg BOOLEAN NOT NULL DEFAULT FALSE,
+       alias_of INT REFERENCES src_pkg ON UPDATE CASCADE ON DELETE CASCADE,
+       creation TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
+       disabled TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT 'infinity'::timestamp with time zone,
+       last_modified TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
+       obsolete BOOLEAN NOT NULL DEFAULT FALSE,
+       CONSTRAINT src_pkg_doesnt_alias_itself CHECK (id <> alias_of),
+       CONSTRAINT src_pkg_is_obsolete_if_disabled CHECK (
+          (obsolete IS FALSE AND disabled='infinity'::timestamp with time zone) OR
+          (obsolete IS TRUE AND disabled < 'infinity'::timestamp with time zone))
+);
+CREATE INDEX src_pkg_pkg ON src_pkg(pkg);
+CREATE UNIQUE INDEX src_pkg_pkg_null ON src_pkg(pkg) WHERE disabled='infinity'::timestamp with time zone;
+CREATE UNIQUE INDEX src_pkg_pkg_disabled ON src_pkg(pkg,disabled);
+INSERT INTO table_comments VALUES ('src_pkg','Source packages');
+INSERT INTO column_comments VALUES ('src_pkg','id','Source package id');
+INSERT INTO column_comments VALUES ('src_pkg','pkg','Source package name');
+INSERT INTO column_comments VALUES ('src_pkg','pseudopkg','True if this is a pseudo package');
+INSERT INTO column_comments VALUES ('src_pkg','alias_of','Source package id which this source package is an alias of');
+
+
+
+CREATE TABLE src_ver (
+       id SERIAL PRIMARY KEY,
+       src_pkg INT NOT NULL REFERENCES src_pkg
+            ON UPDATE CASCADE ON DELETE CASCADE,
+       ver debversion NOT NULL,
+       maintainer INT REFERENCES maintainer
+            ON UPDATE CASCADE ON DELETE SET NULL,
+       upload_date TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
+       based_on INT REFERENCES src_ver
+            ON UPDATE CASCADE ON DELETE CASCADE
+);
+CREATE UNIQUE INDEX src_ver_src_pkg_id_ver ON src_ver(src_pkg,ver);
+INSERT INTO table_comments VALUES ('src_ver','Source Package versions');
+INSERT INTO column_comments VALUES ('src_ver','id','Source package version id');
+INSERT INTO column_comments VALUES ('src_ver','src_pkg','Source package id (matches src_pkg table)');
+INSERT INTO column_comments VALUES ('src_ver','ver','Version of the source package');
+INSERT INTO column_comments VALUES ('src_ver','maintainer','Maintainer id (matches maintainer table)');
+INSERT INTO column_comments VALUES ('src_ver','upload_date','Date this version of the source package was uploaded');
+INSERT INTO column_comments VALUES ('src_ver','based_on','Source package version this version is based on');
+
+
+
+CREATE TABLE bug_ver (
+       id SERIAL PRIMARY KEY,
+       bug INT NOT NULL REFERENCES bug
+         ON UPDATE CASCADE ON DELETE RESTRICT,
+       ver_string TEXT,
+       src_pkg INT REFERENCES src_pkg
+            ON UPDATE CASCADE ON DELETE SET NULL,
+       src_ver INT REFERENCES src_ver
+            ON UPDATE CASCADE ON DELETE SET NULL,
+       found BOOLEAN NOT NULL DEFAULT TRUE,
+       creation TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
+       last_modified TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
+);
+CREATE INDEX bug_ver_src_pkg_id_idx ON bug_ver(src_pkg);
+CREATE INDEX bug_ver_src_pkg_id_src_ver_id_idx ON bug_ver(src_pkg,src_ver);
+CREATE INDEX bug_ver_src_ver_id_idx ON bug_ver(src_ver);
+CREATE UNIQUE INDEX bug_ver_bug_ver_string_found_idx ON bug_ver(bug,ver_string,found);
+INSERT INTO table_comments VALUES ('bug_ver','Bug versions');
+INSERT INTO column_comments VALUES ('bug_ver','id','Bug version id');
+INSERT INTO column_comments VALUES ('bug_ver','bug','Bug number');
+INSERT INTO column_comments VALUES ('bug_ver','ver_string','Version string');
+INSERT INTO column_comments VALUES ('bug_ver','src_pkg','Source package id (matches src_pkg table)');
+INSERT INTO column_comments VALUES ('bug_ver','src_ver','Source package version id (matches src_ver table)');
+INSERT INTO column_comments VALUES ('bug_ver','found','True if this is a found version; false if this is a fixed version');
+INSERT INTO column_comments VALUES ('bug_ver','creation','Time that this entry was created');
+INSERT INTO column_comments VALUES ('bug_ver','last_modified','Time that this entry was modified');
+
+
+CREATE TABLE arch (
+       id SERIAL PRIMARY KEY,
+       arch TEXT NOT NULL
+);
+CREATE UNIQUE INDEX arch_arch_key ON arch(arch);
+INSERT INTO table_comments VALUES ('arch','Architectures');
+INSERT INTO column_comments VALUES ('arch','id','Architecture id');
+INSERT INTO column_comments VALUES ('arch','arch','Architecture name');
+
+
+CREATE TABLE bin_pkg (
+       id SERIAL PRIMARY KEY,
+       pkg TEXT NOT NULL
+);
+CREATE UNIQUE INDEX bin_pkg_pkg_key ON bin_pkg(pkg);
+INSERT INTO table_comments VALUES ('bin_pkg','Binary packages');
+INSERT INTO column_comments VALUES ('bin_pkg','id','Binary package id');
+INSERT INTO column_comments VALUES ('bin_pkg','pkg','Binary package name');
+
+
+CREATE TABLE bin_ver(
+       id SERIAL PRIMARY KEY,
+       bin_pkg INT NOT NULL REFERENCES bin_pkg
+            ON UPDATE CASCADE ON DELETE CASCADE,
+       src_ver INT NOT NULL REFERENCES src_ver
+            ON UPDATE CASCADE ON DELETE CASCADE,
+       arch INT NOT NULL REFERENCES arch
+                   ON UPDATE CASCADE ON DELETE CASCADE,
+       ver debversion NOT NULL
+);
+CREATE INDEX bin_ver_ver_idx ON bin_ver(ver);
+CREATE UNIQUE INDEX bin_ver_bin_pkg_id_arch_idx ON bin_ver(bin_pkg,arch,ver);
+CREATE INDEX bin_ver_src_ver_id_arch_idx ON bin_ver(src_ver,arch);
+CREATE INDEX bin_ver_bin_pkg_id_idx ON bin_ver(bin_pkg);
+CREATE INDEX bin_ver_src_ver_id_idx ON bin_ver(src_ver);
+INSERT INTO table_comments VALUES ('bin_ver','Binary versions');
+INSERT INTO column_comments VALUES ('bin_ver','id','Binary version id');
+INSERT INTO column_comments VALUES ('bin_ver','bin_pkg','Binary package id (matches bin_pkg)');
+INSERT INTO column_comments VALUES ('bin_ver','src_ver','Source version (matchines src_ver)');
+INSERT INTO column_comments VALUES ('bin_ver','arch','Architecture id (matches arch)');
+INSERT INTO column_comments VALUES ('bin_ver','ver','Binary version');
+
+CREATE TABLE tag (
+       id SERIAL PRIMARY KEY,
+       tag TEXT NOT NULL UNIQUE,
+       obsolete BOOLEAN DEFAULT FALSE
+);
+INSERT INTO table_comments VALUES ('tag','Bug tags');
+INSERT INTO column_comments VALUES ('tag','id','Tag id');
+INSERT INTO column_comments VALUES ('tag','tag','Tag name');
+INSERT INTO column_comments VALUES ('tag','obsolete','Whether a tag is obsolete (should not be set on new bugs)');
+
+CREATE TABLE bug_tag (
+       bug INT NOT NULL REFERENCES bug,
+       tag INT NOT NULL REFERENCES tag
+);
+INSERT INTO table_comments VALUES ('bug_tag','Bug <-> tag mapping');
+INSERT INTO column_comments VALUES ('bug_tag','bug','Bug id (matches bug)');
+INSERT INTO column_comments VALUES ('bug_tag','tag','Tag id (matches tag)');
+
+CREATE UNIQUE INDEX bug_tag_bug_tag ON bug_tag (bug,tag);
+CREATE INDEX bug_tag_tag ON bug_tag (tag);
+
+CREATE TABLE user_tag (
+       id SERIAL PRIMARY KEY,
+       tag TEXT NOT NULL,
+       correspondent INT NOT NULL REFERENCES correspondent(id)
+);
+INSERT INTO table_comments VALUES ('user_tag','User bug tags');
+INSERT INTO column_comments VALUES ('user_tag','id','User bug tag id');
+INSERT INTO column_comments VALUES ('user_tag','tag','User bug tag name');
+INSERT INTO column_comments VALUES ('user_tag','correspondent','User bug tag correspondent');
+
+CREATE UNIQUE INDEX user_tag_tag_correspondent ON user_tag(tag,correspondent);
+CREATE INDEX user_tag_correspondent ON user_tag(correspondent);
+
+CREATE TABLE bug_user_tag (
+       bug INT NOT NULL REFERENCES bug,
+       user_tag INT NOT NULL REFERENCES user_tag
+);
+INSERT INTO table_comments VALUES ('bug_user_tag','Bug <-> user tag mapping');
+INSERT INTO column_comments VALUES ('bug_user_tag','bug','Bug id (matches bug)');
+INSERT INTO column_comments VALUES ('bug_user_tag','tag','User tag id (matches user_tag)');
+
+CREATE UNIQUE INDEX bug_user_tag_bug_tag ON bug_user_tag (bug,user_tag);
+CREATE INDEX bug_user_tag_tag ON bug_user_tag (user_tag);
+
+CREATE TABLE bug_binpackage (
+       bug INT NOT NULL REFERENCES bug,
+       bin_pkg INT NOT NULL REFERENCES bin_pkg ON UPDATE CASCADE ON DELETE CASCADE
+);
+CREATE UNIQUE INDEX bug_binpackage_id_pkg ON bug_binpackage(bug,bin_pkg);
+INSERT INTO table_comments VALUES ('bug_binpackage','Bug <-> binary package mapping');
+INSERT INTO column_comments VALUES ('bug_binpackage','bug','Bug id (matches bug)');
+INSERT INTO column_comments VALUES ('bug_binpackage','bin_pkg','Binary package id (matches bin_pkg)');
+
+CREATE TABLE bug_srcpackage (
+       bug INT NOT NULL REFERENCES bug,
+       src_pkg INT NOT NULL REFERENCES src_pkg ON UPDATE CASCADE ON DELETE CASCADE
+);
+CREATE UNIQUE INDEX bug_srcpackage_id_pkg ON bug_srcpackage(bug,src_pkg);
+CREATE INDEX bug_srcpackage_idx_src_pkg ON bug_srcpackage(src_pkg);
+
+INSERT INTO table_comments VALUES ('bug_srcpackage','Bug <-> source package mapping');
+INSERT INTO column_comments VALUES ('bug_srcpackage','bug','Bug id (matches bug)');
+INSERT INTO column_comments VALUES ('bug_srcpackage','src_pkg','Source package id (matches src_pkg)');
+
+CREATE TABLE bug_affects_binpackage (
+       bug INT NOT NULL REFERENCES bug,
+       bin_pkg INT NOT NULL REFERENCES bin_pkg ON UPDATE CASCADE ON DELETE CASCADE
+);
+CREATE UNIQUE INDEX bug_affects_binpackage_id_pkg ON bug_affects_binpackage(bug,bin_pkg);
+INSERT INTO table_comments VALUES ('bug_affects_binpackage','Bug <-> binary package mapping');
+INSERT INTO column_comments VALUES ('bug_affects_binpackage','bug','Bug id (matches bug)');
+INSERT INTO column_comments VALUES ('bug_affects_binpackage','bin_pkg','Binary package id (matches bin_pkg)');
+
+CREATE TABLE bug_affects_srcpackage (
+       bug INT NOT NULL REFERENCES bug,
+       src_pkg INT NOT NULL REFERENCES src_pkg ON UPDATE CASCADE ON DELETE CASCADE
+);
+CREATE UNIQUE INDEX bug_affects_srcpackage_id_pkg ON bug_affects_srcpackage(bug,src_pkg);
+INSERT INTO table_comments VALUES ('bug_affects_srcpackage','Bug <-> source package mapping');
+INSERT INTO column_comments VALUES ('bug_affects_srcpackage','bug','Bug id (matches bug)');
+INSERT INTO column_comments VALUES ('bug_affects_srcpackage','src_pkg','Source package id (matches src_pkg)');
+
+CREATE VIEW bug_package (bug,pkg_id,pkg_type,package) AS
+       SELECT b.bug,b.bin_pkg,'binary',bp.pkg FROM bug_binpackage b JOIN bin_pkg bp ON bp.id=b.bin_pkg UNION
+              SELECT s.bug,s.src_pkg,'source',sp.pkg FROM bug_srcpackage s JOIN src_pkg sp ON sp.id=s.src_pkg UNION
+       SELECT b.bug,b.bin_pkg,'binary_affects',bp.pkg FROM bug_affects_binpackage b JOIN bin_pkg bp ON bp.id=b.bin_pkg UNION
+              SELECT s.bug,s.src_pkg,'source_affects',sp.pkg FROM bug_affects_srcpackage s JOIN src_pkg sp ON sp.id=s.src_pkg;
+
+CREATE VIEW binary_versions (src_pkg, src_ver, bin_pkg, arch, bin_ver) AS
+       SELECT sp.pkg AS src_pkg, sv.ver AS src_ver, bp.pkg AS bin_pkg, a.arch AS arch, b.ver AS bin_ver,
+       svb.ver AS src_ver_based_on, spb.pkg AS src_pkg_based_on
+       FROM bin_ver b JOIN arch a ON b.arch = a.id
+                             JOIN bin_pkg bp ON b.bin_pkg  = bp.id
+                      JOIN src_ver sv ON b.src_ver  = sv.id
+                      JOIN src_pkg sp ON sv.src_pkg = sp.id
+                      LEFT OUTER JOIN src_ver svb ON sv.based_on = svb.id
+                      LEFT OUTER JOIN src_pkg spb ON spb.id = svb.src_pkg;
+
+CREATE TABLE suite (
+       id SERIAL PRIMARY KEY,
+       codename TEXT NOT NULL,
+       suite_name TEXT,
+       version TEXT,
+       active BOOLEAN DEFAULT TRUE);
+CREATE UNIQUE INDEX suite_idx_codename ON suite(codename);
+CREATE UNIQUE INDEX suite_suite_name_key ON suite(suite_name);
+CREATE UNIQUE INDEX suite_idx_version ON suite(version);
+INSERT INTO table_comments VALUES ('suite','Debian Release Suite (stable, testing, etc.)');
+INSERT INTO column_comments VALUES ('suite','id','Suite id');
+INSERT INTO column_comments VALUES ('suite','suite_name','Suite name (testing, stable, etc.)');
+INSERT INTO column_comments VALUES ('suite','version','Suite version; NULL if there is no appropriate version');
+INSERT INTO column_comments VALUES ('suite','codename','Suite codename (sid, squeeze, etc.)');
+INSERT INTO column_comments VALUES ('suite','active','TRUE if the suite is still accepting uploads');
+
+CREATE TABLE bin_associations (
+       id SERIAL PRIMARY KEY,
+       suite INT NOT NULL REFERENCES suite ON DELETE CASCADE ON UPDATE CASCADE,
+       bin INT NOT NULL REFERENCES bin_ver ON DELETE CASCADE ON UPDATE CASCADE,
+       created TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL,
+       modified TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL
+);
+INSERT INTO table_comments VALUES ('bin_associations','Binary <-> suite associations');
+INSERT INTO column_comments VALUES ('bin_associations','id','Binary <-> suite association id');
+INSERT INTO column_comments VALUES ('bin_associations','suite','Suite id (matches suite)');
+INSERT INTO column_comments VALUES ('bin_associations','bin','Binary version id (matches bin_ver)');
+INSERT INTO column_comments VALUES ('bin_associations','created','Time this binary package entered this suite');
+INSERT INTO column_comments VALUES ('bin_associations','modified','Time this entry was modified');
+CREATE UNIQUE INDEX bin_associations_bin_suite ON bin_associations(bin,suite);
+
+CREATE TABLE src_associations (
+       id SERIAL PRIMARY KEY,
+       suite INT NOT NULL REFERENCES suite ON DELETE CASCADE ON UPDATE CASCADE,
+       source INT NOT NULL REFERENCES src_ver ON DELETE CASCADE ON UPDATE CASCADE,
+       created TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL,
+       modified TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL
+);
+INSERT INTO table_comments VALUES ('src_associations','Source <-> suite associations');
+INSERT INTO column_comments VALUES ('src_associations','id','Source <-> suite association id');
+INSERT INTO column_comments VALUES ('src_associations','suite','Suite id (matches suite)');
+INSERT INTO column_comments VALUES ('src_associations','source','Source version id (matches src_ver)');
+INSERT INTO column_comments VALUES ('src_associations','created','Time this source package entered this suite');
+INSERT INTO column_comments VALUES ('src_associations','modified','Time this entry was modified');
+CREATE UNIQUE INDEX src_associations_source_suite ON src_associations(source,suite);
+
+
+CREATE TYPE bug_status_type AS ENUM ('absent','found','fixed','undef');
+CREATE TABLE bug_status_cache (
+       bug INT NOT NULL REFERENCES bug ON DELETE CASCADE ON UPDATE CASCADE,
+       suite INT REFERENCES suite ON DELETE CASCADE ON UPDATE CASCADE,
+       arch INT REFERENCES arch ON DELETE CASCADE ON UPDATE CASCADE,
+       status bug_status_type NOT NULL,
+       modified TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL,
+       asof TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL
+);
+CREATE UNIQUE INDEX bug_status_cache_bug_suite_arch_idx ON bug_status_cache(bug,suite,arch);
+CREATE INDEX bug_status_cache_idx_bug ON bug_status_cache(bug);
+CREATE INDEX bug_status_cache_idx_status ON bug_status_cache(status);
+CREATE INDEX bug_status_cache_idx_arch ON bug_status_cache(arch);
+CREATE INDEX bug_status_cache_idx_suite ON bug_status_cache(suite);
+CREATE INDEX bug_status_cache_idx_asof ON bug_status_cache(asof);
+INSERT INTO table_comments  VALUES ('bug_status_cache','Bug Status Cache');
+INSERT INTO column_comments VALUES ('bug_status_cache','bug','Bug number (matches bug)');
+INSERT INTO column_comments VALUES ('bug_status_cache','suite','Suite id (matches suite)');
+INSERT INTO column_comments VALUES ('bug_status_cache','arch','Architecture id (matches arch)');
+INSERT INTO column_comments VALUES ('bug_status_cache','status','Status (bug status)');
+INSERT INTO column_comments VALUES ('bug_status_cache','modified','Time that this status was last modified');
+INSERT INTO column_comments VALUES ('bug_status_cache','asof','Time that this status was last calculated');
+
+
+
+CREATE TABLE message (
+       id SERIAL PRIMARY KEY,
+       msgid TEXT NOT NULL DEFAULT '',
+       from_complete TEXT NOT NULL DEFAULT '',
+       to_complete TEXT NOT NULL DEFAULT '',
+       subject TEXT NOT NULL DEFAULT '',
+       sent_date TIMESTAMP WITH TIME ZONE,
+       refs TEXT NOT NULL DEFAULT '',
+       spam_score FLOAT NOT NULL DEFAULT 0,
+       is_spam BOOLEAN NOT NULL DEFAULT FALSE
+);
+INSERT INTO table_comments VALUES ('message','Messages sent to bugs');
+INSERT INTO column_comments VALUES ('message','id','Message id');
+INSERT INTO column_comments VALUES ('message','msgid','Message id header');
+INSERT INTO column_comments VALUES ('message','from_complete','Complete from header of message');
+INSERT INTO column_comments VALUES ('message','to_complete','Complete to header of message');
+INSERT INTO column_comments VALUES ('message','subject','Subject of the message');
+INSERT INTO column_comments VALUES ('message','sent_date','Time/date message was sent (from Date header)');
+INSERT INTO column_comments VALUES ('message','refs','Contents of References: header');
+INSERT INTO column_comments VALUES ('message','spam_score','Spam score from spamassassin');
+INSERT INTO column_comments VALUES ('message','is_spam','True if this message was spam and should not be shown');
+CREATE INDEX message_msgid_idx ON message(msgid);
+CREATE UNIQUE INDEX message_msgid_from_complete_to_complete_subject_idx
+    ON message(msgid,from_complete,to_complete,subject);
+CREATE INDEX message_subject_idx ON message(subject);
+
+CREATE TABLE message_refs (
+       message INT NOT NULL REFERENCES message ON DELETE CASCADE ON UPDATE CASCADE,
+       refs INT NOT NULL REFERENCES message ON DELETE CASCADE ON UPDATE CASCADE,
+       inferred BOOLEAN DEFAULT FALSE,
+       primary_ref BOOLEAN DEFAULT FALSE,
+       CONSTRAINT message_doesnt_reference_itself CHECK (message <> refs)
+);
+CREATE UNIQUE INDEX message_refs_message_refs_idx ON message_refs(message,refs);
+CREATE INDEX message_refs_idx_refs ON message_refs(refs);
+CREATE INDEX message_refs_idx_message ON message_refs(message);
+INSERT INTO table_comments VALUES ('message_refs','Message references');
+INSERT INTO column_comments VALUES ('message_refs','message','Message id (matches message)');
+INSERT INTO column_comments VALUES ('message_refs','refs','Reference id (matches message)');
+INSERT INTO column_comments VALUES ('message_refs','inferred','TRUE if this message reference was reconstructed; primarily of use for messages which lack In-Reply-To: or References: headers');
+INSERT INTO column_comments VALUES ('message_refs','primary_ref','TRUE if this message->ref came from In-Reply-To: or similar.');
+
+
+
+CREATE TABLE correspondent_full_name(
+       correspondent INT NOT NULL REFERENCES correspondent ON DELETE CASCADE ON UPDATE CASCADE,
+       full_name TEXT NOT NULL,
+       last_seen TIMESTAMP NOT NULL DEFAULT NOW()
+);
+CREATE UNIQUE INDEX correspondent_full_name_correspondent_full_name_idx 
+    ON correspondent_full_name(correspondent,full_name);
+CREATE INDEX correspondent_full_name_idx_full_name ON correspondent_full_name(full_name);
+CREATE INDEX correspondent_full_name_idx_last_seen ON correspondent_full_name(last_seen);
+INSERT INTO table_comments VALUES ('correspondent_full_name','Full names of BTS correspondents');
+INSERT INTO column_comments VALUES ('correspondent_full_name','correspondent','Correspondent ID (matches correspondent)');
+INSERT INTO column_comments VALUES ('correspondent_full_name','full_name','Correspondent full name (includes e-mail address)');
+
+CREATE TYPE message_correspondent_type AS ENUM ('to','from','envfrom','cc','recv');
+
+CREATE TABLE message_correspondent (
+       message INT NOT NULL REFERENCES message ON DELETE CASCADE ON UPDATE CASCADE,
+       correspondent INT NOT NULL REFERENCES correspondent ON DELETE CASCADE ON UPDATE CASCADE,
+       correspondent_type message_correspondent_type NOT NULL DEFAULT 'to'
+);
+INSERT INTO table_comments VALUES ('message_correspondent','Linkage between correspondent and message');
+INSERT INTO column_comments VALUES ('message_correspondent','message','Message id (matches message)');
+INSERT INTO column_comments VALUES ('message_correspondent','correspondent','Correspondent (matches correspondent)');
+INSERT INTO column_comments VALUES ('message_correspondent','correspondent_type','Type of correspondent (to, from, envfrom, cc, etc.)');
+
+CREATE UNIQUE INDEX message_correspondent_message_correspondent_correspondent_t_idx 
+    ON message_correspondent(message,correspondent,correspondent_type);
+CREATE INDEX message_correspondent_idx_correspondent ON message_correspondent(correspondent);
+CREATE INDEX message_correspondent_idx_message ON message_correspondent(message);
+
+CREATE TABLE bug_message (
+       bug INT NOT NULL REFERENCES bug ON DELETE CASCADE ON UPDATE CASCADE,
+       message INT NOT NULL REFERENCES message ON DELETE CASCADE ON UPDATE CASCADE,
+       message_number INT NOT NULL,
+       bug_log_offset INT,
+       offset_valid TIMESTAMP WITH TIME ZONE
+);
+CREATE UNIQUE INDEX bug_message_bug_message_idx ON bug_message(bug,message);
+CREATE INDEX bug_message_idx_bug_message_number ON bug_message(bug,message_number);
+INSERT INTO table_comments VALUES ('bug_mesage','Mapping between a bug and a message');
+INSERT INTO column_comments VALUES ('bug_message','bug','Bug id (matches bug)');
+INSERT INTO column_comments VALUES ('bug_message','message','Message id (matches message)');
+INSERT INTO column_comments VALUES ('bug_message','message_number','Message number in the bug log');
+INSERT INTO column_comments VALUES ('bug_message','bug_log_offset','Byte offset in the bug log');
+INSERT INTO column_comments VALUES ('bug_message','offset_valid','Time offset was valid');
+