← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~wgrant/launchpad/db-baseline-2210 into lp:launchpad

 

William Grant has proposed merging lp:~wgrant/launchpad/db-baseline-2210 into lp:launchpad.

Commit message:
Rebaseline schema, version 2210.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~wgrant/launchpad/db-baseline-2210/+merge/363648
-- 
The attached diff has been truncated due to its size.
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~wgrant/launchpad/db-baseline-2210 into lp:launchpad.
=== modified file 'database/schema/Makefile'
--- database/schema/Makefile	2018-05-14 13:11:14 +0000
+++ database/schema/Makefile	2019-02-26 07:46:16 +0000
@@ -61,9 +61,9 @@
 # on production. It is generated using newbaseline.py in
 # bzr+ssh://devpad.canonical.com/code/stub/dbascripts
 #
-REV=2209
+REV=2210
 BASELINE=launchpad-${REV}-00-0.sql
-MD5SUM=cc7a493c924196409a22392a16443d52  launchpad-2209-00-0.sql
+MD5SUM=36ae7078cd41916bbbd9c116b2e6aea7  launchpad-2210-00-0.sql
 
 default: all
 

=== renamed file 'database/schema/patch-2209-00-0.sql' => 'database/schema/archive/patch-2209-00-0.sql'
=== renamed file 'database/schema/patch-2209-00-1.sql' => 'database/schema/archive/patch-2209-00-1.sql'
=== renamed file 'database/schema/patch-2209-00-2.sql' => 'database/schema/archive/patch-2209-00-2.sql'
=== renamed file 'database/schema/patch-2209-00-3.sql' => 'database/schema/archive/patch-2209-00-3.sql'
=== renamed file 'database/schema/patch-2209-00-5.sql' => 'database/schema/archive/patch-2209-00-5.sql'
=== renamed file 'database/schema/patch-2209-00-6.sql' => 'database/schema/archive/patch-2209-00-6.sql'
=== renamed file 'database/schema/patch-2209-00-7.sql' => 'database/schema/archive/patch-2209-00-7.sql'
=== renamed file 'database/schema/patch-2209-00-8.sql' => 'database/schema/archive/patch-2209-00-8.sql'
=== renamed file 'database/schema/patch-2209-00-9.sql' => 'database/schema/archive/patch-2209-00-9.sql'
=== renamed file 'database/schema/patch-2209-01-0.sql' => 'database/schema/archive/patch-2209-01-0.sql'
=== renamed file 'database/schema/patch-2209-01-1.sql' => 'database/schema/archive/patch-2209-01-1.sql'
=== renamed file 'database/schema/patch-2209-02-0.sql' => 'database/schema/archive/patch-2209-02-0.sql'
=== renamed file 'database/schema/patch-2209-04-0.sql' => 'database/schema/archive/patch-2209-04-0.sql'
=== renamed file 'database/schema/patch-2209-05-1.sql' => 'database/schema/archive/patch-2209-05-1.sql'
=== renamed file 'database/schema/patch-2209-06-1.sql' => 'database/schema/archive/patch-2209-06-1.sql'
=== renamed file 'database/schema/patch-2209-07-0.sql' => 'database/schema/archive/patch-2209-07-0.sql'
=== renamed file 'database/schema/patch-2209-07-1.sql' => 'database/schema/archive/patch-2209-07-1.sql'
=== renamed file 'database/schema/patch-2209-08-1.sql' => 'database/schema/archive/patch-2209-08-1.sql'
=== renamed file 'database/schema/patch-2209-09-0.sql' => 'database/schema/archive/patch-2209-09-0.sql'
=== renamed file 'database/schema/patch-2209-10-0.sql' => 'database/schema/archive/patch-2209-10-0.sql'
=== renamed file 'database/schema/patch-2209-11-0.sql' => 'database/schema/archive/patch-2209-11-0.sql'
=== renamed file 'database/schema/patch-2209-11-1.sql' => 'database/schema/archive/patch-2209-11-1.sql'
=== renamed file 'database/schema/patch-2209-11-2.sql' => 'database/schema/archive/patch-2209-11-2.sql'
=== renamed file 'database/schema/patch-2209-11-3.sql' => 'database/schema/archive/patch-2209-11-3.sql'
=== renamed file 'database/schema/patch-2209-11-4.sql' => 'database/schema/archive/patch-2209-11-4.sql'
=== renamed file 'database/schema/patch-2209-11-5.sql' => 'database/schema/archive/patch-2209-11-5.sql'
=== renamed file 'database/schema/patch-2209-12-0.sql' => 'database/schema/archive/patch-2209-12-0.sql'
=== renamed file 'database/schema/patch-2209-12-1.sql' => 'database/schema/archive/patch-2209-12-1.sql'
=== renamed file 'database/schema/patch-2209-12-2.sql' => 'database/schema/archive/patch-2209-12-2.sql'
=== renamed file 'database/schema/patch-2209-12-3.sql' => 'database/schema/archive/patch-2209-12-3.sql'
=== renamed file 'database/schema/patch-2209-12-4.sql' => 'database/schema/archive/patch-2209-12-4.sql'
=== renamed file 'database/schema/patch-2209-12-5.sql' => 'database/schema/archive/patch-2209-12-5.sql'
=== renamed file 'database/schema/patch-2209-14-0.sql' => 'database/schema/archive/patch-2209-14-0.sql'
=== renamed file 'database/schema/patch-2209-15-0.sql' => 'database/schema/archive/patch-2209-15-0.sql'
=== renamed file 'database/schema/patch-2209-15-1.sql' => 'database/schema/archive/patch-2209-15-1.sql'
=== renamed file 'database/schema/patch-2209-15-2.sql' => 'database/schema/archive/patch-2209-15-2.sql'
=== renamed file 'database/schema/patch-2209-15-3.sql' => 'database/schema/archive/patch-2209-15-3.sql'
=== renamed file 'database/schema/patch-2209-16-0.sql' => 'database/schema/archive/patch-2209-16-0.sql'
=== renamed file 'database/schema/patch-2209-16-1.sql' => 'database/schema/archive/patch-2209-16-1.sql'
=== renamed file 'database/schema/patch-2209-16-2.sql' => 'database/schema/archive/patch-2209-16-2.sql'
=== renamed file 'database/schema/patch-2209-16-3.sql' => 'database/schema/archive/patch-2209-16-3.sql'
=== renamed file 'database/schema/patch-2209-16-4.sql' => 'database/schema/archive/patch-2209-16-4.sql'
=== renamed file 'database/schema/patch-2209-16-5.sql' => 'database/schema/archive/patch-2209-16-5.sql'
=== renamed file 'database/schema/patch-2209-16-6.sql' => 'database/schema/archive/patch-2209-16-6.sql'
=== renamed file 'database/schema/patch-2209-16-7.sql' => 'database/schema/archive/patch-2209-16-7.sql'
=== renamed file 'database/schema/patch-2209-16-8.sql' => 'database/schema/archive/patch-2209-16-8.sql'
=== renamed file 'database/schema/patch-2209-17-0.sql' => 'database/schema/archive/patch-2209-17-0.sql'
=== renamed file 'database/schema/patch-2209-17-1.sql' => 'database/schema/archive/patch-2209-17-1.sql'
=== renamed file 'database/schema/patch-2209-18-0.sql' => 'database/schema/archive/patch-2209-18-0.sql'
=== renamed file 'database/schema/patch-2209-18-1.sql' => 'database/schema/archive/patch-2209-18-1.sql'
=== renamed file 'database/schema/patch-2209-18-2.sql' => 'database/schema/archive/patch-2209-18-2.sql'
=== renamed file 'database/schema/patch-2209-18-3.sql' => 'database/schema/archive/patch-2209-18-3.sql'
=== renamed file 'database/schema/patch-2209-18-4.sql' => 'database/schema/archive/patch-2209-18-4.sql'
=== renamed file 'database/schema/patch-2209-19-0.sql' => 'database/schema/archive/patch-2209-19-0.sql'
=== renamed file 'database/schema/patch-2209-19-1.sql' => 'database/schema/archive/patch-2209-19-1.sql'
=== renamed file 'database/schema/patch-2209-19-2.sql' => 'database/schema/archive/patch-2209-19-2.sql'
=== renamed file 'database/schema/patch-2209-19-3.sql' => 'database/schema/archive/patch-2209-19-3.sql'
=== renamed file 'database/schema/patch-2209-20-0.sql' => 'database/schema/archive/patch-2209-20-0.sql'
=== renamed file 'database/schema/patch-2209-20-1.sql' => 'database/schema/archive/patch-2209-20-1.sql'
=== renamed file 'database/schema/patch-2209-21-0.sql' => 'database/schema/archive/patch-2209-21-0.sql'
=== renamed file 'database/schema/patch-2209-21-1.sql' => 'database/schema/archive/patch-2209-21-1.sql'
=== renamed file 'database/schema/patch-2209-21-2.sql' => 'database/schema/archive/patch-2209-21-2.sql'
=== renamed file 'database/schema/patch-2209-21-3.sql' => 'database/schema/archive/patch-2209-21-3.sql'
=== renamed file 'database/schema/patch-2209-21-4.sql' => 'database/schema/archive/patch-2209-21-4.sql'
=== renamed file 'database/schema/patch-2209-22-0.sql' => 'database/schema/archive/patch-2209-22-0.sql'
=== renamed file 'database/schema/patch-2209-23-0.sql' => 'database/schema/archive/patch-2209-23-0.sql'
=== renamed file 'database/schema/patch-2209-23-1.sql' => 'database/schema/archive/patch-2209-23-1.sql'
=== renamed file 'database/schema/patch-2209-23-2.sql' => 'database/schema/archive/patch-2209-23-2.sql'
=== renamed file 'database/schema/patch-2209-23-3.sql' => 'database/schema/archive/patch-2209-23-3.sql'
=== renamed file 'database/schema/patch-2209-23-4.sql' => 'database/schema/archive/patch-2209-23-4.sql'
=== renamed file 'database/schema/patch-2209-23-5.sql' => 'database/schema/archive/patch-2209-23-5.sql'
=== renamed file 'database/schema/patch-2209-24-1.sql' => 'database/schema/archive/patch-2209-24-1.sql'
=== renamed file 'database/schema/patch-2209-24-2.sql' => 'database/schema/archive/patch-2209-24-2.sql'
=== renamed file 'database/schema/patch-2209-24-3.sql' => 'database/schema/archive/patch-2209-24-3.sql'
=== renamed file 'database/schema/patch-2209-25-1.sql' => 'database/schema/archive/patch-2209-25-1.sql'
=== renamed file 'database/schema/patch-2209-26-0.sql' => 'database/schema/archive/patch-2209-26-0.sql'
=== renamed file 'database/schema/patch-2209-26-1.sql' => 'database/schema/archive/patch-2209-26-1.sql'
=== renamed file 'database/schema/patch-2209-26-2.sql' => 'database/schema/archive/patch-2209-26-2.sql'
=== renamed file 'database/schema/patch-2209-26-3.sql' => 'database/schema/archive/patch-2209-26-3.sql'
=== renamed file 'database/schema/patch-2209-26-4.sql' => 'database/schema/archive/patch-2209-26-4.sql'
=== renamed file 'database/schema/patch-2209-26-5.sql' => 'database/schema/archive/patch-2209-26-5.sql'
=== renamed file 'database/schema/patch-2209-27-1.sql' => 'database/schema/archive/patch-2209-27-1.sql'
=== renamed file 'database/schema/patch-2209-27-2.sql' => 'database/schema/archive/patch-2209-27-2.sql'
=== renamed file 'database/schema/patch-2209-27-3.sql' => 'database/schema/archive/patch-2209-27-3.sql'
=== renamed file 'database/schema/patch-2209-27-4.sql' => 'database/schema/archive/patch-2209-27-4.sql'
=== renamed file 'database/schema/patch-2209-28-1.sql' => 'database/schema/archive/patch-2209-28-1.sql'
=== renamed file 'database/schema/patch-2209-28-2.sql' => 'database/schema/archive/patch-2209-28-2.sql'
=== renamed file 'database/schema/patch-2209-28-4.sql' => 'database/schema/archive/patch-2209-28-4.sql'
=== renamed file 'database/schema/patch-2209-28-5.sql' => 'database/schema/archive/patch-2209-28-5.sql'
=== renamed file 'database/schema/patch-2209-28-6.sql' => 'database/schema/archive/patch-2209-28-6.sql'
=== renamed file 'database/schema/patch-2209-29-0.sql' => 'database/schema/archive/patch-2209-29-0.sql'
=== renamed file 'database/schema/patch-2209-30-1.sql' => 'database/schema/archive/patch-2209-30-1.sql'
=== renamed file 'database/schema/patch-2209-30-2.sql' => 'database/schema/archive/patch-2209-30-2.sql'
=== renamed file 'database/schema/patch-2209-31-1.sql' => 'database/schema/archive/patch-2209-31-1.sql'
=== renamed file 'database/schema/patch-2209-31-2.sql' => 'database/schema/archive/patch-2209-31-2.sql'
=== renamed file 'database/schema/patch-2209-31-3.sql' => 'database/schema/archive/patch-2209-31-3.sql'
=== renamed file 'database/schema/patch-2209-32-0.sql' => 'database/schema/archive/patch-2209-32-0.sql'
=== renamed file 'database/schema/patch-2209-34-1.sql' => 'database/schema/archive/patch-2209-34-1.sql'
=== renamed file 'database/schema/patch-2209-35-1.sql' => 'database/schema/archive/patch-2209-35-1.sql'
=== renamed file 'database/schema/patch-2209-35-2.sql' => 'database/schema/archive/patch-2209-35-2.sql'
=== renamed file 'database/schema/patch-2209-35-3.sql' => 'database/schema/archive/patch-2209-35-3.sql'
=== renamed file 'database/schema/patch-2209-35-4.sql' => 'database/schema/archive/patch-2209-35-4.sql'
=== renamed file 'database/schema/patch-2209-36-0.sql' => 'database/schema/archive/patch-2209-36-0.sql'
=== renamed file 'database/schema/patch-2209-36-1.sql' => 'database/schema/archive/patch-2209-36-1.sql'
=== renamed file 'database/schema/patch-2209-37-0.sql' => 'database/schema/archive/patch-2209-37-0.sql'
=== renamed file 'database/schema/patch-2209-38-0.sql' => 'database/schema/archive/patch-2209-38-0.sql'
=== renamed file 'database/schema/patch-2209-38-1.sql' => 'database/schema/archive/patch-2209-38-1.sql'
=== renamed file 'database/schema/patch-2209-38-2.sql' => 'database/schema/archive/patch-2209-38-2.sql'
=== renamed file 'database/schema/patch-2209-38-3.sql' => 'database/schema/archive/patch-2209-38-3.sql'
=== renamed file 'database/schema/patch-2209-39-0.sql' => 'database/schema/archive/patch-2209-39-0.sql'
=== renamed file 'database/schema/patch-2209-39-1.sql' => 'database/schema/archive/patch-2209-39-1.sql'
=== renamed file 'database/schema/patch-2209-40-0.sql' => 'database/schema/archive/patch-2209-40-0.sql'
=== renamed file 'database/schema/patch-2209-40-1.sql' => 'database/schema/archive/patch-2209-40-1.sql'
=== renamed file 'database/schema/patch-2209-40-2.sql' => 'database/schema/archive/patch-2209-40-2.sql'
=== renamed file 'database/schema/patch-2209-40-3.sql' => 'database/schema/archive/patch-2209-40-3.sql'
=== renamed file 'database/schema/patch-2209-41-0.sql' => 'database/schema/archive/patch-2209-41-0.sql'
=== renamed file 'database/schema/patch-2209-41-1.sql' => 'database/schema/archive/patch-2209-41-1.sql'
=== renamed file 'database/schema/patch-2209-41-2.sql' => 'database/schema/archive/patch-2209-41-2.sql'
=== renamed file 'database/schema/patch-2209-41-3.sql' => 'database/schema/archive/patch-2209-41-3.sql'
=== renamed file 'database/schema/patch-2209-41-4.sql' => 'database/schema/archive/patch-2209-41-4.sql'
=== renamed file 'database/schema/patch-2209-41-5.sql' => 'database/schema/archive/patch-2209-41-5.sql'
=== renamed file 'database/schema/patch-2209-42-0.sql' => 'database/schema/archive/patch-2209-42-0.sql'
=== renamed file 'database/schema/patch-2209-43-0.sql' => 'database/schema/archive/patch-2209-43-0.sql'
=== renamed file 'database/schema/patch-2209-44-0.sql' => 'database/schema/archive/patch-2209-44-0.sql'
=== renamed file 'database/schema/patch-2209-44-1.sql' => 'database/schema/archive/patch-2209-44-1.sql'
=== renamed file 'database/schema/patch-2209-44-2.sql' => 'database/schema/archive/patch-2209-44-2.sql'
=== renamed file 'database/schema/patch-2209-44-3.sql' => 'database/schema/archive/patch-2209-44-3.sql'
=== renamed file 'database/schema/patch-2209-44-4.sql' => 'database/schema/archive/patch-2209-44-4.sql'
=== renamed file 'database/schema/patch-2209-45-0.sql' => 'database/schema/archive/patch-2209-45-0.sql'
=== renamed file 'database/schema/patch-2209-46-0.sql' => 'database/schema/archive/patch-2209-46-0.sql'
=== renamed file 'database/schema/patch-2209-47-0.sql' => 'database/schema/archive/patch-2209-47-0.sql'
=== renamed file 'database/schema/patch-2209-47-1.sql' => 'database/schema/archive/patch-2209-47-1.sql'
=== renamed file 'database/schema/patch-2209-48-0.sql' => 'database/schema/archive/patch-2209-48-0.sql'
=== renamed file 'database/schema/patch-2209-49-0.sql' => 'database/schema/archive/patch-2209-49-0.sql'
=== renamed file 'database/schema/patch-2209-49-1.sql' => 'database/schema/archive/patch-2209-49-1.sql'
=== renamed file 'database/schema/patch-2209-49-2.sql' => 'database/schema/archive/patch-2209-49-2.sql'
=== renamed file 'database/schema/patch-2209-50-0.sql' => 'database/schema/archive/patch-2209-50-0.sql'
=== renamed file 'database/schema/patch-2209-51-0.sql' => 'database/schema/archive/patch-2209-51-0.sql'
=== renamed file 'database/schema/patch-2209-51-1.sql' => 'database/schema/archive/patch-2209-51-1.sql'
=== renamed file 'database/schema/patch-2209-51-2.sql' => 'database/schema/archive/patch-2209-51-2.sql'
=== renamed file 'database/schema/patch-2209-52-0.sql' => 'database/schema/archive/patch-2209-52-0.sql'
=== renamed file 'database/schema/patch-2209-53-0.sql' => 'database/schema/archive/patch-2209-53-0.sql'
=== renamed file 'database/schema/patch-2209-53-1.sql' => 'database/schema/archive/patch-2209-53-1.sql'
=== renamed file 'database/schema/patch-2209-53-3.sql' => 'database/schema/archive/patch-2209-53-3.sql'
=== renamed file 'database/schema/patch-2209-53-4.sql' => 'database/schema/archive/patch-2209-53-4.sql'
=== renamed file 'database/schema/patch-2209-53-5.sql' => 'database/schema/archive/patch-2209-53-5.sql'
=== renamed file 'database/schema/patch-2209-53-6.sql' => 'database/schema/archive/patch-2209-53-6.sql'
=== renamed file 'database/schema/patch-2209-53-7.sql' => 'database/schema/archive/patch-2209-53-7.sql'
=== renamed file 'database/schema/patch-2209-53-8.sql' => 'database/schema/archive/patch-2209-53-8.sql'
=== renamed file 'database/schema/patch-2209-53-9.sql' => 'database/schema/archive/patch-2209-53-9.sql'
=== renamed file 'database/schema/patch-2209-54-0.sql' => 'database/schema/archive/patch-2209-54-0.sql'
=== renamed file 'database/schema/patch-2209-55-0.sql' => 'database/schema/archive/patch-2209-55-0.sql'
=== renamed file 'database/schema/patch-2209-56-0.sql' => 'database/schema/archive/patch-2209-56-0.sql'
=== renamed file 'database/schema/patch-2209-56-1.sql' => 'database/schema/archive/patch-2209-56-1.sql'
=== renamed file 'database/schema/patch-2209-56-2.sql' => 'database/schema/archive/patch-2209-56-2.sql'
=== renamed file 'database/schema/patch-2209-56-3.sql' => 'database/schema/archive/patch-2209-56-3.sql'
=== renamed file 'database/schema/patch-2209-56-4.sql' => 'database/schema/archive/patch-2209-56-4.sql'
=== renamed file 'database/schema/patch-2209-57-0.sql' => 'database/schema/archive/patch-2209-57-0.sql'
=== renamed file 'database/schema/patch-2209-58-0.sql' => 'database/schema/archive/patch-2209-58-0.sql'
=== renamed file 'database/schema/patch-2209-58-1.sql' => 'database/schema/archive/patch-2209-58-1.sql'
=== renamed file 'database/schema/patch-2209-58-2.sql' => 'database/schema/archive/patch-2209-58-2.sql'
=== renamed file 'database/schema/patch-2209-58-3.sql' => 'database/schema/archive/patch-2209-58-3.sql'
=== renamed file 'database/schema/patch-2209-58-4.sql' => 'database/schema/archive/patch-2209-58-4.sql'
=== renamed file 'database/schema/patch-2209-59-0.sql' => 'database/schema/archive/patch-2209-59-0.sql'
=== renamed file 'database/schema/patch-2209-59-1.sql' => 'database/schema/archive/patch-2209-59-1.sql'
=== renamed file 'database/schema/patch-2209-59-2.sql' => 'database/schema/archive/patch-2209-59-2.sql'
=== renamed file 'database/schema/patch-2209-60-0.sql' => 'database/schema/archive/patch-2209-60-0.sql'
=== renamed file 'database/schema/patch-2209-61-0.sql' => 'database/schema/archive/patch-2209-61-0.sql'
=== renamed file 'database/schema/patch-2209-61-1.sql' => 'database/schema/archive/patch-2209-61-1.sql'
=== renamed file 'database/schema/patch-2209-61-2.sql' => 'database/schema/archive/patch-2209-61-2.sql'
=== renamed file 'database/schema/patch-2209-61-3.sql' => 'database/schema/archive/patch-2209-61-3.sql'
=== renamed file 'database/schema/patch-2209-61-4.sql' => 'database/schema/archive/patch-2209-61-4.sql'
=== renamed file 'database/schema/patch-2209-61-5.sql' => 'database/schema/archive/patch-2209-61-5.sql'
=== renamed file 'database/schema/patch-2209-61-6.sql' => 'database/schema/archive/patch-2209-61-6.sql'
=== renamed file 'database/schema/patch-2209-61-7.sql' => 'database/schema/archive/patch-2209-61-7.sql'
=== renamed file 'database/schema/patch-2209-61-8.sql' => 'database/schema/archive/patch-2209-61-8.sql'
=== renamed file 'database/schema/patch-2209-61-9.sql' => 'database/schema/archive/patch-2209-61-9.sql'
=== renamed file 'database/schema/patch-2209-62-0.sql' => 'database/schema/archive/patch-2209-62-0.sql'
=== renamed file 'database/schema/patch-2209-62-1.sql' => 'database/schema/archive/patch-2209-62-1.sql'
=== renamed file 'database/schema/patch-2209-64-0.sql' => 'database/schema/archive/patch-2209-64-0.sql'
=== renamed file 'database/schema/patch-2209-64-1.sql' => 'database/schema/archive/patch-2209-64-1.sql'
=== renamed file 'database/schema/patch-2209-65-0.sql' => 'database/schema/archive/patch-2209-65-0.sql'
=== renamed file 'database/schema/patch-2209-66-0.sql' => 'database/schema/archive/patch-2209-66-0.sql'
=== renamed file 'database/schema/patch-2209-66-1.sql' => 'database/schema/archive/patch-2209-66-1.sql'
=== renamed file 'database/schema/patch-2209-67-0.sql' => 'database/schema/archive/patch-2209-67-0.sql'
=== renamed file 'database/schema/patch-2209-67-1.sql' => 'database/schema/archive/patch-2209-67-1.sql'
=== renamed file 'database/schema/patch-2209-67-2.sql' => 'database/schema/archive/patch-2209-67-2.sql'
=== renamed file 'database/schema/patch-2209-67-3.sql' => 'database/schema/archive/patch-2209-67-3.sql'
=== renamed file 'database/schema/patch-2209-68-0.sql' => 'database/schema/archive/patch-2209-68-0.sql'
=== renamed file 'database/schema/patch-2209-68-1.sql' => 'database/schema/archive/patch-2209-68-1.sql'
=== renamed file 'database/schema/patch-2209-68-2.sql' => 'database/schema/archive/patch-2209-68-2.sql'
=== renamed file 'database/schema/patch-2209-69-0.sql' => 'database/schema/archive/patch-2209-69-0.sql'
=== renamed file 'database/schema/patch-2209-69-1.sql' => 'database/schema/archive/patch-2209-69-1.sql'
=== renamed file 'database/schema/patch-2209-69-2.sql' => 'database/schema/archive/patch-2209-69-2.sql'
=== renamed file 'database/schema/patch-2209-69-3.sql' => 'database/schema/archive/patch-2209-69-3.sql'
=== renamed file 'database/schema/patch-2209-69-4.sql' => 'database/schema/archive/patch-2209-69-4.sql'
=== renamed file 'database/schema/patch-2209-69-5.sql' => 'database/schema/archive/patch-2209-69-5.sql'
=== renamed file 'database/schema/patch-2209-69-6.sql' => 'database/schema/archive/patch-2209-69-6.sql'
=== renamed file 'database/schema/patch-2209-69-7.sql' => 'database/schema/archive/patch-2209-69-7.sql'
=== renamed file 'database/schema/patch-2209-69-8.sql' => 'database/schema/archive/patch-2209-69-8.sql'
=== renamed file 'database/schema/patch-2209-69-9.sql' => 'database/schema/archive/patch-2209-69-9.sql'
=== renamed file 'database/schema/patch-2209-70-0.sql' => 'database/schema/archive/patch-2209-70-0.sql'
=== renamed file 'database/schema/patch-2209-71-0.sql' => 'database/schema/archive/patch-2209-71-0.sql'
=== renamed file 'database/schema/patch-2209-71-1.sql' => 'database/schema/archive/patch-2209-71-1.sql'
=== renamed file 'database/schema/patch-2209-72-0.sql' => 'database/schema/archive/patch-2209-72-0.sql'
=== renamed file 'database/schema/patch-2209-73-0.sql' => 'database/schema/archive/patch-2209-73-0.sql'
=== renamed file 'database/schema/patch-2209-73-1.sql' => 'database/schema/archive/patch-2209-73-1.sql'
=== renamed file 'database/schema/patch-2209-74-0.sql' => 'database/schema/archive/patch-2209-74-0.sql'
=== renamed file 'database/schema/patch-2209-75-0.sql' => 'database/schema/archive/patch-2209-75-0.sql'
=== renamed file 'database/schema/patch-2209-75-1.sql' => 'database/schema/archive/patch-2209-75-1.sql'
=== renamed file 'database/schema/patch-2209-77-0.sql' => 'database/schema/archive/patch-2209-77-0.sql'
=== renamed file 'database/schema/patch-2209-77-1.sql' => 'database/schema/archive/patch-2209-77-1.sql'
=== renamed file 'database/schema/patch-2209-77-2.sql' => 'database/schema/archive/patch-2209-77-2.sql'
=== renamed file 'database/schema/patch-2209-77-3.sql' => 'database/schema/archive/patch-2209-77-3.sql'
=== renamed file 'database/schema/patch-2209-78-0.sql' => 'database/schema/archive/patch-2209-78-0.sql'
=== renamed file 'database/schema/patch-2209-78-1.sql' => 'database/schema/archive/patch-2209-78-1.sql'
=== renamed file 'database/schema/patch-2209-78-2.sql' => 'database/schema/archive/patch-2209-78-2.sql'
=== renamed file 'database/schema/patch-2209-79-0.sql' => 'database/schema/archive/patch-2209-79-0.sql'
=== renamed file 'database/schema/patch-2209-80-0.sql' => 'database/schema/archive/patch-2209-80-0.sql'
=== renamed file 'database/schema/patch-2209-80-1.sql' => 'database/schema/archive/patch-2209-80-1.sql'
=== renamed file 'database/schema/patch-2209-80-2.sql' => 'database/schema/archive/patch-2209-80-2.sql'
=== renamed file 'database/schema/patch-2209-81-0.sql' => 'database/schema/archive/patch-2209-81-0.sql'
=== renamed file 'database/schema/patch-2209-82-0.sql' => 'database/schema/archive/patch-2209-82-0.sql'
=== renamed file 'database/schema/patch-2209-82-1.sql' => 'database/schema/archive/patch-2209-82-1.sql'
=== renamed file 'database/schema/patch-2209-83-0.sql' => 'database/schema/archive/patch-2209-83-0.sql'
=== renamed file 'database/schema/patch-2209-83-1.sql' => 'database/schema/archive/patch-2209-83-1.sql'
=== renamed file 'database/schema/patch-2209-83-2.sql' => 'database/schema/archive/patch-2209-83-2.sql'
=== renamed file 'database/schema/patch-2209-83-3.sql' => 'database/schema/archive/patch-2209-83-3.sql'
=== renamed file 'database/schema/patch-2209-83-4.sql' => 'database/schema/archive/patch-2209-83-4.sql'
=== renamed file 'database/schema/patch-2209-83-5.sql' => 'database/schema/archive/patch-2209-83-5.sql'
=== renamed file 'database/schema/patch-2209-83-6.sql' => 'database/schema/archive/patch-2209-83-6.sql'
=== renamed file 'database/schema/patch-2209-84-0.sql' => 'database/schema/archive/patch-2209-84-0.sql'
=== renamed file 'database/schema/patch-2209-84-1.sql' => 'database/schema/archive/patch-2209-84-1.sql'
=== renamed file 'database/schema/patch-2209-85-0.sql' => 'database/schema/archive/patch-2209-85-0.sql'
=== renamed file 'database/schema/patch-2209-85-1.sql' => 'database/schema/archive/patch-2209-85-1.sql'
=== renamed file 'database/schema/patch-2209-86-0.sql' => 'database/schema/archive/patch-2209-86-0.sql'
=== renamed file 'database/schema/launchpad-2209-00-0.sql' => 'database/schema/launchpad-2210-00-0.sql'
--- database/schema/launchpad-2209-00-0.sql	2015-07-21 09:04:01 +0000
+++ database/schema/launchpad-2210-00-0.sql	2019-02-26 07:46:16 +0000
@@ -1,9 +1,11 @@
--- Generated Tue Dec  6 20:57:32 2011 UTC
+-- Generated Mon Feb 25 21:35:23 2019 UTC
 
 SET client_min_messages TO ERROR;
 SET statement_timeout = 0;
+SET lock_timeout = 0;
 SET client_encoding = 'UTF8';
 SET standard_conforming_strings = off;
+SELECT pg_catalog.set_config('search_path', '', false);
 SET check_function_bodies = false;
 SET client_min_messages = warning;
 SET escape_string_warning = off;
@@ -11,56 +13,72 @@
 CREATE SCHEMA todrop;
 
 
-CREATE SCHEMA ts2;
-
-
-CREATE PROCEDURAL LANGUAGE plpgsql;
-
-
-CREATE PROCEDURAL LANGUAGE plpythonu;
-
-
-SET search_path = public, pg_catalog;
-
-CREATE TYPE debversion;
-
-
-CREATE FUNCTION debversionin(cstring) RETURNS debversion
+CREATE SCHEMA trgm;
+
+
+CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog;
+
+
+COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language';
+
+
+CREATE EXTENSION IF NOT EXISTS plpythonu WITH SCHEMA pg_catalog;
+
+
+COMMENT ON EXTENSION plpythonu IS 'PL/PythonU untrusted procedural language';
+
+
+CREATE EXTENSION IF NOT EXISTS pg_trgm WITH SCHEMA trgm;
+
+
+COMMENT ON EXTENSION pg_trgm IS 'text similarity measurement and index searching based on trigrams';
+
+
+CREATE EXTENSION IF NOT EXISTS pgstattuple WITH SCHEMA public;
+
+
+COMMENT ON EXTENSION pgstattuple IS 'show tuple-level statistics';
+
+
+CREATE TYPE public.debversion;
+
+
+CREATE FUNCTION public.debversionin(cstring) RETURNS public.debversion
     LANGUAGE internal IMMUTABLE STRICT
     AS $$textin$$;
 
 
-CREATE FUNCTION debversionout(debversion) RETURNS cstring
+CREATE FUNCTION public.debversionout(public.debversion) RETURNS cstring
     LANGUAGE internal IMMUTABLE STRICT
     AS $$textout$$;
 
 
-CREATE FUNCTION debversionrecv(internal) RETURNS debversion
+CREATE FUNCTION public.debversionrecv(internal) RETURNS public.debversion
     LANGUAGE internal STABLE STRICT
     AS $$textrecv$$;
 
 
-CREATE FUNCTION debversionsend(debversion) RETURNS bytea
+CREATE FUNCTION public.debversionsend(public.debversion) RETURNS bytea
     LANGUAGE internal STABLE STRICT
     AS $$textsend$$;
 
 
-CREATE TYPE debversion (
+CREATE TYPE public.debversion (
     INTERNALLENGTH = variable,
-    INPUT = debversionin,
-    OUTPUT = debversionout,
-    RECEIVE = debversionrecv,
-    SEND = debversionsend,
+    INPUT = public.debversionin,
+    OUTPUT = public.debversionout,
+    RECEIVE = public.debversionrecv,
+    SEND = public.debversionsend,
     CATEGORY = 'S',
     ALIGNMENT = int4,
     STORAGE = extended
 );
 
 
-COMMENT ON TYPE debversion IS 'Debian package version number';
-
-
-CREATE TYPE pgstattuple_type AS (
+COMMENT ON TYPE public.debversion IS 'Debian package version number';
+
+
+CREATE TYPE public.pgstattuple_type AS (
 	table_len bigint,
 	tuple_count bigint,
 	tuple_len bigint,
@@ -73,77 +91,337 @@
 );
 
 
-SET search_path = ts2, pg_catalog;
-
-CREATE DOMAIN gtsq AS text;
-
-
-CREATE DOMAIN gtsvector AS pg_catalog.gtsvector;
-
-
-CREATE TYPE statinfo AS (
-	word text,
-	ndoc integer,
-	nentry integer
-);
-
-
-CREATE TYPE tokenout AS (
-	tokid integer,
-	token text
-);
-
-
-CREATE TYPE tokentype AS (
-	tokid integer,
-	alias text,
-	descr text
-);
-
-
-CREATE TYPE tsdebug AS (
-	ts_name text,
-	tok_type text,
-	description text,
-	token text,
-	dict_name text[],
-	tsvector pg_catalog.tsvector
-);
-
-
-CREATE DOMAIN tsquery AS pg_catalog.tsquery;
-
-
-CREATE DOMAIN tsvector AS pg_catalog.tsvector;
-
-
-SET search_path = public, pg_catalog;
-
-CREATE FUNCTION activity() RETURNS SETOF pg_stat_activity
-    LANGUAGE sql SECURITY DEFINER
-    SET search_path TO public
-    AS $$
-    SELECT
-        datid, datname, procpid, usesysid, usename,
-        CASE
-            WHEN current_query LIKE '<IDLE>%'
-                OR current_query LIKE 'autovacuum:%'
-                THEN current_query
-            ELSE
-                '<HIDDEN>'
-        END AS current_query,
-        waiting, xact_start, query_start,
-        backend_start, client_addr, client_port
-    FROM pg_catalog.pg_stat_activity;
-$$;
-
-
-COMMENT ON FUNCTION activity() IS 'SECURITY DEFINER wrapper around pg_stat_activity allowing unprivileged users to access most of its information.';
-
-
-CREATE FUNCTION add_test_openid_identifier(account_ integer) RETURNS boolean
-    LANGUAGE plpgsql SECURITY DEFINER
-    SET search_path TO public
+CREATE DOMAIN public.ts2_tsvector AS tsvector;
+
+
+CREATE FUNCTION public._ftq(text) RETURNS text
+    LANGUAGE plpythonu IMMUTABLE STRICT
+    AS $_$
+        import re
+
+        # I think this method would be more robust if we used a real
+        # tokenizer and parser to generate the query string, but we need
+        # something suitable for use as a stored procedure which currently
+        # means no external dependancies.
+
+        # Convert to Unicode
+        query = args[0].decode('utf8')
+        ## plpy.debug('1 query is %s' % repr(query))
+
+        # Replace tsquery operators with ' '. '<' begins all the phrase
+        # search operators, and a standalone '>' is fine.
+        query = re.sub('[|&!<]', ' ', query)
+
+        # Normalize whitespace
+        query = re.sub("(?u)\s+"," ", query)
+
+        # Convert AND, OR, NOT to tsearch2 punctuation
+        query = re.sub(r"(?u)\bAND\b", "&", query)
+        query = re.sub(r"(?u)\bOR\b", "|", query)
+        query = re.sub(r"(?u)\bNOT\b", " !", query)
+        ## plpy.debug('2 query is %s' % repr(query))
+
+        # Deal with unwanted punctuation.
+        # ':' is used in queries to specify a weight of a word.
+        # '\' is treated differently in to_tsvector() and to_tsquery().
+        punctuation = r'[:\\]'
+        query = re.sub(r"(?u)%s+" % (punctuation,), " ", query)
+        ## plpy.debug('3 query is %s' % repr(query))
+
+        # Now that we have handle case sensitive booleans, convert to lowercase
+        query = query.lower()
+
+        # Remove unpartnered bracket on the left and right
+        query = re.sub(r"(?ux) ^ ( [^(]* ) \)", r"(\1)", query)
+        query = re.sub(r"(?ux) \( ( [^)]* ) $", r"(\1)", query)
+
+        # Remove spurious brackets
+        query = re.sub(r"(?u)\(([^\&\|]*?)\)", r" \1 ", query)
+        ## plpy.debug('5 query is %s' % repr(query))
+
+        # Insert & between tokens without an existing boolean operator
+        # ( not proceeded by (|&!
+        query = re.sub(r"(?u)(?<![\(\|\&\!])\s*\(", "&(", query)
+        ## plpy.debug('6 query is %s' % repr(query))
+        # ) not followed by )|&
+        query = re.sub(r"(?u)\)(?!\s*(\)|\||\&|\s*$))", ")&", query)
+        ## plpy.debug('6.1 query is %s' % repr(query))
+        # Whitespace not proceded by (|&! not followed by &|
+        query = re.sub(r"(?u)(?<![\(\|\&\!\s])\s+(?![\&\|\s])", "&", query)
+        ## plpy.debug('7 query is %s' % repr(query))
+
+        # Detect and repair syntax errors - we are lenient because
+        # this input is generally from users.
+
+        # Fix unbalanced brackets
+        openings = query.count("(")
+        closings = query.count(")")
+        if openings > closings:
+            query = query + " ) "*(openings-closings)
+        elif closings > openings:
+            query = " ( "*(closings-openings) + query
+        ## plpy.debug('8 query is %s' % repr(query))
+
+        # Strip ' character that do not have letters on both sides
+        query = re.sub(r"(?u)((?<!\w)'|'(?!\w))", "", query)
+
+        # Brackets containing nothing but whitespace and booleans, recursive
+        last = ""
+        while last != query:
+            last = query
+            query = re.sub(r"(?u)\([\s\&\|\!]*\)", "", query)
+        ## plpy.debug('9 query is %s' % repr(query))
+
+        # An & or | following a (
+        query = re.sub(r"(?u)(?<=\()[\&\|\s]+", "", query)
+        ## plpy.debug('10 query is %s' % repr(query))
+
+        # An &, | or ! immediatly before a )
+        query = re.sub(r"(?u)[\&\|\!\s]*[\&\|\!]+\s*(?=\))", "", query)
+        ## plpy.debug('11 query is %s' % repr(query))
+
+        # An &,| or ! followed by another boolean.
+        query = re.sub(r"(?ux) \s* ( [\&\|\!] ) [\s\&\|]+", r"\1", query)
+        ## plpy.debug('12 query is %s' % repr(query))
+
+        # Leading & or |
+        query = re.sub(r"(?u)^[\s\&\|]+", "", query)
+        ## plpy.debug('13 query is %s' % repr(query))
+
+        # Trailing &, | or !
+        query = re.sub(r"(?u)[\&\|\!\s]+$", "", query)
+        ## plpy.debug('14 query is %s' % repr(query))
+
+        # If we have nothing but whitespace and tsearch2 operators,
+        # return NULL.
+        if re.search(r"(?u)^[\&\|\!\s\(\)]*$", query) is not None:
+            return None
+
+        # Convert back to UTF-8
+        query = query.encode('utf8')
+        ## plpy.debug('15 query is %s' % repr(query))
+
+        return query or None
+        $_$;
+
+
+CREATE FUNCTION public.accessartifact_denorm_to_artifacts(artifact_id integer) RETURNS void
+    LANGUAGE plpgsql
+    AS $$
+DECLARE
+    artifact_row accessartifact%ROWTYPE;
+BEGIN
+    SELECT * INTO artifact_row FROM accessartifact WHERE id = artifact_id;
+    IF artifact_row.bug IS NOT NULL THEN
+        PERFORM bug_flatten_access(artifact_row.bug);
+    END IF;
+    IF artifact_row.branch IS NOT NULL THEN
+        PERFORM branch_denorm_access(artifact_row.branch);
+    END IF;
+    IF artifact_row.gitrepository IS NOT NULL THEN
+        PERFORM gitrepository_denorm_access(artifact_row.gitrepository);
+    END IF;
+    IF artifact_row.specification IS NOT NULL THEN
+        PERFORM specification_denorm_access(artifact_row.specification);
+    END IF;
+    RETURN;
+END;
+$$;
+
+
+COMMENT ON FUNCTION public.accessartifact_denorm_to_artifacts(artifact_id integer) IS 'Denormalize the policy access and artifact grants to bugs, branches, Git repositories, and specifications.';
+
+
+CREATE FUNCTION public.accessartifact_maintain_denorm_to_artifacts_trig() RETURNS trigger
+    LANGUAGE plpgsql
+    AS $$
+BEGIN
+    IF TG_OP = 'INSERT' THEN
+        PERFORM accessartifact_denorm_to_artifacts(NEW.artifact);
+    ELSIF TG_OP = 'UPDATE' THEN
+        PERFORM accessartifact_denorm_to_artifacts(NEW.artifact);
+        IF OLD.artifact != NEW.artifact THEN
+            PERFORM accessartifact_denorm_to_artifacts(OLD.artifact);
+        END IF;
+    ELSIF TG_OP = 'DELETE' THEN
+        PERFORM accessartifact_denorm_to_artifacts(OLD.artifact);
+    END IF;
+    RETURN NULL;
+END;
+$$;
+
+
+CREATE FUNCTION public.accessartifactgrant_maintain_accesspolicygrantflat_trig() RETURNS trigger
+    LANGUAGE plpgsql SECURITY DEFINER
+    SET search_path TO 'public'
+    AS $$
+BEGIN
+    IF TG_OP = 'INSERT' THEN
+        INSERT INTO AccessPolicyGrantFlat
+            (policy, artifact, grantee)
+            SELECT policy, NEW.artifact, NEW.grantee
+                FROM AccessPolicyArtifact WHERE artifact = NEW.artifact;
+    ELSIF TG_OP = 'UPDATE' THEN
+        IF NEW.artifact != OLD.artifact OR NEW.grantee != OLD.grantee THEN
+            UPDATE AccessPolicyGrantFlat
+                SET artifact=NEW.artifact, grantee=NEW.grantee
+                WHERE artifact = OLD.artifact AND grantee = OLD.grantee;
+        END IF;
+    ELSIF TG_OP = 'DELETE' THEN
+        DELETE FROM AccessPolicyGrantFlat
+            WHERE artifact = OLD.artifact AND grantee = OLD.grantee;
+    END IF;
+    RETURN NULL;
+END;
+$$;
+
+
+CREATE FUNCTION public.accesspolicyartifact_maintain_accesspolicyartifactflat_trig() RETURNS trigger
+    LANGUAGE plpgsql SECURITY DEFINER
+    SET search_path TO 'public'
+    AS $$
+BEGIN
+    IF TG_OP = 'INSERT' THEN
+        INSERT INTO AccessPolicyGrantFlat
+            (policy, artifact, grantee)
+            SELECT NEW.policy, NEW.artifact, grantee
+                FROM AccessArtifactGrant WHERE artifact = NEW.artifact;
+    ELSIF TG_OP = 'UPDATE' THEN
+        IF NEW.policy != OLD.policy OR NEW.artifact != OLD.artifact THEN
+            UPDATE AccessPolicyGrantFlat
+                SET policy=NEW.policy, artifact=NEW.artifact
+                WHERE policy = OLD.policy AND artifact = OLD.artifact;
+        END IF;
+    ELSIF TG_OP = 'DELETE' THEN
+        DELETE FROM AccessPolicyGrantFlat
+            WHERE policy = OLD.policy AND artifact = OLD.artifact;
+    END IF;
+    RETURN NULL;
+END;
+$$;
+
+
+CREATE FUNCTION public.accesspolicygrant_maintain_accesspolicygrantflat_trig() RETURNS trigger
+    LANGUAGE plpgsql SECURITY DEFINER
+    SET search_path TO 'public'
+    AS $$
+BEGIN
+    IF TG_OP = 'INSERT' THEN
+        INSERT INTO AccessPolicyGrantFlat
+            (policy, grantee) VALUES (NEW.policy, NEW.grantee);
+    ELSIF TG_OP = 'UPDATE' THEN
+        IF NEW.policy != OLD.policy OR NEW.grantee != OLD.grantee THEN
+            UPDATE AccessPolicyGrantFlat
+                SET policy=NEW.policy, grantee=NEW.grantee
+                WHERE
+                    policy = OLD.policy
+                    AND grantee = OLD.grantee
+                    AND artifact IS NULL;
+        END IF;
+    ELSIF TG_OP = 'DELETE' THEN
+        DELETE FROM AccessPolicyGrantFlat
+            WHERE
+                policy = OLD.policy
+                AND grantee = OLD.grantee
+                AND artifact IS NULL;
+    END IF;
+    RETURN NULL;
+END;
+$$;
+
+
+CREATE FUNCTION public.activity() RETURNS SETOF pg_stat_activity
+    LANGUAGE plpgsql SECURITY DEFINER
+    SET search_path TO 'public'
+    AS $$
+DECLARE
+    a pg_stat_activity%ROWTYPE;
+BEGIN
+    IF EXISTS (
+            SELECT 1 FROM pg_attribute WHERE
+                attrelid =
+                    (SELECT oid FROM pg_class
+                     WHERE relname = 'pg_stat_activity')
+                AND attname = 'backend_type') THEN
+        -- >= 10
+        RETURN QUERY SELECT
+            datid, datname, pid, usesysid, usename, application_name,
+            client_addr, client_hostname, client_port, backend_start,
+            xact_start, query_start, state_change, wait_event_type,
+            wait_event, state, backend_xid, backend_xmin, backend_type,
+            CASE
+                WHEN query LIKE '<IDLE>%'
+                    OR query LIKE 'autovacuum:%'
+                    THEN query
+                ELSE
+                    '<HIDDEN>'
+            END AS query
+        FROM pg_catalog.pg_stat_activity;
+    ELSIF EXISTS (
+            SELECT 1 FROM pg_attribute WHERE
+                attrelid =
+                    (SELECT oid FROM pg_class
+                     WHERE relname = 'pg_stat_activity')
+                AND attname = 'wait_event_type') THEN
+        -- >= 9.6
+        RETURN QUERY SELECT
+            datid, datname, pid, usesysid, usename, application_name,
+            client_addr, client_hostname, client_port, backend_start,
+            xact_start, query_start, state_change, wait_event_type,
+            wait_event, state, backend_xid, backend_xmin,
+            CASE
+                WHEN query LIKE '<IDLE>%'
+                    OR query LIKE 'autovacuum:%'
+                    THEN query
+                ELSE
+                    '<HIDDEN>'
+            END AS query
+        FROM pg_catalog.pg_stat_activity;
+    ELSIF EXISTS (
+            SELECT 1 FROM pg_attribute WHERE
+                attrelid =
+                    (SELECT oid FROM pg_class
+                     WHERE relname = 'pg_stat_activity')
+                AND attname = 'backend_xid') THEN
+        -- >= 9.4
+        RETURN QUERY SELECT
+            datid, datname, pid, usesysid, usename, application_name,
+            client_addr, client_hostname, client_port, backend_start,
+            xact_start, query_start, state_change, waiting, state,
+            backend_xid, backend_xmin,
+            CASE
+                WHEN query LIKE '<IDLE>%'
+                    OR query LIKE 'autovacuum:%'
+                    THEN query
+                ELSE
+                    '<HIDDEN>'
+            END AS query
+        FROM pg_catalog.pg_stat_activity;
+    ELSE
+        -- >= 9.2; anything older is unsupported
+        RETURN QUERY SELECT
+            datid, datname, pid, usesysid, usename, application_name,
+            client_addr, client_hostname, client_port, backend_start,
+            xact_start, query_start, state_change, waiting, state,
+            CASE
+                WHEN query LIKE '<IDLE>%'
+                    OR query LIKE 'autovacuum:%'
+                    THEN query
+                ELSE
+                    '<HIDDEN>'
+            END AS query
+        FROM pg_catalog.pg_stat_activity;
+    END IF;
+END;
+$$;
+
+
+COMMENT ON FUNCTION public.activity() IS 'SECURITY DEFINER wrapper around pg_stat_activity allowing unprivileged users to access most of its information.';
+
+
+CREATE FUNCTION public.add_test_openid_identifier(account_ integer) RETURNS boolean
+    LANGUAGE plpgsql SECURITY DEFINER
+    SET search_path TO 'public'
     AS $$
 BEGIN
     -- The generated OpenIdIdentifier is not a valid OpenId Identity URL
@@ -161,10 +439,10 @@
 $$;
 
 
-COMMENT ON FUNCTION add_test_openid_identifier(account_ integer) IS 'Add an OpenIdIdentifier to an account that can be used to login in the test environment. These identifiers are not usable on production or staging.';
-
-
-CREATE FUNCTION assert_patch_applied(major integer, minor integer, patch integer) RETURNS boolean
+COMMENT ON FUNCTION public.add_test_openid_identifier(account_ integer) IS 'Add an OpenIdIdentifier to an account that can be used to login in the test environment. These identifiers are not usable on production or staging.';
+
+
+CREATE FUNCTION public.assert_patch_applied(major integer, minor integer, patch integer) RETURNS boolean
     LANGUAGE plpythonu STABLE
     AS $$
     rv = plpy.execute("""
@@ -179,39 +457,98 @@
 $$;
 
 
-COMMENT ON FUNCTION assert_patch_applied(major integer, minor integer, patch integer) IS 'Raise an exception if the given database patch has not been applied.';
-
-
-CREATE FUNCTION bug_maintain_bug_summary() RETURNS trigger
+COMMENT ON FUNCTION public.assert_patch_applied(major integer, minor integer, patch integer) IS 'Raise an exception if the given database patch has not been applied.';
+
+
+CREATE FUNCTION public.branch_denorm_access(branch_id integer) RETURNS void
+    LANGUAGE sql SECURITY DEFINER
+    SET search_path TO 'public'
+    AS $_$
+    UPDATE branch
+        SET access_policy = policies[1], access_grants = grants
+        FROM
+            build_access_cache(
+                (SELECT id FROM accessartifact WHERE branch = $1),
+                (SELECT information_type FROM branch WHERE id = $1))
+            AS (policies integer[], grants integer[])
+        WHERE id = $1;
+$_$;
+
+
+CREATE FUNCTION public.branch_maintain_access_cache_trig() RETURNS trigger
+    LANGUAGE plpgsql
+    AS $$
+BEGIN
+    PERFORM branch_denorm_access(NEW.id);
+    RETURN NULL;
+END;
+$$;
+
+
+CREATE FUNCTION public.bug_build_access_cache(bug_id integer, information_type integer) RETURNS record
+    LANGUAGE sql
+    AS $_$
+    SELECT build_access_cache(
+        (SELECT id FROM accessartifact WHERE bug = $1), $2);
+$_$;
+
+
+COMMENT ON FUNCTION public.bug_build_access_cache(bug_id integer, information_type integer) IS 'Build an access cache for the given bug. Returns ({AccessPolicyArtifact.policy}, {AccessArtifactGrant.grantee}) for private bugs, or (NULL, NULL) for public ones.';
+
+
+CREATE FUNCTION public.bug_flatten_access(bug_id integer) RETURNS void
+    LANGUAGE sql SECURITY DEFINER
+    SET search_path TO 'public'
+    AS $_$
+    UPDATE bugtaskflat
+        SET access_policies = policies, access_grants = grants
+        FROM
+            build_access_cache(
+                (SELECT id FROM accessartifact WHERE bug = $1),
+                (SELECT information_type FROM bug WHERE id = $1))
+            AS (policies integer[], grants integer[])
+        WHERE bug = $1;
+$_$;
+
+
+COMMENT ON FUNCTION public.bug_flatten_access(bug_id integer) IS 'Recalculate the access cache on a bug''s flattened tasks.';
+
+
+CREATE FUNCTION public.bug_maintain_bugtaskflat_trig() RETURNS trigger
     LANGUAGE plpgsql SECURITY DEFINER
-    SET search_path TO public
+    SET search_path TO 'public'
     AS $$
 BEGIN
-    -- There is no INSERT logic, as a bug will not have any summary
-    -- information until BugTask rows have been attached.
-    IF TG_OP = 'UPDATE' THEN
-        IF OLD.duplicateof IS DISTINCT FROM NEW.duplicateof
-            OR OLD.private IS DISTINCT FROM NEW.private
-            OR (OLD.latest_patch_uploaded IS NULL)
-                <> (NEW.latest_patch_uploaded IS NULL) THEN
-            PERFORM unsummarise_bug(OLD);
-            PERFORM summarise_bug(NEW);
-        END IF;
-
-    ELSIF TG_OP = 'DELETE' THEN
-        PERFORM unsummarise_bug(OLD);
-    END IF;
-
-    PERFORM bug_summary_flush_temp_journal();
-    RETURN NULL; -- Ignored - this is an AFTER trigger
+    IF (
+        NEW.duplicateof IS DISTINCT FROM OLD.duplicateof
+        OR NEW.owner IS DISTINCT FROM OLD.owner
+        OR NEW.fti IS DISTINCT FROM OLD.fti
+        OR NEW.information_type IS DISTINCT FROM OLD.information_type
+        OR NEW.date_last_updated IS DISTINCT FROM OLD.date_last_updated
+        OR NEW.heat IS DISTINCT FROM OLD.heat
+        OR NEW.latest_patch_uploaded IS DISTINCT FROM
+            OLD.latest_patch_uploaded) THEN
+        UPDATE bugtaskflat
+            SET
+                duplicateof = NEW.duplicateof,
+                bug_owner = NEW.owner,
+                fti = NEW.fti,
+                information_type = NEW.information_type,
+                date_last_updated = NEW.date_last_updated,
+                heat = NEW.heat,
+                latest_patch_uploaded = NEW.latest_patch_uploaded
+            WHERE bug = OLD.id;
+    END IF;
+
+    IF NEW.information_type IS DISTINCT FROM OLD.information_type THEN
+        PERFORM bug_flatten_access(OLD.id);
+    END IF;
+    RETURN NULL;
 END;
 $$;
 
 
-COMMENT ON FUNCTION bug_maintain_bug_summary() IS 'AFTER trigger on bug maintaining the bugs summaries in bugsummary.';
-
-
-CREATE FUNCTION valid_bug_name(text) RETURNS boolean
+CREATE FUNCTION public.valid_bug_name(text) RETURNS boolean
     LANGUAGE plpythonu IMMUTABLE STRICT
     AS $_$
     import re
@@ -223,7 +560,7 @@
 $_$;
 
 
-COMMENT ON FUNCTION valid_bug_name(text) IS 'validate a bug name
+COMMENT ON FUNCTION public.valid_bug_name(text) IS 'validate a bug name
 
     As per valid_name, except numeric-only names are not allowed (including
     names that look like floats).';
@@ -233,7 +570,7 @@
 
 SET default_with_oids = false;
 
-CREATE TABLE bug (
+CREATE TABLE public.bug (
     id integer NOT NULL,
     datecreated timestamp without time zone DEFAULT timezone('UTC'::text, ('now'::text)::timestamp(6) with time zone) NOT NULL,
     name text,
@@ -241,9 +578,7 @@
     description text NOT NULL,
     owner integer NOT NULL,
     duplicateof integer,
-    fti ts2.tsvector,
-    private boolean DEFAULT false NOT NULL,
-    security_related boolean DEFAULT false NOT NULL,
+    fti public.ts2_tsvector,
     date_last_updated timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL,
     date_made_private timestamp without time zone,
     who_made_private integer,
@@ -255,60 +590,57 @@
     heat integer DEFAULT 0 NOT NULL,
     heat_last_updated timestamp without time zone,
     latest_patch_uploaded timestamp without time zone,
-    access_policy integer,
+    information_type integer NOT NULL,
     CONSTRAINT notduplicateofself CHECK ((NOT (id = duplicateof))),
     CONSTRAINT sane_description CHECK (((ltrim(description) <> ''::text) AND (char_length(description) <= 50000))),
-    CONSTRAINT valid_bug_name CHECK (valid_bug_name(name))
+    CONSTRAINT valid_bug_name CHECK (public.valid_bug_name(name))
 );
 
 
-COMMENT ON TABLE bug IS 'A software bug that requires fixing. This particular bug may be linked to one or more products or source packages to identify the location(s) that this bug is found.';
-
-
-COMMENT ON COLUMN bug.name IS 'A lowercase name uniquely identifying the bug';
-
-
-COMMENT ON COLUMN bug.description IS 'A detailed description of the bug. Initially this will be set to the contents of the initial email or bug filing comment, but later it can be edited to give a more accurate description of the bug itself rather than the symptoms observed by the reporter.';
-
-
-COMMENT ON COLUMN bug.private IS 'Is this bug private? If so, only explicit subscribers will be able to see it';
-
-
-COMMENT ON COLUMN bug.security_related IS 'Is this bug a security issue?';
-
-
-COMMENT ON COLUMN bug.date_last_message IS 'When the last BugMessage was attached to this Bug. Maintained by a trigger on the BugMessage table.';
-
-
-COMMENT ON COLUMN bug.number_of_duplicates IS 'The number of bugs marked as duplicates of this bug, populated by a trigger after setting the duplicateof of bugs.';
-
-
-COMMENT ON COLUMN bug.message_count IS 'The number of messages (currently just comments) on this bugbug, maintained by the set_bug_message_count_t trigger.';
-
-
-COMMENT ON COLUMN bug.users_affected_count IS 'The number of users affected by this bug, maintained by the set_bug_users_affected_count_t trigger.';
-
-
-COMMENT ON COLUMN bug.heat IS 'The relevance of this bug. This value is computed periodically using bug_affects_person and other bug values.';
-
-
-COMMENT ON COLUMN bug.heat_last_updated IS 'The time this bug''s heat was last updated, or NULL if the heat has never yet been updated.';
-
-
-COMMENT ON COLUMN bug.latest_patch_uploaded IS 'The time when the most recent patch has been attached to this bug or NULL if no patches are attached';
-
-
-CREATE FUNCTION bug_row(bug_id integer) RETURNS bug
+COMMENT ON TABLE public.bug IS 'A software bug that requires fixing. This particular bug may be linked to one or more products or source packages to identify the location(s) that this bug is found.';
+
+
+COMMENT ON COLUMN public.bug.name IS 'A lowercase name uniquely identifying the bug';
+
+
+COMMENT ON COLUMN public.bug.description IS 'A detailed description of the bug. Initially this will be set to the contents of the initial email or bug filing comment, but later it can be edited to give a more accurate description of the bug itself rather than the symptoms observed by the reporter.';
+
+
+COMMENT ON COLUMN public.bug.date_last_message IS 'When the last BugMessage was attached to this Bug. Maintained by a trigger on the BugMessage table.';
+
+
+COMMENT ON COLUMN public.bug.number_of_duplicates IS 'The number of bugs marked as duplicates of this bug, populated by a trigger after setting the duplicateof of bugs.';
+
+
+COMMENT ON COLUMN public.bug.message_count IS 'The number of messages (currently just comments) on this bugbug, maintained by the set_bug_message_count_t trigger.';
+
+
+COMMENT ON COLUMN public.bug.users_affected_count IS 'The number of users affected by this bug, maintained by the set_bug_users_affected_count_t trigger.';
+
+
+COMMENT ON COLUMN public.bug.heat IS 'The relevance of this bug. This value is computed periodically using bug_affects_person and other bug values.';
+
+
+COMMENT ON COLUMN public.bug.heat_last_updated IS 'The time this bug''s heat was last updated, or NULL if the heat has never yet been updated.';
+
+
+COMMENT ON COLUMN public.bug.latest_patch_uploaded IS 'The time when the most recent patch has been attached to this bug or NULL if no patches are attached';
+
+
+COMMENT ON COLUMN public.bug.information_type IS 'Enum describing what type of information is stored, such as type of private or security related data, and used to determine how to apply an access policy.';
+
+
+CREATE FUNCTION public.bug_row(bug_id integer) RETURNS public.bug
     LANGUAGE sql STABLE
     AS $_$
     SELECT * FROM Bug WHERE id=$1;
 $_$;
 
 
-COMMENT ON FUNCTION bug_row(bug_id integer) IS 'Helper for manually testing functions requiring a bug row as input. eg. SELECT * FROM bugsummary_tags(bug_row(1))';
-
-
-CREATE TABLE bugsummary (
+COMMENT ON FUNCTION public.bug_row(bug_id integer) IS 'Helper for manually testing functions requiring a bug row as input. eg. SELECT * FROM bugsummary_tags(bug_row(1))';
+
+
+CREATE TABLE public.bugsummary (
     id integer NOT NULL,
     count integer DEFAULT 0 NOT NULL,
     product integer,
@@ -322,12 +654,28 @@
     milestone integer,
     importance integer NOT NULL,
     has_patch boolean NOT NULL,
-    fixed_upstream boolean NOT NULL,
-    CONSTRAINT bugtask_assignment_checks CHECK (CASE WHEN (product IS NOT NULL) THEN ((((productseries IS NULL) AND (distribution IS NULL)) AND (distroseries IS NULL)) AND (sourcepackagename IS NULL)) WHEN (productseries IS NOT NULL) THEN (((distribution IS NULL) AND (distroseries IS NULL)) AND (sourcepackagename IS NULL)) WHEN (distribution IS NOT NULL) THEN (distroseries IS NULL) WHEN (distroseries IS NOT NULL) THEN true ELSE false END)
+    access_policy integer,
+    CONSTRAINT bugtask_assignment_checks CHECK (
+CASE
+    WHEN (product IS NOT NULL) THEN ((((productseries IS NULL) AND (distribution IS NULL)) AND (distroseries IS NULL)) AND (sourcepackagename IS NULL))
+    WHEN (productseries IS NOT NULL) THEN (((distribution IS NULL) AND (distroseries IS NULL)) AND (sourcepackagename IS NULL))
+    WHEN (distribution IS NOT NULL) THEN (distroseries IS NULL)
+    WHEN (distroseries IS NOT NULL) THEN true
+    ELSE false
+END)
 );
 
 
-CREATE FUNCTION bug_summary_dec(bugsummary) RETURNS void
+COMMENT ON TABLE public.bugsummary IS 'A fact table for bug metadata aggregate queries. Each row represents the number of bugs that are in the system addressed by all the dimensions (e.g. product or productseries etc). ';
+
+
+COMMENT ON COLUMN public.bugsummary.sourcepackagename IS 'The sourcepackagename for the aggregate. Counting bugs in a distribution/distroseries requires selecting all rows by sourcepackagename. If this is too slow, add the bug to the NULL row and select with sourcepackagename is NULL to exclude them from the calculations';
+
+
+COMMENT ON COLUMN public.bugsummary.milestone IS 'A milestone present on the bug. All bugs are also aggregated with a NULL entry for milestone to permit querying totals (because the milestone figures cannot be summed as many milestones can be on a single bug)';
+
+
+CREATE FUNCTION public.bug_summary_dec(public.bugsummary) RETURNS void
     LANGUAGE sql
     AS $_$
     -- We own the row reference, so in the absence of bugs this cannot
@@ -353,34 +701,47 @@
             OR milestone = $1.milestone)
         AND importance = $1.importance
         AND has_patch = $1.has_patch
-        AND fixed_upstream = $1.fixed_upstream;
+        AND access_policy IS NOT DISTINCT FROM $1.access_policy;
 $_$;
 
 
-COMMENT ON FUNCTION bug_summary_dec(bugsummary) IS 'UPSERT into bugsummary incrementing one row';
-
-
-CREATE FUNCTION bug_summary_flush_temp_journal() RETURNS void
+COMMENT ON FUNCTION public.bug_summary_dec(public.bugsummary) IS 'UPSERT into bugsummary incrementing one row';
+
+
+CREATE FUNCTION public.bug_summary_flush_temp_journal() RETURNS void
     LANGUAGE plpgsql
     AS $$
 DECLARE
     d bugsummary%ROWTYPE;
 BEGIN
-    -- may get called even though no summaries were made (for simplicity in the
-    -- callers)
+    -- May get called even though no summaries were made (for simplicity in the
+    -- callers). We sum the rows here to minimise the number of inserts
+    -- into the persistent journal, as it's reasonably likely that we'll
+    -- have -1s and +1s cancelling each other out.
     PERFORM ensure_bugsummary_temp_journal();
-    FOR d IN SELECT * FROM bugsummary_temp_journal LOOP
-        PERFORM bugsummary_journal_ins(d);
-    END LOOP;
+    INSERT INTO BugSummaryJournal(
+        count, product, productseries, distribution,
+        distroseries, sourcepackagename, viewed_by, tag,
+        status, milestone, importance, has_patch, access_policy)
+    SELECT
+        SUM(count), product, productseries, distribution,
+        distroseries, sourcepackagename, viewed_by, tag,
+        status, milestone, importance, has_patch, access_policy
+    FROM bugsummary_temp_journal
+    GROUP BY
+        product, productseries, distribution,
+        distroseries, sourcepackagename, viewed_by, tag,
+        status, milestone, importance, has_patch, access_policy
+    HAVING SUM(count) != 0;
     TRUNCATE bugsummary_temp_journal;
 END;
 $$;
 
 
-COMMENT ON FUNCTION bug_summary_flush_temp_journal() IS 'flush the temporary bugsummary journal into the bugsummary table';
-
-
-CREATE FUNCTION bug_summary_inc(d bugsummary) RETURNS void
+COMMENT ON FUNCTION public.bug_summary_flush_temp_journal() IS 'flush the temporary bugsummary journal into the bugsummary table';
+
+
+CREATE FUNCTION public.bug_summary_inc(d public.bugsummary) RETURNS void
     LANGUAGE plpgsql
     AS $_$
 BEGIN
@@ -408,7 +769,7 @@
                 OR milestone = $1.milestone)
             AND importance = $1.importance
             AND has_patch = $1.has_patch
-            AND fixed_upstream = $1.fixed_upstream;
+            AND access_policy IS NOT DISTINCT FROM $1.access_policy;
         IF found THEN
             RETURN;
         END IF;
@@ -419,13 +780,12 @@
             INSERT INTO BugSummary(
                 count, product, productseries, distribution,
                 distroseries, sourcepackagename, viewed_by, tag,
-                status, milestone,
-                importance, has_patch, fixed_upstream)
+                status, milestone, importance, has_patch, access_policy)
             VALUES (
                 d.count, d.product, d.productseries, d.distribution,
                 d.distroseries, d.sourcepackagename, d.viewed_by, d.tag,
-                d.status, d.milestone,
-                d.importance, d.has_patch, d.fixed_upstream);
+                d.status, d.milestone, d.importance, d.has_patch,
+                d.access_policy);
             RETURN;
         EXCEPTION WHEN unique_violation THEN
             -- do nothing, and loop to try the UPDATE again
@@ -435,48 +795,12 @@
 $_$;
 
 
-COMMENT ON FUNCTION bug_summary_inc(d bugsummary) IS 'UPSERT into bugsummary incrementing one row';
-
-
-CREATE FUNCTION bug_summary_temp_journal_ins(d bugsummary) RETURNS void
-    LANGUAGE plpgsql
-    AS $$
-BEGIN
-    INSERT INTO BugSummary_Temp_Journal(
-        count, product, productseries, distribution,
-        distroseries, sourcepackagename, viewed_by, tag,
-        status, milestone, importance, has_patch, fixed_upstream)
-    VALUES (
-        d.count, d.product, d.productseries, d.distribution,
-        d.distroseries, d.sourcepackagename, d.viewed_by, d.tag,
-        d.status, d.milestone, d.importance, d.has_patch, d.fixed_upstream);
-    RETURN;
-END;
-$$;
-
-
-COMMENT ON FUNCTION bug_summary_temp_journal_ins(d bugsummary) IS 'Insert a BugSummary into the temporary journal';
-
-
-CREATE FUNCTION bug_update_heat_copy_to_bugtask() RETURNS trigger
-    LANGUAGE plpgsql SECURITY DEFINER
-    SET search_path TO public
-    AS $$
-BEGIN
-    IF NEW.heat != OLD.heat THEN
-        UPDATE bugtask SET heat=NEW.heat WHERE bugtask.bug=NEW.id;
-    END IF;
-    RETURN NULL; -- Ignored - this is an AFTER trigger
-END;
-$$;
-
-
-COMMENT ON FUNCTION bug_update_heat_copy_to_bugtask() IS 'Copies bug heat to bugtasks when the bug is changed. Runs on UPDATE only because INSERTs do not have bugtasks at the point of insertion.';
-
-
-CREATE FUNCTION bug_update_latest_patch_uploaded(integer) RETURNS void
-    LANGUAGE plpgsql SECURITY DEFINER
-    SET search_path TO public
+COMMENT ON FUNCTION public.bug_summary_inc(d public.bugsummary) IS 'UPSERT into bugsummary incrementing one row';
+
+
+CREATE FUNCTION public.bug_update_latest_patch_uploaded(integer) RETURNS void
+    LANGUAGE plpgsql SECURITY DEFINER
+    SET search_path TO 'public'
     AS $_$
 BEGIN
     UPDATE bug SET latest_patch_uploaded =
@@ -490,9 +814,9 @@
 $_$;
 
 
-CREATE FUNCTION bug_update_latest_patch_uploaded_on_delete() RETURNS trigger
+CREATE FUNCTION public.bug_update_latest_patch_uploaded_on_delete() RETURNS trigger
     LANGUAGE plpgsql SECURITY DEFINER
-    SET search_path TO public
+    SET search_path TO 'public'
     AS $$
 BEGIN
     PERFORM bug_update_latest_patch_uploaded(OLD.bug);
@@ -501,9 +825,9 @@
 $$;
 
 
-CREATE FUNCTION bug_update_latest_patch_uploaded_on_insert_update() RETURNS trigger
+CREATE FUNCTION public.bug_update_latest_patch_uploaded_on_insert_update() RETURNS trigger
     LANGUAGE plpgsql SECURITY DEFINER
-    SET search_path TO public
+    SET search_path TO 'public'
     AS $$
 BEGIN
     PERFORM bug_update_latest_patch_uploaded(NEW.bug);
@@ -512,9 +836,9 @@
 $$;
 
 
-CREATE FUNCTION bugmessage_copy_owner_from_message() RETURNS trigger
+CREATE FUNCTION public.bugmessage_copy_owner_from_message() RETURNS trigger
     LANGUAGE plpgsql SECURITY DEFINER
-    SET search_path TO public
+    SET search_path TO 'public'
     AS $$
 BEGIN
     IF TG_OP = 'INSERT' THEN
@@ -537,145 +861,98 @@
 $$;
 
 
-COMMENT ON FUNCTION bugmessage_copy_owner_from_message() IS 'Copies the message owner into bugmessage when bugmessage changes.';
-
-
-CREATE FUNCTION bugsubscription_maintain_bug_summary() RETURNS trigger
-    LANGUAGE plpgsql SECURITY DEFINER
-    SET search_path TO public
-    AS $$
-BEGIN
-    -- This trigger only works if we are inserting, updating or deleting
-    -- a single row per statement.
-    IF TG_OP = 'INSERT' THEN
-        IF NOT (bug_row(NEW.bug)).private THEN
-            -- Public subscriptions are not aggregated.
-            RETURN NEW;
-        END IF;
-        IF TG_WHEN = 'BEFORE' THEN
-            PERFORM unsummarise_bug(bug_row(NEW.bug));
-        ELSE
-            PERFORM summarise_bug(bug_row(NEW.bug));
-        END IF;
-        PERFORM bug_summary_flush_temp_journal();
-        RETURN NEW;
-    ELSIF TG_OP = 'DELETE' THEN
-        IF NOT (bug_row(OLD.bug)).private THEN
-            -- Public subscriptions are not aggregated.
-            RETURN OLD;
-        END IF;
-        IF TG_WHEN = 'BEFORE' THEN
-            PERFORM unsummarise_bug(bug_row(OLD.bug));
-        ELSE
-            PERFORM summarise_bug(bug_row(OLD.bug));
-        END IF;
-        PERFORM bug_summary_flush_temp_journal();
-        RETURN OLD;
-    ELSE
-        IF (OLD.person IS DISTINCT FROM NEW.person
-            OR OLD.bug IS DISTINCT FROM NEW.bug) THEN
-            IF TG_WHEN = 'BEFORE' THEN
-                IF (bug_row(OLD.bug)).private THEN
-                    -- Public subscriptions are not aggregated.
-                    PERFORM unsummarise_bug(bug_row(OLD.bug));
-                END IF;
-                IF OLD.bug <> NEW.bug AND (bug_row(NEW.bug)).private THEN
-                    -- Public subscriptions are not aggregated.
-                    PERFORM unsummarise_bug(bug_row(NEW.bug));
-                END IF;
-            ELSE
-                IF (bug_row(OLD.bug)).private THEN
-                    -- Public subscriptions are not aggregated.
-                    PERFORM summarise_bug(bug_row(OLD.bug));
-                END IF;
-                IF OLD.bug <> NEW.bug AND (bug_row(NEW.bug)).private THEN
-                    -- Public subscriptions are not aggregated.
-                    PERFORM summarise_bug(bug_row(NEW.bug));
-                END IF;
-            END IF;
-        END IF;
-        PERFORM bug_summary_flush_temp_journal();
-        RETURN NEW;
-    END IF;
-END;
-$$;
-
-
-COMMENT ON FUNCTION bugsubscription_maintain_bug_summary() IS 'AFTER trigger on bugsubscription maintaining the bugs summaries in bugsummary.';
-
-
-CREATE FUNCTION bugsummary_journal_ins(d bugsummary) RETURNS void
-    LANGUAGE plpgsql
-    AS $$
-BEGIN
-    IF d.count <> 0 THEN
-        INSERT INTO BugSummaryJournal (
-            count, product, productseries, distribution,
-            distroseries, sourcepackagename, viewed_by, tag,
-            status, milestone,
-            importance, has_patch, fixed_upstream)
-        VALUES (
-            d.count, d.product, d.productseries, d.distribution,
-            d.distroseries, d.sourcepackagename, d.viewed_by, d.tag,
-            d.status, d.milestone,
-            d.importance, d.has_patch, d.fixed_upstream);
-    END IF;
-END;
-$$;
-
-
-COMMENT ON FUNCTION bugsummary_journal_ins(d bugsummary) IS 'Add an entry into BugSummaryJournal';
-
-
-CREATE FUNCTION bugsummary_locations(bug_row bug) RETURNS SETOF bugsummary
-    LANGUAGE plpgsql
-    AS $$
-BEGIN
-    IF BUG_ROW.duplicateof IS NOT NULL THEN
+COMMENT ON FUNCTION public.bugmessage_copy_owner_from_message() IS 'Copies the message owner into bugmessage when bugmessage changes.';
+
+
+CREATE FUNCTION public.bugsummary_journal_bug(bug_row public.bug, _count integer) RETURNS void
+    LANGUAGE plpgsql
+    AS $$
+DECLARE
+    btf_row bugtaskflat%ROWTYPE;
+BEGIN
+    FOR btf_row IN SELECT * FROM bugtaskflat WHERE bug = bug_row.id
+    LOOP
+        PERFORM bugsummary_journal_bugtaskflat(btf_row, _count);
+    END LOOP;
+END;
+$$;
+
+
+CREATE TABLE public.bugtaskflat (
+    bugtask integer NOT NULL,
+    bug integer NOT NULL,
+    datecreated timestamp without time zone,
+    duplicateof integer,
+    bug_owner integer NOT NULL,
+    fti public.ts2_tsvector,
+    information_type integer NOT NULL,
+    date_last_updated timestamp without time zone NOT NULL,
+    heat integer NOT NULL,
+    product integer,
+    productseries integer,
+    distribution integer,
+    distroseries integer,
+    sourcepackagename integer,
+    status integer NOT NULL,
+    importance integer NOT NULL,
+    assignee integer,
+    milestone integer,
+    owner integer NOT NULL,
+    active boolean NOT NULL,
+    access_policies integer[],
+    access_grants integer[],
+    latest_patch_uploaded timestamp without time zone,
+    date_closed timestamp without time zone
+);
+
+
+CREATE FUNCTION public.bugsummary_journal_bugtaskflat(btf_row public.bugtaskflat, _count integer) RETURNS void
+    LANGUAGE plpgsql
+    AS $$
+BEGIN
+    PERFORM ensure_bugsummary_temp_journal();
+    INSERT INTO BugSummary_Temp_Journal(
+        count, product, productseries, distribution,
+        distroseries, sourcepackagename, viewed_by, tag,
+        status, milestone, importance, has_patch, access_policy)
+    SELECT
+        _count, product, productseries, distribution,
+        distroseries, sourcepackagename, viewed_by, tag,
+        status, milestone, importance, has_patch, access_policy
+        FROM bugsummary_locations(btf_row);
+END;
+$$;
+
+
+CREATE FUNCTION public.bugsummary_locations(btf_row public.bugtaskflat) RETURNS SETOF public.bugsummary
+    LANGUAGE plpgsql
+    AS $$
+BEGIN
+    IF btf_row.duplicateof IS NOT NULL THEN
         RETURN;
     END IF;
     RETURN QUERY
         SELECT
             CAST(NULL AS integer) AS id,
             CAST(1 AS integer) AS count,
-            product, productseries, distribution, distroseries,
-            sourcepackagename, person AS viewed_by, tag, status, milestone,
-            importance,
-            BUG_ROW.latest_patch_uploaded IS NOT NULL AS has_patch,
-            (EXISTS (
-                SELECT TRUE FROM BugTask AS RBT
-                WHERE
-                    RBT.bug = tasks.bug
-                    -- This would just be 'RBT.id <> tasks.id', except
-                    -- that the records from tasks are summaries and not
-                    -- real bugtasks, and do not have an id.
-                    AND (RBT.product IS DISTINCT FROM tasks.product
-                        OR RBT.productseries
-                            IS DISTINCT FROM tasks.productseries
-                        OR RBT.distribution IS DISTINCT FROM tasks.distribution
-                        OR RBT.distroseries IS DISTINCT FROM tasks.distroseries
-                        OR RBT.sourcepackagename
-                            IS DISTINCT FROM tasks.sourcepackagename)
-                    -- Flagged as INVALID, FIXCOMMITTED or FIXRELEASED
-                    -- via a bugwatch, or FIXCOMMITTED or FIXRELEASED on
-                    -- the product.
-                    AND ((bugwatch IS NOT NULL AND status IN (17, 25, 30))
-                        OR (bugwatch IS NULL AND product IS NOT NULL
-                            AND status IN (25, 30))))
-                )::boolean AS fixed_upstream
-        FROM bugsummary_tasks(BUG_ROW) AS tasks
-        JOIN bugsummary_tags(BUG_ROW) AS bug_tags ON TRUE
-        LEFT OUTER JOIN bugsummary_viewers(BUG_ROW) AS bug_viewers ON TRUE;
+            bug_targets.product, bug_targets.productseries,
+            bug_targets.distribution, bug_targets.distroseries,
+            bug_targets.sourcepackagename,
+            bug_viewers.viewed_by, bug_tags.tag, btf_row.status,
+            btf_row.milestone, btf_row.importance,
+            btf_row.latest_patch_uploaded IS NOT NULL AS has_patch,
+            bug_viewers.access_policy
+        FROM
+            bugsummary_targets(btf_row) as bug_targets,
+            bugsummary_tags(btf_row) AS bug_tags,
+            bugsummary_viewers(btf_row) AS bug_viewers;
 END;
 $$;
 
 
-COMMENT ON FUNCTION bugsummary_locations(bug_row bug) IS 'Calculate what BugSummary rows should exist for a given Bug.';
-
-
-CREATE FUNCTION bugsummary_rollup_journal(batchsize integer DEFAULT NULL::integer) RETURNS void
+CREATE FUNCTION public.bugsummary_rollup_journal(batchsize integer DEFAULT NULL::integer) RETURNS void
     LANGUAGE plpgsql SECURITY DEFINER
-    SET search_path TO public
+    SET search_path TO 'public'
     AS $$
 DECLARE
     d bugsummary%ROWTYPE;
@@ -710,13 +987,13 @@
             milestone,
             importance,
             has_patch,
-            fixed_upstream
+            access_policy
         FROM BugSummaryJournal
         WHERE id <= max_id
         GROUP BY
             product, productseries, distribution, distroseries,
             sourcepackagename, viewed_by, tag, status, milestone,
-            importance, has_patch, fixed_upstream
+            importance, has_patch, access_policy
         HAVING sum(count) <> 0
     LOOP
         IF d.count < 0 THEN
@@ -734,10 +1011,10 @@
 $$;
 
 
-COMMENT ON FUNCTION bugsummary_rollup_journal(batchsize integer) IS 'Collate and migrate rows from BugSummaryJournal to BugSummary';
-
-
-CREATE FUNCTION valid_name(text) RETURNS boolean
+COMMENT ON FUNCTION public.bugsummary_rollup_journal(batchsize integer) IS 'Collate and migrate rows from BugSummaryJournal to BugSummary';
+
+
+CREATE FUNCTION public.valid_name(text) RETURNS boolean
     LANGUAGE plpythonu IMMUTABLE STRICT
     AS $$
     import re
@@ -749,7 +1026,7 @@
 $$;
 
 
-COMMENT ON FUNCTION valid_name(text) IS 'validate a name.
+COMMENT ON FUNCTION public.valid_name(text) IS 'validate a name.
 
     Names must contain only lowercase letters, numbers, ., & -. They
     must start with an alphanumeric. They are ASCII only. Names are useful
@@ -760,446 +1037,347 @@
     namespace conflict if URL traversal is possible by name as well as id.';
 
 
-CREATE TABLE bugtag (
+CREATE TABLE public.bugtag (
     id integer NOT NULL,
     bug integer NOT NULL,
     tag text NOT NULL,
-    CONSTRAINT valid_tag CHECK (valid_name(tag))
-);
-
-
-COMMENT ON TABLE bugtag IS 'Attaches simple text tags to a bug.';
-
-
-COMMENT ON COLUMN bugtag.bug IS 'The bug the tags is attached to.';
-
-
-COMMENT ON COLUMN bugtag.tag IS 'The text representation of the tag.';
-
-
-CREATE FUNCTION bugsummary_tags(bug_row bug) RETURNS SETOF bugtag
-    LANGUAGE sql STABLE
-    AS $_$
-    SELECT * FROM BugTag WHERE BugTag.bug = $1.id
-    UNION ALL
-    SELECT NULL::integer, $1.id, NULL::text;
-$_$;
-
-
-COMMENT ON FUNCTION bugsummary_tags(bug_row bug) IS 'Return (bug, tag) for all tags + (bug, NULL::text)';
-
-
-CREATE TABLE bugtask (
-    id integer NOT NULL,
-    bug integer NOT NULL,
-    product integer,
-    distribution integer,
-    distroseries integer,
-    sourcepackagename integer,
-    binarypackagename integer,
-    status integer NOT NULL,
-    importance integer DEFAULT 5 NOT NULL,
-    assignee integer,
-    date_assigned timestamp without time zone,
-    datecreated timestamp without time zone DEFAULT timezone('UTC'::text, ('now'::text)::timestamp(6) with time zone),
-    owner integer NOT NULL,
-    milestone integer,
-    bugwatch integer,
-    fti ts2.tsvector,
-    targetnamecache text,
-    date_confirmed timestamp without time zone,
-    date_inprogress timestamp without time zone,
-    date_closed timestamp without time zone,
-    productseries integer,
-    date_incomplete timestamp without time zone,
-    date_left_new timestamp without time zone,
-    date_triaged timestamp without time zone,
-    date_fix_committed timestamp without time zone,
-    date_fix_released timestamp without time zone,
-    date_left_closed timestamp without time zone,
-    heat_rank integer DEFAULT 0 NOT NULL,
-    date_milestone_set timestamp without time zone,
-    heat integer DEFAULT 0 NOT NULL,
-    CONSTRAINT bugtask_assignment_checks CHECK (CASE WHEN (product IS NOT NULL) THEN ((((productseries IS NULL) AND (distribution IS NULL)) AND (distroseries IS NULL)) AND (sourcepackagename IS NULL)) WHEN (productseries IS NOT NULL) THEN (((distribution IS NULL) AND (distroseries IS NULL)) AND (sourcepackagename IS NULL)) WHEN (distribution IS NOT NULL) THEN (distroseries IS NULL) WHEN (distroseries IS NOT NULL) THEN true ELSE false END)
-);
-
-
-COMMENT ON TABLE bugtask IS 'Links a given Bug to a particular (sourcepackagename, distro) or product.';
-
-
-COMMENT ON COLUMN bugtask.bug IS 'The bug that is assigned to this (sourcepackagename, distro) or product.';
-
-
-COMMENT ON COLUMN bugtask.product IS 'The product in which this bug shows up.';
-
-
-COMMENT ON COLUMN bugtask.distribution IS 'The distro of the named sourcepackage.';
-
-
-COMMENT ON COLUMN bugtask.sourcepackagename IS 'The name of the sourcepackage in which this bug shows up.';
-
-
-COMMENT ON COLUMN bugtask.binarypackagename IS 'The name of the binary package built from the source package. This column may only contain a value if this bug task is linked to a sourcepackage (not a product)';
-
-
-COMMENT ON COLUMN bugtask.status IS 'The general health of the bug, e.g. Accepted, Rejected, etc.';
-
-
-COMMENT ON COLUMN bugtask.importance IS 'The importance of fixing the bug.';
-
-
-COMMENT ON COLUMN bugtask.assignee IS 'The person who has been assigned to fix this bug in this product or (sourcepackagename, distro)';
-
-
-COMMENT ON COLUMN bugtask.date_assigned IS 'The date on which the bug in this (sourcepackagename, distro) or product was assigned to someone to fix';
-
-
-COMMENT ON COLUMN bugtask.datecreated IS 'A timestamp for the creation of this bug assignment. Note that this is not the date the bug was created (though it might be), it''s the date the bug was assigned to this product, which could have come later.';
-
-
-COMMENT ON COLUMN bugtask.milestone IS 'A way to mark a bug for grouping purposes, e.g. to say it needs to be fixed by version 1.2';
-
-
-COMMENT ON COLUMN bugtask.bugwatch IS 'This column allows us to link a bug
-task to a bug watch. In other words, we are connecting the state of the task
-to the state of the bug in a different bug tracking system. To the best of
-our ability we''ll try and keep the bug task syncronised with the state of
-the remote bug watch.';
-
-
-COMMENT ON COLUMN bugtask.targetnamecache IS 'A cached value of the target name of this bugtask, to make it easier to sort and search on the target name.';
-
-
-COMMENT ON COLUMN bugtask.date_confirmed IS 'The date when this bug transitioned from an unconfirmed status to a confirmed one. If the state regresses to a one that logically occurs before Confirmed, e.g., Unconfirmed, this date is cleared.';
-
-
-COMMENT ON COLUMN bugtask.date_inprogress IS 'The date on which this bug transitioned from not being in progress to a state >= In Progress. If the status moves back to a pre-In Progress state, this date is cleared';
-
-
-COMMENT ON COLUMN bugtask.date_closed IS 'The date when this bug transitioned to a resolved state, e.g., Rejected, Fix Released, etc. If the state changes back to a pre-closed state, this date is cleared';
-
-
-COMMENT ON COLUMN bugtask.productseries IS 'The product series to which the bug is targeted';
-
-
-COMMENT ON COLUMN bugtask.date_left_new IS 'The date when this bug first transitioned out of the NEW status.';
-
-
-COMMENT ON COLUMN bugtask.date_triaged IS 'The date when this bug transitioned to a status >= TRIAGED.';
-
-
-COMMENT ON COLUMN bugtask.date_fix_committed IS 'The date when this bug transitioned to a status >= FIXCOMMITTED.';
-
-
-COMMENT ON COLUMN bugtask.date_fix_released IS 'The date when this bug transitioned to a FIXRELEASED status.';
-
-
-COMMENT ON COLUMN bugtask.date_left_closed IS 'The date when this bug last transitioned out of a CLOSED status.';
-
-
-COMMENT ON COLUMN bugtask.heat_rank IS 'The heat bin in which this bugtask appears, as a value from the BugTaskHeatRank enumeration.';
-
-
-COMMENT ON COLUMN bugtask.date_milestone_set IS 'The date when this bug was targed to the milestone that is currently set.';
-
-
-CREATE FUNCTION bugsummary_tasks(bug_row bug) RETURNS SETOF bugtask
-    LANGUAGE plpgsql STABLE
-    AS $$
-DECLARE
-    bt bugtask%ROWTYPE;
-    r record;
-BEGIN
-    bt.bug = BUG_ROW.id;
-
-    -- One row only for each target permutation - need to ignore other fields
-    -- like date last modified to deal with conjoined masters and multiple
-    -- sourcepackage tasks in a distro.
-    FOR r IN
-        SELECT
-            product, productseries, distribution, distroseries,
-            sourcepackagename, status, milestone, importance, bugwatch
-        FROM BugTask WHERE bug=BUG_ROW.id
-        UNION -- Implicit DISTINCT
-        SELECT
-            product, productseries, distribution, distroseries,
-            NULL, status, milestone, importance, bugwatch
-        FROM BugTask WHERE bug=BUG_ROW.id AND sourcepackagename IS NOT NULL
-    LOOP
-        bt.product = r.product;
-        bt.productseries = r.productseries;
-        bt.distribution = r.distribution;
-        bt.distroseries = r.distroseries;
-        bt.sourcepackagename = r.sourcepackagename;
-        bt.status = r.status;
-        bt.milestone = r.milestone;
-        bt.importance = r.importance;
-        bt.bugwatch = r.bugwatch;
-        RETURN NEXT bt;
-    END LOOP;
-END;
-$$;
-
-
-COMMENT ON FUNCTION bugsummary_tasks(bug_row bug) IS 'Return all tasks for the bug + all sourcepackagename tasks again with the sourcepackagename squashed';
-
-
-CREATE TABLE bugsubscription (
-    id integer NOT NULL,
-    person integer NOT NULL,
-    bug integer NOT NULL,
-    date_created timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL,
-    subscribed_by integer NOT NULL,
-    bug_notification_level integer DEFAULT 40 NOT NULL
-);
-
-
-COMMENT ON TABLE bugsubscription IS 'A subscription by a Person to a bug.';
-
-
-COMMENT ON COLUMN bugsubscription.bug_notification_level IS 'The level of notifications which the Person will receive from this subscription.';
-
-
-CREATE FUNCTION bugsummary_viewers(bug_row bug) RETURNS SETOF bugsubscription
-    LANGUAGE sql STABLE
-    AS $_$
-    SELECT *
-    FROM BugSubscription
-    WHERE
-        bugsubscription.bug=$1.id
-        AND $1.private IS TRUE;
-$_$;
-
-
-COMMENT ON FUNCTION bugsummary_viewers(bug_row bug) IS 'Return (bug, viewer) for all viewers if private, nothing otherwise';
-
-
-CREATE FUNCTION bugtag_maintain_bug_summary() RETURNS trigger
-    LANGUAGE plpgsql SECURITY DEFINER
-    SET search_path TO public
-    AS $$
-BEGIN
-    IF TG_OP = 'INSERT' THEN
-        IF TG_WHEN = 'BEFORE' THEN
-            PERFORM unsummarise_bug(bug_row(NEW.bug));
-        ELSE
-            PERFORM summarise_bug(bug_row(NEW.bug));
-        END IF;
-        PERFORM bug_summary_flush_temp_journal();
-        RETURN NEW;
-    ELSIF TG_OP = 'DELETE' THEN
-        IF TG_WHEN = 'BEFORE' THEN
-            PERFORM unsummarise_bug(bug_row(OLD.bug));
-        ELSE
-            PERFORM summarise_bug(bug_row(OLD.bug));
-        END IF;
-        PERFORM bug_summary_flush_temp_journal();
-        RETURN OLD;
-    ELSE
-        IF TG_WHEN = 'BEFORE' THEN
-            PERFORM unsummarise_bug(bug_row(OLD.bug));
-            IF OLD.bug <> NEW.bug THEN
-                PERFORM unsummarise_bug(bug_row(NEW.bug));
-            END IF;
-        ELSE
-            PERFORM summarise_bug(bug_row(OLD.bug));
-            IF OLD.bug <> NEW.bug THEN
-                PERFORM summarise_bug(bug_row(NEW.bug));
-            END IF;
-        END IF;
-        PERFORM bug_summary_flush_temp_journal();
-        RETURN NEW;
-    END IF;
-END;
-$$;
-
-
-COMMENT ON FUNCTION bugtag_maintain_bug_summary() IS 'AFTER trigger on bugtag maintaining the bugs summaries in bugsummary.';
-
-
-CREATE FUNCTION bugtask_maintain_bug_summary() RETURNS trigger
-    LANGUAGE plpgsql SECURITY DEFINER
-    SET search_path TO public
-    AS $$
-BEGIN
-    -- This trigger only works if we are inserting, updating or deleting
-    -- a single row per statement.
-
-    -- Unlike bug_maintain_bug_summary, this trigger does not have access
-    -- to the old bug when invoked as an AFTER trigger. To work around this
-    -- we install this trigger as both a BEFORE and an AFTER trigger.
-    IF TG_OP = 'INSERT' THEN
-        IF TG_WHEN = 'BEFORE' THEN
-            PERFORM unsummarise_bug(bug_row(NEW.bug));
-        ELSE
-            PERFORM summarise_bug(bug_row(NEW.bug));
-        END IF;
-        PERFORM bug_summary_flush_temp_journal();
-        RETURN NEW;
-
-    ELSIF TG_OP = 'DELETE' THEN
-        IF TG_WHEN = 'BEFORE' THEN
-            PERFORM unsummarise_bug(bug_row(OLD.bug));
-        ELSE
-            PERFORM summarise_bug(bug_row(OLD.bug));
-        END IF;
-        PERFORM bug_summary_flush_temp_journal();
-        RETURN OLD;
-
-    ELSE
-        IF (OLD.product IS DISTINCT FROM NEW.product
-            OR OLD.productseries IS DISTINCT FROM NEW.productseries
-            OR OLD.distribution IS DISTINCT FROM NEW.distribution
-            OR OLD.distroseries IS DISTINCT FROM NEW.distroseries
-            OR OLD.sourcepackagename IS DISTINCT FROM NEW.sourcepackagename
-            OR OLD.status IS DISTINCT FROM NEW.status
-            OR OLD.importance IS DISTINCT FROM NEW.importance
-            OR OLD.bugwatch IS DISTINCT FROM NEW.bugwatch
-            OR OLD.milestone IS DISTINCT FROM NEW.milestone) THEN
-
-            IF TG_WHEN = 'BEFORE' THEN
-                PERFORM unsummarise_bug(bug_row(OLD.bug));
-                IF OLD.bug <> NEW.bug THEN
-                    PERFORM unsummarise_bug(bug_row(NEW.bug));
-                END IF;
-            ELSE
-                PERFORM summarise_bug(bug_row(OLD.bug));
-                IF OLD.bug <> NEW.bug THEN
-                    PERFORM summarise_bug(bug_row(NEW.bug));
-                END IF;
-            END IF;
-        END IF;
-        PERFORM bug_summary_flush_temp_journal();
-        RETURN NEW;
-    END IF;
-END;
-$$;
-
-
-COMMENT ON FUNCTION bugtask_maintain_bug_summary() IS 'Both BEFORE & AFTER trigger on bugtask maintaining the bugs summaries in bugsummary.';
-
-
-CREATE FUNCTION calculate_bug_heat(bug_id integer) RETURNS integer
-    LANGUAGE plpythonu STABLE STRICT
-    AS $$
-    from datetime import datetime
-
-    class BugHeatConstants:
-        PRIVACY = 150
-        SECURITY = 250
-        DUPLICATE = 6
-        AFFECTED_USER = 4
-        SUBSCRIBER = 2
-
-    def get_max_heat_for_bug(bug_id):
-        results = plpy.execute("""
-            SELECT MAX(
-                GREATEST(Product.max_bug_heat,
-                         DistributionSourcePackage.max_bug_heat))
-                    AS max_heat
-            FROM BugTask
-            LEFT OUTER JOIN ProductSeries ON
-                BugTask.productseries = ProductSeries.id
-            LEFT OUTER JOIN Product ON (
-                BugTask.product = Product.id
-                OR ProductSeries.product = Product.id)
-            LEFT OUTER JOIN DistroSeries ON
-                BugTask.distroseries = DistroSeries.id
-            LEFT OUTER JOIN Distribution ON (
-                BugTask.distribution = Distribution.id
-                OR DistroSeries.distribution = Distribution.id)
-            LEFT OUTER JOIN DistributionSourcePackage ON (
-                BugTask.sourcepackagename =
-                    DistributionSourcePackage.sourcepackagename)
-            WHERE
-                BugTask.bug = %s""" % bug_id)
-
-        return results[0]['max_heat']
-
-    # It would be nice to be able to just SELECT * here, but we need the
-    # timestamps to be in a format that datetime.fromtimestamp() will
-    # understand.
-    bug_data = plpy.execute("""
-        SELECT
-            duplicateof,
-            private,
-            security_related,
-            number_of_duplicates,
-            users_affected_count,
-            EXTRACT(epoch from datecreated)
-                AS timestamp_date_created,
-            EXTRACT(epoch from date_last_updated)
-                AS timestamp_date_last_updated,
-            EXTRACT(epoch from date_last_message)
-                AS timestamp_date_last_message
-        FROM Bug WHERE id = %s""" % bug_id)
-
-    if bug_data.nrows() == 0:
-        raise Exception("Bug %s doesn't exist." % bug_id)
-
-    bug = bug_data[0]
-    if bug['duplicateof'] is not None:
-        return None
-
-    heat = {}
-    heat['dupes'] = (
-        BugHeatConstants.DUPLICATE * bug['number_of_duplicates'])
-    heat['affected_users'] = (
-        BugHeatConstants.AFFECTED_USER *
-        bug['users_affected_count'])
-
-    if bug['private']:
-        heat['privacy'] = BugHeatConstants.PRIVACY
-    if bug['security_related']:
-        heat['security'] = BugHeatConstants.SECURITY
-
-    # Get the heat from subscribers, both direct and via duplicates.
-    subs_from_dupes = plpy.execute("""
-        SELECT COUNT(DISTINCT BugSubscription.person) AS sub_count
-        FROM BugSubscription, Bug
-        WHERE Bug.id = BugSubscription.bug
-            AND (Bug.id = %s OR Bug.duplicateof = %s)"""
-        % (bug_id, bug_id))
-
-    heat['subcribers'] = (
-        BugHeatConstants.SUBSCRIBER
-        * subs_from_dupes[0]['sub_count'])
-
-    total_heat = sum(heat.values())
-
-    # Bugs decay over time. Every day the bug isn't touched its heat
-    # decreases by 1%.
-    date_last_updated = datetime.fromtimestamp(
-        bug['timestamp_date_last_updated'])
-    days_since_last_update = (datetime.utcnow() - date_last_updated).days
-    total_heat = int(total_heat * (0.99 ** days_since_last_update))
-
-    if days_since_last_update > 0:
-        # Bug heat increases by a quarter of the maximum bug heat
-        # divided by the number of days since the bug's creation date.
-        date_created = datetime.fromtimestamp(
-            bug['timestamp_date_created'])
-
-        if bug['timestamp_date_last_message'] is not None:
-            date_last_message = datetime.fromtimestamp(
-                bug['timestamp_date_last_message'])
-            oldest_date = max(date_last_updated, date_last_message)
-        else:
-            date_last_message = None
-            oldest_date = date_last_updated
-
-        days_since_last_activity = (datetime.utcnow() - oldest_date).days
-        days_since_created = (datetime.utcnow() - date_created).days
-        max_heat = get_max_heat_for_bug(bug_id)
-        if max_heat is not None and days_since_created > 0:
-            total_heat = (
-                total_heat + (max_heat * 0.25 / days_since_created))
-
-    return int(total_heat)
-$$;
-
-
-CREATE FUNCTION cursor_fetch(cur refcursor, n integer) RETURNS SETOF record
+    CONSTRAINT valid_tag CHECK (public.valid_name(tag))
+);
+
+
+COMMENT ON TABLE public.bugtag IS 'Attaches simple text tags to a bug.';
+
+
+COMMENT ON COLUMN public.bugtag.bug IS 'The bug the tags is attached to.';
+
+
+COMMENT ON COLUMN public.bugtag.tag IS 'The text representation of the tag.';
+
+
+CREATE FUNCTION public.bugsummary_tags(btf_row public.bugtaskflat) RETURNS SETOF public.bugtag
+    LANGUAGE sql STABLE
+    AS $_$
+    SELECT * FROM BugTag WHERE BugTag.bug = $1.bug
+    UNION ALL
+    SELECT NULL::integer, $1.bug, NULL::text;
+$_$;
+
+
+CREATE FUNCTION public.bugsummary_targets(btf_row public.bugtaskflat) RETURNS TABLE(product integer, productseries integer, distribution integer, distroseries integer, sourcepackagename integer)
+    LANGUAGE sql IMMUTABLE
+    AS $_$
+    -- Include a sourcepackagename-free task if this one has a
+    -- sourcepackagename, so package tasks are also counted in their
+    -- distro/series.
+    SELECT
+        $1.product, $1.productseries, $1.distribution,
+        $1.distroseries, $1.sourcepackagename
+    UNION -- Implicit DISTINCT
+    SELECT
+        $1.product, $1.productseries, $1.distribution,
+        $1.distroseries, NULL;
+$_$;
+
+
+CREATE FUNCTION public.bugsummary_viewers(btf_row public.bugtaskflat) RETURNS TABLE(viewed_by integer, access_policy integer)
+    LANGUAGE sql IMMUTABLE
+    AS $_$
+    SELECT NULL::integer, NULL::integer WHERE $1.information_type IN (1, 2)
+    UNION ALL
+    SELECT unnest($1.access_grants), NULL::integer
+    WHERE $1.information_type NOT IN (1, 2)
+    UNION ALL
+    SELECT NULL::integer, unnest($1.access_policies)
+    WHERE $1.information_type NOT IN (1, 2);
+$_$;
+
+
+CREATE FUNCTION public.bugtag_maintain_bug_summary() RETURNS trigger
+    LANGUAGE plpgsql SECURITY DEFINER
+    SET search_path TO 'public'
+    AS $$
+BEGIN
+    IF TG_OP = 'INSERT' THEN
+        IF TG_WHEN = 'BEFORE' THEN
+            PERFORM unsummarise_bug(NEW.bug);
+        ELSE
+            PERFORM summarise_bug(NEW.bug);
+        END IF;
+        PERFORM bug_summary_flush_temp_journal();
+        RETURN NEW;
+    ELSIF TG_OP = 'DELETE' THEN
+        IF TG_WHEN = 'BEFORE' THEN
+            PERFORM unsummarise_bug(OLD.bug);
+        ELSE
+            PERFORM summarise_bug(OLD.bug);
+        END IF;
+        PERFORM bug_summary_flush_temp_journal();
+        RETURN OLD;
+    ELSE
+        IF TG_WHEN = 'BEFORE' THEN
+            PERFORM unsummarise_bug(OLD.bug);
+            IF OLD.bug <> NEW.bug THEN
+                PERFORM unsummarise_bug(NEW.bug);
+            END IF;
+        ELSE
+            PERFORM summarise_bug(OLD.bug);
+            IF OLD.bug <> NEW.bug THEN
+                PERFORM summarise_bug(NEW.bug);
+            END IF;
+        END IF;
+        PERFORM bug_summary_flush_temp_journal();
+        RETURN NEW;
+    END IF;
+END;
+$$;
+
+
+COMMENT ON FUNCTION public.bugtag_maintain_bug_summary() IS 'AFTER trigger on bugtag maintaining the bugs summaries in bugsummary.';
+
+
+CREATE FUNCTION public.bugtask_flatten(task_id integer, check_only boolean) RETURNS boolean
+    LANGUAGE plpgsql SECURITY DEFINER
+    SET search_path TO 'public'
+    AS $$
+DECLARE
+    bug_row Bug%ROWTYPE;
+    task_row BugTask%ROWTYPE;
+    old_flat_row BugTaskFlat%ROWTYPE;
+    new_flat_row BugTaskFlat%ROWTYPE;
+    _product_active boolean;
+    _access_policies integer[];
+    _access_grants integer[];
+BEGIN
+    -- This is the master function to update BugTaskFlat, but there are
+    -- maintenance triggers and jobs on the involved tables that update
+    -- it directly. Any changes here probably require a corresponding
+    -- change in other trigger functions.
+
+    SELECT * INTO task_row FROM BugTask WHERE id = task_id;
+    SELECT * INTO old_flat_row FROM BugTaskFlat WHERE bugtask = task_id;
+
+    -- If the task doesn't exist, ensure that there's no flat row.
+    IF task_row.id IS NULL THEN
+        IF old_flat_row.bugtask IS NOT NULL THEN
+            IF NOT check_only THEN
+                DELETE FROM BugTaskFlat WHERE bugtask = task_id;
+            END IF;
+            RETURN FALSE;
+        ELSE
+            RETURN TRUE;
+        END IF;
+    END IF;
+
+    SELECT * FROM bug INTO bug_row WHERE id = task_row.bug;
+
+    -- If it's a product(series) task, we must consult the active flag.
+    IF task_row.product IS NOT NULL THEN
+        SELECT product.active INTO _product_active
+            FROM product WHERE product.id = task_row.product LIMIT 1;
+    ELSIF task_row.productseries IS NOT NULL THEN
+        SELECT product.active INTO _product_active
+            FROM
+                product
+                JOIN productseries ON productseries.product = product.id
+            WHERE productseries.id = task_row.productseries LIMIT 1;
+    END IF;
+
+    SELECT policies, grants
+        INTO _access_policies, _access_grants
+        FROM bug_build_access_cache(bug_row.id, bug_row.information_type)
+            AS (policies integer[], grants integer[]);
+
+    -- Compile the new flat row.
+    SELECT task_row.id, bug_row.id, task_row.datecreated,
+           bug_row.duplicateof, bug_row.owner, bug_row.fti,
+           bug_row.information_type, bug_row.date_last_updated,
+           bug_row.heat, task_row.product, task_row.productseries,
+           task_row.distribution, task_row.distroseries,
+           task_row.sourcepackagename, task_row.status,
+           task_row.importance, task_row.assignee,
+           task_row.milestone, task_row.owner,
+           COALESCE(_product_active, TRUE),
+           _access_policies,
+           _access_grants,
+           bug_row.latest_patch_uploaded, task_row.date_closed
+           INTO new_flat_row;
+
+    -- Calculate the necessary updates.
+    IF old_flat_row.bugtask IS NULL THEN
+        IF NOT check_only THEN
+            INSERT INTO BugTaskFlat VALUES (new_flat_row.*);
+        END IF;
+        RETURN FALSE;
+    ELSIF new_flat_row != old_flat_row THEN
+        IF NOT check_only THEN
+            UPDATE BugTaskFlat SET
+                bug = new_flat_row.bug,
+                datecreated = new_flat_row.datecreated,
+                duplicateof = new_flat_row.duplicateof,
+                bug_owner = new_flat_row.bug_owner,
+                fti = new_flat_row.fti,
+                information_type = new_flat_row.information_type,
+                date_last_updated = new_flat_row.date_last_updated,
+                heat = new_flat_row.heat,
+                product = new_flat_row.product,
+                productseries = new_flat_row.productseries,
+                distribution = new_flat_row.distribution,
+                distroseries = new_flat_row.distroseries,
+                sourcepackagename = new_flat_row.sourcepackagename,
+                status = new_flat_row.status,
+                importance = new_flat_row.importance,
+                assignee = new_flat_row.assignee,
+                milestone = new_flat_row.milestone,
+                owner = new_flat_row.owner,
+                active = new_flat_row.active,
+                access_policies = new_flat_row.access_policies,
+                access_grants = new_flat_row.access_grants,
+                date_closed = new_flat_row.date_closed,
+                latest_patch_uploaded = new_flat_row.latest_patch_uploaded
+                WHERE bugtask = new_flat_row.bugtask;
+        END IF;
+        RETURN FALSE;
+    ELSE
+        RETURN TRUE;
+    END IF;
+END;
+$$;
+
+
+COMMENT ON FUNCTION public.bugtask_flatten(task_id integer, check_only boolean) IS 'Create or update a BugTaskFlat row from the source tables. Returns whether the row was up to date. If check_only is true, the row is not brought up to date.';
+
+
+CREATE FUNCTION public.bugtask_maintain_bugtaskflat_trig() RETURNS trigger
+    LANGUAGE plpgsql SECURITY DEFINER
+    SET search_path TO 'public'
+    AS $$
+BEGIN
+    IF TG_OP = 'INSERT' THEN
+        PERFORM bugtask_flatten(NEW.id, FALSE);
+    ELSIF TG_OP = 'UPDATE' THEN
+        IF NEW.bug != OLD.bug THEN
+            RAISE EXCEPTION 'cannot move bugtask to a different bug';
+        ELSIF (NEW.product IS DISTINCT FROM OLD.product
+            OR NEW.productseries IS DISTINCT FROM OLD.productseries) THEN
+            -- product.active may differ. Do a full update.
+            PERFORM bugtask_flatten(NEW.id, FALSE);
+        ELSIF (
+            NEW.datecreated IS DISTINCT FROM OLD.datecreated
+            OR NEW.product IS DISTINCT FROM OLD.product
+            OR NEW.productseries IS DISTINCT FROM OLD.productseries
+            OR NEW.distribution IS DISTINCT FROM OLD.distribution
+            OR NEW.distroseries IS DISTINCT FROM OLD.distroseries
+            OR NEW.sourcepackagename IS DISTINCT FROM OLD.sourcepackagename
+            OR NEW.status IS DISTINCT FROM OLD.status
+            OR NEW.importance IS DISTINCT FROM OLD.importance
+            OR NEW.assignee IS DISTINCT FROM OLD.assignee
+            OR NEW.milestone IS DISTINCT FROM OLD.milestone
+            OR NEW.owner IS DISTINCT FROM OLD.owner
+            OR NEW.date_closed IS DISTINCT FROM OLD.date_closed) THEN
+            -- Otherwise just update the columns from bugtask.
+            -- Access policies and grants may have changed due to target
+            -- transitions, but an earlier trigger will already have
+            -- mirrored them to all relevant flat tasks.
+            UPDATE BugTaskFlat SET
+                datecreated = NEW.datecreated,
+                product = NEW.product,
+                productseries = NEW.productseries,
+                distribution = NEW.distribution,
+                distroseries = NEW.distroseries,
+                sourcepackagename = NEW.sourcepackagename,
+                status = NEW.status,
+                importance = NEW.importance,
+                assignee = NEW.assignee,
+                milestone = NEW.milestone,
+                owner = NEW.owner,
+                date_closed = NEW.date_closed
+                WHERE bugtask = NEW.id;
+        END IF;
+    ELSIF TG_OP = 'DELETE' THEN
+        PERFORM bugtask_flatten(OLD.id, FALSE);
+    END IF;
+    RETURN NULL;
+END;
+$$;
+
+
+CREATE FUNCTION public.bugtaskflat_maintain_bug_summary() RETURNS trigger
+    LANGUAGE plpgsql SECURITY DEFINER
+    SET search_path TO 'public'
+    AS $$
+BEGIN
+    IF TG_OP = 'INSERT' THEN
+        PERFORM bugsummary_journal_bugtaskflat(NEW, 1);
+        PERFORM bug_summary_flush_temp_journal();
+    ELSIF TG_OP = 'DELETE' THEN
+        PERFORM bugsummary_journal_bugtaskflat(OLD, -1);
+        PERFORM bug_summary_flush_temp_journal();
+    ELSIF
+        NEW.product IS DISTINCT FROM OLD.product
+        OR NEW.productseries IS DISTINCT FROM OLD.productseries
+        OR NEW.distribution IS DISTINCT FROM OLD.distribution
+        OR NEW.distroseries IS DISTINCT FROM OLD.distroseries
+        OR NEW.sourcepackagename IS DISTINCT FROM OLD.sourcepackagename
+        OR NEW.status IS DISTINCT FROM OLD.status
+        OR NEW.milestone IS DISTINCT FROM OLD.milestone
+        OR NEW.importance IS DISTINCT FROM OLD.importance
+        OR NEW.latest_patch_uploaded IS DISTINCT FROM OLD.latest_patch_uploaded
+        OR NEW.information_type IS DISTINCT FROM OLD.information_type
+        OR NEW.access_grants IS DISTINCT FROM OLD.access_grants
+        OR NEW.access_policies IS DISTINCT FROM OLD.access_policies
+        OR NEW.duplicateof IS DISTINCT FROM OLD.duplicateof
+    THEN
+        PERFORM bugsummary_journal_bugtaskflat(OLD, -1);
+        PERFORM bugsummary_journal_bugtaskflat(NEW, 1);
+        PERFORM bug_summary_flush_temp_journal();
+    END IF;
+    RETURN NULL;
+END;
+$$;
+
+
+CREATE FUNCTION public.build_access_cache(art_id integer, information_type integer) RETURNS record
+    LANGUAGE plpgsql
+    AS $$
+DECLARE
+    _policies integer[];
+    _grants integer[];
+    cache record;
+BEGIN
+    -- If private, grab the access control information.
+    -- If public, access_policies and access_grants are NULL.
+    -- 3 == PRIVATESECURITY, 4 == USERDATA, 5 == PROPRIETARY
+    -- 6 == EMBARGOED
+    IF information_type NOT IN (1, 2) THEN
+        SELECT COALESCE(array_agg(policy ORDER BY policy), ARRAY[]::integer[])
+            INTO _policies FROM accesspolicyartifact WHERE artifact = art_id;
+        SELECT COALESCE(array_agg(grantee ORDER BY grantee), ARRAY[]::integer[])
+            INTO _grants FROM accessartifactgrant WHERE artifact = art_id;
+    END IF;
+    cache := (_policies, _grants);
+    RETURN cache;
+END;
+$$;
+
+
+CREATE FUNCTION public.calculate_bug_heat(bug_id integer) RETURNS integer
+    LANGUAGE sql STABLE STRICT
+    AS $_$
+    SELECT
+        (CASE information_type WHEN 1 THEN 0 WHEN 2 THEN 250
+            WHEN 3 THEN 400 ELSE 150 END)
+        + (number_of_duplicates * 6)
+        + (users_affected_count * 4)
+        + (
+            SELECT COUNT(DISTINCT person) * 2 
+            FROM BugSubscription
+            JOIN Bug AS SubBug ON BugSubscription.bug = SubBug.id
+            WHERE SubBug.id = $1 OR SubBug.duplicateof = $1)::integer AS heat
+    FROM Bug WHERE Bug.id = $1;
+$_$;
+
+
+CREATE FUNCTION public.cursor_fetch(cur refcursor, n integer) RETURNS SETOF record
     LANGUAGE plpgsql
     AS $$
 DECLARE
@@ -1217,86 +1395,86 @@
 $$;
 
 
-COMMENT ON FUNCTION cursor_fetch(cur refcursor, n integer) IS 'Fetch the next n items from a cursor. Work around for not being able to use FETCH inside a SELECT statement.';
-
-
-CREATE FUNCTION debversion(character) RETURNS debversion
+COMMENT ON FUNCTION public.cursor_fetch(cur refcursor, n integer) IS 'Fetch the next n items from a cursor. Work around for not being able to use FETCH inside a SELECT statement.';
+
+
+CREATE FUNCTION public.debversion(character) RETURNS public.debversion
     LANGUAGE internal IMMUTABLE STRICT
     AS $$rtrim1$$;
 
 
-CREATE FUNCTION debversion_cmp(version1 debversion, version2 debversion) RETURNS integer
+CREATE FUNCTION public.debversion_cmp(version1 public.debversion, version2 public.debversion) RETURNS integer
     LANGUAGE c IMMUTABLE STRICT
     AS '$libdir/debversion', 'debversion_cmp';
 
 
-COMMENT ON FUNCTION debversion_cmp(version1 debversion, version2 debversion) IS 'Compare Debian versions';
-
-
-CREATE FUNCTION debversion_eq(version1 debversion, version2 debversion) RETURNS boolean
+COMMENT ON FUNCTION public.debversion_cmp(version1 public.debversion, version2 public.debversion) IS 'Compare Debian versions';
+
+
+CREATE FUNCTION public.debversion_eq(version1 public.debversion, version2 public.debversion) RETURNS boolean
     LANGUAGE c IMMUTABLE STRICT
     AS '$libdir/debversion', 'debversion_eq';
 
 
-COMMENT ON FUNCTION debversion_eq(version1 debversion, version2 debversion) IS 'debversion equal';
-
-
-CREATE FUNCTION debversion_ge(version1 debversion, version2 debversion) RETURNS boolean
+COMMENT ON FUNCTION public.debversion_eq(version1 public.debversion, version2 public.debversion) IS 'debversion equal';
+
+
+CREATE FUNCTION public.debversion_ge(version1 public.debversion, version2 public.debversion) RETURNS boolean
     LANGUAGE c IMMUTABLE STRICT
     AS '$libdir/debversion', 'debversion_ge';
 
 
-COMMENT ON FUNCTION debversion_ge(version1 debversion, version2 debversion) IS 'debversion greater-than-or-equal';
-
-
-CREATE FUNCTION debversion_gt(version1 debversion, version2 debversion) RETURNS boolean
+COMMENT ON FUNCTION public.debversion_ge(version1 public.debversion, version2 public.debversion) IS 'debversion greater-than-or-equal';
+
+
+CREATE FUNCTION public.debversion_gt(version1 public.debversion, version2 public.debversion) RETURNS boolean
     LANGUAGE c IMMUTABLE STRICT
     AS '$libdir/debversion', 'debversion_gt';
 
 
-COMMENT ON FUNCTION debversion_gt(version1 debversion, version2 debversion) IS 'debversion greater-than';
-
-
-CREATE FUNCTION debversion_hash(debversion) RETURNS integer
+COMMENT ON FUNCTION public.debversion_gt(version1 public.debversion, version2 public.debversion) IS 'debversion greater-than';
+
+
+CREATE FUNCTION public.debversion_hash(public.debversion) RETURNS integer
     LANGUAGE c IMMUTABLE STRICT
     AS '$libdir/debversion', 'debversion_hash';
 
 
-CREATE FUNCTION debversion_larger(version1 debversion, version2 debversion) RETURNS debversion
+CREATE FUNCTION public.debversion_larger(version1 public.debversion, version2 public.debversion) RETURNS public.debversion
     LANGUAGE c IMMUTABLE STRICT
     AS '$libdir/debversion', 'debversion_larger';
 
 
-CREATE FUNCTION debversion_le(version1 debversion, version2 debversion) RETURNS boolean
+CREATE FUNCTION public.debversion_le(version1 public.debversion, version2 public.debversion) RETURNS boolean
     LANGUAGE c IMMUTABLE STRICT
     AS '$libdir/debversion', 'debversion_le';
 
 
-COMMENT ON FUNCTION debversion_le(version1 debversion, version2 debversion) IS 'debversion less-than-or-equal';
-
-
-CREATE FUNCTION debversion_lt(version1 debversion, version2 debversion) RETURNS boolean
+COMMENT ON FUNCTION public.debversion_le(version1 public.debversion, version2 public.debversion) IS 'debversion less-than-or-equal';
+
+
+CREATE FUNCTION public.debversion_lt(version1 public.debversion, version2 public.debversion) RETURNS boolean
     LANGUAGE c IMMUTABLE STRICT
     AS '$libdir/debversion', 'debversion_lt';
 
 
-COMMENT ON FUNCTION debversion_lt(version1 debversion, version2 debversion) IS 'debversion less-than';
-
-
-CREATE FUNCTION debversion_ne(version1 debversion, version2 debversion) RETURNS boolean
+COMMENT ON FUNCTION public.debversion_lt(version1 public.debversion, version2 public.debversion) IS 'debversion less-than';
+
+
+CREATE FUNCTION public.debversion_ne(version1 public.debversion, version2 public.debversion) RETURNS boolean
     LANGUAGE c IMMUTABLE STRICT
     AS '$libdir/debversion', 'debversion_ne';
 
 
-COMMENT ON FUNCTION debversion_ne(version1 debversion, version2 debversion) IS 'debversion not equal';
-
-
-CREATE FUNCTION debversion_smaller(version1 debversion, version2 debversion) RETURNS debversion
+COMMENT ON FUNCTION public.debversion_ne(version1 public.debversion, version2 public.debversion) IS 'debversion not equal';
+
+
+CREATE FUNCTION public.debversion_smaller(version1 public.debversion, version2 public.debversion) RETURNS public.debversion
     LANGUAGE c IMMUTABLE STRICT
     AS '$libdir/debversion', 'debversion_smaller';
 
 
-CREATE FUNCTION debversion_sort_key(version text) RETURNS text
+CREATE FUNCTION public.debversion_sort_key(version text) RETURNS text
     LANGUAGE plpythonu IMMUTABLE STRICT
     AS $_$
     # If this method is altered, then any functional indexes using it
@@ -1365,13 +1543,12 @@
 $_$;
 
 
-COMMENT ON FUNCTION debversion_sort_key(version text) IS 'Return a string suitable for sorting debian version strings on';
-
-
-CREATE FUNCTION ensure_bugsummary_temp_journal() RETURNS void
+COMMENT ON FUNCTION public.debversion_sort_key(version text) IS 'Return a string suitable for sorting debian version strings on';
+
+
+CREATE FUNCTION public.ensure_bugsummary_temp_journal() RETURNS void
     LANGUAGE plpgsql
     AS $$
-DECLARE
 BEGIN
     CREATE TEMPORARY TABLE bugsummary_temp_journal (
         LIKE bugsummary ) ON COMMIT DROP;
@@ -1383,48 +1560,66 @@
 $$;
 
 
-COMMENT ON FUNCTION ensure_bugsummary_temp_journal() IS 'Create a temporary table bugsummary_temp_journal if it does not exist.';
-
-
-CREATE FUNCTION generate_openid_identifier() RETURNS text
+COMMENT ON FUNCTION public.ensure_bugsummary_temp_journal() IS 'Create a temporary table bugsummary_temp_journal if it does not exist.';
+
+
+CREATE FUNCTION public.ftiupdate() RETURNS trigger
     LANGUAGE plpythonu
-    AS $$
-    from random import choice
-
-    # Non display confusing characters.
-    chars = '34678bcdefhkmnprstwxyzABCDEFGHJKLMNPQRTWXY'
-
-    # Character length of tokens. Can be increased, decreased or even made
-    # random - Launchpad does not care. 7 means it takes 40 bytes to store
-    # a null-terminated Launchpad identity URL on the current domain name.
-    length=7
-
-    loop_count = 0
-    while loop_count < 20000:
-        # Generate a random openid_identifier
-        oid = ''.join(choice(chars) for count in range(length))
-
-        # Check if the oid is already in the db, although this is pretty
-        # unlikely
-        rv = plpy.execute("""
-            SELECT COUNT(*) AS num FROM Account WHERE openid_identifier = '%s'
-            """ % oid, 1)
-        if rv[0]['num'] == 0:
-            return oid
-        loop_count += 1
-        if loop_count == 1:
-            plpy.warning(
-                'Clash generating unique openid_identifier. '
-                'Increase length if you see this warning too much.')
-    plpy.error(
-        "Unable to generate unique openid_identifier. "
-        "Need to increase length of tokens.")
-$$;
-
-
-CREATE FUNCTION getlocalnodeid() RETURNS integer
+    AS $_$
+    new = TD["new"]
+    args = TD["args"][:]
+
+    # Short circuit if none of the relevant columns have been
+    # modified and fti is not being set to NULL (setting the fti
+    # column to NULL is thus how we can force a rebuild of the fti
+    # column).
+    if TD["event"] == "UPDATE" and new["fti"] != None:
+        old = TD["old"]
+        relevant_modification = False
+        for column_name in args[::2]:
+            if new[column_name] != old[column_name]:
+                relevant_modification = True
+                break
+        if not relevant_modification:
+            return "OK"
+
+    # Generate an SQL statement that turns the requested
+    # column values into a weighted tsvector
+    sql = []
+    for i in range(0, len(args), 2):
+        sql.append(
+                "setweight(to_tsvector('default', coalesce("
+                "substring(ltrim($%d) from 1 for 2500),'')),"
+                "CAST($%d AS \"char\"))" % (i + 1, i + 2))
+        args[i] = new[args[i]]
+
+    sql = "SELECT %s AS fti" % "||".join(sql)
+
+    # Execute and store in the fti column
+    plan = plpy.prepare(sql, ["text", "char"] * (len(args)/2))
+    new["fti"] = plpy.execute(plan, args, 1)[0]["fti"]
+
+    # Tell PostgreSQL we have modified the data
+    return "MODIFY"
+$_$;
+
+
+COMMENT ON FUNCTION public.ftiupdate() IS 'Trigger function that keeps the fti tsvector column up to date.';
+
+
+CREATE FUNCTION public.ftq(text) RETURNS tsquery
+    LANGUAGE plpythonu IMMUTABLE STRICT
+    AS $_$
+        p = plpy.prepare(
+            "SELECT to_tsquery('default', _ftq($1)) AS x", ["text"])
+        query = plpy.execute(p, args, 1)[0]["x"]
+        return query or None
+        $_$;
+
+
+CREATE FUNCTION public.getlocalnodeid() RETURNS integer
     LANGUAGE plpgsql STABLE SECURITY DEFINER
-    SET search_path TO public
+    SET search_path TO 'public'
     AS $$
     DECLARE
         v_node_id integer;
@@ -1438,70 +1633,48 @@
 $$;
 
 
-COMMENT ON FUNCTION getlocalnodeid() IS 'Return the replication node id for this node, or NULL if not a replicated installation.';
-
-
-CREATE FUNCTION is_blacklisted_name(text, integer) RETURNS boolean
+COMMENT ON FUNCTION public.getlocalnodeid() IS 'Return the replication node id for this node, or NULL if not a replicated installation.';
+
+
+CREATE FUNCTION public.gitrepository_denorm_access(gitrepository_id integer) RETURNS void
+    LANGUAGE sql SECURITY DEFINER
+    SET search_path TO 'public'
+    AS $_$
+    UPDATE GitRepository
+        SET access_policy = policies[1], access_grants = grants
+        FROM
+            build_access_cache(
+                (SELECT id FROM accessartifact WHERE gitrepository = $1),
+                (SELECT information_type FROM gitrepository WHERE id = $1))
+            AS (policies integer[], grants integer[])
+        WHERE id = $1;
+$_$;
+
+
+CREATE FUNCTION public.gitrepository_maintain_access_cache_trig() RETURNS trigger
+    LANGUAGE plpgsql
+    AS $$
+BEGIN
+    PERFORM gitrepository_denorm_access(NEW.id);
+    RETURN NULL;
+END;
+$$;
+
+
+CREATE FUNCTION public.is_blacklisted_name(text, integer) RETURNS boolean
     LANGUAGE sql STABLE STRICT SECURITY DEFINER
-    SET search_path TO public
+    SET search_path TO 'public'
     AS $_$
     SELECT COALESCE(name_blacklist_match($1, $2)::boolean, FALSE);
 $_$;
 
 
-COMMENT ON FUNCTION is_blacklisted_name(text, integer) IS 'Return TRUE if any regular expressions stored in the NameBlacklist table match the givenname, otherwise return FALSE.';
-
-
-CREATE FUNCTION is_person(text) RETURNS boolean
-    LANGUAGE sql STABLE STRICT
-    AS $_$
-    SELECT count(*)>0 FROM Person WHERE name=$1 AND teamowner IS NULL;
-$_$;
-
-
-COMMENT ON FUNCTION is_person(text) IS 'True if the given name identifies a person in the Person table';
-
-
-CREATE FUNCTION is_printable_ascii(text) RETURNS boolean
-    LANGUAGE plpythonu IMMUTABLE STRICT
-    AS $_$
-    import re, string
-    try:
-        text = args[0].decode("ASCII")
-    except UnicodeError:
-        return False
-    if re.search(r"^[%s]*$" % re.escape(string.printable), text) is None:
-        return False
-    return True
-$_$;
-
-
-COMMENT ON FUNCTION is_printable_ascii(text) IS 'True if the string is pure printable US-ASCII';
-
-
-CREATE FUNCTION is_team(integer) RETURNS boolean
-    LANGUAGE sql STABLE STRICT
-    AS $_$
-    SELECT count(*)>0 FROM Person WHERE id=$1 AND teamowner IS NOT NULL;
-$_$;
-
-
-COMMENT ON FUNCTION is_team(integer) IS 'True if the given id identifies a team in the Person table';
-
-
-CREATE FUNCTION is_team(text) RETURNS boolean
-    LANGUAGE sql STABLE STRICT
-    AS $_$
-    SELECT count(*)>0 FROM Person WHERE name=$1 AND teamowner IS NOT NULL;
-$_$;
-
-
-COMMENT ON FUNCTION is_team(text) IS 'True if the given name identifies a team in the Person table';
-
-
-CREATE FUNCTION lp_mirror_account_ins() RETURNS trigger
+COMMENT ON FUNCTION public.is_blacklisted_name(text, integer) IS 'Return TRUE if any regular expressions stored in the NameBlacklist table match the givenname, otherwise return FALSE.';
+
+
+CREATE FUNCTION public.lp_mirror_account_ins() RETURNS trigger
     LANGUAGE plpgsql SECURITY DEFINER
-    SET search_path TO public
+    SET search_path TO 'public'
     AS $$
 BEGIN
     INSERT INTO lp_Account (id, openid_identifier)
@@ -1511,9 +1684,9 @@
 $$;
 
 
-CREATE FUNCTION lp_mirror_account_upd() RETURNS trigger
+CREATE FUNCTION public.lp_mirror_account_upd() RETURNS trigger
     LANGUAGE plpgsql SECURITY DEFINER
-    SET search_path TO public
+    SET search_path TO 'public'
     AS $$
 BEGIN
     IF OLD.id <> NEW.id OR OLD.openid_identifier <> NEW.openid_identifier THEN
@@ -1526,9 +1699,9 @@
 $$;
 
 
-CREATE FUNCTION lp_mirror_del() RETURNS trigger
+CREATE FUNCTION public.lp_mirror_del() RETURNS trigger
     LANGUAGE plpgsql SECURITY DEFINER
-    SET search_path TO public
+    SET search_path TO 'public'
     AS $$
 BEGIN
     EXECUTE 'DELETE FROM lp_' || TG_TABLE_NAME || ' WHERE id=' || OLD.id;
@@ -1537,9 +1710,9 @@
 $$;
 
 
-CREATE FUNCTION lp_mirror_openididentifier_del() RETURNS trigger
+CREATE FUNCTION public.lp_mirror_openididentifier_del() RETURNS trigger
     LANGUAGE plpgsql SECURITY DEFINER
-    SET search_path TO public
+    SET search_path TO 'public'
     AS $$
 DECLARE
     next_identifier text;
@@ -1562,9 +1735,9 @@
 $$;
 
 
-CREATE FUNCTION lp_mirror_openididentifier_ins() RETURNS trigger
+CREATE FUNCTION public.lp_mirror_openididentifier_ins() RETURNS trigger
     LANGUAGE plpgsql SECURITY DEFINER
-    SET search_path TO public
+    SET search_path TO 'public'
     AS $$
 BEGIN
     -- Support obsolete lp_Account.openid_identifier as best we can
@@ -1584,9 +1757,9 @@
 $$;
 
 
-CREATE FUNCTION lp_mirror_openididentifier_upd() RETURNS trigger
+CREATE FUNCTION public.lp_mirror_openididentifier_upd() RETURNS trigger
     LANGUAGE plpgsql SECURITY DEFINER
-    SET search_path TO public
+    SET search_path TO 'public'
     AS $$
 BEGIN
     IF OLD.identifier <> NEW.identifier THEN
@@ -1604,9 +1777,9 @@
 $$;
 
 
-CREATE FUNCTION lp_mirror_person_ins() RETURNS trigger
+CREATE FUNCTION public.lp_mirror_person_ins() RETURNS trigger
     LANGUAGE plpgsql SECURITY DEFINER
-    SET search_path TO public
+    SET search_path TO 'public'
     AS $$
 BEGIN
     INSERT INTO lp_Person (
@@ -1634,9 +1807,9 @@
 $$;
 
 
-CREATE FUNCTION lp_mirror_person_upd() RETURNS trigger
+CREATE FUNCTION public.lp_mirror_person_upd() RETURNS trigger
     LANGUAGE plpgsql SECURITY DEFINER
-    SET search_path TO public
+    SET search_path TO 'public'
     AS $$
 BEGIN
     UPDATE lp_Person
@@ -1676,9 +1849,9 @@
 $$;
 
 
-CREATE FUNCTION lp_mirror_personlocation_ins() RETURNS trigger
+CREATE FUNCTION public.lp_mirror_personlocation_ins() RETURNS trigger
     LANGUAGE plpgsql SECURITY DEFINER
-    SET search_path TO public
+    SET search_path TO 'public'
     AS $$
 BEGIN
     INSERT INTO lp_PersonLocation SELECT NEW.*;
@@ -1687,9 +1860,9 @@
 $$;
 
 
-CREATE FUNCTION lp_mirror_personlocation_upd() RETURNS trigger
+CREATE FUNCTION public.lp_mirror_personlocation_upd() RETURNS trigger
     LANGUAGE plpgsql SECURITY DEFINER
-    SET search_path TO public
+    SET search_path TO 'public'
     AS $$
 BEGIN
     UPDATE lp_PersonLocation
@@ -1709,9 +1882,9 @@
 $$;
 
 
-CREATE FUNCTION lp_mirror_teamparticipation_ins() RETURNS trigger
+CREATE FUNCTION public.lp_mirror_teamparticipation_ins() RETURNS trigger
     LANGUAGE plpgsql SECURITY DEFINER
-    SET search_path TO public
+    SET search_path TO 'public'
     AS $$
 BEGIN
     INSERT INTO lp_TeamParticipation SELECT NEW.*;
@@ -1720,9 +1893,9 @@
 $$;
 
 
-CREATE FUNCTION lp_mirror_teamparticipation_upd() RETURNS trigger
+CREATE FUNCTION public.lp_mirror_teamparticipation_upd() RETURNS trigger
     LANGUAGE plpgsql SECURITY DEFINER
-    SET search_path TO public
+    SET search_path TO 'public'
     AS $$
 BEGIN
     UPDATE lp_TeamParticipation
@@ -1735,28 +1908,9 @@
 $$;
 
 
-CREATE FUNCTION maintain_transitively_private() RETURNS trigger
-    LANGUAGE plpgsql
-    AS $$
-BEGIN
-    IF TG_OP = 'UPDATE' THEN
-        IF (NEW.stacked_on IS NOT DISTINCT FROM OLD.stacked_on
-            AND NEW.private IS NOT DISTINCT FROM OLD.private) THEN
-            RETURN NULL;
-        END IF;
-    END IF;
-    PERFORM update_transitively_private(NEW.id);
-    RETURN NULL;
-END;
-$$;
-
-
-COMMENT ON FUNCTION maintain_transitively_private() IS 'Trigger maintaining the Branch transitively_private column';
-
-
-CREATE FUNCTION message_copy_owner_to_bugmessage() RETURNS trigger
+CREATE FUNCTION public.message_copy_owner_to_bugmessage() RETURNS trigger
     LANGUAGE plpgsql SECURITY DEFINER
-    SET search_path TO public
+    SET search_path TO 'public'
     AS $$
 BEGIN
     IF NEW.owner != OLD.owner THEN
@@ -1770,12 +1924,12 @@
 $$;
 
 
-COMMENT ON FUNCTION message_copy_owner_to_bugmessage() IS 'Copies the message owner into bugmessage when message changes.';
-
-
-CREATE FUNCTION message_copy_owner_to_questionmessage() RETURNS trigger
+COMMENT ON FUNCTION public.message_copy_owner_to_bugmessage() IS 'Copies the message owner into bugmessage when message changes.';
+
+
+CREATE FUNCTION public.message_copy_owner_to_questionmessage() RETURNS trigger
     LANGUAGE plpgsql SECURITY DEFINER
-    SET search_path TO public
+    SET search_path TO 'public'
     AS $$
 BEGIN
     IF NEW.owner != OLD.owner THEN
@@ -1789,10 +1943,10 @@
 $$;
 
 
-COMMENT ON FUNCTION message_copy_owner_to_questionmessage() IS 'Copies the message owner into questionmessage when message changes.';
-
-
-CREATE FUNCTION milestone_sort_key(dateexpected timestamp without time zone, name text) RETURNS text
+COMMENT ON FUNCTION public.message_copy_owner_to_questionmessage() IS 'Copies the message owner into questionmessage when message changes.';
+
+
+CREATE FUNCTION public.milestone_sort_key(dateexpected timestamp without time zone, name text) RETURNS text
     LANGUAGE plpythonu IMMUTABLE
     AS $$
     # If this method is altered, then any functional indexes using it
@@ -1813,10 +1967,10 @@
 $$;
 
 
-COMMENT ON FUNCTION milestone_sort_key(dateexpected timestamp without time zone, name text) IS 'Sort by the Milestone dateexpected and name. If the dateexpected is NULL, then it is converted to a date far in the future, so it will be sorted as a milestone in the future.';
-
-
-CREATE FUNCTION mv_branch_distribution_update() RETURNS trigger
+COMMENT ON FUNCTION public.milestone_sort_key(dateexpected timestamp without time zone, name text) IS 'Sort by the Milestone dateexpected and name. If the dateexpected is NULL, then it is converted to a date far in the future, so it will be sorted as a milestone in the future.';
+
+
+CREATE FUNCTION public.mv_branch_distribution_update() RETURNS trigger
     LANGUAGE plpgsql
     AS $$
 BEGIN
@@ -1834,10 +1988,10 @@
 $$;
 
 
-COMMENT ON FUNCTION mv_branch_distribution_update() IS 'Maintain Branch name cache when Distribution is modified.';
-
-
-CREATE FUNCTION mv_branch_distroseries_update() RETURNS trigger
+COMMENT ON FUNCTION public.mv_branch_distribution_update() IS 'Maintain Branch name cache when Distribution is modified.';
+
+
+CREATE FUNCTION public.mv_branch_distroseries_update() RETURNS trigger
     LANGUAGE plpgsql
     AS $$
 BEGIN
@@ -1853,10 +2007,10 @@
 $$;
 
 
-COMMENT ON FUNCTION mv_branch_distroseries_update() IS 'Maintain Branch name cache when Distroseries is modified.';
-
-
-CREATE FUNCTION mv_branch_person_update() RETURNS trigger
+COMMENT ON FUNCTION public.mv_branch_distroseries_update() IS 'Maintain Branch name cache when Distroseries is modified.';
+
+
+CREATE FUNCTION public.mv_branch_person_update() RETURNS trigger
     LANGUAGE plpgsql
     AS $$
 DECLARE
@@ -1873,10 +2027,10 @@
 $$;
 
 
-COMMENT ON FUNCTION mv_branch_person_update() IS 'Maintain Branch name cache when Person is modified.';
-
-
-CREATE FUNCTION mv_branch_product_update() RETURNS trigger
+COMMENT ON FUNCTION public.mv_branch_person_update() IS 'Maintain Branch name cache when Person is modified.';
+
+
+CREATE FUNCTION public.mv_branch_product_update() RETURNS trigger
     LANGUAGE plpgsql
     AS $$
 DECLARE
@@ -1893,12 +2047,12 @@
 $$;
 
 
-COMMENT ON FUNCTION mv_branch_product_update() IS 'Maintain Branch name cache when Product is modified.';
-
-
-CREATE FUNCTION mv_pillarname_distribution() RETURNS trigger
+COMMENT ON FUNCTION public.mv_branch_product_update() IS 'Maintain Branch name cache when Product is modified.';
+
+
+CREATE FUNCTION public.mv_pillarname_distribution() RETURNS trigger
     LANGUAGE plpgsql SECURITY DEFINER
-    SET search_path TO public
+    SET search_path TO 'public'
     AS $$
 BEGIN
     IF TG_OP = 'INSERT' THEN
@@ -1912,12 +2066,12 @@
 $$;
 
 
-COMMENT ON FUNCTION mv_pillarname_distribution() IS 'Trigger maintaining the PillarName table';
-
-
-CREATE FUNCTION mv_pillarname_product() RETURNS trigger
+COMMENT ON FUNCTION public.mv_pillarname_distribution() IS 'Trigger maintaining the PillarName table';
+
+
+CREATE FUNCTION public.mv_pillarname_product() RETURNS trigger
     LANGUAGE plpgsql SECURITY DEFINER
-    SET search_path TO public
+    SET search_path TO 'public'
     AS $$
 BEGIN
     IF TG_OP = 'INSERT' THEN
@@ -1932,12 +2086,12 @@
 $$;
 
 
-COMMENT ON FUNCTION mv_pillarname_product() IS 'Trigger maintaining the PillarName table';
-
-
-CREATE FUNCTION mv_pillarname_project() RETURNS trigger
+COMMENT ON FUNCTION public.mv_pillarname_product() IS 'Trigger maintaining the PillarName table';
+
+
+CREATE FUNCTION public.mv_pillarname_project() RETURNS trigger
     LANGUAGE plpgsql SECURITY DEFINER
-    SET search_path TO public
+    SET search_path TO 'public'
     AS $$
 BEGIN
     IF TG_OP = 'INSERT' THEN
@@ -1952,221 +2106,47 @@
 $$;
 
 
-COMMENT ON FUNCTION mv_pillarname_project() IS 'Trigger maintaining the PillarName table';
-
-
-CREATE FUNCTION mv_pofiletranslator_pomsgset() RETURNS trigger
-    LANGUAGE plpgsql
-    AS $$
-BEGIN
-    IF TG_OP = 'DELETE' THEN
-        RAISE EXCEPTION
-            'Deletions from POMsgSet not supported by the POFileTranslator materialized view';
-    ELSIF TG_OP = 'UPDATE' THEN
-        IF OLD.pofile != NEW.pofile THEN
-            RAISE EXCEPTION
-                'Changing POMsgSet.pofile not supported by the POFileTranslator materialized view';
-        END IF;
-    END IF;
-    RETURN NEW;
-END;
-$$;
-
-
-COMMENT ON FUNCTION mv_pofiletranslator_pomsgset() IS 'Trigger enforing no POMsgSet deletions or POMsgSet.pofile changes';
-
-
-CREATE FUNCTION mv_pofiletranslator_posubmission() RETURNS trigger
-    LANGUAGE plpgsql SECURITY DEFINER
-    AS $$
-DECLARE
-    v_pofile INTEGER;
-    v_trash_old BOOLEAN;
-BEGIN
-    -- If we are deleting a row, we need to remove the existing
-    -- POFileTranslator row and reinsert the historical data if it exists.
-    -- We also treat UPDATEs that change the key (person, pofile) the same
-    -- as deletes. UPDATEs that don't change these columns are treated like
-    -- INSERTs below.
-    IF TG_OP = 'INSERT' THEN
-        v_trash_old := FALSE;
-    ELSIF TG_OP = 'DELETE' THEN
-        v_trash_old := TRUE;
-    ELSE -- UPDATE
-        v_trash_old = (
-            OLD.person != NEW.person OR OLD.pomsgset != NEW.pomsgset
-            );
-    END IF;
-
-    IF v_trash_old THEN
-
-        -- Delete the old record.
-        DELETE FROM POFileTranslator USING POMsgSet
-        WHERE POFileTranslator.pofile = POMsgSet.pofile
-            AND POFileTranslator.person = OLD.person
-            AND POMsgSet.id = OLD.pomsgset;
-
-        -- Insert a past record if there is one.
-        INSERT INTO POFileTranslator (
-            person, pofile, latest_posubmission, date_last_touched
-            )
-            SELECT DISTINCT ON (POSubmission.person, POMsgSet.pofile)
-                POSubmission.person, POMsgSet.pofile,
-                POSubmission.id, POSubmission.datecreated
-            FROM POSubmission, POMsgSet
-            WHERE POSubmission.pomsgset = POMsgSet.id
-                AND POSubmission.pomsgset = OLD.pomsgset
-                AND POSubmission.person = OLD.person
-            ORDER BY
-                POSubmission.person, POMsgSet.pofile,
-                POSubmission.datecreated DESC, POSubmission.id DESC;
-
-        -- No NEW with DELETE, so we can short circuit and leave.
-        IF TG_OP = 'DELETE' THEN
-            RETURN NULL; -- Ignored because this is an AFTER trigger
-        END IF;
-    END IF;
-
-    -- Get our new pofile id
-    SELECT INTO v_pofile POMsgSet.pofile FROM POMsgSet
-    WHERE POMsgSet.id = NEW.pomsgset;
-
-    -- Standard 'upsert' loop to avoid race conditions.
-    LOOP
-        UPDATE POFileTranslator
-            SET
-                date_last_touched = CURRENT_TIMESTAMP AT TIME ZONE 'UTC',
-                latest_posubmission = NEW.id
-            WHERE
-                person = NEW.person
-                AND pofile = v_pofile;
-        IF found THEN
-            RETURN NULL; -- Return value ignored as this is an AFTER trigger
-        END IF;
-
-        BEGIN
-            INSERT INTO POFileTranslator (person, pofile, latest_posubmission)
-            VALUES (NEW.person, v_pofile, NEW.id);
-            RETURN NULL; -- Return value ignored as this is an AFTER trigger
-        EXCEPTION WHEN unique_violation THEN
-            -- do nothing
-        END;
-    END LOOP;
-END;
-$$;
-
-
-COMMENT ON FUNCTION mv_pofiletranslator_posubmission() IS 'Trigger maintaining the POFileTranslator table';
-
-
-CREATE FUNCTION mv_pofiletranslator_translationmessage() RETURNS trigger
-    LANGUAGE plpgsql SECURITY DEFINER
-    SET search_path TO public
-    AS $$
-DECLARE
-    v_trash_old BOOLEAN;
-BEGIN
-    -- If we are deleting a row, we need to remove the existing
-    -- POFileTranslator row and reinsert the historical data if it exists.
-    -- We also treat UPDATEs that change the key (submitter) the same
-    -- as deletes. UPDATEs that don't change these columns are treated like
-    -- INSERTs below.
-    IF TG_OP = 'INSERT' THEN
-        v_trash_old := FALSE;
-    ELSIF TG_OP = 'DELETE' THEN
-        v_trash_old := TRUE;
-    ELSE -- UPDATE
-        v_trash_old = (
-            OLD.submitter != NEW.submitter
-            );
-    END IF;
-
-    IF v_trash_old THEN
-        -- Was this somebody's most-recently-changed message?
-        -- If so, delete the entry for that change.
-        DELETE FROM POFileTranslator
-        WHERE latest_message = OLD.id;
-        IF FOUND THEN
-            -- We deleted the entry for somebody's latest contribution.
-            -- Find that person's latest remaining contribution and
-            -- create a new record for that.
-            INSERT INTO POFileTranslator (
-                person, pofile, latest_message, date_last_touched
-                )
-            SELECT DISTINCT ON (person, pofile.id)
-                new_latest_message.submitter AS person,
-                pofile.id,
-                new_latest_message.id,
-                greatest(new_latest_message.date_created,
-                         new_latest_message.date_reviewed)
-              FROM POFile
-              JOIN TranslationTemplateItem AS old_template_item
-                ON OLD.potmsgset = old_template_item.potmsgset AND
-                   old_template_item.potemplate = pofile.potemplate AND
-                   pofile.language = OLD.language
-              JOIN TranslationTemplateItem AS new_template_item
-                ON (old_template_item.potemplate =
-                     new_template_item.potemplate)
-              JOIN TranslationMessage AS new_latest_message
-                ON new_latest_message.potmsgset =
-                       new_template_item.potmsgset AND
-                   new_latest_message.language = OLD.language
-              LEFT OUTER JOIN POfileTranslator AS ExistingEntry
-                ON ExistingEntry.person = OLD.submitter AND
-                   ExistingEntry.pofile = POFile.id
-              WHERE
-                new_latest_message.submitter = OLD.submitter AND
-                ExistingEntry IS NULL
-              ORDER BY new_latest_message.submitter, pofile.id,
-                       new_latest_message.date_created DESC,
-                       new_latest_message.id DESC;
-        END IF;
-
-        -- No NEW with DELETE, so we can short circuit and leave.
-        IF TG_OP = 'DELETE' THEN
-            RETURN NULL; -- Ignored because this is an AFTER trigger
-        END IF;
-    END IF;
-
-    -- Standard 'upsert' loop to avoid race conditions.
-    LOOP
-        UPDATE POFileTranslator
-        SET
-            date_last_touched = CURRENT_TIMESTAMP AT TIME ZONE 'UTC',
-            latest_message = NEW.id
-        FROM POFile, TranslationTemplateItem
-        WHERE person = NEW.submitter AND
-              TranslationTemplateItem.potmsgset=NEW.potmsgset AND
-              TranslationTemplateItem.potemplate=pofile.potemplate AND
-              pofile.language=NEW.language AND
-              POFileTranslator.pofile = pofile.id;
-        IF found THEN
-            RETURN NULL; -- Return value ignored as this is an AFTER trigger
-        END IF;
-
-        BEGIN
-            INSERT INTO POFileTranslator (person, pofile, latest_message)
-            SELECT DISTINCT ON (NEW.submitter, pofile.id)
-                NEW.submitter, pofile.id, NEW.id
-              FROM TranslationTemplateItem
-              JOIN POFile
-                ON pofile.language = NEW.language AND
-                   pofile.potemplate = translationtemplateitem.potemplate
-              WHERE
-                TranslationTemplateItem.potmsgset = NEW.potmsgset;
-            RETURN NULL; -- Return value ignored as this is an AFTER trigger
-        EXCEPTION WHEN unique_violation THEN
-            -- do nothing
-        END;
-    END LOOP;
-END;
-$$;
-
-
-COMMENT ON FUNCTION mv_pofiletranslator_translationmessage() IS 'Trigger maintaining the POFileTranslator table';
-
-
-CREATE FUNCTION mv_validpersonorteamcache_emailaddress() RETURNS trigger
+COMMENT ON FUNCTION public.mv_pillarname_project() IS 'Trigger maintaining the PillarName table';
+
+
+CREATE FUNCTION public.mv_pofiletranslator_translationmessage() RETURNS trigger
+    LANGUAGE plpgsql SECURITY DEFINER
+    SET search_path TO 'public'
+    AS $$
+BEGIN
+    -- Update any existing entries.
+    UPDATE POFileTranslator
+    SET date_last_touched = CURRENT_TIMESTAMP AT TIME ZONE 'UTC'
+    FROM POFile, TranslationTemplateItem
+    WHERE person = NEW.submitter AND
+        TranslationTemplateItem.potmsgset = NEW.potmsgset AND
+        TranslationTemplateItem.potemplate = POFile.potemplate AND
+        POFile.language = NEW.language AND
+        POFileTranslator.pofile = POFile.id;
+
+    -- Insert any missing entries.
+    INSERT INTO POFileTranslator (person, pofile)
+    SELECT DISTINCT NEW.submitter, POFile.id
+    FROM TranslationTemplateItem
+    JOIN POFile ON
+        POFile.language = NEW.language AND
+        POFile.potemplate = TranslationTemplateItem.potemplate
+    WHERE
+        TranslationTemplateItem.potmsgset = NEW.potmsgset AND
+        NOT EXISTS (
+            SELECT *
+            FROM POFileTranslator
+            WHERE person = NEW.submitter AND pofile = POFile.id
+        );
+    RETURN NULL;
+END;
+$$;
+
+
+COMMENT ON FUNCTION public.mv_pofiletranslator_translationmessage() IS 'Trigger maintaining the POFileTranslator table';
+
+
+CREATE FUNCTION public.mv_validpersonorteamcache_emailaddress() RETURNS trigger
     LANGUAGE plpythonu SECURITY DEFINER
     AS $_$
     # This trigger function keeps the ValidPersonOrTeamCache materialized
@@ -2258,10 +2238,10 @@
 $_$;
 
 
-COMMENT ON FUNCTION mv_validpersonorteamcache_emailaddress() IS 'A trigger for maintaining the ValidPersonOrTeamCache eager materialized view when changes are made to the EmailAddress table';
-
-
-CREATE FUNCTION mv_validpersonorteamcache_person() RETURNS trigger
+COMMENT ON FUNCTION public.mv_validpersonorteamcache_emailaddress() IS 'A trigger for maintaining the ValidPersonOrTeamCache eager materialized view when changes are made to the EmailAddress table';
+
+
+CREATE FUNCTION public.mv_validpersonorteamcache_person() RETURNS trigger
     LANGUAGE plpythonu SECURITY DEFINER
     AS $_$
     # This trigger function could be simplified by simply issuing
@@ -2322,12 +2302,12 @@
 $_$;
 
 
-COMMENT ON FUNCTION mv_validpersonorteamcache_person() IS 'A trigger for maintaining the ValidPersonOrTeamCache eager materialized view when changes are made to the Person table';
-
-
-CREATE FUNCTION name_blacklist_match(text, integer) RETURNS integer
+COMMENT ON FUNCTION public.mv_validpersonorteamcache_person() IS 'A trigger for maintaining the ValidPersonOrTeamCache eager materialized view when changes are made to the Person table';
+
+
+CREATE FUNCTION public.name_blacklist_match(text, integer) RETURNS integer
     LANGUAGE plpythonu STABLE STRICT SECURITY DEFINER
-    SET search_path TO public
+    SET search_path TO 'public'
     AS $_$
     import re
     name = args[0].decode("UTF-8")
@@ -2396,10 +2376,10 @@
 $_$;
 
 
-COMMENT ON FUNCTION name_blacklist_match(text, integer) IS 'Return the id of the row in the NameBlacklist table that matches the given name, or NULL if no regexps in the NameBlacklist table match.';
-
-
-CREATE FUNCTION null_count(p_values anyarray) RETURNS integer
+COMMENT ON FUNCTION public.name_blacklist_match(text, integer) IS 'Return the id of the row in the NameBlacklist table that matches the given name, or NULL if no regexps in the NameBlacklist table match.';
+
+
+CREATE FUNCTION public.null_count(p_values anyarray) RETURNS integer
     LANGUAGE plpgsql IMMUTABLE STRICT
     AS $$
 DECLARE
@@ -2416,10 +2396,10 @@
 $$;
 
 
-COMMENT ON FUNCTION null_count(p_values anyarray) IS 'Return the number of NULLs in the first row of the given array.';
-
-
-CREATE FUNCTION packageset_deleted_trig() RETURNS trigger
+COMMENT ON FUNCTION public.null_count(p_values anyarray) IS 'Return the number of NULLs in the first row of the given array.';
+
+
+CREATE FUNCTION public.packageset_deleted_trig() RETURNS trigger
     LANGUAGE plpgsql
     AS $$
 BEGIN
@@ -2436,10 +2416,10 @@
 $$;
 
 
-COMMENT ON FUNCTION packageset_deleted_trig() IS 'Remove any DAG edges leading to/from the deleted package set.';
-
-
-CREATE FUNCTION packageset_inserted_trig() RETURNS trigger
+COMMENT ON FUNCTION public.packageset_deleted_trig() IS 'Remove any DAG edges leading to/from the deleted package set.';
+
+
+CREATE FUNCTION public.packageset_inserted_trig() RETURNS trigger
     LANGUAGE plpgsql
     AS $$
 BEGIN
@@ -2453,10 +2433,10 @@
 $$;
 
 
-COMMENT ON FUNCTION packageset_inserted_trig() IS 'Insert self-referencing DAG edge when a new package set is inserted.';
-
-
-CREATE FUNCTION packagesetinclusion_deleted_trig() RETURNS trigger
+COMMENT ON FUNCTION public.packageset_inserted_trig() IS 'Insert self-referencing DAG edge when a new package set is inserted.';
+
+
+CREATE FUNCTION public.packagesetinclusion_deleted_trig() RETURNS trigger
     LANGUAGE plpgsql
     AS $$
 BEGIN
@@ -2524,10 +2504,10 @@
 $$;
 
 
-COMMENT ON FUNCTION packagesetinclusion_deleted_trig() IS 'Maintain the transitive closure in the DAG when an edge leading to/from a package set is deleted.';
-
-
-CREATE FUNCTION packagesetinclusion_inserted_trig() RETURNS trigger
+COMMENT ON FUNCTION public.packagesetinclusion_deleted_trig() IS 'Maintain the transitive closure in the DAG when an edge leading to/from a package set is deleted.';
+
+
+CREATE FUNCTION public.packagesetinclusion_inserted_trig() RETURNS trigger
     LANGUAGE plpgsql
     AS $$
 BEGIN
@@ -2598,10 +2578,10 @@
 $$;
 
 
-COMMENT ON FUNCTION packagesetinclusion_inserted_trig() IS 'Maintain the transitive closure in the DAG for a newly inserted edge leading to/from a package set.';
-
-
-CREATE FUNCTION person_sort_key(displayname text, name text) RETURNS text
+COMMENT ON FUNCTION public.packagesetinclusion_inserted_trig() IS 'Maintain the transitive closure in the DAG for a newly inserted edge leading to/from a package set.';
+
+
+CREATE FUNCTION public.person_sort_key(displayname text, name text) RETURNS text
     LANGUAGE plpythonu IMMUTABLE STRICT
     AS $$
     # NB: If this implementation is changed, the person_sort_idx needs to be
@@ -2623,32 +2603,17 @@
 $$;
 
 
-COMMENT ON FUNCTION person_sort_key(displayname text, name text) IS 'Return a string suitable for sorting people on, generated by stripping noise out of displayname and concatenating name';
-
-
-CREATE FUNCTION pgstattuple(text) RETURNS pgstattuple_type
-    LANGUAGE c STRICT
-    AS '$libdir/pgstattuple', 'pgstattuple';
-
-
-CREATE FUNCTION pgstattuple(oid) RETURNS pgstattuple_type
-    LANGUAGE c STRICT
-    AS '$libdir/pgstattuple', 'pgstattuplebyid';
-
-
-CREATE FUNCTION plpgsql_call_handler() RETURNS language_handler
+COMMENT ON FUNCTION public.person_sort_key(displayname text, name text) IS 'Return a string suitable for sorting people on, generated by stripping noise out of displayname and concatenating name';
+
+
+CREATE FUNCTION public.plpgsql_call_handler() RETURNS language_handler
     LANGUAGE c
     AS '$libdir/plpgsql', 'plpgsql_call_handler';
 
 
-CREATE FUNCTION plpython_call_handler() RETURNS language_handler
-    LANGUAGE c
-    AS '$libdir/plpython', 'plpython_call_handler';
-
-
-CREATE FUNCTION questionmessage_copy_owner_from_message() RETURNS trigger
+CREATE FUNCTION public.questionmessage_copy_owner_from_message() RETURNS trigger
     LANGUAGE plpgsql SECURITY DEFINER
-    SET search_path TO public
+    SET search_path TO 'public'
     AS $$
 BEGIN
     IF TG_OP = 'INSERT' THEN
@@ -2671,12 +2636,12 @@
 $$;
 
 
-COMMENT ON FUNCTION questionmessage_copy_owner_from_message() IS 'Copies the message owner into QuestionMessage when QuestionMessage changes.';
-
-
-CREATE FUNCTION replication_lag() RETURNS interval
+COMMENT ON FUNCTION public.questionmessage_copy_owner_from_message() IS 'Copies the message owner into QuestionMessage when QuestionMessage changes.';
+
+
+CREATE FUNCTION public.replication_lag() RETURNS interval
     LANGUAGE plpgsql STABLE SECURITY DEFINER
-    SET search_path TO public
+    SET search_path TO 'public'
     AS $$
     DECLARE
         v_lag interval;
@@ -2693,12 +2658,12 @@
 $$;
 
 
-COMMENT ON FUNCTION replication_lag() IS 'Returns the worst lag time in our cluster, or NULL if not a replicated installation. Only returns meaningful results on the lpmain replication set master.';
-
-
-CREATE FUNCTION replication_lag(node_id integer) RETURNS interval
+COMMENT ON FUNCTION public.replication_lag() IS 'Returns the worst lag time in our cluster, or NULL if not a replicated installation. Only returns meaningful results on the lpmain replication set master.';
+
+
+CREATE FUNCTION public.replication_lag(node_id integer) RETURNS interval
     LANGUAGE plpgsql STABLE SECURITY DEFINER
-    SET search_path TO public
+    SET search_path TO 'public'
     AS $$
     DECLARE
         v_lag interval;
@@ -2717,10 +2682,10 @@
 $$;
 
 
-COMMENT ON FUNCTION replication_lag(node_id integer) IS 'Returns the lag time of the lpmain replication set to the given node, or NULL if not a replicated installation. The node id parameter can be obtained by calling getlocalnodeid() on the relevant database. This function only returns meaningful results on the lpmain replication set master.';
-
-
-CREATE FUNCTION sane_version(text) RETURNS boolean
+COMMENT ON FUNCTION public.replication_lag(node_id integer) IS 'Returns the lag time of the lpmain replication set to the given node, or NULL if not a replicated installation. The node id parameter can be obtained by calling getlocalnodeid() on the relevant database. This function only returns meaningful results on the lpmain replication set master.';
+
+
+CREATE FUNCTION public.sane_version(text) RETURNS boolean
     LANGUAGE plpythonu IMMUTABLE STRICT
     AS $_$
     import re
@@ -2733,12 +2698,12 @@
 $_$;
 
 
-COMMENT ON FUNCTION sane_version(text) IS 'A sane version number for use by ProductRelease and DistroRelease. We may make it less strict if required, but it would be nice if we can enforce simple version strings because we use them in URLs';
-
-
-CREATE FUNCTION set_bug_date_last_message() RETURNS trigger
+COMMENT ON FUNCTION public.sane_version(text) IS 'A sane version number for use by ProductRelease and DistroRelease. We may make it less strict if required, but it would be nice if we can enforce simple version strings because we use them in URLs';
+
+
+CREATE FUNCTION public.set_bug_date_last_message() RETURNS trigger
     LANGUAGE plpgsql SECURITY DEFINER
-    SET search_path TO public
+    SET search_path TO 'public'
     AS $$
 BEGIN
     IF TG_OP = 'INSERT' THEN
@@ -2763,10 +2728,10 @@
 $$;
 
 
-COMMENT ON FUNCTION set_bug_date_last_message() IS 'AFTER INSERT trigger on BugMessage maintaining the Bug.date_last_message column';
-
-
-CREATE FUNCTION set_bug_message_count() RETURNS trigger
+COMMENT ON FUNCTION public.set_bug_date_last_message() IS 'AFTER INSERT trigger on BugMessage maintaining the Bug.date_last_message column';
+
+
+CREATE FUNCTION public.set_bug_message_count() RETURNS trigger
     LANGUAGE plpgsql
     AS $$
 BEGIN
@@ -2791,10 +2756,10 @@
 $$;
 
 
-COMMENT ON FUNCTION set_bug_message_count() IS 'AFTER UPDATE trigger on BugAffectsPerson maintaining the Bug.users_affected_count column';
-
-
-CREATE FUNCTION set_bug_number_of_duplicates() RETURNS trigger
+COMMENT ON FUNCTION public.set_bug_message_count() IS 'AFTER UPDATE trigger on BugAffectsPerson maintaining the Bug.users_affected_count column';
+
+
+CREATE FUNCTION public.set_bug_number_of_duplicates() RETURNS trigger
     LANGUAGE plpgsql
     AS $$
 BEGIN
@@ -2826,10 +2791,10 @@
 $$;
 
 
-COMMENT ON FUNCTION set_bug_number_of_duplicates() IS 'AFTER UPDATE trigger on Bug maintaining the Bug.number_of_duplicates column';
-
-
-CREATE FUNCTION set_bug_users_affected_count() RETURNS trigger
+COMMENT ON FUNCTION public.set_bug_number_of_duplicates() IS 'AFTER UPDATE trigger on Bug maintaining the Bug.number_of_duplicates column';
+
+
+CREATE FUNCTION public.set_bug_users_affected_count() RETURNS trigger
     LANGUAGE plpgsql
     AS $$
 BEGIN
@@ -2878,7 +2843,7 @@
 $$;
 
 
-CREATE FUNCTION set_bugtask_date_milestone_set() RETURNS trigger
+CREATE FUNCTION public.set_bugtask_date_milestone_set() RETURNS trigger
     LANGUAGE plpgsql
     AS $$
 BEGIN
@@ -2924,10 +2889,10 @@
 $$;
 
 
-COMMENT ON FUNCTION set_bugtask_date_milestone_set() IS 'Update BugTask.date_milestone_set when BugTask.milestone is changed.';
-
-
-CREATE FUNCTION set_date_status_set() RETURNS trigger
+COMMENT ON FUNCTION public.set_bugtask_date_milestone_set() IS 'Update BugTask.date_milestone_set when BugTask.milestone is changed.';
+
+
+CREATE FUNCTION public.set_date_status_set() RETURNS trigger
     LANGUAGE plpgsql
     AS $$
 BEGIN
@@ -2939,74 +2904,10 @@
 $$;
 
 
-COMMENT ON FUNCTION set_date_status_set() IS 'BEFORE UPDATE trigger on Account that maintains the Account.date_status_set column.';
-
-
-CREATE FUNCTION set_openid_identifier() RETURNS trigger
-    LANGUAGE plpythonu
-    AS $$
-    # If someone is trying to explicitly set the openid_identifier, let them.
-    # This also causes openid_identifiers to be left alone if this is an
-    # UPDATE trigger.
-    if TD['new']['openid_identifier'] is not None:
-        return None
-
-    from random import choice
-
-    # Non display confusing characters
-    chars = '34678bcdefhkmnprstwxyzABCDEFGHJKLMNPQRTWXY'
-
-    # character length of tokens. Can be increased, decreased or even made
-    # random - Launchpad does not care. 7 means it takes 40 bytes to store
-    # a null-terminated Launchpad identity URL on the current domain name.
-    length=7
-
-    loop_count = 0
-    while loop_count < 20000:
-        # Generate a random openid_identifier
-        oid = ''.join(choice(chars) for count in range(length))
-
-        # Check if the oid is already in the db, although this is pretty
-        # unlikely
-        rv = plpy.execute("""
-            SELECT COUNT(*) AS num FROM Person WHERE openid_identifier = '%s'
-            """ % oid, 1)
-        if rv[0]['num'] == 0:
-            TD['new']['openid_identifier'] = oid
-            return "MODIFY"
-        loop_count += 1
-        if loop_count == 1:
-            plpy.warning(
-                'Clash generating unique openid_identifier. '
-                'Increase length if you see this warning too much.')
-    plpy.error(
-        "Unable to generate unique openid_identifier. "
-        "Need to increase length of tokens.")
-$$;
-
-
-CREATE FUNCTION set_shipit_normalized_address() RETURNS trigger
-    LANGUAGE plpgsql
-    AS $$
-    BEGIN
-        NEW.normalized_address =
-            lower(
-                -- Strip off everything that's not alphanumeric
-                -- characters.
-                regexp_replace(
-                    coalesce(NEW.addressline1, '') || ' ' ||
-                    coalesce(NEW.addressline2, '') || ' ' ||
-                    coalesce(NEW.city, ''),
-                    '[^a-zA-Z0-9]+', '', 'g'));
-        RETURN NEW;
-    END;
-$$;
-
-
-COMMENT ON FUNCTION set_shipit_normalized_address() IS 'Store a normalized concatenation of the request''s address into the normalized_address column.';
-
-
-CREATE FUNCTION sha1(text) RETURNS character
+COMMENT ON FUNCTION public.set_date_status_set() IS 'BEFORE UPDATE trigger on Account that maintains the Account.date_status_set column.';
+
+
+CREATE FUNCTION public.sha1(text) RETURNS character
     LANGUAGE plpythonu IMMUTABLE STRICT
     AS $$
     import hashlib
@@ -3014,56 +2915,63 @@
 $$;
 
 
-COMMENT ON FUNCTION sha1(text) IS 'Return the SHA1 one way cryptographic hash as a string of 40 hex digits';
-
-
-CREATE FUNCTION summarise_bug(bug_row bug) RETURNS void
-    LANGUAGE plpgsql
-    AS $$
-DECLARE
-    d bugsummary%ROWTYPE;
-BEGIN
-    PERFORM ensure_bugsummary_temp_journal();
-    FOR d IN SELECT * FROM bugsummary_locations(BUG_ROW) LOOP
-        d.count = 1;
-        PERFORM bug_summary_temp_journal_ins(d);
-    END LOOP;
-END;
-$$;
-
-
-COMMENT ON FUNCTION summarise_bug(bug_row bug) IS 'AFTER summarise a bug row into bugsummary.';
-
-
-CREATE FUNCTION ulower(text) RETURNS text
+COMMENT ON FUNCTION public.sha1(text) IS 'Return the SHA1 one way cryptographic hash as a string of 40 hex digits';
+
+
+CREATE FUNCTION public.specification_denorm_access(spec_id integer) RETURNS void
+    LANGUAGE sql SECURITY DEFINER
+    SET search_path TO 'public'
+    AS $_$
+    UPDATE specification
+        SET access_policy = policies[1], access_grants = grants
+        FROM
+            build_access_cache(
+                (SELECT id FROM accessartifact WHERE specification = $1),
+                (SELECT information_type FROM specification WHERE id = $1))
+            AS (policies integer[], grants integer[])
+        WHERE id = $1;
+$_$;
+
+
+CREATE FUNCTION public.specification_maintain_access_cache_trig() RETURNS trigger
+    LANGUAGE plpgsql
+    AS $$
+BEGIN
+    PERFORM specification_denorm_access(NEW.id);
+    RETURN NULL;
+END;
+$$;
+
+
+CREATE FUNCTION public.summarise_bug(bug integer) RETURNS void
+    LANGUAGE plpgsql
+    AS $$
+BEGIN
+    PERFORM bugsummary_journal_bug(bug_row(bug), 1);
+END;
+$$;
+
+
+CREATE FUNCTION public.ulower(text) RETURNS text
     LANGUAGE plpythonu IMMUTABLE STRICT
     AS $$
     return args[0].decode('utf8').lower().encode('utf8')
 $$;
 
 
-COMMENT ON FUNCTION ulower(text) IS 'Return the lower case version of a UTF-8 encoded string.';
-
-
-CREATE FUNCTION unsummarise_bug(bug_row bug) RETURNS void
+COMMENT ON FUNCTION public.ulower(text) IS 'Return the lower case version of a UTF-8 encoded string.';
+
+
+CREATE FUNCTION public.unsummarise_bug(bug integer) RETURNS void
     LANGUAGE plpgsql
     AS $$
-DECLARE
-    d bugsummary%ROWTYPE;
 BEGIN
-    PERFORM ensure_bugsummary_temp_journal();
-    FOR d IN SELECT * FROM bugsummary_locations(BUG_ROW) LOOP
-        d.count = -1;
-        PERFORM bug_summary_temp_journal_ins(d);
-    END LOOP;
+    PERFORM bugsummary_journal_bug(bug_row(bug), -1);
 END;
 $$;
 
 
-COMMENT ON FUNCTION unsummarise_bug(bug_row bug) IS 'AFTER unsummarise a bug row from bugsummary.';
-
-
-CREATE FUNCTION update_branch_name_cache() RETURNS trigger
+CREATE FUNCTION public.update_branch_name_cache() RETURNS trigger
     LANGUAGE plpgsql
     AS $$
 DECLARE
@@ -3075,7 +2983,7 @@
         OR NEW.unique_name IS NULL
         OR OLD.owner_name <> NEW.owner_name
         OR OLD.unique_name <> NEW.unique_name
-        OR (NEW.target_suffix IS NULL <> OLD.target_suffix IS NULL)
+        OR ((NEW.target_suffix IS NULL) <> (OLD.target_suffix IS NULL))
         OR COALESCE(OLD.target_suffix, '') <> COALESCE(NEW.target_suffix, '')
         OR OLD.name <> NEW.name
         OR OLD.owner <> NEW.owner
@@ -3111,12 +3019,12 @@
 $$;
 
 
-COMMENT ON FUNCTION update_branch_name_cache() IS 'Maintain the cached name columns in Branch.';
-
-
-CREATE FUNCTION update_database_disk_utilization() RETURNS void
+COMMENT ON FUNCTION public.update_branch_name_cache() IS 'Maintain the cached name columns in Branch.';
+
+
+CREATE FUNCTION public.update_database_disk_utilization() RETURNS void
     LANGUAGE sql SECURITY DEFINER
-    SET search_path TO public
+    SET search_path TO 'public'
     AS $$
     INSERT INTO DatabaseDiskUtilization
     SELECT
@@ -3136,6 +3044,7 @@
         (stat).free_space,
         (stat).free_percent
     FROM (
+        -- Tables
         SELECT
             pg_namespace.nspname AS namespace,
             pg_class.relname AS name,
@@ -3151,6 +3060,7 @@
 
         UNION ALL
         
+        -- Indexes
         SELECT
             pg_namespace_table.nspname AS namespace,
             pg_class_table.relname AS name,
@@ -3163,12 +3073,15 @@
             pg_namespace AS pg_namespace_index,
             pg_class AS pg_class_table,
             pg_class AS pg_class_index,
-            pg_index
+            pg_index,
+            pg_am
         WHERE
             pg_class_index.relkind = 'i'
+            AND pg_am.amname <> 'gin' -- pgstattuple doesn't support GIN
             AND pg_table_is_visible(pg_class_table.oid)
             AND pg_class_index.relnamespace = pg_namespace_index.oid
             AND pg_class_table.relnamespace = pg_namespace_table.oid
+            AND pg_class_index.relam = pg_am.oid
             AND pg_index.indexrelid = pg_class_index.oid
             AND pg_index.indrelid = pg_class_table.oid
 
@@ -3208,20 +3121,22 @@
             pg_namespace AS pg_namespace_index,
             pg_class AS pg_class_table,
             pg_class AS pg_class_index,
-            pg_class AS pg_class_toast
+            pg_class AS pg_class_toast,
+            pg_index
         WHERE
             pg_class_table.relnamespace = pg_namespace_table.oid
             AND pg_table_is_visible(pg_class_table.oid)
             AND pg_class_index.relnamespace = pg_namespace_index.oid
             AND pg_class_table.reltoastrelid = pg_class_toast.oid
-            AND pg_class_index.oid = pg_class_toast.reltoastidxid
+            AND pg_class_index.oid = pg_index.indexrelid
+            AND pg_index.indrelid = pg_class_toast.oid
         ) AS whatever;
 $$;
 
 
-CREATE FUNCTION update_database_stats() RETURNS void
+CREATE FUNCTION public.update_database_stats() RETURNS void
     LANGUAGE plpythonu SECURITY DEFINER
-    SET search_path TO public
+    SET search_path TO 'public'
     AS $_$
     import re
     import subprocess
@@ -3306,12 +3221,12 @@
 $_$;
 
 
-COMMENT ON FUNCTION update_database_stats() IS 'Copies rows from pg_stat_user_tables into DatabaseTableStats. We use a stored procedure because it is problematic for us to grant permissions on objects in the pg_catalog schema.';
-
-
-CREATE FUNCTION update_replication_lag_cache() RETURNS boolean
+COMMENT ON FUNCTION public.update_database_stats() IS 'Copies rows from pg_stat_user_tables into DatabaseTableStats. We use a stored procedure because it is problematic for us to grant permissions on objects in the pg_catalog schema.';
+
+
+CREATE FUNCTION public.update_replication_lag_cache() RETURNS boolean
     LANGUAGE plpgsql SECURITY DEFINER
-    SET search_path TO public
+    SET search_path TO 'public'
     AS $$
     BEGIN
         DELETE FROM DatabaseReplicationLag;
@@ -3329,64 +3244,10 @@
 $$;
 
 
-COMMENT ON FUNCTION update_replication_lag_cache() IS 'Updates the DatabaseReplicationLag materialized view.';
-
-
-CREATE FUNCTION update_transitively_private(start_branch integer, _root_branch integer DEFAULT NULL::integer, _root_transitively_private boolean DEFAULT NULL::boolean) RETURNS void
-    LANGUAGE plpgsql SECURITY DEFINER
-    SET search_path TO public
-    AS $$
-DECLARE
-    root_transitively_private boolean := _root_transitively_private;
-    root_branch int := _root_branch;
-BEGIN
-    IF root_transitively_private IS NULL THEN
-        -- We can't just trust the transitively_private flag of the
-        -- branch we are stacked on, as if we are updating multiple
-        -- records they will be updated in an indeterminate order.
-        -- We need a recursive query.
-        UPDATE Branch SET transitively_private = (
-            WITH RECURSIVE stacked_branches AS (
-                SELECT
-                    top_branch.id, top_branch.stacked_on, top_branch.private
-                FROM Branch AS top_branch
-                WHERE top_branch.id = start_branch
-                UNION ALL
-                SELECT
-                    sub_branch.id, sub_branch.stacked_on, sub_branch.private
-                FROM stacked_branches, Branch AS sub_branch
-                WHERE
-                    stacked_branches.stacked_on = sub_branch.id
-                    AND stacked_branches.stacked_on != start_branch
-                    -- Shortcircuit. No need to recurse if already private.
-                    AND stacked_branches.private IS FALSE
-                    )
-            SELECT COUNT(*) > 0
-            FROM stacked_branches
-            WHERE private IS TRUE)
-        WHERE Branch.id = start_branch
-        RETURNING transitively_private INTO root_transitively_private;
-        root_branch := start_branch;
-    ELSE
-        -- Now we have calculated the correct transitively_private flag
-        -- we can trust it.
-        UPDATE Branch SET
-            transitively_private = GREATEST(private, root_transitively_private)
-        WHERE id = root_branch;
-    END IF;
-
-    -- Recurse to branches stacked on this one.
-    PERFORM update_transitively_private(
-        start_branch, id, GREATEST(private, root_transitively_private))
-    FROM Branch WHERE stacked_on = root_branch AND id != start_branch;
-END;
-$$;
-
-
-COMMENT ON FUNCTION update_transitively_private(start_branch integer, _root_branch integer, _root_transitively_private boolean) IS 'A branch is transitively private if it is private or is stacked on any transitively private branches.';
-
-
-CREATE FUNCTION valid_absolute_url(text) RETURNS boolean
+COMMENT ON FUNCTION public.update_replication_lag_cache() IS 'Updates the DatabaseReplicationLag materialized view.';
+
+
+CREATE FUNCTION public.valid_absolute_url(text) RETURNS boolean
     LANGUAGE plpythonu IMMUTABLE STRICT
     AS $$
     from urlparse import urlparse, uses_netloc
@@ -3403,10 +3264,10 @@
 $$;
 
 
-COMMENT ON FUNCTION valid_absolute_url(text) IS 'Ensure the given test is a valid absolute URL, containing both protocol and network location';
-
-
-CREATE FUNCTION valid_branch_name(text) RETURNS boolean
+COMMENT ON FUNCTION public.valid_absolute_url(text) IS 'Ensure the given test is a valid absolute URL, containing both protocol and network location';
+
+
+CREATE FUNCTION public.valid_branch_name(text) RETURNS boolean
     LANGUAGE plpythonu IMMUTABLE STRICT
     AS $$
     import re
@@ -3418,27 +3279,27 @@
 $$;
 
 
-COMMENT ON FUNCTION valid_branch_name(text) IS 'validate a branch name.
+COMMENT ON FUNCTION public.valid_branch_name(text) IS 'validate a branch name.
 
     As per valid_name, except we allow uppercase and @';
 
 
-CREATE FUNCTION valid_cve(text) RETURNS boolean
+CREATE FUNCTION public.valid_cve(text) RETURNS boolean
     LANGUAGE plpythonu IMMUTABLE STRICT
     AS $_$
     import re
     name = args[0]
-    pat = r"^(19|20)\d{2}-\d{4}$"
+    pat = r"^(19|20)\d{2}-\d{4,}$"
     if re.match(pat, name):
         return 1
     return 0
 $_$;
 
 
-COMMENT ON FUNCTION valid_cve(text) IS 'validate a common vulnerability number as defined on www.cve.mitre.org, minus the CAN- or CVE- prefix.';
-
-
-CREATE FUNCTION valid_debian_version(text) RETURNS boolean
+COMMENT ON FUNCTION public.valid_cve(text) IS 'validate a common vulnerability number as defined on www.cve.mitre.org, minus the CAN- or CVE- prefix.';
+
+
+CREATE FUNCTION public.valid_debian_version(text) RETURNS boolean
     LANGUAGE plpythonu IMMUTABLE STRICT
     AS $_$
     import re
@@ -3462,10 +3323,10 @@
 $_$;
 
 
-COMMENT ON FUNCTION valid_debian_version(text) IS 'validate a version number as per Debian Policy';
-
-
-CREATE FUNCTION valid_fingerprint(text) RETURNS boolean
+COMMENT ON FUNCTION public.valid_debian_version(text) IS 'validate a version number as per Debian Policy';
+
+
+CREATE FUNCTION public.valid_fingerprint(text) RETURNS boolean
     LANGUAGE plpythonu IMMUTABLE STRICT
     AS $$
     import re
@@ -3476,10 +3337,27 @@
 $$;
 
 
-COMMENT ON FUNCTION valid_fingerprint(text) IS 'Returns true if passed a valid GPG fingerprint. Valid GPG fingerprints are a 40 character long hexadecimal number in uppercase.';
-
-
-CREATE FUNCTION valid_keyid(text) RETURNS boolean
+COMMENT ON FUNCTION public.valid_fingerprint(text) IS 'Returns true if passed a valid GPG fingerprint. Valid GPG fingerprints are a 40 character long hexadecimal number in uppercase.';
+
+
+CREATE FUNCTION public.valid_git_repository_name(text) RETURNS boolean
+    LANGUAGE plpythonu IMMUTABLE STRICT
+    AS $$
+    import re
+    name = args[0]
+    pat = r"^(?i)[a-z0-9][a-z0-9+\.\-@_]*\Z"
+    if not name.endswith(".git") and re.match(pat, name):
+        return 1
+    return 0
+$$;
+
+
+COMMENT ON FUNCTION public.valid_git_repository_name(text) IS 'validate a Git repository name.
+
+    As per valid_branch_name, except we disallow names ending in ".git".';
+
+
+CREATE FUNCTION public.valid_keyid(text) RETURNS boolean
     LANGUAGE plpythonu IMMUTABLE STRICT
     AS $$
     import re
@@ -3490,10 +3368,10 @@
 $$;
 
 
-COMMENT ON FUNCTION valid_keyid(text) IS 'Returns true if passed a valid GPG keyid. Valid GPG keyids are an 8 character long hexadecimal number in uppercase (in reality, they are 16 characters long but we are using the ''common'' definition.';
-
-
-CREATE FUNCTION valid_regexp(text) RETURNS boolean
+COMMENT ON FUNCTION public.valid_keyid(text) IS 'Returns true if passed a valid GPG keyid. Valid GPG keyids are an 8 character long hexadecimal number in uppercase (in reality, they are 16 characters long but we are using the ''common'' definition.';
+
+
+CREATE FUNCTION public.valid_regexp(text) RETURNS boolean
     LANGUAGE plpythonu IMMUTABLE STRICT
     AS $$
     import re
@@ -3506,10 +3384,10 @@
 $$;
 
 
-COMMENT ON FUNCTION valid_regexp(text) IS 'Returns true if the input can be compiled as a regular expression.';
-
-
-CREATE FUNCTION version_sort_key(version text) RETURNS text
+COMMENT ON FUNCTION public.valid_regexp(text) IS 'Returns true if the input can be compiled as a regular expression.';
+
+
+CREATE FUNCTION public.version_sort_key(version text) RETURNS text
     LANGUAGE plpythonu IMMUTABLE STRICT
     AS $$
     # If this method is altered, then any functional indexes using it
@@ -3529,10 +3407,10 @@
 $$;
 
 
-COMMENT ON FUNCTION version_sort_key(version text) IS 'Sort a field as version numbers that do not necessarily conform to debian package versions (For example, when "2-2" should be considered greater than "1:1"). debversion_sort_key() should be used for debian versions. Numbers will be sorted after letters unlike typical ASCII, so that a descending sort will put the latest version number that starts with a number instead of a letter will be at the top. E.g. ascending is [a, z, 1, 9] and descending is [9, 1, z, a].';
-
-
-CREATE FUNCTION you_are_your_own_member() RETURNS trigger
+COMMENT ON FUNCTION public.version_sort_key(version text) IS 'Sort a field as version numbers that do not necessarily conform to debian package versions (For example, when "2-2" should be considered greater than "1:1"). debversion_sort_key() should be used for debian versions. Numbers will be sorted after letters unlike typical ASCII, so that a descending sort will put the latest version number that starts with a number instead of a letter will be at the top. E.g. ascending is [a, z, 1, 9] and descending is [9, 1, z, a].';
+
+
+CREATE FUNCTION public.you_are_your_own_member() RETURNS trigger
     LANGUAGE plpgsql
     AS $$
     BEGIN
@@ -3543,873 +3421,116 @@
 $$;
 
 
-COMMENT ON FUNCTION you_are_your_own_member() IS 'Trigger function to ensure that every row added to the Person table gets a corresponding row in the TeamParticipation table, as per the TeamParticipationUsage page on the Launchpad wiki';
-
-
-SET search_path = ts2, pg_catalog;
-
-CREATE FUNCTION _ftq(text) RETURNS text
-    LANGUAGE plpythonu IMMUTABLE STRICT
-    AS $_$
-        import re
-
-        # I think this method would be more robust if we used a real
-        # tokenizer and parser to generate the query string, but we need
-        # something suitable for use as a stored procedure which currently
-        # means no external dependancies.
-
-        # Convert to Unicode
-        query = args[0].decode('utf8')
-        ## plpy.debug('1 query is %s' % repr(query))
-
-        # Normalize whitespace
-        query = re.sub("(?u)\s+"," ", query)
-
-        # Convert AND, OR, NOT and - to tsearch2 punctuation
-        query = re.sub(r"(?u)(?:^|\s)-([\w\(])", r" !\1", query)
-        query = re.sub(r"(?u)\bAND\b", "&", query)
-        query = re.sub(r"(?u)\bOR\b", "|", query)
-        query = re.sub(r"(?u)\bNOT\b", " !", query)
-        ## plpy.debug('2 query is %s' % repr(query))
-
-        # Deal with unwanted punctuation. We convert strings of punctuation
-        # inside words to a '-' character for the hypenation handling below
-        # to deal with further. Outside of words we replace with whitespace.
-        # We don't mess with -&|!()' as they are handled later.
-        #punctuation = re.escape(r'`~@#$%^*+=[]{}:;"<>,.?\/')
-        punctuation = r"[^\w\s\-\&\|\!\(\)']"
-        query = re.sub(r"(?u)(\w)%s+(\w)" % (punctuation,), r"\1-\2", query)
-        query = re.sub(r"(?u)%s+" % (punctuation,), " ", query)
-        ## plpy.debug('3 query is %s' % repr(query))
-
-        # Strip ! characters inside and at the end of a word
-        query = re.sub(r"(?u)(?<=\w)[\!]+", " ", query)
-
-        # Now that we have handle case sensitive booleans, convert to lowercase
-        query = query.lower()
-
-        # Convert foo-bar to ((foo&bar)|foobar) and foo-bar-baz to
-        # ((foo&bar&baz)|foobarbaz)
-        def hyphen_repl(match):
-            bits = match.group(0).split("-")
-            return "((%s)|%s)" % ("&".join(bits), "".join(bits))
-        query = re.sub(r"(?u)\b\w+-[\w\-]+\b", hyphen_repl, query)
-        ## plpy.debug('4 query is %s' % repr(query))
-
-        # Any remaining - characters are spurious
-        query = query.replace('-','')
-
-        # Remove unpartnered bracket on the left and right
-        query = re.sub(r"(?ux) ^ ( [^(]* ) \)", r"(\1)", query)
-        query = re.sub(r"(?ux) \( ( [^)]* ) $", r"(\1)", query)
-
-        # Remove spurious brackets
-        query = re.sub(r"(?u)\(([^\&\|]*?)\)", r" \1 ", query)
-        ## plpy.debug('5 query is %s' % repr(query))
-
-        # Insert & between tokens without an existing boolean operator
-        # ( not proceeded by (|&!
-        query = re.sub(r"(?u)(?<![\(\|\&\!])\s*\(", "&(", query)
-        ## plpy.debug('6 query is %s' % repr(query))
-        # ) not followed by )|&
-        query = re.sub(r"(?u)\)(?!\s*(\)|\||\&|\s*$))", ")&", query)
-        ## plpy.debug('6.1 query is %s' % repr(query))
-        # Whitespace not proceded by (|&! not followed by &|
-        query = re.sub(r"(?u)(?<![\(\|\&\!\s])\s+(?![\&\|\s])", "&", query)
-        ## plpy.debug('7 query is %s' % repr(query))
-
-        # Detect and repair syntax errors - we are lenient because
-        # this input is generally from users.
-
-        # Fix unbalanced brackets
-        openings = query.count("(")
-        closings = query.count(")")
-        if openings > closings:
-            query = query + " ) "*(openings-closings)
-        elif closings > openings:
-            query = " ( "*(closings-openings) + query
-        ## plpy.debug('8 query is %s' % repr(query))
-
-        # Strip ' character that do not have letters on both sides
-        query = re.sub(r"(?u)((?<!\w)'|'(?!\w))", "", query)
-
-        # Brackets containing nothing but whitespace and booleans, recursive
-        last = ""
-        while last != query:
-            last = query
-            query = re.sub(r"(?u)\([\s\&\|\!]*\)", "", query)
-        ## plpy.debug('9 query is %s' % repr(query))
-
-        # An & or | following a (
-        query = re.sub(r"(?u)(?<=\()[\&\|\s]+", "", query)
-        ## plpy.debug('10 query is %s' % repr(query))
-
-        # An &, | or ! immediatly before a )
-        query = re.sub(r"(?u)[\&\|\!\s]*[\&\|\!]+\s*(?=\))", "", query)
-        ## plpy.debug('11 query is %s' % repr(query))
-
-        # An &,| or ! followed by another boolean.
-        query = re.sub(r"(?ux) \s* ( [\&\|\!] ) [\s\&\|]+", r"\1", query)
-        ## plpy.debug('12 query is %s' % repr(query))
-
-        # Leading & or |
-        query = re.sub(r"(?u)^[\s\&\|]+", "", query)
-        ## plpy.debug('13 query is %s' % repr(query))
-
-        # Trailing &, | or !
-        query = re.sub(r"(?u)[\&\|\!\s]+$", "", query)
-        ## plpy.debug('14 query is %s' % repr(query))
-
-        # If we have nothing but whitespace and tsearch2 operators,
-        # return NULL.
-        if re.search(r"(?u)^[\&\|\!\s\(\)]*$", query) is not None:
-            return None
-
-        # Convert back to UTF-8
-        query = query.encode('utf8')
-        ## plpy.debug('15 query is %s' % repr(query))
-        
-        return query or None
-        $_$;
-
-
-CREATE FUNCTION _get_parser_from_curcfg() RETURNS text
-    LANGUAGE sql IMMUTABLE STRICT
-    AS $$select prsname::text from pg_catalog.pg_ts_parser p join pg_ts_config c on cfgparser = p.oid where c.oid = show_curcfg();$$;
-
-
-CREATE FUNCTION concat(pg_catalog.tsvector, pg_catalog.tsvector) RETURNS pg_catalog.tsvector
-    LANGUAGE internal IMMUTABLE STRICT
-    AS $$tsvector_concat$$;
-
-
-CREATE FUNCTION dex_init(internal) RETURNS internal
-    LANGUAGE c
-    AS '$libdir/tsearch2', 'tsa_dex_init';
-
-
-CREATE FUNCTION dex_lexize(internal, internal, integer) RETURNS internal
-    LANGUAGE c STRICT
-    AS '$libdir/tsearch2', 'tsa_dex_lexize';
-
-
-CREATE FUNCTION ftiupdate() RETURNS trigger
-    LANGUAGE plpythonu
-    AS $_$
-    new = TD["new"]
-    args = TD["args"][:]
-
-    # Short circuit if none of the relevant columns have been
-    # modified and fti is not being set to NULL (setting the fti
-    # column to NULL is thus how we can force a rebuild of the fti
-    # column).
-    if TD["event"] == "UPDATE" and new["fti"] != None:
-        old = TD["old"]
-        relevant_modification = False
-        for column_name in args[::2]:
-            if new[column_name] != old[column_name]:
-                relevant_modification = True
-                break
-        if not relevant_modification:
-            return "OK"
-
-    # Generate an SQL statement that turns the requested
-    # column values into a weighted tsvector
-    sql = []
-    for i in range(0, len(args), 2):
-        sql.append(
-                "ts2.setweight(ts2.to_tsvector('default', coalesce("
-                "substring(ltrim($%d) from 1 for 2500),'')),"
-                "CAST($%d AS \"char\"))" % (i + 1, i + 2))
-        args[i] = new[args[i]]
-
-    sql = "SELECT %s AS fti" % "||".join(sql)
-
-    # Execute and store in the fti column
-    plan = plpy.prepare(sql, ["text", "char"] * (len(args)/2))
-    new["fti"] = plpy.execute(plan, args, 1)[0]["fti"]
-
-    # Tell PostgreSQL we have modified the data
-    return "MODIFY"
-$_$;
-
-
-COMMENT ON FUNCTION ftiupdate() IS 'Trigger function that keeps the fti tsvector column up to date.';
-
-
-CREATE FUNCTION ftq(text) RETURNS pg_catalog.tsquery
-    LANGUAGE plpythonu IMMUTABLE STRICT
-    AS $_$
-        import re
-
-        # I think this method would be more robust if we used a real
-        # tokenizer and parser to generate the query string, but we need
-        # something suitable for use as a stored procedure which currently
-        # means no external dependancies.
-
-        # Convert to Unicode
-        query = args[0].decode('utf8')
-        ## plpy.debug('1 query is %s' % repr(query))
-
-        # Normalize whitespace
-        query = re.sub("(?u)\s+"," ", query)
-
-        # Convert AND, OR, NOT and - to tsearch2 punctuation
-        query = re.sub(r"(?u)(?:^|\s)-([\w\(])", r" !\1", query)
-        query = re.sub(r"(?u)\bAND\b", "&", query)
-        query = re.sub(r"(?u)\bOR\b", "|", query)
-        query = re.sub(r"(?u)\bNOT\b", " !", query)
-        ## plpy.debug('2 query is %s' % repr(query))
-
-        # Deal with unwanted punctuation. We convert strings of punctuation
-        # inside words to a '-' character for the hypenation handling below
-        # to deal with further. Outside of words we replace with whitespace.
-        # We don't mess with -&|!()' as they are handled later.
-        #punctuation = re.escape(r'`~@#$%^*+=[]{}:;"<>,.?\/')
-        punctuation = r"[^\w\s\-\&\|\!\(\)']"
-        query = re.sub(r"(?u)(\w)%s+(\w)" % (punctuation,), r"\1-\2", query)
-        query = re.sub(r"(?u)%s+" % (punctuation,), " ", query)
-        ## plpy.debug('3 query is %s' % repr(query))
-
-        # Strip ! characters inside and at the end of a word
-        query = re.sub(r"(?u)(?<=\w)[\!]+", " ", query)
-
-        # Now that we have handle case sensitive booleans, convert to lowercase
-        query = query.lower()
-
-        # Convert foo-bar to ((foo&bar)|foobar) and foo-bar-baz to
-        # ((foo&bar&baz)|foobarbaz)
-        def hyphen_repl(match):
-            bits = match.group(0).split("-")
-            return "((%s)|%s)" % ("&".join(bits), "".join(bits))
-        query = re.sub(r"(?u)\b\w+-[\w\-]+\b", hyphen_repl, query)
-        ## plpy.debug('4 query is %s' % repr(query))
-
-        # Any remaining - characters are spurious
-        query = query.replace('-','')
-
-        # Remove unpartnered bracket on the left and right
-        query = re.sub(r"(?ux) ^ ( [^(]* ) \)", r"(\1)", query)
-        query = re.sub(r"(?ux) \( ( [^)]* ) $", r"(\1)", query)
-
-        # Remove spurious brackets
-        query = re.sub(r"(?u)\(([^\&\|]*?)\)", r" \1 ", query)
-        ## plpy.debug('5 query is %s' % repr(query))
-
-        # Insert & between tokens without an existing boolean operator
-        # ( not proceeded by (|&!
-        query = re.sub(r"(?u)(?<![\(\|\&\!])\s*\(", "&(", query)
-        ## plpy.debug('6 query is %s' % repr(query))
-        # ) not followed by )|&
-        query = re.sub(r"(?u)\)(?!\s*(\)|\||\&|\s*$))", ")&", query)
-        ## plpy.debug('6.1 query is %s' % repr(query))
-        # Whitespace not proceded by (|&! not followed by &|
-        query = re.sub(r"(?u)(?<![\(\|\&\!\s])\s+(?![\&\|\s])", "&", query)
-        ## plpy.debug('7 query is %s' % repr(query))
-
-        # Detect and repair syntax errors - we are lenient because
-        # this input is generally from users.
-
-        # Fix unbalanced brackets
-        openings = query.count("(")
-        closings = query.count(")")
-        if openings > closings:
-            query = query + " ) "*(openings-closings)
-        elif closings > openings:
-            query = " ( "*(closings-openings) + query
-        ## plpy.debug('8 query is %s' % repr(query))
-
-        # Strip ' character that do not have letters on both sides
-        query = re.sub(r"(?u)((?<!\w)'|'(?!\w))", "", query)
-
-        # Brackets containing nothing but whitespace and booleans, recursive
-        last = ""
-        while last != query:
-            last = query
-            query = re.sub(r"(?u)\([\s\&\|\!]*\)", "", query)
-        ## plpy.debug('9 query is %s' % repr(query))
-
-        # An & or | following a (
-        query = re.sub(r"(?u)(?<=\()[\&\|\s]+", "", query)
-        ## plpy.debug('10 query is %s' % repr(query))
-
-        # An &, | or ! immediatly before a )
-        query = re.sub(r"(?u)[\&\|\!\s]*[\&\|\!]+\s*(?=\))", "", query)
-        ## plpy.debug('11 query is %s' % repr(query))
-
-        # An &,| or ! followed by another boolean.
-        query = re.sub(r"(?ux) \s* ( [\&\|\!] ) [\s\&\|]+", r"\1", query)
-        ## plpy.debug('12 query is %s' % repr(query))
-
-        # Leading & or |
-        query = re.sub(r"(?u)^[\s\&\|]+", "", query)
-        ## plpy.debug('13 query is %s' % repr(query))
-
-        # Trailing &, | or !
-        query = re.sub(r"(?u)[\&\|\!\s]+$", "", query)
-        ## plpy.debug('14 query is %s' % repr(query))
-
-        # If we have nothing but whitespace and tsearch2 operators,
-        # return NULL.
-        if re.search(r"(?u)^[\&\|\!\s\(\)]*$", query) is not None:
-            return None
-
-        # Convert back to UTF-8
-        query = query.encode('utf8')
-        ## plpy.debug('15 query is %s' % repr(query))
-        
-        p = plpy.prepare("SELECT to_tsquery('default', $1) AS x", ["text"])
-        query = plpy.execute(p, [query], 1)[0]["x"]
-        return query or None
-        $_$;
-
-
-COMMENT ON FUNCTION ftq(text) IS 'Convert a string to an unparsed tsearch2 query';
-
-
-CREATE FUNCTION get_covers(pg_catalog.tsvector, pg_catalog.tsquery) RETURNS text
-    LANGUAGE c STRICT
-    AS '$libdir/tsearch2', 'tsa_get_covers';
-
-
-CREATE FUNCTION headline(oid, text, pg_catalog.tsquery, text) RETURNS text
-    LANGUAGE internal IMMUTABLE STRICT
-    AS $$ts_headline_byid_opt$$;
-
-
-CREATE FUNCTION headline(oid, text, pg_catalog.tsquery) RETURNS text
-    LANGUAGE internal IMMUTABLE STRICT
-    AS $$ts_headline_byid$$;
-
-
-CREATE FUNCTION headline(text, text, pg_catalog.tsquery, text) RETURNS text
-    LANGUAGE c IMMUTABLE STRICT
-    AS '$libdir/tsearch2', 'tsa_headline_byname';
-
-
-CREATE FUNCTION headline(text, text, pg_catalog.tsquery) RETURNS text
-    LANGUAGE c IMMUTABLE STRICT
-    AS '$libdir/tsearch2', 'tsa_headline_byname';
-
-
-CREATE FUNCTION headline(text, pg_catalog.tsquery, text) RETURNS text
-    LANGUAGE internal IMMUTABLE STRICT
-    AS $$ts_headline_opt$$;
-
-
-CREATE FUNCTION headline(text, pg_catalog.tsquery) RETURNS text
-    LANGUAGE internal IMMUTABLE STRICT
-    AS $$ts_headline$$;
-
-
-CREATE FUNCTION length(pg_catalog.tsvector) RETURNS integer
-    LANGUAGE internal IMMUTABLE STRICT
-    AS $$tsvector_length$$;
-
-
-CREATE FUNCTION lexize(oid, text) RETURNS text[]
-    LANGUAGE internal STRICT
-    AS $$ts_lexize$$;
-
-
-CREATE FUNCTION lexize(text, text) RETURNS text[]
-    LANGUAGE c STRICT
-    AS '$libdir/tsearch2', 'tsa_lexize_byname';
-
-
-CREATE FUNCTION lexize(text) RETURNS text[]
-    LANGUAGE c STRICT
-    AS '$libdir/tsearch2', 'tsa_lexize_bycurrent';
-
-
-CREATE FUNCTION numnode(pg_catalog.tsquery) RETURNS integer
-    LANGUAGE internal IMMUTABLE STRICT
-    AS $$tsquery_numnode$$;
-
-
-CREATE FUNCTION parse(oid, text) RETURNS SETOF tokenout
-    LANGUAGE internal STRICT
-    AS $$ts_parse_byid$$;
-
-
-CREATE FUNCTION parse(text, text) RETURNS SETOF tokenout
-    LANGUAGE internal STRICT
-    AS $$ts_parse_byname$$;
-
-
-CREATE FUNCTION parse(text) RETURNS SETOF tokenout
-    LANGUAGE c STRICT
-    AS '$libdir/tsearch2', 'tsa_parse_current';
-
-
-CREATE FUNCTION plainto_tsquery(oid, text) RETURNS pg_catalog.tsquery
-    LANGUAGE internal IMMUTABLE STRICT
-    AS $$plainto_tsquery_byid$$;
-
-
-CREATE FUNCTION plainto_tsquery(text, text) RETURNS pg_catalog.tsquery
-    LANGUAGE c IMMUTABLE STRICT
-    AS '$libdir/tsearch2', 'tsa_plainto_tsquery_name';
-
-
-CREATE FUNCTION plainto_tsquery(text) RETURNS pg_catalog.tsquery
-    LANGUAGE internal IMMUTABLE STRICT
-    AS $$plainto_tsquery$$;
-
-
-CREATE FUNCTION prsd_end(internal) RETURNS void
-    LANGUAGE c
-    AS '$libdir/tsearch2', 'tsa_prsd_end';
-
-
-CREATE FUNCTION prsd_getlexeme(internal, internal, internal) RETURNS integer
-    LANGUAGE c
-    AS '$libdir/tsearch2', 'tsa_prsd_getlexeme';
-
-
-CREATE FUNCTION prsd_headline(internal, internal, internal) RETURNS internal
-    LANGUAGE c
-    AS '$libdir/tsearch2', 'tsa_prsd_headline';
-
-
-CREATE FUNCTION prsd_lextype(internal) RETURNS internal
-    LANGUAGE c
-    AS '$libdir/tsearch2', 'tsa_prsd_lextype';
-
-
-CREATE FUNCTION prsd_start(internal, integer) RETURNS internal
-    LANGUAGE c
-    AS '$libdir/tsearch2', 'tsa_prsd_start';
-
-
-CREATE FUNCTION querytree(pg_catalog.tsquery) RETURNS text
-    LANGUAGE internal STRICT
-    AS $$tsquerytree$$;
-
-
-CREATE FUNCTION rank(real[], pg_catalog.tsvector, pg_catalog.tsquery) RETURNS real
-    LANGUAGE internal IMMUTABLE STRICT
-    AS $$ts_rank_wtt$$;
-
-
-CREATE FUNCTION rank(real[], pg_catalog.tsvector, pg_catalog.tsquery, integer) RETURNS real
-    LANGUAGE internal IMMUTABLE STRICT
-    AS $$ts_rank_wttf$$;
-
-
-CREATE FUNCTION rank(pg_catalog.tsvector, pg_catalog.tsquery) RETURNS real
-    LANGUAGE internal IMMUTABLE STRICT
-    AS $$ts_rank_tt$$;
-
-
-CREATE FUNCTION rank(pg_catalog.tsvector, pg_catalog.tsquery, integer) RETURNS real
-    LANGUAGE internal IMMUTABLE STRICT
-    AS $$ts_rank_ttf$$;
-
-
-CREATE FUNCTION rank_cd(real[], pg_catalog.tsvector, pg_catalog.tsquery) RETURNS real
-    LANGUAGE internal IMMUTABLE STRICT
-    AS $$ts_rankcd_wtt$$;
-
-
-CREATE FUNCTION rank_cd(real[], pg_catalog.tsvector, pg_catalog.tsquery, integer) RETURNS real
-    LANGUAGE internal IMMUTABLE STRICT
-    AS $$ts_rankcd_wttf$$;
-
-
-CREATE FUNCTION rank_cd(pg_catalog.tsvector, pg_catalog.tsquery) RETURNS real
-    LANGUAGE internal IMMUTABLE STRICT
-    AS $$ts_rankcd_tt$$;
-
-
-CREATE FUNCTION rank_cd(pg_catalog.tsvector, pg_catalog.tsquery, integer) RETURNS real
-    LANGUAGE internal IMMUTABLE STRICT
-    AS $$ts_rankcd_ttf$$;
-
-
-CREATE FUNCTION reset_tsearch() RETURNS void
-    LANGUAGE c STRICT
-    AS '$libdir/tsearch2', 'tsa_reset_tsearch';
-
-
-CREATE FUNCTION rewrite(pg_catalog.tsquery, text) RETURNS pg_catalog.tsquery
-    LANGUAGE internal IMMUTABLE STRICT
-    AS $$tsquery_rewrite_query$$;
-
-
-CREATE FUNCTION rewrite(pg_catalog.tsquery, pg_catalog.tsquery, pg_catalog.tsquery) RETURNS pg_catalog.tsquery
-    LANGUAGE internal IMMUTABLE STRICT
-    AS $$tsquery_rewrite$$;
-
-
-CREATE FUNCTION rewrite_accum(pg_catalog.tsquery, pg_catalog.tsquery[]) RETURNS pg_catalog.tsquery
-    LANGUAGE c
-    AS '$libdir/tsearch2', 'tsa_rewrite_accum';
-
-
-CREATE FUNCTION rewrite_finish(pg_catalog.tsquery) RETURNS pg_catalog.tsquery
-    LANGUAGE c
-    AS '$libdir/tsearch2', 'tsa_rewrite_finish';
-
-
-CREATE FUNCTION set_curcfg(integer) RETURNS void
-    LANGUAGE c STRICT
-    AS '$libdir/tsearch2', 'tsa_set_curcfg';
-
-
-CREATE FUNCTION set_curcfg(text) RETURNS void
-    LANGUAGE c STRICT
-    AS '$libdir/tsearch2', 'tsa_set_curcfg_byname';
-
-
-CREATE FUNCTION set_curdict(integer) RETURNS void
-    LANGUAGE c STRICT
-    AS '$libdir/tsearch2', 'tsa_set_curdict';
-
-
-CREATE FUNCTION set_curdict(text) RETURNS void
-    LANGUAGE c STRICT
-    AS '$libdir/tsearch2', 'tsa_set_curdict_byname';
-
-
-CREATE FUNCTION set_curprs(integer) RETURNS void
-    LANGUAGE c STRICT
-    AS '$libdir/tsearch2', 'tsa_set_curprs';
-
-
-CREATE FUNCTION set_curprs(text) RETURNS void
-    LANGUAGE c STRICT
-    AS '$libdir/tsearch2', 'tsa_set_curprs_byname';
-
-
-CREATE FUNCTION setweight(pg_catalog.tsvector, "char") RETURNS pg_catalog.tsvector
-    LANGUAGE internal IMMUTABLE STRICT
-    AS $$tsvector_setweight$$;
-
-
-CREATE FUNCTION show_curcfg() RETURNS oid
-    LANGUAGE internal STABLE STRICT
-    AS $$get_current_ts_config$$;
-
-
-CREATE FUNCTION snb_en_init(internal) RETURNS internal
-    LANGUAGE c
-    AS '$libdir/tsearch2', 'tsa_snb_en_init';
-
-
-CREATE FUNCTION snb_lexize(internal, internal, integer) RETURNS internal
-    LANGUAGE c STRICT
-    AS '$libdir/tsearch2', 'tsa_snb_lexize';
-
-
-CREATE FUNCTION snb_ru_init(internal) RETURNS internal
-    LANGUAGE c
-    AS '$libdir/tsearch2', 'tsa_snb_ru_init';
-
-
-CREATE FUNCTION snb_ru_init_koi8(internal) RETURNS internal
-    LANGUAGE c
-    AS '$libdir/tsearch2', 'tsa_snb_ru_init_koi8';
-
-
-CREATE FUNCTION snb_ru_init_utf8(internal) RETURNS internal
-    LANGUAGE c
-    AS '$libdir/tsearch2', 'tsa_snb_ru_init_utf8';
-
-
-CREATE FUNCTION spell_init(internal) RETURNS internal
-    LANGUAGE c
-    AS '$libdir/tsearch2', 'tsa_spell_init';
-
-
-CREATE FUNCTION spell_lexize(internal, internal, integer) RETURNS internal
-    LANGUAGE c STRICT
-    AS '$libdir/tsearch2', 'tsa_spell_lexize';
-
-
-CREATE FUNCTION stat(text) RETURNS SETOF statinfo
-    LANGUAGE internal STRICT
-    AS $$ts_stat1$$;
-
-
-CREATE FUNCTION stat(text, text) RETURNS SETOF statinfo
-    LANGUAGE internal STRICT
-    AS $$ts_stat2$$;
-
-
-CREATE FUNCTION strip(pg_catalog.tsvector) RETURNS pg_catalog.tsvector
-    LANGUAGE internal IMMUTABLE STRICT
-    AS $$tsvector_strip$$;
-
-
-CREATE FUNCTION syn_init(internal) RETURNS internal
-    LANGUAGE c
-    AS '$libdir/tsearch2', 'tsa_syn_init';
-
-
-CREATE FUNCTION syn_lexize(internal, internal, integer) RETURNS internal
-    LANGUAGE c STRICT
-    AS '$libdir/tsearch2', 'tsa_syn_lexize';
-
-
-CREATE FUNCTION thesaurus_init(internal) RETURNS internal
-    LANGUAGE c
-    AS '$libdir/tsearch2', 'tsa_thesaurus_init';
-
-
-CREATE FUNCTION thesaurus_lexize(internal, internal, integer, internal) RETURNS internal
-    LANGUAGE c STRICT
-    AS '$libdir/tsearch2', 'tsa_thesaurus_lexize';
-
-
-CREATE FUNCTION to_tsquery(oid, text) RETURNS pg_catalog.tsquery
-    LANGUAGE internal IMMUTABLE STRICT
-    AS $$to_tsquery_byid$$;
-
-
-CREATE FUNCTION to_tsquery(text, text) RETURNS pg_catalog.tsquery
-    LANGUAGE c IMMUTABLE STRICT
-    AS '$libdir/tsearch2', 'tsa_to_tsquery_name';
-
-
-CREATE FUNCTION to_tsquery(text) RETURNS pg_catalog.tsquery
-    LANGUAGE internal IMMUTABLE STRICT
-    AS $$to_tsquery$$;
-
-
-CREATE FUNCTION to_tsvector(oid, text) RETURNS pg_catalog.tsvector
-    LANGUAGE internal IMMUTABLE STRICT
-    AS $$to_tsvector_byid$$;
-
-
-CREATE FUNCTION to_tsvector(text, text) RETURNS pg_catalog.tsvector
-    LANGUAGE c IMMUTABLE STRICT
-    AS '$libdir/tsearch2', 'tsa_to_tsvector_name';
-
-
-CREATE FUNCTION to_tsvector(text) RETURNS pg_catalog.tsvector
-    LANGUAGE internal IMMUTABLE STRICT
-    AS $$to_tsvector$$;
-
-
-CREATE FUNCTION token_type(integer) RETURNS SETOF tokentype
-    LANGUAGE internal STRICT ROWS 16
-    AS $$ts_token_type_byid$$;
-
-
-CREATE FUNCTION token_type(text) RETURNS SETOF tokentype
-    LANGUAGE internal STRICT ROWS 16
-    AS $$ts_token_type_byname$$;
-
-
-CREATE FUNCTION token_type() RETURNS SETOF tokentype
-    LANGUAGE c STRICT ROWS 16
-    AS '$libdir/tsearch2', 'tsa_token_type_current';
-
-
-CREATE FUNCTION ts_debug(text) RETURNS SETOF tsdebug
-    LANGUAGE sql STRICT
-    AS $_$
-select
-        (select c.cfgname::text from pg_catalog.pg_ts_config as c
-         where c.oid = show_curcfg()),
-        t.alias as tok_type,
-        t.descr as description,
-        p.token,
-        ARRAY ( SELECT m.mapdict::pg_catalog.regdictionary::pg_catalog.text
-                FROM pg_catalog.pg_ts_config_map AS m
-                WHERE m.mapcfg = show_curcfg() AND m.maptokentype = p.tokid
-                ORDER BY m.mapseqno )
-        AS dict_name,
-        strip(to_tsvector(p.token)) as tsvector
-from
-        parse( _get_parser_from_curcfg(), $1 ) as p,
-        token_type() as t
-where
-        t.tokid = p.tokid
-$_$;
-
-
-CREATE FUNCTION tsearch2() RETURNS trigger
-    LANGUAGE c
-    AS '$libdir/tsearch2', 'tsa_tsearch2';
-
-
-CREATE FUNCTION tsq_mcontained(pg_catalog.tsquery, pg_catalog.tsquery) RETURNS boolean
-    LANGUAGE internal IMMUTABLE STRICT
-    AS $$tsq_mcontained$$;
-
-
-CREATE FUNCTION tsq_mcontains(pg_catalog.tsquery, pg_catalog.tsquery) RETURNS boolean
-    LANGUAGE internal IMMUTABLE STRICT
-    AS $$tsq_mcontains$$;
-
-
-CREATE FUNCTION tsquery_and(pg_catalog.tsquery, pg_catalog.tsquery) RETURNS pg_catalog.tsquery
-    LANGUAGE internal IMMUTABLE STRICT
-    AS $$tsquery_and$$;
-
-
-CREATE FUNCTION tsquery_not(pg_catalog.tsquery) RETURNS pg_catalog.tsquery
-    LANGUAGE internal IMMUTABLE STRICT
-    AS $$tsquery_not$$;
-
-
-CREATE FUNCTION tsquery_or(pg_catalog.tsquery, pg_catalog.tsquery) RETURNS pg_catalog.tsquery
-    LANGUAGE internal IMMUTABLE STRICT
-    AS $$tsquery_or$$;
-
-
-SET search_path = public, pg_catalog;
-
-CREATE OPERATOR > (
-    PROCEDURE = debversion_gt,
-    LEFTARG = debversion,
-    RIGHTARG = debversion,
-    COMMUTATOR = <,
-    NEGATOR = >=
-);
-
-
-COMMENT ON OPERATOR > (debversion, debversion) IS 'debversion greater-than';
-
-
-CREATE AGGREGATE max(debversion) (
-    SFUNC = debversion_larger,
-    STYPE = debversion,
-    SORTOP = >
-);
-
-
-CREATE OPERATOR < (
-    PROCEDURE = debversion_lt,
-    LEFTARG = debversion,
-    RIGHTARG = debversion,
-    COMMUTATOR = >,
-    NEGATOR = >=
-);
-
-
-COMMENT ON OPERATOR < (debversion, debversion) IS 'debversion less-than';
-
-
-CREATE AGGREGATE min(debversion) (
-    SFUNC = debversion_smaller,
-    STYPE = debversion,
-    SORTOP = <
-);
-
-
-SET search_path = ts2, pg_catalog;
-
-CREATE AGGREGATE rewrite(pg_catalog.tsquery[]) (
-    SFUNC = rewrite_accum,
-    STYPE = pg_catalog.tsquery,
-    FINALFUNC = rewrite_finish
-);
-
-
-SET search_path = public, pg_catalog;
-
-CREATE OPERATOR <= (
-    PROCEDURE = debversion_le,
-    LEFTARG = debversion,
-    RIGHTARG = debversion,
-    COMMUTATOR = >=,
-    NEGATOR = >
-);
-
-
-COMMENT ON OPERATOR <= (debversion, debversion) IS 'debversion less-than-or-equal';
-
-
-CREATE OPERATOR <> (
-    PROCEDURE = debversion_ne,
-    LEFTARG = debversion,
-    RIGHTARG = debversion,
-    COMMUTATOR = <>,
-    NEGATOR = =
-);
-
-
-COMMENT ON OPERATOR <> (debversion, debversion) IS 'debversion not equal';
-
-
-CREATE OPERATOR = (
-    PROCEDURE = debversion_eq,
-    LEFTARG = debversion,
-    RIGHTARG = debversion,
-    COMMUTATOR = =,
-    NEGATOR = <>
-);
-
-
-COMMENT ON OPERATOR = (debversion, debversion) IS 'debversion equal';
-
-
-CREATE OPERATOR >= (
-    PROCEDURE = debversion_ge,
-    LEFTARG = debversion,
-    RIGHTARG = debversion,
-    COMMUTATOR = <=,
-    NEGATOR = <
-);
-
-
-COMMENT ON OPERATOR >= (debversion, debversion) IS 'debversion greater-than-or-equal';
-
-
-CREATE OPERATOR FAMILY debversion_ops USING btree;
-
-
-CREATE OPERATOR CLASS debversion_ops
-    DEFAULT FOR TYPE debversion USING btree AS
-    OPERATOR 1 <(debversion,debversion) ,
-    OPERATOR 2 <=(debversion,debversion) ,
-    OPERATOR 3 =(debversion,debversion) ,
-    OPERATOR 4 >=(debversion,debversion) ,
-    OPERATOR 5 >(debversion,debversion) ,
-    FUNCTION 1 debversion_cmp(debversion,debversion);
-
-
-CREATE OPERATOR FAMILY debversion_ops USING hash;
-
-
-CREATE OPERATOR CLASS debversion_ops
-    DEFAULT FOR TYPE debversion USING hash AS
-    OPERATOR 1 =(debversion,debversion) ,
-    FUNCTION 1 debversion_hash(debversion);
-
-
-SET search_path = ts2, pg_catalog;
-
-CREATE OPERATOR FAMILY tsquery_ops USING btree;
-
-
-CREATE OPERATOR CLASS tsquery_ops
-    FOR TYPE pg_catalog.tsquery USING btree AS
-    OPERATOR 1 <(pg_catalog.tsquery,pg_catalog.tsquery) ,
-    OPERATOR 2 <=(pg_catalog.tsquery,pg_catalog.tsquery) ,
-    OPERATOR 3 =(pg_catalog.tsquery,pg_catalog.tsquery) ,
-    OPERATOR 4 >=(pg_catalog.tsquery,pg_catalog.tsquery) ,
-    OPERATOR 5 >(pg_catalog.tsquery,pg_catalog.tsquery) ,
-    FUNCTION 1 tsquery_cmp(pg_catalog.tsquery,pg_catalog.tsquery);
-
-
-CREATE OPERATOR FAMILY tsvector_ops USING btree;
-
-
-CREATE OPERATOR CLASS tsvector_ops
-    FOR TYPE pg_catalog.tsvector USING btree AS
-    OPERATOR 1 <(pg_catalog.tsvector,pg_catalog.tsvector) ,
-    OPERATOR 2 <=(pg_catalog.tsvector,pg_catalog.tsvector) ,
-    OPERATOR 3 =(pg_catalog.tsvector,pg_catalog.tsvector) ,
-    OPERATOR 4 >=(pg_catalog.tsvector,pg_catalog.tsvector) ,
-    OPERATOR 5 >(pg_catalog.tsvector,pg_catalog.tsvector) ,
-    FUNCTION 1 tsvector_cmp(pg_catalog.tsvector,pg_catalog.tsvector);
-
-
-SET search_path = pg_catalog;
+COMMENT ON FUNCTION public.you_are_your_own_member() IS 'Trigger function to ensure that every row added to the Person table gets a corresponding row in the TeamParticipation table, as per the TeamParticipationUsage page on the Launchpad wiki';
+
+
+CREATE OPERATOR public.> (
+    PROCEDURE = public.debversion_gt,
+    LEFTARG = public.debversion,
+    RIGHTARG = public.debversion,
+    COMMUTATOR = OPERATOR(public.<),
+    NEGATOR = OPERATOR(public.>=)
+);
+
+
+COMMENT ON OPERATOR public.> (public.debversion, public.debversion) IS 'debversion greater-than';
+
+
+CREATE AGGREGATE public.max(public.debversion) (
+    SFUNC = public.debversion_larger,
+    STYPE = public.debversion,
+    SORTOP = OPERATOR(public.>)
+);
+
+
+CREATE OPERATOR public.< (
+    PROCEDURE = public.debversion_lt,
+    LEFTARG = public.debversion,
+    RIGHTARG = public.debversion,
+    COMMUTATOR = OPERATOR(public.>),
+    NEGATOR = OPERATOR(public.>=)
+);
+
+
+COMMENT ON OPERATOR public.< (public.debversion, public.debversion) IS 'debversion less-than';
+
+
+CREATE AGGREGATE public.min(public.debversion) (
+    SFUNC = public.debversion_smaller,
+    STYPE = public.debversion,
+    SORTOP = OPERATOR(public.<)
+);
+
+
+CREATE OPERATOR public.<= (
+    PROCEDURE = public.debversion_le,
+    LEFTARG = public.debversion,
+    RIGHTARG = public.debversion,
+    COMMUTATOR = OPERATOR(public.>=),
+    NEGATOR = OPERATOR(public.>)
+);
+
+
+COMMENT ON OPERATOR public.<= (public.debversion, public.debversion) IS 'debversion less-than-or-equal';
+
+
+CREATE OPERATOR public.<> (
+    PROCEDURE = public.debversion_ne,
+    LEFTARG = public.debversion,
+    RIGHTARG = public.debversion,
+    COMMUTATOR = OPERATOR(public.<>),
+    NEGATOR = OPERATOR(public.=)
+);
+
+
+COMMENT ON OPERATOR public.<> (public.debversion, public.debversion) IS 'debversion not equal';
+
+
+CREATE OPERATOR public.= (
+    PROCEDURE = public.debversion_eq,
+    LEFTARG = public.debversion,
+    RIGHTARG = public.debversion,
+    COMMUTATOR = OPERATOR(public.=),
+    NEGATOR = OPERATOR(public.<>)
+);
+
+
+COMMENT ON OPERATOR public.= (public.debversion, public.debversion) IS 'debversion equal';
+
+
+CREATE OPERATOR public.>= (
+    PROCEDURE = public.debversion_ge,
+    LEFTARG = public.debversion,
+    RIGHTARG = public.debversion,
+    COMMUTATOR = OPERATOR(public.<=),
+    NEGATOR = OPERATOR(public.<)
+);
+
+
+COMMENT ON OPERATOR public.>= (public.debversion, public.debversion) IS 'debversion greater-than-or-equal';
+
+
+CREATE OPERATOR FAMILY public.debversion_ops USING btree;
+
+
+CREATE OPERATOR CLASS public.debversion_ops
+    DEFAULT FOR TYPE public.debversion USING btree FAMILY public.debversion_ops AS
+    OPERATOR 1 public.<(public.debversion,public.debversion) ,
+    OPERATOR 2 public.<=(public.debversion,public.debversion) ,
+    OPERATOR 3 public.=(public.debversion,public.debversion) ,
+    OPERATOR 4 public.>=(public.debversion,public.debversion) ,
+    OPERATOR 5 public.>(public.debversion,public.debversion) ,
+    FUNCTION 1 (public.debversion, public.debversion) public.debversion_cmp(public.debversion,public.debversion);
+
+
+CREATE OPERATOR FAMILY public.debversion_ops USING hash;
+
+
+CREATE OPERATOR CLASS public.debversion_ops
+    DEFAULT FOR TYPE public.debversion USING hash FAMILY public.debversion_ops AS
+    OPERATOR 1 public.=(public.debversion,public.debversion) ,
+    FUNCTION 1 (public.debversion, public.debversion) public.debversion_hash(public.debversion);
+
 
 CREATE CAST (character AS public.debversion) WITH FUNCTION public.debversion(character);
 
@@ -4429,134 +3550,226 @@
 CREATE CAST (character varying AS public.debversion) WITHOUT FUNCTION AS ASSIGNMENT;
 
 
-SET search_path = ts2, pg_catalog;
-
-CREATE TEXT SEARCH CONFIGURATION "default" (
+CREATE TEXT SEARCH CONFIGURATION public."default" (
     PARSER = pg_catalog."default" );
 
-ALTER TEXT SEARCH CONFIGURATION "default"
+ALTER TEXT SEARCH CONFIGURATION public."default"
     ADD MAPPING FOR asciiword WITH english_stem;
 
-ALTER TEXT SEARCH CONFIGURATION "default"
+ALTER TEXT SEARCH CONFIGURATION public."default"
     ADD MAPPING FOR word WITH english_stem;
 
-ALTER TEXT SEARCH CONFIGURATION "default"
+ALTER TEXT SEARCH CONFIGURATION public."default"
     ADD MAPPING FOR numword WITH simple;
 
-ALTER TEXT SEARCH CONFIGURATION "default"
+ALTER TEXT SEARCH CONFIGURATION public."default"
     ADD MAPPING FOR email WITH simple;
 
-ALTER TEXT SEARCH CONFIGURATION "default"
+ALTER TEXT SEARCH CONFIGURATION public."default"
     ADD MAPPING FOR url WITH simple;
 
-ALTER TEXT SEARCH CONFIGURATION "default"
+ALTER TEXT SEARCH CONFIGURATION public."default"
     ADD MAPPING FOR host WITH simple;
 
-ALTER TEXT SEARCH CONFIGURATION "default"
+ALTER TEXT SEARCH CONFIGURATION public."default"
     ADD MAPPING FOR sfloat WITH simple;
 
-ALTER TEXT SEARCH CONFIGURATION "default"
+ALTER TEXT SEARCH CONFIGURATION public."default"
     ADD MAPPING FOR version WITH simple;
 
-ALTER TEXT SEARCH CONFIGURATION "default"
+ALTER TEXT SEARCH CONFIGURATION public."default"
     ADD MAPPING FOR hword_numpart WITH simple;
 
-ALTER TEXT SEARCH CONFIGURATION "default"
+ALTER TEXT SEARCH CONFIGURATION public."default"
     ADD MAPPING FOR hword_part WITH english_stem;
 
-ALTER TEXT SEARCH CONFIGURATION "default"
+ALTER TEXT SEARCH CONFIGURATION public."default"
     ADD MAPPING FOR hword_asciipart WITH english_stem;
 
-ALTER TEXT SEARCH CONFIGURATION "default"
+ALTER TEXT SEARCH CONFIGURATION public."default"
     ADD MAPPING FOR numhword WITH simple;
 
-ALTER TEXT SEARCH CONFIGURATION "default"
+ALTER TEXT SEARCH CONFIGURATION public."default"
     ADD MAPPING FOR asciihword WITH english_stem;
 
-ALTER TEXT SEARCH CONFIGURATION "default"
+ALTER TEXT SEARCH CONFIGURATION public."default"
     ADD MAPPING FOR hword WITH english_stem;
 
-ALTER TEXT SEARCH CONFIGURATION "default"
+ALTER TEXT SEARCH CONFIGURATION public."default"
     ADD MAPPING FOR url_path WITH simple;
 
-ALTER TEXT SEARCH CONFIGURATION "default"
+ALTER TEXT SEARCH CONFIGURATION public."default"
     ADD MAPPING FOR file WITH simple;
 
-ALTER TEXT SEARCH CONFIGURATION "default"
+ALTER TEXT SEARCH CONFIGURATION public."default"
     ADD MAPPING FOR "float" WITH simple;
 
-ALTER TEXT SEARCH CONFIGURATION "default"
+ALTER TEXT SEARCH CONFIGURATION public."default"
     ADD MAPPING FOR "int" WITH simple;
 
-ALTER TEXT SEARCH CONFIGURATION "default"
+ALTER TEXT SEARCH CONFIGURATION public."default"
     ADD MAPPING FOR uint WITH simple;
 
 
-SET search_path = public, pg_catalog;
-
-CREATE TABLE accesspolicy (
+CREATE TABLE public.accessartifact (
+    id integer NOT NULL,
+    bug integer,
+    branch integer,
+    specification integer,
+    gitrepository integer,
+    CONSTRAINT has_artifact CHECK ((public.null_count(ARRAY[bug, branch, gitrepository, specification]) = 3))
+);
+
+
+COMMENT ON TABLE public.accessartifact IS 'An artifact that an access grant can apply to. Additional private artifacts should be handled by adding new columns here, rather than new tables or columns on AccessArtifactGrant.';
+
+
+COMMENT ON COLUMN public.accessartifact.bug IS 'The bug that this abstract artifact represents.';
+
+
+COMMENT ON COLUMN public.accessartifact.branch IS 'The branch that this abstract artifact represents.';
+
+
+CREATE SEQUENCE public.accessartifact_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER SEQUENCE public.accessartifact_id_seq OWNED BY public.accessartifact.id;
+
+
+CREATE TABLE public.accessartifactgrant (
+    artifact integer NOT NULL,
+    grantee integer NOT NULL,
+    grantor integer NOT NULL,
+    date_created timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL
+);
+
+
+COMMENT ON TABLE public.accessartifactgrant IS 'A grant for a person to access an artifact.';
+
+
+COMMENT ON COLUMN public.accessartifactgrant.artifact IS 'The artifact on which access is granted.';
+
+
+COMMENT ON COLUMN public.accessartifactgrant.grantee IS 'The person to whom access is granted.';
+
+
+COMMENT ON COLUMN public.accessartifactgrant.grantor IS 'The person who granted the access.';
+
+
+COMMENT ON COLUMN public.accessartifactgrant.date_created IS 'The date the access was granted.';
+
+
+CREATE TABLE public.accesspolicy (
     id integer NOT NULL,
     product integer,
     distribution integer,
-    type integer NOT NULL,
-    CONSTRAINT has_target CHECK (((product IS NULL) <> (distribution IS NULL)))
-);
-
-
-CREATE SEQUENCE accesspolicy_id_seq
-    START WITH 1
-    INCREMENT BY 1
-    NO MAXVALUE
-    NO MINVALUE
-    CACHE 1;
-
-
-ALTER SEQUENCE accesspolicy_id_seq OWNED BY accesspolicy.id;
-
-
-CREATE TABLE accesspolicyartifact (
-    id integer NOT NULL,
-    bug integer,
-    branch integer,
-    policy integer,
-    CONSTRAINT has_artifact CHECK (((bug IS NULL) <> (branch IS NULL)))
-);
-
-
-CREATE SEQUENCE accesspolicyartifact_id_seq
-    START WITH 1
-    INCREMENT BY 1
-    NO MAXVALUE
-    NO MINVALUE
-    CACHE 1;
-
-
-ALTER SEQUENCE accesspolicyartifact_id_seq OWNED BY accesspolicyartifact.id;
-
-
-CREATE TABLE accesspolicygrant (
-    id integer NOT NULL,
+    type integer,
+    person integer,
+    CONSTRAINT has_target CHECK (((((type IS NOT NULL) AND ((product IS NULL) <> (distribution IS NULL))) AND (person IS NULL)) OR ((((type IS NULL) AND (person IS NOT NULL)) AND (product IS NULL)) AND (distribution IS NULL))))
+);
+
+
+COMMENT ON TABLE public.accesspolicy IS 'An access policy used to manage a project or distribution''s artifacts.';
+
+
+COMMENT ON COLUMN public.accesspolicy.product IS 'The product that this policy is used on.';
+
+
+COMMENT ON COLUMN public.accesspolicy.distribution IS 'The distribution that this policy is used on.';
+
+
+COMMENT ON COLUMN public.accesspolicy.type IS 'The type of policy (an enum value). Private, Security, etc.';
+
+
+COMMENT ON COLUMN public.accesspolicy.person IS 'The private team that this policy is used on.';
+
+
+CREATE SEQUENCE public.accesspolicy_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER SEQUENCE public.accesspolicy_id_seq OWNED BY public.accesspolicy.id;
+
+
+CREATE TABLE public.accesspolicyartifact (
+    artifact integer NOT NULL,
+    policy integer NOT NULL
+);
+
+
+COMMENT ON TABLE public.accesspolicyartifact IS 'An association between an artifact and a policy. A grant for any related policy grants access to the artifact.';
+
+
+COMMENT ON COLUMN public.accesspolicyartifact.artifact IS 'The artifact associated with this policy.';
+
+
+COMMENT ON COLUMN public.accesspolicyartifact.policy IS 'The policy associated with this artifact.';
+
+
+CREATE TABLE public.accesspolicygrant (
+    policy integer NOT NULL,
     grantee integer NOT NULL,
     grantor integer NOT NULL,
-    date_created timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL,
-    policy integer,
+    date_created timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL
+);
+
+
+COMMENT ON TABLE public.accesspolicygrant IS 'A grant for a person to access a policy''s artifacts.';
+
+
+COMMENT ON COLUMN public.accesspolicygrant.policy IS 'The policy on which access is granted.';
+
+
+COMMENT ON COLUMN public.accesspolicygrant.grantee IS 'The person to whom access is granted.';
+
+
+COMMENT ON COLUMN public.accesspolicygrant.grantor IS 'The person who granted the access.';
+
+
+COMMENT ON COLUMN public.accesspolicygrant.date_created IS 'The date the access was granted.';
+
+
+CREATE TABLE public.accesspolicygrantflat (
+    id integer NOT NULL,
+    policy integer NOT NULL,
     artifact integer,
-    CONSTRAINT has_target CHECK (((policy IS NULL) <> (artifact IS NULL)))
+    grantee integer NOT NULL
 );
 
 
-CREATE SEQUENCE accesspolicygrant_id_seq
+COMMENT ON TABLE public.accesspolicygrantflat IS 'A fact table for access queries. AccessPolicyGrants are included verbatim, but AccessArtifactGrants are included with their artifacts'' corresponding policies.';
+
+
+COMMENT ON COLUMN public.accesspolicygrantflat.policy IS 'The policy on which access is granted.';
+
+
+COMMENT ON COLUMN public.accesspolicygrantflat.artifact IS 'The artifact on which access is granted. If null, the grant is for the whole policy';
+
+
+COMMENT ON COLUMN public.accesspolicygrantflat.grantee IS 'The person to whom access is granted.';
+
+
+CREATE SEQUENCE public.accesspolicygrantflat_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE accesspolicygrant_id_seq OWNED BY accesspolicygrant.id;
-
-
-CREATE TABLE account (
+ALTER SEQUENCE public.accesspolicygrantflat_id_seq OWNED BY public.accesspolicygrantflat.id;
+
+
+CREATE TABLE public.account (
     id integer NOT NULL,
     date_created timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL,
     creation_rationale integer NOT NULL,
@@ -4567,61 +3780,33 @@
 );
 
 
-COMMENT ON TABLE account IS 'An account that may be used for authenticating to Canonical or other systems.';
-
-
-COMMENT ON COLUMN account.status IS 'The status of the account.';
-
-
-COMMENT ON COLUMN account.date_status_set IS 'When the status was last changed.';
-
-
-COMMENT ON COLUMN account.displayname IS 'Name to display when rendering information about this account.';
-
-
-COMMENT ON COLUMN account.status_comment IS 'The comment on the status of the account.';
-
-
-CREATE SEQUENCE account_id_seq
-    START WITH 1
-    INCREMENT BY 1
-    NO MAXVALUE
-    NO MINVALUE
-    CACHE 1;
-
-
-ALTER SEQUENCE account_id_seq OWNED BY account.id;
-
-
-CREATE TABLE accountpassword (
-    id integer NOT NULL,
-    account integer NOT NULL,
-    password text NOT NULL
-);
-
-
-COMMENT ON TABLE accountpassword IS 'A password used to authenticate an Account.';
-
-
-COMMENT ON COLUMN accountpassword.password IS 'SSHA digest encrypted password.';
-
-
-CREATE SEQUENCE accountpassword_id_seq
-    START WITH 1
-    INCREMENT BY 1
-    NO MAXVALUE
-    NO MINVALUE
-    CACHE 1;
-
-
-ALTER SEQUENCE accountpassword_id_seq OWNED BY accountpassword.id;
-
-
-CREATE VIEW alllocks AS
-    SELECT a.procpid, a.usename, (now() - a.query_start) AS age, c.relname, l.mode, l.granted, a.current_query FROM ((pg_locks l JOIN pg_class c ON ((l.relation = c.oid))) LEFT JOIN pg_stat_activity a ON ((a.procpid = l.pid)));
-
-
-CREATE TABLE announcement (
+COMMENT ON TABLE public.account IS 'An account that may be used for authenticating to Canonical or other systems.';
+
+
+COMMENT ON COLUMN public.account.status IS 'The status of the account.';
+
+
+COMMENT ON COLUMN public.account.date_status_set IS 'When the status was last changed.';
+
+
+COMMENT ON COLUMN public.account.displayname IS 'Name to display when rendering information about this account.';
+
+
+COMMENT ON COLUMN public.account.status_comment IS 'The comment on the status of the account.';
+
+
+CREATE SEQUENCE public.account_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER SEQUENCE public.account_id_seq OWNED BY public.account.id;
+
+
+CREATE TABLE public.announcement (
     id integer NOT NULL,
     date_created timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL,
     date_announced timestamp without time zone,
@@ -4635,34 +3820,34 @@
     active boolean DEFAULT true NOT NULL,
     date_updated timestamp without time zone,
     CONSTRAINT has_target CHECK ((((product IS NOT NULL) OR (project IS NOT NULL)) OR (distribution IS NOT NULL))),
-    CONSTRAINT valid_url CHECK (valid_absolute_url(url))
+    CONSTRAINT valid_url CHECK (public.valid_absolute_url(url))
 );
 
 
-COMMENT ON TABLE announcement IS 'A project announcement. This is a single item of news or information that the project is communicating. Announcements can be attached to a Project, a Product or a Distribution.';
-
-
-COMMENT ON COLUMN announcement.date_announced IS 'The date at which an announcement will become public, if it is active. If this is not set then the announcement will not become public until someone consciously publishes it (which sets this date).';
-
-
-COMMENT ON COLUMN announcement.url IS 'A web location for the announcement itself.';
-
-
-COMMENT ON COLUMN announcement.active IS 'Whether or not the announcement is public. This is TRUE by default, but can be set to FALSE if the project "retracts" the announcement.';
-
-
-CREATE SEQUENCE announcement_id_seq
+COMMENT ON TABLE public.announcement IS 'A project announcement. This is a single item of news or information that the project is communicating. Announcements can be attached to a Project, a Product or a Distribution.';
+
+
+COMMENT ON COLUMN public.announcement.date_announced IS 'The date at which an announcement will become public, if it is active. If this is not set then the announcement will not become public until someone consciously publishes it (which sets this date).';
+
+
+COMMENT ON COLUMN public.announcement.url IS 'A web location for the announcement itself.';
+
+
+COMMENT ON COLUMN public.announcement.active IS 'Whether or not the announcement is public. This is TRUE by default, but can be set to FALSE if the project "retracts" the announcement.';
+
+
+CREATE SEQUENCE public.announcement_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE announcement_id_seq OWNED BY announcement.id;
-
-
-CREATE TABLE answercontact (
+ALTER SEQUENCE public.announcement_id_seq OWNED BY public.announcement.id;
+
+
+CREATE TABLE public.answercontact (
     id integer NOT NULL,
     product integer,
     distribution integer,
@@ -4673,36 +3858,36 @@
 );
 
 
-COMMENT ON TABLE answercontact IS 'Defines the answer contact for a given question target. The answer contact will be automatically notified about changes to any questions filed on the question target.';
-
-
-COMMENT ON COLUMN answercontact.product IS 'The product that the answer contact supports.';
-
-
-COMMENT ON COLUMN answercontact.distribution IS 'The distribution that the answer contact supports.';
-
-
-COMMENT ON COLUMN answercontact.sourcepackagename IS 'The sourcepackagename that the answer contact supports.';
-
-
-COMMENT ON COLUMN answercontact.person IS 'The person or team associated with the question target.';
-
-
-COMMENT ON COLUMN answercontact.date_created IS 'The date the answer contact was submitted.';
-
-
-CREATE SEQUENCE answercontact_id_seq
+COMMENT ON TABLE public.answercontact IS 'Defines the answer contact for a given question target. The answer contact will be automatically notified about changes to any questions filed on the question target.';
+
+
+COMMENT ON COLUMN public.answercontact.product IS 'The product that the answer contact supports.';
+
+
+COMMENT ON COLUMN public.answercontact.distribution IS 'The distribution that the answer contact supports.';
+
+
+COMMENT ON COLUMN public.answercontact.sourcepackagename IS 'The sourcepackagename that the answer contact supports.';
+
+
+COMMENT ON COLUMN public.answercontact.person IS 'The person or team associated with the question target.';
+
+
+COMMENT ON COLUMN public.answercontact.date_created IS 'The date the answer contact was submitted.';
+
+
+CREATE SEQUENCE public.answercontact_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE answercontact_id_seq OWNED BY answercontact.id;
-
-
-CREATE TABLE apportjob (
+ALTER SEQUENCE public.answercontact_id_seq OWNED BY public.answercontact.id;
+
+
+CREATE TABLE public.apportjob (
     id integer NOT NULL,
     job integer NOT NULL,
     blob integer NOT NULL,
@@ -4711,30 +3896,30 @@
 );
 
 
-COMMENT ON TABLE apportjob IS 'Contains references to jobs to be run against Apport BLOBs.';
-
-
-COMMENT ON COLUMN apportjob.blob IS 'The TemporaryBlobStorage entry on which the job is to be run.';
-
-
-COMMENT ON COLUMN apportjob.job_type IS 'The type of job (enumeration value). Allows us to query the database for a given subset of ApportJobs.';
-
-
-COMMENT ON COLUMN apportjob.json_data IS 'A JSON struct containing data for the job.';
-
-
-CREATE SEQUENCE apportjob_id_seq
+COMMENT ON TABLE public.apportjob IS 'Contains references to jobs to be run against Apport BLOBs.';
+
+
+COMMENT ON COLUMN public.apportjob.blob IS 'The TemporaryBlobStorage entry on which the job is to be run.';
+
+
+COMMENT ON COLUMN public.apportjob.job_type IS 'The type of job (enumeration value). Allows us to query the database for a given subset of ApportJobs.';
+
+
+COMMENT ON COLUMN public.apportjob.json_data IS 'A JSON struct containing data for the job.';
+
+
+CREATE SEQUENCE public.apportjob_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE apportjob_id_seq OWNED BY apportjob.id;
-
-
-CREATE TABLE archive (
+ALTER SEQUENCE public.apportjob_id_seq OWNED BY public.apportjob.id;
+
+
+CREATE TABLE public.archive (
     id integer NOT NULL,
     owner integer NOT NULL,
     description text,
@@ -4746,7 +3931,7 @@
     sources_cached integer,
     binaries_cached integer,
     package_description_cache text,
-    fti ts2.tsvector,
+    fti public.ts2_tsvector,
     buildd_secret text,
     require_virtualized boolean DEFAULT true NOT NULL,
     name text DEFAULT 'default'::text NOT NULL,
@@ -4765,178 +3950,191 @@
     relative_build_score integer DEFAULT 0 NOT NULL,
     external_dependencies text,
     status integer DEFAULT 0 NOT NULL,
-    commercial boolean DEFAULT false NOT NULL,
+    suppress_subscription_notifications boolean DEFAULT false NOT NULL,
     build_debug_symbols boolean DEFAULT false NOT NULL,
+    publish_debug_symbols boolean DEFAULT false,
+    permit_obsolete_series_uploads boolean DEFAULT false,
+    signing_key_owner integer,
+    signing_key_fingerprint text,
+    dirty_suites text,
     CONSTRAINT valid_buildd_secret CHECK ((((private = true) AND (buildd_secret IS NOT NULL)) OR (private = false))),
-    CONSTRAINT valid_name CHECK (valid_name(name))
-);
-
-
-COMMENT ON TABLE archive IS 'A package archive. Commonly either a distribution''s main_archive or a ppa''s archive.';
-
-
-COMMENT ON COLUMN archive.owner IS 'Identifies the PPA owner when it has one.';
-
-
-COMMENT ON COLUMN archive.description IS 'Allow users to describe their PPAs content.';
-
-
-COMMENT ON COLUMN archive.enabled IS 'Whether or not the PPA is enabled for accepting uploads.';
-
-
-COMMENT ON COLUMN archive.authorized_size IS 'Size, in MiB, allowed for this PPA.';
-
-
-COMMENT ON COLUMN archive.distribution IS 'The distribution that uses this archive.';
-
-
-COMMENT ON COLUMN archive.purpose IS 'The purpose of this archive, e.g. COMMERCIAL.  See the ArchivePurpose DBSchema item.';
-
-
-COMMENT ON COLUMN archive.private IS 'Whether or not the archive is private. This affects the global visibility of the archive.';
-
-
-COMMENT ON COLUMN archive.sources_cached IS 'Number of sources already cached for this archive.';
-
-
-COMMENT ON COLUMN archive.binaries_cached IS 'Number of binaries already cached for this archive.';
-
-
-COMMENT ON COLUMN archive.package_description_cache IS 'Text blob containing all source and binary names and descriptions concatenated. Used to to build the tsearch indexes on this table.';
-
-
-COMMENT ON COLUMN archive.require_virtualized IS 'Whether this archive has binaries that should be built on a virtual machine, e.g. PPAs';
-
-
-COMMENT ON COLUMN archive.name IS 'The name of the archive.';
-
-
-COMMENT ON COLUMN archive.publish IS 'Whether this archive should be published.';
-
-
-COMMENT ON COLUMN archive.date_updated IS 'When were the rebuild statistics last updated?';
-
-
-COMMENT ON COLUMN archive.total_count IS 'How many source packages are in the rebuild archive altogether?';
-
-
-COMMENT ON COLUMN archive.pending_count IS 'How many packages still need building?';
-
-
-COMMENT ON COLUMN archive.succeeded_count IS 'How many source packages were built sucessfully?';
-
-
-COMMENT ON COLUMN archive.failed_count IS 'How many packages failed to build?';
-
-
-COMMENT ON COLUMN archive.building_count IS 'How many packages are building at present?';
-
-
-COMMENT ON COLUMN archive.signing_key IS 'The GpgKey used for signing this archive.';
-
-
-COMMENT ON COLUMN archive.removed_binary_retention_days IS 'The number of days before superseded or deleted binary files are expired in the librarian, or zero for never.';
-
-
-COMMENT ON COLUMN archive.num_old_versions_published IS 'The number of versions of a package to keep published before older versions are superseded.';
-
-
-COMMENT ON COLUMN archive.displayname IS 'User defined displayname for this archive.';
-
-
-COMMENT ON COLUMN archive.relative_build_score IS 'A delta to the build score that is applied to all builds in this archive.';
-
-
-COMMENT ON COLUMN archive.external_dependencies IS 'Newline-separated list of repositories to be used to retrieve any external build dependencies when building packages in this archive, in the format: deb http[s]://[user:pass@]<host>[/path] %(series)s[-pocket] [components]  The series variable is replaced with the series name of the context build.  This column is specifically and only intended for OEM migration to Launchpad and should be re-examined in October 2010 to see if it is still relevant.';
-
-
-COMMENT ON COLUMN archive.status IS 'The status of this archive, e.g. ACTIVE.  See the ArchiveState DBSchema item.';
-
-
-COMMENT ON COLUMN archive.commercial IS 'Whether this archive is a commercial Archive and should appear in the Software Center.';
-
-
-COMMENT ON COLUMN archive.build_debug_symbols IS 'Whether builds for this archive should create debug symbol packages.';
-
-
-CREATE SEQUENCE archive_id_seq
-    START WITH 1
-    INCREMENT BY 1
-    NO MAXVALUE
-    NO MINVALUE
-    CACHE 1;
-
-
-ALTER SEQUENCE archive_id_seq OWNED BY archive.id;
-
-
-CREATE TABLE archivearch (
-    id integer NOT NULL,
-    archive integer NOT NULL,
-    processorfamily integer NOT NULL
-);
-
-
-COMMENT ON TABLE archivearch IS 'ArchiveArch: A table that allows a user to specify which architectures an archive requires or supports.';
-
-
-COMMENT ON COLUMN archivearch.archive IS 'The archive for which an architecture is specified.';
-
-
-COMMENT ON COLUMN archivearch.processorfamily IS 'The architecture specified for the archive on hand.';
-
-
-CREATE SEQUENCE archivearch_id_seq
-    START WITH 1
-    INCREMENT BY 1
-    NO MAXVALUE
-    NO MINVALUE
-    CACHE 1;
-
-
-ALTER SEQUENCE archivearch_id_seq OWNED BY archivearch.id;
-
-
-CREATE TABLE archiveauthtoken (
-    id integer NOT NULL,
-    archive integer NOT NULL,
-    person integer NOT NULL,
+    CONSTRAINT valid_name CHECK (public.valid_name(name)),
+    CONSTRAINT valid_signing_key_fingerprint CHECK (((signing_key_fingerprint IS NULL) OR public.valid_fingerprint(signing_key_fingerprint)))
+);
+
+
+COMMENT ON TABLE public.archive IS 'A package archive. Commonly either a distribution''s main_archive or a ppa''s archive.';
+
+
+COMMENT ON COLUMN public.archive.owner IS 'Identifies the PPA owner when it has one.';
+
+
+COMMENT ON COLUMN public.archive.description IS 'Allow users to describe their PPAs content.';
+
+
+COMMENT ON COLUMN public.archive.enabled IS 'Whether or not the PPA is enabled for accepting uploads.';
+
+
+COMMENT ON COLUMN public.archive.authorized_size IS 'Size, in MiB, allowed for this PPA.';
+
+
+COMMENT ON COLUMN public.archive.distribution IS 'The distribution that uses this archive.';
+
+
+COMMENT ON COLUMN public.archive.purpose IS 'The purpose of this archive, e.g. COMMERCIAL.  See the ArchivePurpose DBSchema item.';
+
+
+COMMENT ON COLUMN public.archive.private IS 'Whether or not the archive is private. This affects the global visibility of the archive.';
+
+
+COMMENT ON COLUMN public.archive.sources_cached IS 'Number of sources already cached for this archive.';
+
+
+COMMENT ON COLUMN public.archive.binaries_cached IS 'Number of binaries already cached for this archive.';
+
+
+COMMENT ON COLUMN public.archive.package_description_cache IS 'Text blob containing all source and binary names and descriptions concatenated. Used to to build the tsearch indexes on this table.';
+
+
+COMMENT ON COLUMN public.archive.require_virtualized IS 'Whether this archive has binaries that should be built on a virtual machine, e.g. PPAs';
+
+
+COMMENT ON COLUMN public.archive.name IS 'The name of the archive.';
+
+
+COMMENT ON COLUMN public.archive.publish IS 'Whether this archive should be published.';
+
+
+COMMENT ON COLUMN public.archive.date_updated IS 'When were the rebuild statistics last updated?';
+
+
+COMMENT ON COLUMN public.archive.total_count IS 'How many source packages are in the rebuild archive altogether?';
+
+
+COMMENT ON COLUMN public.archive.pending_count IS 'How many packages still need building?';
+
+
+COMMENT ON COLUMN public.archive.succeeded_count IS 'How many source packages were built sucessfully?';
+
+
+COMMENT ON COLUMN public.archive.failed_count IS 'How many packages failed to build?';
+
+
+COMMENT ON COLUMN public.archive.building_count IS 'How many packages are building at present?';
+
+
+COMMENT ON COLUMN public.archive.signing_key IS 'The GpgKey used for signing this archive.';
+
+
+COMMENT ON COLUMN public.archive.removed_binary_retention_days IS 'The number of days before superseded or deleted binary files are expired in the librarian, or zero for never.';
+
+
+COMMENT ON COLUMN public.archive.num_old_versions_published IS 'The number of versions of a package to keep published before older versions are superseded.';
+
+
+COMMENT ON COLUMN public.archive.displayname IS 'User defined displayname for this archive.';
+
+
+COMMENT ON COLUMN public.archive.relative_build_score IS 'A delta to the build score that is applied to all builds in this archive.';
+
+
+COMMENT ON COLUMN public.archive.external_dependencies IS 'Newline-separated list of repositories to be used to retrieve any external build dependencies when building packages in this archive, in the format: deb http[s]://[user:pass@]<host>[/path] %(series)s[-pocket] [components]  The series variable is replaced with the series name of the context build.  This column is specifically and only intended for OEM migration to Launchpad and should be re-examined in October 2010 to see if it is still relevant.';
+
+
+COMMENT ON COLUMN public.archive.status IS 'The status of this archive, e.g. ACTIVE.  See the ArchiveState DBSchema item.';
+
+
+COMMENT ON COLUMN public.archive.suppress_subscription_notifications IS 'Whether to suppress notifications about subscriptions.';
+
+
+COMMENT ON COLUMN public.archive.build_debug_symbols IS 'Whether builds for this archive should create debug symbol packages.';
+
+
+COMMENT ON COLUMN public.archive.dirty_suites IS 'A JSON-encoded list of suites in this archive that should be considered dirty on the next publisher run regardless of publications.';
+
+
+CREATE SEQUENCE public.archive_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER SEQUENCE public.archive_id_seq OWNED BY public.archive.id;
+
+
+CREATE TABLE public.archivearch (
+    id integer NOT NULL,
+    archive integer NOT NULL,
+    processor integer NOT NULL
+);
+
+
+COMMENT ON TABLE public.archivearch IS 'ArchiveArch: A table that allows a user to specify which architectures an archive requires or supports.';
+
+
+COMMENT ON COLUMN public.archivearch.archive IS 'The archive for which an architecture is specified.';
+
+
+COMMENT ON COLUMN public.archivearch.processor IS 'The architecture specified for the archive on hand.';
+
+
+CREATE SEQUENCE public.archivearch_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER SEQUENCE public.archivearch_id_seq OWNED BY public.archivearch.id;
+
+
+CREATE TABLE public.archiveauthtoken (
+    id integer NOT NULL,
+    archive integer NOT NULL,
+    person integer,
     date_created timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL,
     date_deactivated timestamp without time zone,
-    token text NOT NULL
+    token text NOT NULL,
+    name text
 );
 
 
-COMMENT ON TABLE archiveauthtoken IS 'Authorisation tokens to use in .htaccess for published archives.';
-
-
-COMMENT ON COLUMN archiveauthtoken.archive IS 'The archive to which this token refers.';
-
-
-COMMENT ON COLUMN archiveauthtoken.person IS 'The person to which this token applies.';
-
-
-COMMENT ON COLUMN archiveauthtoken.date_created IS 'The date and time this token was created.';
-
-
-COMMENT ON COLUMN archiveauthtoken.date_deactivated IS 'The date and time this token was deactivated.';
-
-
-COMMENT ON COLUMN archiveauthtoken.token IS 'The token text for this authorisation.';
-
-
-CREATE SEQUENCE archiveauthtoken_id_seq
+COMMENT ON TABLE public.archiveauthtoken IS 'Authorisation tokens to use in .htaccess for published archives.';
+
+
+COMMENT ON COLUMN public.archiveauthtoken.archive IS 'The archive to which this token refers.';
+
+
+COMMENT ON COLUMN public.archiveauthtoken.person IS 'The person to which this token applies.';
+
+
+COMMENT ON COLUMN public.archiveauthtoken.date_created IS 'The date and time this token was created.';
+
+
+COMMENT ON COLUMN public.archiveauthtoken.date_deactivated IS 'The date and time this token was deactivated.';
+
+
+COMMENT ON COLUMN public.archiveauthtoken.token IS 'The token text for this authorisation.';
+
+
+COMMENT ON COLUMN public.archiveauthtoken.name IS 'The name for this named token.';
+
+
+CREATE SEQUENCE public.archiveauthtoken_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE archiveauthtoken_id_seq OWNED BY archiveauthtoken.id;
-
-
-CREATE TABLE archivedependency (
+ALTER SEQUENCE public.archiveauthtoken_id_seq OWNED BY public.archiveauthtoken.id;
+
+
+CREATE TABLE public.archivedependency (
     id integer NOT NULL,
     date_created timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL,
     archive integer NOT NULL,
@@ -4947,30 +4145,69 @@
 );
 
 
-COMMENT ON TABLE archivedependency IS 'This table maps a given archive to all other archives it should depend on.';
-
-
-COMMENT ON COLUMN archivedependency.date_created IS 'Instant when the dependency was created.';
-
-
-COMMENT ON COLUMN archivedependency.archive IS 'The archive where the dependency should be applied.';
-
-
-COMMENT ON COLUMN archivedependency.dependency IS 'The archive to depend on.';
-
-
-CREATE SEQUENCE archivedependency_id_seq
-    START WITH 1
-    INCREMENT BY 1
-    NO MAXVALUE
-    NO MINVALUE
-    CACHE 1;
-
-
-ALTER SEQUENCE archivedependency_id_seq OWNED BY archivedependency.id;
-
-
-CREATE TABLE archivejob (
+COMMENT ON TABLE public.archivedependency IS 'This table maps a given archive to all other archives it should depend on.';
+
+
+COMMENT ON COLUMN public.archivedependency.date_created IS 'Instant when the dependency was created.';
+
+
+COMMENT ON COLUMN public.archivedependency.archive IS 'The archive where the dependency should be applied.';
+
+
+COMMENT ON COLUMN public.archivedependency.dependency IS 'The archive to depend on.';
+
+
+CREATE SEQUENCE public.archivedependency_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER SEQUENCE public.archivedependency_id_seq OWNED BY public.archivedependency.id;
+
+
+CREATE TABLE public.archivefile (
+    id integer NOT NULL,
+    archive integer NOT NULL,
+    container text NOT NULL,
+    path text NOT NULL,
+    library_file integer NOT NULL,
+    scheduled_deletion_date timestamp without time zone
+);
+
+
+COMMENT ON TABLE public.archivefile IS 'A file in an archive.';
+
+
+COMMENT ON COLUMN public.archivefile.archive IS 'The archive containing the file.';
+
+
+COMMENT ON COLUMN public.archivefile.container IS 'An identifier for the component that manages this file.';
+
+
+COMMENT ON COLUMN public.archivefile.path IS 'The path to the file within the published archive.';
+
+
+COMMENT ON COLUMN public.archivefile.library_file IS 'The file in the librarian.';
+
+
+COMMENT ON COLUMN public.archivefile.scheduled_deletion_date IS 'The date when this file should stop being published.';
+
+
+CREATE SEQUENCE public.archivefile_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER SEQUENCE public.archivefile_id_seq OWNED BY public.archivefile.id;
+
+
+CREATE TABLE public.archivejob (
     id integer NOT NULL,
     job integer NOT NULL,
     archive integer NOT NULL,
@@ -4979,30 +4216,30 @@
 );
 
 
-COMMENT ON TABLE archivejob IS 'Contains references to jobs to be run against Archives.';
-
-
-COMMENT ON COLUMN archivejob.archive IS 'The archive on which the job is to be run.';
-
-
-COMMENT ON COLUMN archivejob.job_type IS 'The type of job (enumeration value). Allows us to query the database for a given subset of ArchiveJobs.';
-
-
-COMMENT ON COLUMN archivejob.json_data IS 'A JSON struct containing data for the job.';
-
-
-CREATE SEQUENCE archivejob_id_seq
+COMMENT ON TABLE public.archivejob IS 'Contains references to jobs to be run against Archives.';
+
+
+COMMENT ON COLUMN public.archivejob.archive IS 'The archive on which the job is to be run.';
+
+
+COMMENT ON COLUMN public.archivejob.job_type IS 'The type of job (enumeration value). Allows us to query the database for a given subset of ArchiveJobs.';
+
+
+COMMENT ON COLUMN public.archivejob.json_data IS 'A JSON struct containing data for the job.';
+
+
+CREATE SEQUENCE public.archivejob_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE archivejob_id_seq OWNED BY archivejob.id;
-
-
-CREATE TABLE archivepermission (
+ALTER SEQUENCE public.archivejob_id_seq OWNED BY public.archivejob.id;
+
+
+CREATE TABLE public.archivepermission (
     id integer NOT NULL,
     date_created timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL,
     person integer NOT NULL,
@@ -5012,49 +4249,57 @@
     sourcepackagename integer,
     packageset integer,
     explicit boolean DEFAULT false NOT NULL,
-    CONSTRAINT one_target CHECK ((null_count(ARRAY[packageset, component, sourcepackagename]) = 2))
+    pocket integer,
+    distroseries integer,
+    CONSTRAINT one_target CHECK ((public.null_count(ARRAY[packageset, component, sourcepackagename, pocket]) = 3))
 );
 
 
-COMMENT ON TABLE archivepermission IS 'ArchivePermission: A record of who has permission to upload and approve uploads to an archive (and hence a distribution)';
-
-
-COMMENT ON COLUMN archivepermission.date_created IS 'The date that this permission was created.';
-
-
-COMMENT ON COLUMN archivepermission.person IS 'The person or team to whom the permission is being granted.';
-
-
-COMMENT ON COLUMN archivepermission.permission IS 'The permission type being granted.';
-
-
-COMMENT ON COLUMN archivepermission.archive IS 'The archive to which this permission applies.';
-
-
-COMMENT ON COLUMN archivepermission.component IS 'The component to which this upload permission applies.';
-
-
-COMMENT ON COLUMN archivepermission.sourcepackagename IS 'The source package name to which this permission applies.  This can be used to provide package-level permissions to single users.';
-
-
-COMMENT ON COLUMN archivepermission.packageset IS 'The package set to which this permission applies.';
-
-
-COMMENT ON COLUMN archivepermission.explicit IS 'This flag is set for package sets containing high-profile packages that must not break and/or require specialist skills for proper handling e.g. the kernel.';
-
-
-CREATE SEQUENCE archivepermission_id_seq
+COMMENT ON TABLE public.archivepermission IS 'ArchivePermission: A record of who has permission to upload and approve uploads to an archive (and hence a distribution)';
+
+
+COMMENT ON COLUMN public.archivepermission.date_created IS 'The date that this permission was created.';
+
+
+COMMENT ON COLUMN public.archivepermission.person IS 'The person or team to whom the permission is being granted.';
+
+
+COMMENT ON COLUMN public.archivepermission.permission IS 'The permission type being granted.';
+
+
+COMMENT ON COLUMN public.archivepermission.archive IS 'The archive to which this permission applies.';
+
+
+COMMENT ON COLUMN public.archivepermission.component IS 'The component to which this upload permission applies.';
+
+
+COMMENT ON COLUMN public.archivepermission.sourcepackagename IS 'The source package name to which this permission applies.  This can be used to provide package-level permissions to single users.';
+
+
+COMMENT ON COLUMN public.archivepermission.packageset IS 'The package set to which this permission applies.';
+
+
+COMMENT ON COLUMN public.archivepermission.explicit IS 'This flag is set for package sets containing high-profile packages that must not break and/or require specialist skills for proper handling e.g. the kernel.';
+
+
+COMMENT ON COLUMN public.archivepermission.pocket IS 'The pocket to which this permission applies.';
+
+
+COMMENT ON COLUMN public.archivepermission.distroseries IS 'An optional distroseries to which this permission applies.';
+
+
+CREATE SEQUENCE public.archivepermission_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE archivepermission_id_seq OWNED BY archivepermission.id;
-
-
-CREATE TABLE archivesubscriber (
+ALTER SEQUENCE public.archivepermission_id_seq OWNED BY public.archivepermission.id;
+
+
+CREATE TABLE public.archivesubscriber (
     id integer NOT NULL,
     archive integer NOT NULL,
     registrant integer NOT NULL,
@@ -5068,109 +4313,134 @@
 );
 
 
-COMMENT ON TABLE archivesubscriber IS 'An authorised person or team subscription to an archive.';
-
-
-COMMENT ON COLUMN archivesubscriber.archive IS 'The archive that the subscriber is authorised to see.';
-
-
-COMMENT ON COLUMN archivesubscriber.registrant IS 'The person who authorised this subscriber.';
-
-
-COMMENT ON COLUMN archivesubscriber.date_created IS 'The date and time this subscription was created.';
-
-
-COMMENT ON COLUMN archivesubscriber.subscriber IS 'The person or team that this subscription refers to.';
-
-
-COMMENT ON COLUMN archivesubscriber.date_expires IS 'The date and time this subscription will expire. If NULL, it does not expire.';
-
-
-COMMENT ON COLUMN archivesubscriber.status IS 'The status of the subscription, e.g. PENDING, ACTIVE, CANCELLING, CANCELLED.';
-
-
-COMMENT ON COLUMN archivesubscriber.description IS 'An optional note for the archive owner to describe the subscription.';
-
-
-COMMENT ON COLUMN archivesubscriber.date_cancelled IS 'The date and time this subscription was revoked.';
-
-
-COMMENT ON COLUMN archivesubscriber.cancelled_by IS 'The person who revoked this subscription.';
-
-
-CREATE SEQUENCE archivesubscriber_id_seq
+COMMENT ON TABLE public.archivesubscriber IS 'An authorised person or team subscription to an archive.';
+
+
+COMMENT ON COLUMN public.archivesubscriber.archive IS 'The archive that the subscriber is authorised to see.';
+
+
+COMMENT ON COLUMN public.archivesubscriber.registrant IS 'The person who authorised this subscriber.';
+
+
+COMMENT ON COLUMN public.archivesubscriber.date_created IS 'The date and time this subscription was created.';
+
+
+COMMENT ON COLUMN public.archivesubscriber.subscriber IS 'The person or team that this subscription refers to.';
+
+
+COMMENT ON COLUMN public.archivesubscriber.date_expires IS 'The date and time this subscription will expire. If NULL, it does not expire.';
+
+
+COMMENT ON COLUMN public.archivesubscriber.status IS 'The status of the subscription, e.g. PENDING, ACTIVE, CANCELLING, CANCELLED.';
+
+
+COMMENT ON COLUMN public.archivesubscriber.description IS 'An optional note for the archive owner to describe the subscription.';
+
+
+COMMENT ON COLUMN public.archivesubscriber.date_cancelled IS 'The date and time this subscription was revoked.';
+
+
+COMMENT ON COLUMN public.archivesubscriber.cancelled_by IS 'The person who revoked this subscription.';
+
+
+CREATE SEQUENCE public.archivesubscriber_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE archivesubscriber_id_seq OWNED BY archivesubscriber.id;
-
-
-CREATE TABLE binarypackagename (
-    id integer NOT NULL,
-    name text NOT NULL,
-    CONSTRAINT valid_name CHECK (valid_name(name))
-);
-
-
-COMMENT ON TABLE binarypackagename IS 'BinaryPackageName: A soyuz binary package name.';
-
-
-COMMENT ON COLUMN binarypackagename.name IS 'A lowercase name identifying one or more binarypackages';
-
-
-CREATE TABLE sourcepackagename (
-    id integer NOT NULL,
-    name text NOT NULL,
-    CONSTRAINT valid_name CHECK (valid_name(name))
-);
-
-
-COMMENT ON TABLE sourcepackagename IS 'SourcePackageName: A soyuz source package name.';
-
-
-COMMENT ON COLUMN sourcepackagename.name IS 'A lowercase name identifying one or more sourcepackages';
-
-
-CREATE VIEW binaryandsourcepackagenameview AS
-    SELECT binarypackagename.name FROM binarypackagename UNION SELECT sourcepackagename.name FROM sourcepackagename;
-
-
-CREATE TABLE binarypackagebuild (
-    id integer NOT NULL,
-    package_build integer NOT NULL,
+ALTER SEQUENCE public.archivesubscriber_id_seq OWNED BY public.archivesubscriber.id;
+
+
+CREATE TABLE public.binarypackagename (
+    id integer NOT NULL,
+    name text NOT NULL,
+    CONSTRAINT valid_name CHECK (public.valid_name(name))
+);
+
+
+COMMENT ON TABLE public.binarypackagename IS 'BinaryPackageName: A soyuz binary package name.';
+
+
+COMMENT ON COLUMN public.binarypackagename.name IS 'A lowercase name identifying one or more binarypackages';
+
+
+CREATE TABLE public.sourcepackagename (
+    id integer NOT NULL,
+    name text NOT NULL,
+    CONSTRAINT valid_name CHECK (public.valid_name(name))
+);
+
+
+COMMENT ON TABLE public.sourcepackagename IS 'SourcePackageName: A soyuz source package name.';
+
+
+COMMENT ON COLUMN public.sourcepackagename.name IS 'A lowercase name identifying one or more sourcepackages';
+
+
+CREATE VIEW public.binaryandsourcepackagenameview AS
+ SELECT binarypackagename.name
+   FROM public.binarypackagename
+UNION
+ SELECT sourcepackagename.name
+   FROM public.sourcepackagename;
+
+
+CREATE TABLE public.binarypackagebuild (
+    id integer NOT NULL,
     distro_arch_series integer NOT NULL,
-    source_package_release integer NOT NULL
+    source_package_release integer NOT NULL,
+    archive integer NOT NULL,
+    pocket integer NOT NULL,
+    processor integer,
+    virtualized boolean,
+    date_created timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL,
+    date_started timestamp without time zone,
+    date_finished timestamp without time zone,
+    date_first_dispatched timestamp without time zone,
+    builder integer,
+    status integer NOT NULL,
+    log integer,
+    upload_log integer,
+    dependencies text,
+    failure_count integer DEFAULT 0 NOT NULL,
+    build_farm_job integer NOT NULL,
+    distribution integer NOT NULL,
+    distro_series integer NOT NULL,
+    is_distro_archive boolean NOT NULL,
+    source_package_name integer NOT NULL,
+    arch_indep boolean NOT NULL,
+    external_dependencies text,
+    buildinfo integer
 );
 
 
-COMMENT ON TABLE binarypackagebuild IS 'BinaryPackageBuild: This table links a package build with a distroarchseries and sourcepackagerelease.';
-
-
-COMMENT ON COLUMN binarypackagebuild.package_build IS 'Points to the related package build with the base information.';
-
-
-COMMENT ON COLUMN binarypackagebuild.distro_arch_series IS 'Points the target DistroArchSeries for this build.';
-
-
-COMMENT ON COLUMN binarypackagebuild.source_package_release IS 'SourcePackageRelease which originated this build.';
-
-
-CREATE SEQUENCE binarypackagebuild_id_seq
+COMMENT ON TABLE public.binarypackagebuild IS 'BinaryPackageBuild: This table links a package build with a distroarchseries and sourcepackagerelease.';
+
+
+COMMENT ON COLUMN public.binarypackagebuild.distro_arch_series IS 'Points the target DistroArchSeries for this build.';
+
+
+COMMENT ON COLUMN public.binarypackagebuild.source_package_release IS 'SourcePackageRelease which originated this build.';
+
+
+COMMENT ON COLUMN public.binarypackagebuild.external_dependencies IS 'Newline-separated list of repositories to be used to retrieve any external build dependencies when performing this build, in the format: "deb http[s]://[user:pass@]<host>[/path] series[-pocket] [components]".  This is intended for bootstrapping build-dependency loops.';
+
+
+CREATE SEQUENCE public.binarypackagebuild_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE binarypackagebuild_id_seq OWNED BY binarypackagebuild.id;
-
-
-CREATE TABLE binarypackagefile (
+ALTER SEQUENCE public.binarypackagebuild_id_seq OWNED BY public.binarypackagebuild.id;
+
+
+CREATE TABLE public.binarypackagefile (
     binarypackagerelease integer NOT NULL,
     libraryfile integer NOT NULL,
     filetype integer NOT NULL,
@@ -5178,30 +4448,41 @@
 );
 
 
-COMMENT ON TABLE binarypackagefile IS 'BinaryPackageFile: A soyuz <-> librarian link table. This table represents the ownership in the librarian of a file which represents a binary package';
-
-
-COMMENT ON COLUMN binarypackagefile.binarypackagerelease IS 'The binary package which is represented by the file';
-
-
-COMMENT ON COLUMN binarypackagefile.libraryfile IS 'The file in the librarian which represents the package';
-
-
-COMMENT ON COLUMN binarypackagefile.filetype IS 'The "type" of the file. E.g. DEB, RPM';
-
-
-CREATE SEQUENCE binarypackagefile_id_seq
-    START WITH 1
-    INCREMENT BY 1
-    NO MAXVALUE
-    NO MINVALUE
-    CACHE 1;
-
-
-ALTER SEQUENCE binarypackagefile_id_seq OWNED BY binarypackagefile.id;
-
-
-CREATE TABLE binarypackagepublishinghistory (
+COMMENT ON TABLE public.binarypackagefile IS 'BinaryPackageFile: A soyuz <-> librarian link table. This table represents the ownership in the librarian of a file which represents a binary package';
+
+
+COMMENT ON COLUMN public.binarypackagefile.binarypackagerelease IS 'The binary package which is represented by the file';
+
+
+COMMENT ON COLUMN public.binarypackagefile.libraryfile IS 'The file in the librarian which represents the package';
+
+
+COMMENT ON COLUMN public.binarypackagefile.filetype IS 'The "type" of the file. E.g. DEB, RPM';
+
+
+CREATE SEQUENCE public.binarypackagefile_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER SEQUENCE public.binarypackagefile_id_seq OWNED BY public.binarypackagefile.id;
+
+
+CREATE SEQUENCE public.binarypackagename_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER SEQUENCE public.binarypackagename_id_seq OWNED BY public.binarypackagename.id;
+
+
+CREATE TABLE public.binarypackagepublishinghistory (
     id integer NOT NULL,
     binarypackagerelease integer NOT NULL,
     distroarchseries integer NOT NULL,
@@ -5220,68 +4501,86 @@
     archive integer NOT NULL,
     removed_by integer,
     removal_comment text,
-    binarypackagename integer
+    binarypackagename integer NOT NULL,
+    phased_update_percentage smallint
 );
 
 
-COMMENT ON TABLE binarypackagepublishinghistory IS 'PackagePublishingHistory: The history of a BinaryPackagePublishing record. This table represents the lifetime of a publishing record from inception to deletion. Records are never removed from here and in time the publishing table may become a view onto this table. A column being NULL indicates there''s no data for that state transition. E.g. a package which is removed without being superseded won''t have datesuperseded or supersededby filled in.';
-
-
-COMMENT ON COLUMN binarypackagepublishinghistory.binarypackagerelease IS 'The binarypackage being published.';
-
-
-COMMENT ON COLUMN binarypackagepublishinghistory.distroarchseries IS 'The distroarchseries into which the binarypackage is being published.';
-
-
-COMMENT ON COLUMN binarypackagepublishinghistory.status IS 'The current status of the publishing.';
-
-
-COMMENT ON COLUMN binarypackagepublishinghistory.component IS 'The component into which the publishing takes place.';
-
-
-COMMENT ON COLUMN binarypackagepublishinghistory.section IS 'The section into which the publishing takes place.';
-
-
-COMMENT ON COLUMN binarypackagepublishinghistory.priority IS 'The priority at which the publishing takes place.';
-
-
-COMMENT ON COLUMN binarypackagepublishinghistory.datecreated IS 'The date/time on which the publishing record was created.';
-
-
-COMMENT ON COLUMN binarypackagepublishinghistory.datepublished IS 'The date/time on which the source was actually published into an archive.';
-
-
-COMMENT ON COLUMN binarypackagepublishinghistory.datesuperseded IS 'The date/time on which the source was superseded by a new source.';
-
-
-COMMENT ON COLUMN binarypackagepublishinghistory.supersededby IS 'The build which superseded this package. This seems odd but it is important because a new build may not actually build a given binarypackage and we need to supersede it appropriately';
-
-
-COMMENT ON COLUMN binarypackagepublishinghistory.datemadepending IS 'The date/time on which this publishing record was made to be pending removal from the archive.';
-
-
-COMMENT ON COLUMN binarypackagepublishinghistory.scheduleddeletiondate IS 'The date/time at which the package is/was scheduled to be deleted.';
-
-
-COMMENT ON COLUMN binarypackagepublishinghistory.dateremoved IS 'The date/time at which the package was actually deleted.';
-
-
-COMMENT ON COLUMN binarypackagepublishinghistory.pocket IS 'The pocket into which this record is published. The RELEASE pocket (zero) provides behaviour as normal. Other pockets may append things to the distroseries name such as the UPDATES pocket (-updates) or the SECURITY pocket (-security).';
-
-
-COMMENT ON COLUMN binarypackagepublishinghistory.archive IS 'Target archive for this publishing record.';
-
-
-COMMENT ON COLUMN binarypackagepublishinghistory.removed_by IS 'Person responsible for the removal.';
-
-
-COMMENT ON COLUMN binarypackagepublishinghistory.removal_comment IS 'Reason why the publication was removed.';
-
-
-CREATE TABLE binarypackagerelease (
+COMMENT ON TABLE public.binarypackagepublishinghistory IS 'PackagePublishingHistory: The history of a BinaryPackagePublishing record. This table represents the lifetime of a publishing record from inception to deletion. Records are never removed from here and in time the publishing table may become a view onto this table. A column being NULL indicates there''s no data for that state transition. E.g. a package which is removed without being superseded won''t have datesuperseded or supersededby filled in.';
+
+
+COMMENT ON COLUMN public.binarypackagepublishinghistory.binarypackagerelease IS 'The binarypackage being published.';
+
+
+COMMENT ON COLUMN public.binarypackagepublishinghistory.distroarchseries IS 'The distroarchseries into which the binarypackage is being published.';
+
+
+COMMENT ON COLUMN public.binarypackagepublishinghistory.status IS 'The current status of the publishing.';
+
+
+COMMENT ON COLUMN public.binarypackagepublishinghistory.component IS 'The component into which the publishing takes place.';
+
+
+COMMENT ON COLUMN public.binarypackagepublishinghistory.section IS 'The section into which the publishing takes place.';
+
+
+COMMENT ON COLUMN public.binarypackagepublishinghistory.priority IS 'The priority at which the publishing takes place.';
+
+
+COMMENT ON COLUMN public.binarypackagepublishinghistory.datecreated IS 'The date/time on which the publishing record was created.';
+
+
+COMMENT ON COLUMN public.binarypackagepublishinghistory.datepublished IS 'The date/time on which the source was actually published into an archive.';
+
+
+COMMENT ON COLUMN public.binarypackagepublishinghistory.datesuperseded IS 'The date/time on which the source was superseded by a new source.';
+
+
+COMMENT ON COLUMN public.binarypackagepublishinghistory.supersededby IS 'The build which superseded this package. This seems odd but it is important because a new build may not actually build a given binarypackage and we need to supersede it appropriately';
+
+
+COMMENT ON COLUMN public.binarypackagepublishinghistory.datemadepending IS 'The date/time on which this publishing record was made to be pending removal from the archive.';
+
+
+COMMENT ON COLUMN public.binarypackagepublishinghistory.scheduleddeletiondate IS 'The date/time at which the package is/was scheduled to be deleted.';
+
+
+COMMENT ON COLUMN public.binarypackagepublishinghistory.dateremoved IS 'The date/time at which the package was actually deleted.';
+
+
+COMMENT ON COLUMN public.binarypackagepublishinghistory.pocket IS 'The pocket into which this record is published. The RELEASE pocket (zero) provides behaviour as normal. Other pockets may append things to the distroseries name such as the UPDATES pocket (-updates) or the SECURITY pocket (-security).';
+
+
+COMMENT ON COLUMN public.binarypackagepublishinghistory.archive IS 'Target archive for this publishing record.';
+
+
+COMMENT ON COLUMN public.binarypackagepublishinghistory.removed_by IS 'Person responsible for the removal.';
+
+
+COMMENT ON COLUMN public.binarypackagepublishinghistory.removal_comment IS 'Reason why the publication was removed.';
+
+
+COMMENT ON COLUMN public.binarypackagepublishinghistory.binarypackagename IS 'Reference to a BinaryPackageName.';
+
+
+COMMENT ON COLUMN public.binarypackagepublishinghistory.phased_update_percentage IS 'Percentage of users for whom this package should be recommended. NULL indicates no phasing, i.e. publish the update for everyone.';
+
+
+CREATE SEQUENCE public.binarypackagepublishinghistory_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER SEQUENCE public.binarypackagepublishinghistory_id_seq OWNED BY public.binarypackagepublishinghistory.id;
+
+
+CREATE TABLE public.binarypackagerelease (
     id integer NOT NULL,
     binarypackagename integer NOT NULL,
-    version debversion NOT NULL,
+    version public.debversion NOT NULL,
     summary text NOT NULL,
     description text NOT NULL,
     build integer NOT NULL,
@@ -5299,7 +4598,7 @@
     essential boolean NOT NULL,
     installedsize integer,
     architecturespecific boolean NOT NULL,
-    fti ts2.tsvector,
+    fti public.ts2_tsvector,
     datecreated timestamp without time zone DEFAULT timezone('UTC'::text, ('now'::text)::timestamp(6) with time zone) NOT NULL,
     pre_depends text,
     enhances text,
@@ -5307,514 +4606,100 @@
     debug_package integer,
     user_defined_fields text,
     homepage text,
-    CONSTRAINT valid_version CHECK (valid_debian_version((version)::text))
-);
-
-
-COMMENT ON TABLE binarypackagerelease IS 'BinaryPackageRelease: A soyuz binary package representation. This table stores the records for each binary package uploaded into the system. Each sourcepackagerelease may build various binarypackages on various architectures.';
-
-
-COMMENT ON COLUMN binarypackagerelease.binarypackagename IS 'A reference to the name of the binary package';
-
-
-COMMENT ON COLUMN binarypackagerelease.version IS 'The version of the binary package. E.g. "1.0-2"';
-
-
-COMMENT ON COLUMN binarypackagerelease.summary IS 'A summary of the binary package. Commonly used on listings of binary packages';
-
-
-COMMENT ON COLUMN binarypackagerelease.description IS 'A longer more detailed description of the binary package';
-
-
-COMMENT ON COLUMN binarypackagerelease.build IS 'The build in which this binarypackage was produced';
-
-
-COMMENT ON COLUMN binarypackagerelease.binpackageformat IS 'The binarypackage format. E.g. RPM, DEB etc';
-
-
-COMMENT ON COLUMN binarypackagerelease.component IS 'The archive component that this binarypackage is in. E.g. main, universe etc';
-
-
-COMMENT ON COLUMN binarypackagerelease.section IS 'The archive section that this binarypackage is in. E.g. devel, libdevel, editors';
-
-
-COMMENT ON COLUMN binarypackagerelease.priority IS 'The priority that this package has. E.g. Base, Standard, Extra, Optional';
-
-
-COMMENT ON COLUMN binarypackagerelease.shlibdeps IS 'The shared library dependencies of this binary package';
-
-
-COMMENT ON COLUMN binarypackagerelease.depends IS 'The list of packages this binarypackage depends on';
-
-
-COMMENT ON COLUMN binarypackagerelease.recommends IS 'The list of packages this binarypackage recommends. Recommended packages often enhance the behaviour of a package.';
-
-
-COMMENT ON COLUMN binarypackagerelease.suggests IS 'The list of packages this binarypackage suggests.';
-
-
-COMMENT ON COLUMN binarypackagerelease.conflicts IS 'The list of packages this binarypackage conflicts with.';
-
-
-COMMENT ON COLUMN binarypackagerelease.replaces IS 'The list of packages this binarypackage replaces files in. Often this is used to provide an upgrade path between two binarypackages of different names';
-
-
-COMMENT ON COLUMN binarypackagerelease.provides IS 'The list of virtual packages (or real packages under some circumstances) which this binarypackage provides.';
-
-
-COMMENT ON COLUMN binarypackagerelease.essential IS 'Whether or not this binarypackage is essential to the smooth operation of a base system';
-
-
-COMMENT ON COLUMN binarypackagerelease.installedsize IS 'What the installed size of the binarypackage is. This is represented as a number of kilobytes of storage.';
-
-
-COMMENT ON COLUMN binarypackagerelease.architecturespecific IS 'This field indicates whether or not a binarypackage is architecture-specific. If it is not specific to any given architecture then it can automatically be included in all the distroarchseries which pertain.';
-
-
-COMMENT ON COLUMN binarypackagerelease.pre_depends IS 'The list of packages this binary requires to be installed beforehand in apt/dpkg format, as it is in control file "Pre-Depends:" field.';
-
-
-COMMENT ON COLUMN binarypackagerelease.enhances IS 'The list of packages pointed as "enhanced" after the installation of this package, as it is in control file "Enhances:" field.';
-
-
-COMMENT ON COLUMN binarypackagerelease.breaks IS 'The list of packages which will be broken by the installtion of this package, as it is in the control file "Breaks:" field.';
-
-
-COMMENT ON COLUMN binarypackagerelease.debug_package IS 'The corresponding binary package release containing debug symbols for this binary, if any.';
-
-
-COMMENT ON COLUMN binarypackagerelease.user_defined_fields IS 'A JSON struct containing a sequence of key-value pairs with user defined fields in the control file.';
-
-
-COMMENT ON COLUMN binarypackagerelease.homepage IS 'Upstream project homepage URL, not checked for validity.';
-
-
-CREATE TABLE component (
-    id integer NOT NULL,
-    name text NOT NULL,
-    description text,
-    CONSTRAINT valid_name CHECK (valid_name(name))
-);
-
-
-COMMENT ON TABLE component IS 'Known components in Launchpad';
-
-
-COMMENT ON COLUMN component.name IS 'Component name text';
-
-
-COMMENT ON COLUMN component.description IS 'Description of this component.';
-
-
-CREATE TABLE distroarchseries (
-    id integer NOT NULL,
-    distroseries integer NOT NULL,
-    processorfamily integer NOT NULL,
-    architecturetag text NOT NULL,
-    owner integer NOT NULL,
-    official boolean NOT NULL,
-    package_count integer DEFAULT 0 NOT NULL,
-    date_created timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL,
-    supports_virtualized boolean DEFAULT false NOT NULL,
-    enabled boolean DEFAULT true NOT NULL,
-    CONSTRAINT valid_architecturetag CHECK (valid_name(architecturetag))
-);
-
-
-COMMENT ON TABLE distroarchseries IS 'DistroArchSeries: A soyuz distribution release for a given architecture. A distroseries runs on various architectures. The distroarchseries groups that architecture-specific stuff.';
-
-
-COMMENT ON COLUMN distroarchseries.distroseries IS 'The distribution which this distroarchseries is part of.';
-
-
-COMMENT ON COLUMN distroarchseries.processorfamily IS 'A link to the ProcessorFamily table, giving the architecture of this DistroArchSeries.';
-
-
-COMMENT ON COLUMN distroarchseries.architecturetag IS 'The name of this architecture in the context of this specific distro release. For example, some distributions might label amd64 as amd64, others might call is x86_64. This information is used, for example, in determining the names of the actual package files... such as the "amd64" part of "apache2_2.0.56-1_amd64.deb"';
-
-
-COMMENT ON COLUMN distroarchseries.official IS 'Whether or not this architecture or "port" is an official release. If it is not official then you may not be able to install it or get all the packages for it.';
-
-
-COMMENT ON COLUMN distroarchseries.package_count IS 'A cache of the number of binary packages published in this distro arch release. The count only includes packages published in the release pocket.';
-
-
-COMMENT ON COLUMN distroarchseries.supports_virtualized IS 'Whether or not
-virtualized build support should be provided by this specific distroarchseries';
-
-
-COMMENT ON COLUMN distroarchseries.enabled IS 'Whether to allow build creation and publishing for this DistroArchSeries.';
-
-
-CREATE TABLE distroseries (
-    id integer NOT NULL,
-    distribution integer NOT NULL,
-    name text NOT NULL,
-    title text NOT NULL,
-    description text NOT NULL,
-    version text NOT NULL,
-    releasestatus integer NOT NULL,
-    datereleased timestamp without time zone,
-    parent_series integer,
-    registrant integer NOT NULL,
-    summary text NOT NULL,
-    displayname text NOT NULL,
-    datelastlangpack timestamp without time zone,
-    messagecount integer DEFAULT 0 NOT NULL,
-    nominatedarchindep integer,
-    changeslist text,
-    binarycount integer DEFAULT 0 NOT NULL,
-    sourcecount integer DEFAULT 0 NOT NULL,
-    driver integer,
-    date_created timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL,
-    hide_all_translations boolean DEFAULT true NOT NULL,
-    defer_translation_imports boolean DEFAULT true NOT NULL,
-    language_pack_base integer,
-    language_pack_delta integer,
-    language_pack_proposed integer,
-    language_pack_full_export_requested boolean DEFAULT false NOT NULL,
-    backports_not_automatic boolean DEFAULT false NOT NULL,
-    include_long_descriptions boolean DEFAULT true NOT NULL,
-    CONSTRAINT valid_language_pack_delta CHECK (((language_pack_base IS NOT NULL) OR (language_pack_delta IS NULL))),
-    CONSTRAINT valid_name CHECK (valid_name(name)),
-    CONSTRAINT valid_version CHECK (sane_version(version))
-);
-
-
-COMMENT ON TABLE distroseries IS 'DistroSeries: A soyuz distribution release. A DistroSeries is a given version of a distribution. E.g. "Warty" "Hoary" "Sarge" etc.';
-
-
-COMMENT ON COLUMN distroseries.distribution IS 'The distribution which contains this distroseries.';
-
-
-COMMENT ON COLUMN distroseries.name IS 'The unique name of the distroseries. This is a short name in lower case and would be used in sources.list configuration and in generated URLs. E.g. "warty" "sarge" "sid"';
-
-
-COMMENT ON COLUMN distroseries.title IS 'The display-name title of the distroseries E.g. "Warty Warthog"';
-
-
-COMMENT ON COLUMN distroseries.description IS 'The long detailed description of the release. This may describe the focus of the release or other related information.';
-
-
-COMMENT ON COLUMN distroseries.version IS 'The version of the release. E.g. warty would be "4.10" and hoary would be "5.4"';
-
-
-COMMENT ON COLUMN distroseries.releasestatus IS 'The current release status of this distroseries. E.g. "pre-release freeze" or "released"';
-
-
-COMMENT ON COLUMN distroseries.datereleased IS 'The date on which this distroseries was released. (obviously only valid for released distributions)';
-
-
-COMMENT ON COLUMN distroseries.parent_series IS 'The parent distroseries on which this distribution is based. This is related to the inheritance stuff.';
-
-
-COMMENT ON COLUMN distroseries.registrant IS 'The ultimate owner of this distroseries.';
-
-
-COMMENT ON COLUMN distroseries.summary IS 'A brief summary of the distro release. This will be displayed in bold at the top of the distroseries page, above the distroseries description. It should include any high points that are particularly important to draw to the attention of users.';
-
-
-COMMENT ON COLUMN distroseries.datelastlangpack IS 'The date we last generated a base language pack for this release. Language update packs for this release will only include translations added after that date.';
-
-
-COMMENT ON COLUMN distroseries.messagecount IS 'This is a cached value and may be a few hours out of sync with reality. It should, however, be in sync with the values in DistroSeriesLanguage, and should never be updated separately. The total number of translation messages in this distro release, as per IRosettaStats.';
-
-
-COMMENT ON COLUMN distroseries.nominatedarchindep IS 'This is the DistroArchSeries nominated to build architecture independent packages within this DistroRelase, it is mandatory for buildable distroseries, i.e., Auto Build System will avoid to create build jobs for a DistroSeries with no nominatedarchindep, but the database model allow us to do it (for non-buildable DistroSeries). See further info in NominatedArchIndep specification.';
-
-
-COMMENT ON COLUMN distroseries.changeslist IS 'The email address (name name) of the changes announcement list for this distroseries. If NULL, no announcement mail will be sent.';
-
-
-COMMENT ON COLUMN distroseries.binarycount IS 'A cache of the number of distinct binary package names published in this distro release.';
-
-
-COMMENT ON COLUMN distroseries.sourcecount IS 'A cache of the number of distinct source package names published in this distro release.';
-
-
-COMMENT ON COLUMN distroseries.driver IS 'This is a person or team who can act as a driver for this specific release - note that the distribution drivers can also set goals for any release.';
-
-
-COMMENT ON COLUMN distroseries.hide_all_translations IS 'Whether we should hid
-e all available translations for this distro release to non admin users.';
-
-
-COMMENT ON COLUMN distroseries.defer_translation_imports IS 'Don''t accept PO imports for this release just now.';
-
-
-COMMENT ON COLUMN distroseries.language_pack_base IS 'Current full export language pack for this distribution release.';
-
-
-COMMENT ON COLUMN distroseries.language_pack_delta IS 'Current language pack update based on language_pack_base information.';
-
-
-COMMENT ON COLUMN distroseries.language_pack_proposed IS 'Either a full or update language pack being tested to be used in language_pack_base or language_pack_delta.';
-
-
-COMMENT ON COLUMN distroseries.language_pack_full_export_requested IS 'Whether next language pack export should be a full export or an update.';
-
-
-CREATE TABLE libraryfilealias (
-    id integer NOT NULL,
-    content integer,
-    filename text NOT NULL,
-    mimetype text NOT NULL,
-    expires timestamp without time zone,
-    last_accessed timestamp without time zone DEFAULT timezone('UTC'::text, ('now'::text)::timestamp(6) with time zone) NOT NULL,
-    date_created timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL,
-    restricted boolean DEFAULT false NOT NULL,
-    hits integer DEFAULT 0 NOT NULL,
-    CONSTRAINT valid_filename CHECK ((filename !~~ '%/%'::text))
-);
-
-
-COMMENT ON TABLE libraryfilealias IS 'LibraryFileAlias: A librarian file''s alias. The librarian stores, along with the file contents, a record stating the file name and mimetype. This table represents it.';
-
-
-COMMENT ON COLUMN libraryfilealias.content IS 'The libraryfilecontent which is the data in this file.';
-
-
-COMMENT ON COLUMN libraryfilealias.filename IS 'The name of the file. E.g. "foo_1.0-1_i386.deb"';
-
-
-COMMENT ON COLUMN libraryfilealias.mimetype IS 'The mime type of the file. E.g. "application/x-debian-package"';
-
-
-COMMENT ON COLUMN libraryfilealias.expires IS 'The expiry date of this file. If NULL, this item may be removed as soon as it is no longer referenced. If set, the item will not be removed until this date. Once the date is passed, the file may be removed from disk even if this item is still being referenced (in which case content.deleted will be true)';
-
-
-COMMENT ON COLUMN libraryfilealias.last_accessed IS 'Roughly when this file was last retrieved from the Librarian. Initially set to this item''s creation date.';
-
-
-COMMENT ON COLUMN libraryfilealias.date_created IS 'The timestamp when this alias was created.';
-
-
-COMMENT ON COLUMN libraryfilealias.restricted IS 'Is this file available only from the restricted librarian?';
-
-
-COMMENT ON COLUMN libraryfilealias.hits IS 'The number of times this file has been downloaded.';
-
-
-CREATE TABLE sourcepackagerelease (
-    id integer NOT NULL,
-    creator integer NOT NULL,
-    version debversion NOT NULL,
-    dateuploaded timestamp without time zone DEFAULT timezone('UTC'::text, ('now'::text)::timestamp(6) with time zone) NOT NULL,
-    urgency integer NOT NULL,
-    dscsigningkey integer,
-    component integer NOT NULL,
-    changelog_entry text,
-    builddepends text,
-    builddependsindep text,
-    architecturehintlist text NOT NULL,
-    dsc text,
-    section integer NOT NULL,
-    maintainer integer NOT NULL,
-    sourcepackagename integer NOT NULL,
-    upload_distroseries integer NOT NULL,
-    format integer NOT NULL,
-    dsc_maintainer_rfc822 text,
-    dsc_standards_version text,
-    dsc_format text NOT NULL,
-    dsc_binaries text,
-    upload_archive integer,
-    copyright text,
-    build_conflicts text,
-    build_conflicts_indep text,
-    sourcepackage_recipe_build integer,
-    changelog integer,
-    user_defined_fields text,
-    homepage text,
-    CONSTRAINT valid_version CHECK (valid_debian_version((version)::text))
-);
-
-
-COMMENT ON TABLE sourcepackagerelease IS 'SourcePackageRelease: A source
-package release. This table represents a specific release of a source
-package. Source package releases may be published into a distroseries, or
-even multiple distroseries.';
-
-
-COMMENT ON COLUMN sourcepackagerelease.creator IS 'The creator of this
-sourcepackagerelease. This is the person referred to in the top entry in the
-package changelog in debian terms. Note that a source package maintainer in
-Ubuntu might be person A, but a particular release of that source package
-might in fact have been created by a different person B. The maintainer
-would be recorded in the Maintainership table, while the creator of THIS
-release would be recorded in the SourcePackageRelease.creator field.';
-
-
-COMMENT ON COLUMN sourcepackagerelease.version IS 'The version string for
-this source package release. E.g. "1.0-2" or "1.4-5ubuntu9.1". Note that, in
-ubuntu-style and redhat-style distributions, the version+sourcepackagename
-is unique, even across distroseries. In other words, you cannot have a
-foo-1.2-1 package in Hoary that is different from foo-1.2-1 in Warty.';
-
-
-COMMENT ON COLUMN sourcepackagerelease.dateuploaded IS 'The date/time that
-this sourcepackagerelease was first uploaded to the Launchpad.';
-
-
-COMMENT ON COLUMN sourcepackagerelease.urgency IS 'The urgency of the
-upload. This is generally used to prioritise buildd activity but may also be
-used for "testing" systems or security work in the future. The "urgency" is
-set by the uploader, in the DSC file.';
-
-
-COMMENT ON COLUMN sourcepackagerelease.dscsigningkey IS 'The GPG key used to
-sign the DSC. This is not necessarily the maintainer''s key, or the
-creator''s key. For example, it''s possible to produce a package, then ask a
-sponsor to upload it.';
-
-
-COMMENT ON COLUMN sourcepackagerelease.component IS 'The component in which
-this sourcepackagerelease is intended (by the uploader) to reside. E.g.
-main, universe, restricted. Note that the distribution managers will often
-override this data and publish the package in an entirely different
-component.';
-
-
-COMMENT ON COLUMN sourcepackagerelease.changelog_entry IS 'Changelog text section extracted from the changesfile.';
-
-
-COMMENT ON COLUMN sourcepackagerelease.builddepends IS 'The build
-dependencies for this source package release.';
-
-
-COMMENT ON COLUMN sourcepackagerelease.builddependsindep IS 'The
-architecture-independant build dependancies for this source package release.';
-
-
-COMMENT ON COLUMN sourcepackagerelease.architecturehintlist IS 'The
-architectures which this source package release believes it should be built.
-This is used as a hint to the build management system when deciding what
-builds are still needed.';
-
-
-COMMENT ON COLUMN sourcepackagerelease.dsc IS 'The "Debian Source Control"
-file for the sourcepackagerelease, from its upload into Ubuntu for the
-first time.';
-
-
-COMMENT ON COLUMN sourcepackagerelease.section IS 'This integer field references the Section which the source package claims to be in';
-
-
-COMMENT ON COLUMN sourcepackagerelease.maintainer IS 'Reference to the person noted as source package maintainer in the DSC.';
-
-
-COMMENT ON COLUMN sourcepackagerelease.sourcepackagename IS 'Reference to a SourcePackageName.';
-
-
-COMMENT ON COLUMN sourcepackagerelease.upload_distroseries IS 'The
-distroseries into which this source package release was uploaded into
-Launchpad / Ubuntu for the first time. In general, this will be the
-development Ubuntu release into which this package was uploaded. For a
-package which was unchanged between warty and hoary, this would show Warty.
-For a package which was uploaded into Hoary, this would show Hoary.';
-
-
-COMMENT ON COLUMN sourcepackagerelease.format IS 'The format of this
-sourcepackage release, e.g. DPKG, RPM, EBUILD, etc. This is an enum, and the
-values are listed in dbschema.SourcePackageFormat';
-
-
-COMMENT ON COLUMN sourcepackagerelease.dsc_maintainer_rfc822 IS 'The original maintainer line in RFC-822 format, to be used in archive indexes.';
-
-
-COMMENT ON COLUMN sourcepackagerelease.dsc_standards_version IS 'DSC standards version (such as "3.6.2", "3.5.9", etc) used to build this source.';
-
-
-COMMENT ON COLUMN sourcepackagerelease.dsc_format IS 'DSC format version (such as "1.0").';
-
-
-COMMENT ON COLUMN sourcepackagerelease.dsc_binaries IS 'DSC binary line, claimed binary-names produce by this source.';
-
-
-COMMENT ON COLUMN sourcepackagerelease.upload_archive IS 'The archive into which this sourcepackagerelese was originally uploaded.';
-
-
-COMMENT ON COLUMN sourcepackagerelease.copyright IS 'The copyright associated with this sourcepackage. Often in the case of debian packages and will be found after the installation in /usr/share/doc/<binarypackagename>/copyright';
-
-
-COMMENT ON COLUMN sourcepackagerelease.build_conflicts IS 'The list of packages that will conflict with this source while building, as mentioned in the control file "Build-Conflicts:" field.';
-
-
-COMMENT ON COLUMN sourcepackagerelease.build_conflicts_indep IS 'The list of packages that will conflict with this source while building in architecture independent environment, as mentioned in the control file "Build-Conflicts-Indep:" field.';
-
-
-COMMENT ON COLUMN sourcepackagerelease.changelog IS 'The LibraryFileAlias ID of changelog associated with this sourcepackage.  Often in the case of debian packages and will be found after the installation in /usr/share/doc/<binarypackagename>/changelog.Debian.gz';
-
-
-COMMENT ON COLUMN sourcepackagerelease.user_defined_fields IS 'A JSON struct containing a sequence of key-value pairs with user defined fields in the control file.';
-
-
-COMMENT ON COLUMN sourcepackagerelease.homepage IS 'Upstream project homepage URL, not checked for validity.';
-
-
-CREATE VIEW binarypackagefilepublishing AS
-    SELECT (((libraryfilealias.id)::text || '.'::text) || (securebinarypackagepublishinghistory.id)::text) AS id, distroseries.distribution, securebinarypackagepublishinghistory.id AS binarypackagepublishing, component.name AS componentname, libraryfilealias.filename AS libraryfilealiasfilename, sourcepackagename.name AS sourcepackagename, binarypackagefile.libraryfile AS libraryfilealias, distroseries.name AS distroseriesname, distroarchseries.architecturetag, securebinarypackagepublishinghistory.status AS publishingstatus, securebinarypackagepublishinghistory.pocket, securebinarypackagepublishinghistory.archive FROM (((((((((binarypackagepublishinghistory securebinarypackagepublishinghistory JOIN binarypackagerelease ON ((securebinarypackagepublishinghistory.binarypackagerelease = binarypackagerelease.id))) JOIN binarypackagebuild ON ((binarypackagerelease.build = binarypackagebuild.id))) JOIN sourcepackagerelease ON ((binarypackagebuild.source_package_release = sourcepackagerelease.id))) JOIN sourcepackagename ON ((sourcepackagerelease.sourcepackagename = sourcepackagename.id))) JOIN binarypackagefile ON ((binarypackagefile.binarypackagerelease = binarypackagerelease.id))) JOIN libraryfilealias ON ((binarypackagefile.libraryfile = libraryfilealias.id))) JOIN distroarchseries ON ((securebinarypackagepublishinghistory.distroarchseries = distroarchseries.id))) JOIN distroseries ON ((distroarchseries.distroseries = distroseries.id))) JOIN component ON ((securebinarypackagepublishinghistory.component = component.id))) WHERE (securebinarypackagepublishinghistory.dateremoved IS NULL);
-
-
-COMMENT ON VIEW binarypackagefilepublishing IS 'This view is used mostly by Lucille while performing publishing and unpublishing operations. It lists all the files associated with a binarypackage and collates all the textual representations needed for publishing components etc to allow rapid queries from SQLObject.';
-
-
-CREATE SEQUENCE binarypackagename_id_seq
-    START WITH 1
-    INCREMENT BY 1
-    NO MAXVALUE
-    NO MINVALUE
-    CACHE 1;
-
-
-ALTER SEQUENCE binarypackagename_id_seq OWNED BY binarypackagename.id;
-
-
-CREATE TABLE binarypackagepath (
-    id integer NOT NULL,
-    path bytea NOT NULL
-);
-
-
-CREATE SEQUENCE binarypackagepath_id_seq
-    START WITH 1
-    INCREMENT BY 1
-    NO MAXVALUE
-    NO MINVALUE
-    CACHE 1;
-
-
-ALTER SEQUENCE binarypackagepath_id_seq OWNED BY binarypackagepath.id;
-
-
-CREATE SEQUENCE binarypackagepublishinghistory_id_seq
-    START WITH 1
-    INCREMENT BY 1
-    NO MAXVALUE
-    NO MINVALUE
-    CACHE 1;
-
-
-ALTER SEQUENCE binarypackagepublishinghistory_id_seq OWNED BY binarypackagepublishinghistory.id;
-
-
-CREATE SEQUENCE binarypackagerelease_id_seq
-    START WITH 1
-    INCREMENT BY 1
-    NO MAXVALUE
-    NO MINVALUE
-    CACHE 1;
-
-
-ALTER SEQUENCE binarypackagerelease_id_seq OWNED BY binarypackagerelease.id;
-
-
-CREATE TABLE binarypackagereleasecontents (
-    binarypackagerelease integer NOT NULL,
-    binarypackagepath integer NOT NULL
-);
-
-
-CREATE TABLE binarypackagereleasedownloadcount (
+    CONSTRAINT valid_version CHECK (public.valid_debian_version((version)::text))
+);
+
+
+COMMENT ON TABLE public.binarypackagerelease IS 'BinaryPackageRelease: A soyuz binary package representation. This table stores the records for each binary package uploaded into the system. Each sourcepackagerelease may build various binarypackages on various architectures.';
+
+
+COMMENT ON COLUMN public.binarypackagerelease.binarypackagename IS 'A reference to the name of the binary package';
+
+
+COMMENT ON COLUMN public.binarypackagerelease.version IS 'The version of the binary package. E.g. "1.0-2"';
+
+
+COMMENT ON COLUMN public.binarypackagerelease.summary IS 'A summary of the binary package. Commonly used on listings of binary packages';
+
+
+COMMENT ON COLUMN public.binarypackagerelease.description IS 'A longer more detailed description of the binary package';
+
+
+COMMENT ON COLUMN public.binarypackagerelease.build IS 'The build in which this binarypackage was produced';
+
+
+COMMENT ON COLUMN public.binarypackagerelease.binpackageformat IS 'The binarypackage format. E.g. RPM, DEB etc';
+
+
+COMMENT ON COLUMN public.binarypackagerelease.component IS 'The archive component that this binarypackage is in. E.g. main, universe etc';
+
+
+COMMENT ON COLUMN public.binarypackagerelease.section IS 'The archive section that this binarypackage is in. E.g. devel, libdevel, editors';
+
+
+COMMENT ON COLUMN public.binarypackagerelease.priority IS 'The priority that this package has. E.g. Base, Standard, Extra, Optional';
+
+
+COMMENT ON COLUMN public.binarypackagerelease.shlibdeps IS 'The shared library dependencies of this binary package';
+
+
+COMMENT ON COLUMN public.binarypackagerelease.depends IS 'The list of packages this binarypackage depends on';
+
+
+COMMENT ON COLUMN public.binarypackagerelease.recommends IS 'The list of packages this binarypackage recommends. Recommended packages often enhance the behaviour of a package.';
+
+
+COMMENT ON COLUMN public.binarypackagerelease.suggests IS 'The list of packages this binarypackage suggests.';
+
+
+COMMENT ON COLUMN public.binarypackagerelease.conflicts IS 'The list of packages this binarypackage conflicts with.';
+
+
+COMMENT ON COLUMN public.binarypackagerelease.replaces IS 'The list of packages this binarypackage replaces files in. Often this is used to provide an upgrade path between two binarypackages of different names';
+
+
+COMMENT ON COLUMN public.binarypackagerelease.provides IS 'The list of virtual packages (or real packages under some circumstances) which this binarypackage provides.';
+
+
+COMMENT ON COLUMN public.binarypackagerelease.essential IS 'Whether or not this binarypackage is essential to the smooth operation of a base system';
+
+
+COMMENT ON COLUMN public.binarypackagerelease.installedsize IS 'What the installed size of the binarypackage is. This is represented as a number of kilobytes of storage.';
+
+
+COMMENT ON COLUMN public.binarypackagerelease.architecturespecific IS 'This field indicates whether or not a binarypackage is architecture-specific. If it is not specific to any given architecture then it can automatically be included in all the distroarchseries which pertain.';
+
+
+COMMENT ON COLUMN public.binarypackagerelease.pre_depends IS 'The list of packages this binary requires to be installed beforehand in apt/dpkg format, as it is in control file "Pre-Depends:" field.';
+
+
+COMMENT ON COLUMN public.binarypackagerelease.enhances IS 'The list of packages pointed as "enhanced" after the installation of this package, as it is in control file "Enhances:" field.';
+
+
+COMMENT ON COLUMN public.binarypackagerelease.breaks IS 'The list of packages which will be broken by the installtion of this package, as it is in the control file "Breaks:" field.';
+
+
+COMMENT ON COLUMN public.binarypackagerelease.debug_package IS 'The corresponding binary package release containing debug symbols for this binary, if any.';
+
+
+COMMENT ON COLUMN public.binarypackagerelease.user_defined_fields IS 'A JSON struct containing a sequence of key-value pairs with user defined fields in the control file.';
+
+
+COMMENT ON COLUMN public.binarypackagerelease.homepage IS 'Upstream project homepage URL, not checked for validity.';
+
+
+CREATE SEQUENCE public.binarypackagerelease_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER SEQUENCE public.binarypackagerelease_id_seq OWNED BY public.binarypackagerelease.id;
+
+
+CREATE TABLE public.binarypackagereleasedownloadcount (
     id integer NOT NULL,
     archive integer NOT NULL,
     binary_package_release integer NOT NULL,
@@ -5824,24 +4709,23 @@
 );
 
 
-CREATE SEQUENCE binarypackagereleasedownloadcount_id_seq
+CREATE SEQUENCE public.binarypackagereleasedownloadcount_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE binarypackagereleasedownloadcount_id_seq OWNED BY binarypackagereleasedownloadcount.id;
-
-
-CREATE TABLE branch (
+ALTER SEQUENCE public.binarypackagereleasedownloadcount_id_seq OWNED BY public.binarypackagereleasedownloadcount.id;
+
+
+CREATE TABLE public.branch (
     id integer NOT NULL,
     title text,
     summary text,
     owner integer NOT NULL,
     product integer,
-    author integer,
     name text NOT NULL,
     home_page text,
     url text,
@@ -5857,7 +4741,6 @@
     date_created timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL,
     revision_count integer DEFAULT 0 NOT NULL,
     next_mirror_time timestamp without time zone,
-    private boolean DEFAULT false NOT NULL,
     branch_type integer NOT NULL,
     reviewer integer,
     date_last_modified timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL,
@@ -5872,110 +4755,103 @@
     target_suffix text,
     unique_name text,
     size_on_disk bigint,
-    merge_queue integer,
-    merge_queue_config text,
-    transitively_private boolean DEFAULT true NOT NULL,
+    information_type integer NOT NULL,
     access_policy integer,
+    access_grants integer[],
     CONSTRAINT branch_type_url_consistent CHECK (((((branch_type = 2) AND (url IS NOT NULL)) OR ((branch_type = ANY (ARRAY[1, 3])) AND (url IS NULL))) OR (branch_type = 4))),
     CONSTRAINT branch_url_no_trailing_slash CHECK ((url !~~ '%/'::text)),
     CONSTRAINT branch_url_not_supermirror CHECK ((url !~~ 'http://bazaar.launchpad.net/%'::text)),
     CONSTRAINT one_container CHECK ((((distroseries IS NULL) = (sourcepackagename IS NULL)) AND ((distroseries IS NULL) OR (product IS NULL)))),
-    CONSTRAINT valid_home_page CHECK (valid_absolute_url(home_page)),
-    CONSTRAINT valid_name CHECK (valid_branch_name(name)),
-    CONSTRAINT valid_url CHECK (valid_absolute_url(url))
+    CONSTRAINT valid_home_page CHECK (public.valid_absolute_url(home_page)),
+    CONSTRAINT valid_name CHECK (public.valid_branch_name(name)),
+    CONSTRAINT valid_url CHECK (public.valid_absolute_url(url))
 );
 
 
-COMMENT ON TABLE branch IS 'Bzr branch';
-
-
-COMMENT ON COLUMN branch.summary IS 'A single paragraph description of the branch';
-
-
-COMMENT ON COLUMN branch.home_page IS 'This column is deprecated and to be removed soon.';
-
-
-COMMENT ON COLUMN branch.whiteboard IS 'Notes on the current status of the branch';
-
-
-COMMENT ON COLUMN branch.lifecycle_status IS 'Authors assesment of the branchs maturity';
-
-
-COMMENT ON COLUMN branch.last_mirrored IS 'The time when the branch was last mirrored.';
-
-
-COMMENT ON COLUMN branch.mirror_status_message IS 'The last message we got when mirroring this branch.';
-
-
-COMMENT ON COLUMN branch.last_scanned IS 'The time when the branch was last scanned.';
-
-
-COMMENT ON COLUMN branch.last_scanned_id IS 'The revision ID of the branch when it was last scanned.';
-
-
-COMMENT ON COLUMN branch.last_mirrored_id IS 'The revision ID of the branch when it was last mirrored.';
-
-
-COMMENT ON COLUMN branch.revision_count IS 'The number of revisions in the associated bazaar branch revision_history.';
-
-
-COMMENT ON COLUMN branch.next_mirror_time IS 'The time when we will next mirror this branch (NULL means never). This will be set automatically by pushing to a hosted branch, which, once mirrored, will be set back to NULL.';
-
-
-COMMENT ON COLUMN branch.private IS 'If the branch is private, then only the owner and subscribers of the branch can see it.';
-
-
-COMMENT ON COLUMN branch.branch_type IS 'Branches are currently one of HOSTED (1), MIRRORED (2), or IMPORTED (3).';
-
-
-COMMENT ON COLUMN branch.reviewer IS 'The reviewer (person or) team are able to transition merge proposals targetted at the branch throught the CODE_APPROVED state.';
-
-
-COMMENT ON COLUMN branch.date_last_modified IS 'A branch is modified any time a user updates something using a view, a new revision for the branch is scanned, or the branch is linked to a bug, blueprint or merge proposal.';
-
-
-COMMENT ON COLUMN branch.registrant IS 'The user that registered the branch.';
-
-
-COMMENT ON COLUMN branch.branch_format IS 'The bzr branch format';
-
-
-COMMENT ON COLUMN branch.repository_format IS 'The bzr repository format';
-
-
-COMMENT ON COLUMN branch.metadir_format IS 'The bzr metadir format';
-
-
-COMMENT ON COLUMN branch.stacked_on IS 'The Launchpad branch that this branch is stacked on (if any).';
-
-
-COMMENT ON COLUMN branch.distroseries IS 'The distribution series that the branch belongs to.';
-
-
-COMMENT ON COLUMN branch.sourcepackagename IS 'The source package this is a branch of.';
-
-
-COMMENT ON COLUMN branch.size_on_disk IS 'The size in bytes of this branch in the mirrored area.';
-
-
-COMMENT ON COLUMN branch.merge_queue IS 'A reference to the BranchMergeQueue record that manages merges.';
-
-
-COMMENT ON COLUMN branch.merge_queue_config IS 'A JSON string of configuration values that can be read by a merge queue script.';
-
-
-CREATE SEQUENCE branch_id_seq
+COMMENT ON TABLE public.branch IS 'Bzr branch';
+
+
+COMMENT ON COLUMN public.branch.summary IS 'A single paragraph description of the branch';
+
+
+COMMENT ON COLUMN public.branch.home_page IS 'This column is deprecated and to be removed soon.';
+
+
+COMMENT ON COLUMN public.branch.whiteboard IS 'Notes on the current status of the branch';
+
+
+COMMENT ON COLUMN public.branch.lifecycle_status IS 'Authors assesment of the branchs maturity';
+
+
+COMMENT ON COLUMN public.branch.last_mirrored IS 'The time when the branch was last mirrored.';
+
+
+COMMENT ON COLUMN public.branch.mirror_status_message IS 'The last message we got when mirroring this branch.';
+
+
+COMMENT ON COLUMN public.branch.last_scanned IS 'The time when the branch was last scanned.';
+
+
+COMMENT ON COLUMN public.branch.last_scanned_id IS 'The revision ID of the branch when it was last scanned.';
+
+
+COMMENT ON COLUMN public.branch.last_mirrored_id IS 'The revision ID of the branch when it was last mirrored.';
+
+
+COMMENT ON COLUMN public.branch.revision_count IS 'The number of revisions in the associated bazaar branch revision_history.';
+
+
+COMMENT ON COLUMN public.branch.next_mirror_time IS 'The time when we will next mirror this branch (NULL means never). This will be set automatically by pushing to a hosted branch, which, once mirrored, will be set back to NULL.';
+
+
+COMMENT ON COLUMN public.branch.branch_type IS 'Branches are currently one of HOSTED (1), MIRRORED (2), or IMPORTED (3).';
+
+
+COMMENT ON COLUMN public.branch.reviewer IS 'The reviewer (person or) team are able to transition merge proposals targetted at the branch throught the CODE_APPROVED state.';
+
+
+COMMENT ON COLUMN public.branch.date_last_modified IS 'A branch is modified any time a user updates something using a view, a new revision for the branch is scanned, or the branch is linked to a bug, blueprint or merge proposal.';
+
+
+COMMENT ON COLUMN public.branch.registrant IS 'The user that registered the branch.';
+
+
+COMMENT ON COLUMN public.branch.branch_format IS 'The bzr branch format';
+
+
+COMMENT ON COLUMN public.branch.repository_format IS 'The bzr repository format';
+
+
+COMMENT ON COLUMN public.branch.metadir_format IS 'The bzr metadir format';
+
+
+COMMENT ON COLUMN public.branch.stacked_on IS 'The Launchpad branch that this branch is stacked on (if any).';
+
+
+COMMENT ON COLUMN public.branch.distroseries IS 'The distribution series that the branch belongs to.';
+
+
+COMMENT ON COLUMN public.branch.sourcepackagename IS 'The source package this is a branch of.';
+
+
+COMMENT ON COLUMN public.branch.size_on_disk IS 'The size in bytes of this branch in the mirrored area.';
+
+
+COMMENT ON COLUMN public.branch.information_type IS 'Enum describing what type of information is stored, such as type of private or security related data, and used to determine how to apply an access policy.';
+
+
+CREATE SEQUENCE public.branch_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE branch_id_seq OWNED BY branch.id;
-
-
-CREATE TABLE branchjob (
+ALTER SEQUENCE public.branch_id_seq OWNED BY public.branch.id;
+
+
+CREATE TABLE public.branchjob (
     id integer NOT NULL,
     job integer NOT NULL,
     branch integer,
@@ -5984,37 +4860,37 @@
 );
 
 
-COMMENT ON TABLE branchjob IS 'Contains references to jobs that are executed for a branch.';
-
-
-COMMENT ON COLUMN branchjob.job IS 'A reference to a row in the Job table that has all the common job details.';
-
-
-COMMENT ON COLUMN branchjob.branch IS 'The branch that this job is for.';
-
-
-COMMENT ON COLUMN branchjob.job_type IS 'The type of job, like new revisions, or attribute change.';
-
-
-COMMENT ON COLUMN branchjob.json_data IS 'Data that is specific to the type of job, whether this be the revisions to send email out for, or the changes that were recorded for the branch.';
-
-
-CREATE SEQUENCE branchjob_id_seq
+COMMENT ON TABLE public.branchjob IS 'Contains references to jobs that are executed for a branch.';
+
+
+COMMENT ON COLUMN public.branchjob.job IS 'A reference to a row in the Job table that has all the common job details.';
+
+
+COMMENT ON COLUMN public.branchjob.branch IS 'The branch that this job is for.';
+
+
+COMMENT ON COLUMN public.branchjob.job_type IS 'The type of job, like new revisions, or attribute change.';
+
+
+COMMENT ON COLUMN public.branchjob.json_data IS 'Data that is specific to the type of job, whether this be the revisions to send email out for, or the changes that were recorded for the branch.';
+
+
+CREATE SEQUENCE public.branchjob_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE branchjob_id_seq OWNED BY branchjob.id;
-
-
-CREATE TABLE branchmergeproposal (
+ALTER SEQUENCE public.branchjob_id_seq OWNED BY public.branchjob.id;
+
+
+CREATE TABLE public.branchmergeproposal (
     id integer NOT NULL,
     registrant integer NOT NULL,
-    source_branch integer NOT NULL,
-    target_branch integer NOT NULL,
+    source_branch integer,
+    target_branch integer,
     dependent_branch integer,
     whiteboard text,
     date_merged timestamp without time zone,
@@ -6038,109 +4914,119 @@
     merge_log_file integer,
     superseded_by integer,
     root_message_id text,
-    merge_diff integer,
     description text,
+    source_git_repository integer,
+    source_git_path text,
+    source_git_commit_sha1 character(40),
+    target_git_repository integer,
+    target_git_path text,
+    target_git_commit_sha1 character(40),
+    dependent_git_repository integer,
+    dependent_git_path text,
+    dependent_git_commit_sha1 character(40),
+    CONSTRAINT consistent_dependent_git_ref CHECK ((((dependent_git_repository IS NULL) = (dependent_git_path IS NULL)) AND ((dependent_git_repository IS NULL) = (dependent_git_commit_sha1 IS NULL)))),
+    CONSTRAINT consistent_source_git_ref CHECK ((((source_git_repository IS NULL) = (source_git_path IS NULL)) AND ((source_git_repository IS NULL) = (source_git_commit_sha1 IS NULL)))),
+    CONSTRAINT consistent_target_git_ref CHECK ((((target_git_repository IS NULL) = (target_git_path IS NULL)) AND ((target_git_repository IS NULL) = (target_git_commit_sha1 IS NULL)))),
     CONSTRAINT different_branches CHECK ((((source_branch <> target_branch) AND (dependent_branch <> source_branch)) AND (dependent_branch <> target_branch))),
+    CONSTRAINT different_git_refs CHECK (((source_git_repository IS NULL) OR ((((source_git_repository <> target_git_repository) OR (source_git_path <> target_git_path)) AND ((dependent_git_repository <> source_git_repository) OR (dependent_git_path <> source_git_path))) AND ((dependent_git_repository <> target_git_repository) OR (dependent_git_path <> target_git_path))))),
+    CONSTRAINT one_vcs CHECK ((((((source_branch IS NOT NULL) AND (target_branch IS NOT NULL)) <> ((source_git_repository IS NOT NULL) AND (target_git_repository IS NOT NULL))) AND ((dependent_branch IS NULL) OR (source_branch IS NOT NULL))) AND ((dependent_git_repository IS NULL) OR (source_git_repository IS NOT NULL)))),
     CONSTRAINT positive_revno CHECK (((merged_revno IS NULL) OR (merged_revno > 0)))
 );
 
 
-COMMENT ON TABLE branchmergeproposal IS 'Branch merge proposals record the intent of landing (or merging) one branch on another.';
-
-
-COMMENT ON COLUMN branchmergeproposal.registrant IS 'The person that created the merge proposal.';
-
-
-COMMENT ON COLUMN branchmergeproposal.source_branch IS 'The branch where the work is being written.  This branch contains the changes that the registrant wants to land.';
-
-
-COMMENT ON COLUMN branchmergeproposal.target_branch IS 'The branch where the user wants the changes from the source branch to be merged into.';
-
-
-COMMENT ON COLUMN branchmergeproposal.dependent_branch IS 'If the source branch was not branched off the target branch, then this is considered the dependent_branch.';
-
-
-COMMENT ON COLUMN branchmergeproposal.whiteboard IS 'Used to write other information about the branch, like test URLs.';
-
-
-COMMENT ON COLUMN branchmergeproposal.date_merged IS 'This is the date that merge occurred.';
-
-
-COMMENT ON COLUMN branchmergeproposal.merged_revno IS 'This is the revision number of the revision on the target branch that includes the merge from the source branch.';
-
-
-COMMENT ON COLUMN branchmergeproposal.merge_reporter IS 'This is the user that marked the proposal as merged.';
-
-
-COMMENT ON COLUMN branchmergeproposal.date_created IS 'When the registrant created the merge proposal.';
-
-
-COMMENT ON COLUMN branchmergeproposal.commit_message IS 'This is the commit message that is to be used when the branch is landed by a robot.';
-
-
-COMMENT ON COLUMN branchmergeproposal.queue_position IS 'The position on the merge proposal in the overall landing queue.  If the branch has a merge_robot set and the merge robot controls multiple branches then the queue position is unique over all the queued merge proposals for the landing robot.';
-
-
-COMMENT ON COLUMN branchmergeproposal.queue_status IS 'This is the current state of the merge proposal.';
-
-
-COMMENT ON COLUMN branchmergeproposal.date_review_requested IS 'The date that the merge proposal enters the REVIEW_REQUESTED state. This is stored so that we can determine how long a branch has been waiting for code approval.';
-
-
-COMMENT ON COLUMN branchmergeproposal.reviewer IS 'The individual who said that the code in this branch is OK to land.';
-
-
-COMMENT ON COLUMN branchmergeproposal.date_reviewed IS 'When the reviewer said the code is OK to land.';
-
-
-COMMENT ON COLUMN branchmergeproposal.reviewed_revision_id IS 'The Bazaar revision ID that was approved to land.';
-
-
-COMMENT ON COLUMN branchmergeproposal.queuer IS 'The individual who submitted the branch to the merge queue. This is usually the merge proposal registrant.';
-
-
-COMMENT ON COLUMN branchmergeproposal.date_queued IS 'When the queuer submitted the branch to the merge queue.';
-
-
-COMMENT ON COLUMN branchmergeproposal.queued_revision_id IS 'The Bazaar revision ID that is queued to land.';
-
-
-COMMENT ON COLUMN branchmergeproposal.merger IS 'The merger is the person who merged the branch.';
-
-
-COMMENT ON COLUMN branchmergeproposal.merged_revision_id IS 'The Bazaar revision ID that was actually merged.  If the owner of the source branch is a trusted person, this may be different than the revision_id that was actually queued or reviewed.';
-
-
-COMMENT ON COLUMN branchmergeproposal.date_merge_started IS 'If the merge is performed by a bot the time the merge was started is recorded otherwise it is NULL.';
-
-
-COMMENT ON COLUMN branchmergeproposal.date_merge_finished IS 'If the merge is performed by a bot the time the merge was finished is recorded otherwise it is NULL.';
-
-
-COMMENT ON COLUMN branchmergeproposal.merge_log_file IS 'If the merge is performed by a bot the log file is accessible from the librarian.';
-
-
-COMMENT ON COLUMN branchmergeproposal.superseded_by IS 'The proposal to merge has been superceded by this one.';
-
-
-COMMENT ON COLUMN branchmergeproposal.root_message_id IS 'The root message of this BranchMergeProposal''s mail thread.';
-
-
-COMMENT ON COLUMN branchmergeproposal.merge_diff IS 'The diff showing the predicted result of a merge.';
-
-
-CREATE SEQUENCE branchmergeproposal_id_seq
+COMMENT ON TABLE public.branchmergeproposal IS 'Branch merge proposals record the intent of landing (or merging) one branch on another.';
+
+
+COMMENT ON COLUMN public.branchmergeproposal.registrant IS 'The person that created the merge proposal.';
+
+
+COMMENT ON COLUMN public.branchmergeproposal.source_branch IS 'The branch where the work is being written.  This branch contains the changes that the registrant wants to land.';
+
+
+COMMENT ON COLUMN public.branchmergeproposal.target_branch IS 'The branch where the user wants the changes from the source branch to be merged into.';
+
+
+COMMENT ON COLUMN public.branchmergeproposal.dependent_branch IS 'If the source branch was not branched off the target branch, then this is considered the dependent_branch.';
+
+
+COMMENT ON COLUMN public.branchmergeproposal.whiteboard IS 'Used to write other information about the branch, like test URLs.';
+
+
+COMMENT ON COLUMN public.branchmergeproposal.date_merged IS 'This is the date that merge occurred.';
+
+
+COMMENT ON COLUMN public.branchmergeproposal.merged_revno IS 'This is the revision number of the revision on the target branch that includes the merge from the source branch.';
+
+
+COMMENT ON COLUMN public.branchmergeproposal.merge_reporter IS 'This is the user that marked the proposal as merged.';
+
+
+COMMENT ON COLUMN public.branchmergeproposal.date_created IS 'When the registrant created the merge proposal.';
+
+
+COMMENT ON COLUMN public.branchmergeproposal.commit_message IS 'This is the commit message that is to be used when the branch is landed by a robot.';
+
+
+COMMENT ON COLUMN public.branchmergeproposal.queue_position IS 'The position on the merge proposal in the overall landing queue.  If the branch has a merge_robot set and the merge robot controls multiple branches then the queue position is unique over all the queued merge proposals for the landing robot.';
+
+
+COMMENT ON COLUMN public.branchmergeproposal.queue_status IS 'This is the current state of the merge proposal.';
+
+
+COMMENT ON COLUMN public.branchmergeproposal.date_review_requested IS 'The date that the merge proposal enters the REVIEW_REQUESTED state. This is stored so that we can determine how long a branch has been waiting for code approval.';
+
+
+COMMENT ON COLUMN public.branchmergeproposal.reviewer IS 'The individual who said that the code in this branch is OK to land.';
+
+
+COMMENT ON COLUMN public.branchmergeproposal.date_reviewed IS 'When the reviewer said the code is OK to land.';
+
+
+COMMENT ON COLUMN public.branchmergeproposal.reviewed_revision_id IS 'The Bazaar revision ID that was approved to land.';
+
+
+COMMENT ON COLUMN public.branchmergeproposal.queuer IS 'The individual who submitted the branch to the merge queue. This is usually the merge proposal registrant.';
+
+
+COMMENT ON COLUMN public.branchmergeproposal.date_queued IS 'When the queuer submitted the branch to the merge queue.';
+
+
+COMMENT ON COLUMN public.branchmergeproposal.queued_revision_id IS 'The Bazaar revision ID that is queued to land.';
+
+
+COMMENT ON COLUMN public.branchmergeproposal.merger IS 'The merger is the person who merged the branch.';
+
+
+COMMENT ON COLUMN public.branchmergeproposal.merged_revision_id IS 'The Bazaar revision ID that was actually merged.  If the owner of the source branch is a trusted person, this may be different than the revision_id that was actually queued or reviewed.';
+
+
+COMMENT ON COLUMN public.branchmergeproposal.date_merge_started IS 'If the merge is performed by a bot the time the merge was started is recorded otherwise it is NULL.';
+
+
+COMMENT ON COLUMN public.branchmergeproposal.date_merge_finished IS 'If the merge is performed by a bot the time the merge was finished is recorded otherwise it is NULL.';
+
+
+COMMENT ON COLUMN public.branchmergeproposal.merge_log_file IS 'If the merge is performed by a bot the log file is accessible from the librarian.';
+
+
+COMMENT ON COLUMN public.branchmergeproposal.superseded_by IS 'The proposal to merge has been superceded by this one.';
+
+
+COMMENT ON COLUMN public.branchmergeproposal.root_message_id IS 'The root message of this BranchMergeProposal''s mail thread.';
+
+
+CREATE SEQUENCE public.branchmergeproposal_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE branchmergeproposal_id_seq OWNED BY branchmergeproposal.id;
-
-
-CREATE TABLE branchmergeproposaljob (
+ALTER SEQUENCE public.branchmergeproposal_id_seq OWNED BY public.branchmergeproposal.id;
+
+
+CREATE TABLE public.branchmergeproposaljob (
     id integer NOT NULL,
     job integer NOT NULL,
     branch_merge_proposal integer NOT NULL,
@@ -6149,90 +5035,41 @@
 );
 
 
-COMMENT ON TABLE branchmergeproposaljob IS 'Contains references to jobs that are executed for a branch merge proposal.';
-
-
-COMMENT ON COLUMN branchmergeproposaljob.job IS 'A reference to a row in the Job table that has all the common job details.';
-
-
-COMMENT ON COLUMN branchmergeproposaljob.branch_merge_proposal IS 'The branch merge proposal that this job is for.';
-
-
-COMMENT ON COLUMN branchmergeproposaljob.job_type IS 'The type of job, like new proposal, review comment, or new review requested.';
-
-
-COMMENT ON COLUMN branchmergeproposaljob.json_data IS 'Data that is specific to the type of job, normally references to code review messages and or votes.';
-
-
-CREATE SEQUENCE branchmergeproposaljob_id_seq
-    START WITH 1
-    INCREMENT BY 1
-    NO MAXVALUE
-    NO MINVALUE
-    CACHE 1;
-
-
-ALTER SEQUENCE branchmergeproposaljob_id_seq OWNED BY branchmergeproposaljob.id;
-
-
-CREATE TABLE branchmergequeue (
-    id integer NOT NULL,
-    registrant integer NOT NULL,
-    owner integer NOT NULL,
-    name text NOT NULL,
-    description text,
-    configuration text,
-    date_created timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL,
-    CONSTRAINT valid_name CHECK (valid_name(name))
-);
-
-
-COMMENT ON TABLE branchmergequeue IS 'Queue for managing the merge workflow for branches.';
-
-
-COMMENT ON COLUMN branchmergequeue.id IS 'The id of the merge queue.';
-
-
-COMMENT ON COLUMN branchmergequeue.registrant IS 'A reference to the person who created the merge queue.';
-
-
-COMMENT ON COLUMN branchmergequeue.owner IS 'A reference to the person who owns the merge queue.';
-
-
-COMMENT ON COLUMN branchmergequeue.name IS 'The name of the queue.';
-
-
-COMMENT ON COLUMN branchmergequeue.description IS 'A description of the queue.';
-
-
-COMMENT ON COLUMN branchmergequeue.configuration IS 'A JSON string of configuration data to be read by the merging script.';
-
-
-COMMENT ON COLUMN branchmergequeue.date_created IS 'The date the queue was created.';
-
-
-CREATE SEQUENCE branchmergequeue_id_seq
-    START WITH 1
-    INCREMENT BY 1
-    NO MAXVALUE
-    NO MINVALUE
-    CACHE 1;
-
-
-ALTER SEQUENCE branchmergequeue_id_seq OWNED BY branchmergequeue.id;
-
-
-CREATE TABLE branchrevision (
+COMMENT ON TABLE public.branchmergeproposaljob IS 'Contains references to jobs that are executed for a branch merge proposal.';
+
+
+COMMENT ON COLUMN public.branchmergeproposaljob.job IS 'A reference to a row in the Job table that has all the common job details.';
+
+
+COMMENT ON COLUMN public.branchmergeproposaljob.branch_merge_proposal IS 'The branch merge proposal that this job is for.';
+
+
+COMMENT ON COLUMN public.branchmergeproposaljob.job_type IS 'The type of job, like new proposal, review comment, or new review requested.';
+
+
+COMMENT ON COLUMN public.branchmergeproposaljob.json_data IS 'Data that is specific to the type of job, normally references to code review messages and or votes.';
+
+
+CREATE SEQUENCE public.branchmergeproposaljob_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER SEQUENCE public.branchmergeproposaljob_id_seq OWNED BY public.branchmergeproposaljob.id;
+
+
+CREATE TABLE public.branchrevision (
     sequence integer,
     branch integer NOT NULL,
     revision integer NOT NULL
 )
-WITH (fillfactor=100);
-ALTER TABLE ONLY branchrevision ALTER COLUMN branch SET STATISTICS 500;
-ALTER TABLE ONLY branchrevision ALTER COLUMN revision SET STATISTICS 500;
-
-
-CREATE TABLE branchsubscription (
+WITH (fillfactor='100');
+
+
+CREATE TABLE public.branchsubscription (
     id integer NOT NULL,
     person integer NOT NULL,
     branch integer NOT NULL,
@@ -6244,83 +5081,47 @@
 );
 
 
-COMMENT ON TABLE branchsubscription IS 'An association between a person or team and a bazaar branch.';
-
-
-COMMENT ON COLUMN branchsubscription.person IS 'The person or team associated with the branch.';
-
-
-COMMENT ON COLUMN branchsubscription.branch IS 'The branch associated with the person or team.';
-
-
-COMMENT ON COLUMN branchsubscription.notification_level IS 'The level of email the person wants to receive from branch updates.';
-
-
-COMMENT ON COLUMN branchsubscription.max_diff_lines IS 'If the generated diff for a revision is larger than this number, then the diff is not sent in the notification email.';
-
-
-COMMENT ON COLUMN branchsubscription.review_level IS 'The level of email the person wants to receive from review activity';
-
-
-CREATE SEQUENCE branchsubscription_id_seq
-    START WITH 1
-    INCREMENT BY 1
-    NO MAXVALUE
-    NO MINVALUE
-    CACHE 1;
-
-
-ALTER SEQUENCE branchsubscription_id_seq OWNED BY branchsubscription.id;
-
-
-CREATE TABLE branchvisibilitypolicy (
-    id integer NOT NULL,
-    project integer,
-    product integer,
-    team integer,
-    policy integer DEFAULT 1 NOT NULL,
-    CONSTRAINT only_one_target CHECK (((project IS NULL) <> (product IS NULL)))
-);
-
-
-COMMENT ON TABLE branchvisibilitypolicy IS 'Defines the policy for the initial visibility of branches.';
-
-
-COMMENT ON COLUMN branchvisibilitypolicy.project IS 'Even though projects don''t directly have branches themselves, if a product of the project does not specify its own branch visibility policies, those of the project are used.';
-
-
-COMMENT ON COLUMN branchvisibilitypolicy.product IS 'The product that the visibility policies apply to.';
-
-
-COMMENT ON COLUMN branchvisibilitypolicy.team IS 'Refers to the team that the policy applies to.  NULL is used to indicate ALL people, as there is no team defined for *everybody*.';
-
-
-COMMENT ON COLUMN branchvisibilitypolicy.policy IS 'An enumerated type, one of PUBLIC or PRIVATE.  PUBLIC is the default value.';
-
-
-CREATE SEQUENCE branchvisibilitypolicy_id_seq
-    START WITH 1
-    INCREMENT BY 1
-    NO MAXVALUE
-    NO MINVALUE
-    CACHE 1;
-
-
-ALTER SEQUENCE branchvisibilitypolicy_id_seq OWNED BY branchvisibilitypolicy.id;
-
-
-CREATE SEQUENCE bug_id_seq
-    START WITH 1
-    INCREMENT BY 1
-    NO MAXVALUE
-    NO MINVALUE
-    CACHE 1;
-
-
-ALTER SEQUENCE bug_id_seq OWNED BY bug.id;
-
-
-CREATE TABLE bugactivity (
+COMMENT ON TABLE public.branchsubscription IS 'An association between a person or team and a bazaar branch.';
+
+
+COMMENT ON COLUMN public.branchsubscription.person IS 'The person or team associated with the branch.';
+
+
+COMMENT ON COLUMN public.branchsubscription.branch IS 'The branch associated with the person or team.';
+
+
+COMMENT ON COLUMN public.branchsubscription.notification_level IS 'The level of email the person wants to receive from branch updates.';
+
+
+COMMENT ON COLUMN public.branchsubscription.max_diff_lines IS 'If the generated diff for a revision is larger than this number, then the diff is not sent in the notification email.';
+
+
+COMMENT ON COLUMN public.branchsubscription.review_level IS 'The level of email the person wants to receive from review activity';
+
+
+CREATE SEQUENCE public.branchsubscription_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER SEQUENCE public.branchsubscription_id_seq OWNED BY public.branchsubscription.id;
+
+
+CREATE SEQUENCE public.bug_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER SEQUENCE public.bug_id_seq OWNED BY public.bug.id;
+
+
+CREATE TABLE public.bugactivity (
     id integer NOT NULL,
     bug integer NOT NULL,
     datechanged timestamp without time zone DEFAULT timezone('UTC'::text, ('now'::text)::timestamp(6) with time zone) NOT NULL,
@@ -6330,21 +5131,21 @@
     newvalue text,
     message text
 )
-WITH (fillfactor=100);
-
-
-CREATE SEQUENCE bugactivity_id_seq
+WITH (fillfactor='100');
+
+
+CREATE SEQUENCE public.bugactivity_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE bugactivity_id_seq OWNED BY bugactivity.id;
-
-
-CREATE TABLE bugaffectsperson (
+ALTER SEQUENCE public.bugactivity_id_seq OWNED BY public.bugactivity.id;
+
+
+CREATE TABLE public.bugaffectsperson (
     id integer NOT NULL,
     bug integer NOT NULL,
     person integer NOT NULL,
@@ -6352,27 +5153,27 @@
 );
 
 
-COMMENT ON TABLE bugaffectsperson IS 'This table maintains a mapping between bugs and users indicating that they are affected by that bug. The value is calculated and cached in the Bug.users_affected_count column.';
-
-
-COMMENT ON COLUMN bugaffectsperson.bug IS 'The bug affecting this person.';
-
-
-COMMENT ON COLUMN bugaffectsperson.person IS 'The person affected by this bug.';
-
-
-CREATE SEQUENCE bugaffectsperson_id_seq
+COMMENT ON TABLE public.bugaffectsperson IS 'This table maintains a mapping between bugs and users indicating that they are affected by that bug. The value is calculated and cached in the Bug.users_affected_count column.';
+
+
+COMMENT ON COLUMN public.bugaffectsperson.bug IS 'The bug affecting this person.';
+
+
+COMMENT ON COLUMN public.bugaffectsperson.person IS 'The person affected by this bug.';
+
+
+CREATE SEQUENCE public.bugaffectsperson_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE bugaffectsperson_id_seq OWNED BY bugaffectsperson.id;
-
-
-CREATE TABLE bugattachment (
+ALTER SEQUENCE public.bugaffectsperson_id_seq OWNED BY public.bugaffectsperson.id;
+
+
+CREATE TABLE public.bugattachment (
     id integer NOT NULL,
     message integer NOT NULL,
     name text,
@@ -6380,22 +5181,22 @@
     libraryfile integer NOT NULL,
     bug integer NOT NULL,
     type integer NOT NULL,
-    CONSTRAINT valid_name CHECK (valid_name(name))
+    CONSTRAINT valid_name CHECK (public.valid_name(name))
 );
 
 
-CREATE SEQUENCE bugattachment_id_seq
+CREATE SEQUENCE public.bugattachment_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE bugattachment_id_seq OWNED BY bugattachment.id;
-
-
-CREATE TABLE bugbranch (
+ALTER SEQUENCE public.bugattachment_id_seq OWNED BY public.bugattachment.id;
+
+
+CREATE TABLE public.bugbranch (
     id integer NOT NULL,
     datecreated timestamp without time zone DEFAULT timezone('UTC'::text, ('now'::text)::timestamp(6) with time zone) NOT NULL,
     bug integer NOT NULL,
@@ -6406,90 +5207,36 @@
 );
 
 
-COMMENT ON TABLE bugbranch IS 'A branch related to a bug, most likely a branch for fixing the bug.';
-
-
-COMMENT ON COLUMN bugbranch.bug IS 'The bug associated with this branch.';
-
-
-COMMENT ON COLUMN bugbranch.branch IS 'The branch associated to the bug.';
-
-
-COMMENT ON COLUMN bugbranch.revision_hint IS 'An optional revision at which this branch became interesting to this bug, and/or may contain a fix for the bug.';
-
-
-COMMENT ON COLUMN bugbranch.whiteboard IS 'Additional information about the status of the bugfix in this branch.';
-
-
-COMMENT ON COLUMN bugbranch.registrant IS 'The person who linked the bug to the branch.';
-
-
-CREATE SEQUENCE bugbranch_id_seq
-    START WITH 1
-    INCREMENT BY 1
-    NO MAXVALUE
-    NO MINVALUE
-    CACHE 1;
-
-
-ALTER SEQUENCE bugbranch_id_seq OWNED BY bugbranch.id;
-
-
-CREATE TABLE bugcve (
-    id integer NOT NULL,
-    bug integer NOT NULL,
-    cve integer NOT NULL,
-    date_created timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL
-);
-
-
-COMMENT ON TABLE bugcve IS 'A table that records the link between a given malone bug number, and a CVE entry.';
-
-
-CREATE SEQUENCE bugcve_id_seq
-    START WITH 1
-    INCREMENT BY 1
-    NO MAXVALUE
-    NO MINVALUE
-    CACHE 1;
-
-
-ALTER SEQUENCE bugcve_id_seq OWNED BY bugcve.id;
-
-
-CREATE TABLE bugjob (
-    id integer NOT NULL,
-    job integer NOT NULL,
-    bug integer NOT NULL,
-    job_type integer NOT NULL,
-    json_data text
-);
-
-
-COMMENT ON TABLE bugjob IS 'Contains references to jobs to be run against Bugs.';
-
-
-COMMENT ON COLUMN bugjob.bug IS 'The bug on which the job is to be run.';
-
-
-COMMENT ON COLUMN bugjob.job_type IS 'The type of job (enumeration value). Allows us to query the database for a given subset of BugJobs.';
-
-
-COMMENT ON COLUMN bugjob.json_data IS 'A JSON struct containing data for the job.';
-
-
-CREATE SEQUENCE bugjob_id_seq
-    START WITH 1
-    INCREMENT BY 1
-    NO MAXVALUE
-    NO MINVALUE
-    CACHE 1;
-
-
-ALTER SEQUENCE bugjob_id_seq OWNED BY bugjob.id;
-
-
-CREATE TABLE bugmessage (
+COMMENT ON TABLE public.bugbranch IS 'A branch related to a bug, most likely a branch for fixing the bug.';
+
+
+COMMENT ON COLUMN public.bugbranch.bug IS 'The bug associated with this branch.';
+
+
+COMMENT ON COLUMN public.bugbranch.branch IS 'The branch associated to the bug.';
+
+
+COMMENT ON COLUMN public.bugbranch.revision_hint IS 'An optional revision at which this branch became interesting to this bug, and/or may contain a fix for the bug.';
+
+
+COMMENT ON COLUMN public.bugbranch.whiteboard IS 'Additional information about the status of the bugfix in this branch.';
+
+
+COMMENT ON COLUMN public.bugbranch.registrant IS 'The person who linked the bug to the branch.';
+
+
+CREATE SEQUENCE public.bugbranch_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER SEQUENCE public.bugbranch_id_seq OWNED BY public.bugbranch.id;
+
+
+CREATE TABLE public.bugmessage (
     id integer NOT NULL,
     bug integer NOT NULL,
     message integer NOT NULL,
@@ -6501,37 +5248,52 @@
 );
 
 
-COMMENT ON TABLE bugmessage IS 'This table maps a message to a bug. In other words, it shows that a particular message is associated with a particular bug.';
-
-
-COMMENT ON COLUMN bugmessage.bugwatch IS 'The external bug this bug comment was imported from.';
-
-
-COMMENT ON COLUMN bugmessage.remote_comment_id IS 'The id this bug comment has in the external bug tracker, if it is an imported comment. If it is NULL while having a bugwatch set, this comment was added in Launchpad and needs to be pushed to the external bug tracker.';
-
-
-COMMENT ON COLUMN bugmessage.index IS 'The index (used in urls) of the message in a particular bug.';
-
-
-CREATE SEQUENCE bugmessage_id_seq
+COMMENT ON TABLE public.bugmessage IS 'This table maps a message to a bug. In other words, it shows that a particular message is associated with a particular bug.';
+
+
+COMMENT ON COLUMN public.bugmessage.bugwatch IS 'The external bug this bug comment was imported from.';
+
+
+COMMENT ON COLUMN public.bugmessage.remote_comment_id IS 'The id this bug comment has in the external bug tracker, if it is an imported comment. If it is NULL while having a bugwatch set, this comment was added in Launchpad and needs to be pushed to the external bug tracker.';
+
+
+COMMENT ON COLUMN public.bugmessage.index IS 'The index (used in urls) of the message in a particular bug.';
+
+
+COMMENT ON COLUMN public.bugmessage.owner IS 'Denormalised owner from Message, used for efficient queries on commentors.';
+
+
+CREATE SEQUENCE public.bugmessage_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE bugmessage_id_seq OWNED BY bugmessage.id;
-
-
-CREATE TABLE bugmute (
+ALTER SEQUENCE public.bugmessage_id_seq OWNED BY public.bugmessage.id;
+
+
+CREATE TABLE public.bugmute (
     person integer NOT NULL,
     bug integer NOT NULL,
     date_created timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL
 );
 
 
-CREATE TABLE bugnomination (
+COMMENT ON TABLE public.bugmute IS 'Mutes for bug notifications.';
+
+
+COMMENT ON COLUMN public.bugmute.person IS 'The person that muted all notifications from this bug.';
+
+
+COMMENT ON COLUMN public.bugmute.bug IS 'The bug of this record';
+
+
+COMMENT ON COLUMN public.bugmute.date_created IS 'The date at which this mute was created.';
+
+
+CREATE TABLE public.bugnomination (
     id integer NOT NULL,
     bug integer NOT NULL,
     distroseries integer,
@@ -6545,45 +5307,45 @@
 );
 
 
-COMMENT ON TABLE bugnomination IS 'A bug nominated for fixing in a distroseries or productseries';
-
-
-COMMENT ON COLUMN bugnomination.bug IS 'The bug being nominated.';
-
-
-COMMENT ON COLUMN bugnomination.distroseries IS 'The distroseries for which the bug is nominated.';
-
-
-COMMENT ON COLUMN bugnomination.productseries IS 'The productseries for which the bug is nominated.';
-
-
-COMMENT ON COLUMN bugnomination.status IS 'The status of the nomination.';
-
-
-COMMENT ON COLUMN bugnomination.date_created IS 'The date the nomination was submitted.';
-
-
-COMMENT ON COLUMN bugnomination.date_decided IS 'The date the nomination was approved or declined.';
-
-
-COMMENT ON COLUMN bugnomination.owner IS 'The person that submitted the nomination';
-
-
-COMMENT ON COLUMN bugnomination.decider IS 'The person who approved or declined the nomination';
-
-
-CREATE SEQUENCE bugnomination_id_seq
+COMMENT ON TABLE public.bugnomination IS 'A bug nominated for fixing in a distroseries or productseries';
+
+
+COMMENT ON COLUMN public.bugnomination.bug IS 'The bug being nominated.';
+
+
+COMMENT ON COLUMN public.bugnomination.distroseries IS 'The distroseries for which the bug is nominated.';
+
+
+COMMENT ON COLUMN public.bugnomination.productseries IS 'The productseries for which the bug is nominated.';
+
+
+COMMENT ON COLUMN public.bugnomination.status IS 'The status of the nomination.';
+
+
+COMMENT ON COLUMN public.bugnomination.date_created IS 'The date the nomination was submitted.';
+
+
+COMMENT ON COLUMN public.bugnomination.date_decided IS 'The date the nomination was approved or declined.';
+
+
+COMMENT ON COLUMN public.bugnomination.owner IS 'The person that submitted the nomination';
+
+
+COMMENT ON COLUMN public.bugnomination.decider IS 'The person who approved or declined the nomination';
+
+
+CREATE SEQUENCE public.bugnomination_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE bugnomination_id_seq OWNED BY bugnomination.id;
-
-
-CREATE TABLE bugnotification (
+ALTER SEQUENCE public.bugnomination_id_seq OWNED BY public.bugnomination.id;
+
+
+CREATE TABLE public.bugnotification (
     id integer NOT NULL,
     bug integer NOT NULL,
     message integer NOT NULL,
@@ -6594,33 +5356,39 @@
 );
 
 
-COMMENT ON TABLE bugnotification IS 'The text representation of changes to a bug, which are used to send email notifications to bug changes.';
-
-
-COMMENT ON COLUMN bugnotification.bug IS 'The bug that was changed.';
-
-
-COMMENT ON COLUMN bugnotification.message IS 'The message the contains the textual representation of the change.';
-
-
-COMMENT ON COLUMN bugnotification.is_comment IS 'Is the change a comment addition.';
-
-
-COMMENT ON COLUMN bugnotification.date_emailed IS 'When this notification was emailed to the bug subscribers.';
-
-
-CREATE SEQUENCE bugnotification_id_seq
+COMMENT ON TABLE public.bugnotification IS 'The text representation of changes to a bug, which are used to send email notifications to bug changes.';
+
+
+COMMENT ON COLUMN public.bugnotification.bug IS 'The bug that was changed.';
+
+
+COMMENT ON COLUMN public.bugnotification.message IS 'The message the contains the textual representation of the change.';
+
+
+COMMENT ON COLUMN public.bugnotification.is_comment IS 'Is the change a comment addition.';
+
+
+COMMENT ON COLUMN public.bugnotification.date_emailed IS 'When this notification was emailed to the bug subscribers.';
+
+
+COMMENT ON COLUMN public.bugnotification.status IS 'The status of this bug notification: pending, omitted, or sent.';
+
+
+COMMENT ON COLUMN public.bugnotification.activity IS 'The BugActivity record corresponding to this notification, if any.';
+
+
+CREATE SEQUENCE public.bugnotification_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE bugnotification_id_seq OWNED BY bugnotification.id;
-
-
-CREATE TABLE bugnotificationarchive (
+ALTER SEQUENCE public.bugnotification_id_seq OWNED BY public.bugnotification.id;
+
+
+CREATE TABLE public.bugnotificationarchive (
     id integer NOT NULL,
     bug integer,
     message integer,
@@ -6629,40 +5397,49 @@
 );
 
 
-CREATE TABLE bugnotificationattachment (
+CREATE TABLE public.bugnotificationattachment (
     id integer NOT NULL,
     message integer NOT NULL,
     bug_notification integer NOT NULL
 );
 
 
-COMMENT ON TABLE bugnotificationattachment IS 'Attachments to be attached to a bug notification.';
-
-
-COMMENT ON COLUMN bugnotificationattachment.message IS 'A message to be attached to the sent bug notification. It will be attached as a mime/multipart part, with a content type of message/rfc822.';
-
-
-COMMENT ON COLUMN bugnotificationattachment.bug_notification IS 'The bug notification, to which things should be attached to.';
-
-
-CREATE SEQUENCE bugnotificationattachment_id_seq
+COMMENT ON TABLE public.bugnotificationattachment IS 'Attachments to be attached to a bug notification.';
+
+
+COMMENT ON COLUMN public.bugnotificationattachment.message IS 'A message to be attached to the sent bug notification. It will be attached as a mime/multipart part, with a content type of message/rfc822.';
+
+
+COMMENT ON COLUMN public.bugnotificationattachment.bug_notification IS 'The bug notification, to which things should be attached to.';
+
+
+CREATE SEQUENCE public.bugnotificationattachment_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE bugnotificationattachment_id_seq OWNED BY bugnotificationattachment.id;
-
-
-CREATE TABLE bugnotificationfilter (
+ALTER SEQUENCE public.bugnotificationattachment_id_seq OWNED BY public.bugnotificationattachment.id;
+
+
+CREATE TABLE public.bugnotificationfilter (
     bug_notification integer NOT NULL,
     bug_subscription_filter integer NOT NULL
 );
 
 
-CREATE TABLE bugnotificationrecipient (
+COMMENT ON TABLE public.bugnotificationfilter IS 'BugSubscriptionFilters that caused BugNotification to be generated.';
+
+
+COMMENT ON COLUMN public.bugnotificationfilter.bug_notification IS 'The bug notification which a filter caused to be emitted.';
+
+
+COMMENT ON COLUMN public.bugnotificationfilter.bug_subscription_filter IS 'A BugSubscriptionFilter that caused a notification to go off.';
+
+
+CREATE TABLE public.bugnotificationrecipient (
     id integer NOT NULL,
     bug_notification integer NOT NULL,
     person integer NOT NULL,
@@ -6671,53 +5448,60 @@
 );
 
 
-COMMENT ON TABLE bugnotificationrecipient IS 'The recipient for a bug notification.';
-
-
-COMMENT ON COLUMN bugnotificationrecipient.bug_notification IS 'The notification this recipient should get.';
-
-
-COMMENT ON COLUMN bugnotificationrecipient.person IS 'The person who should receive this notification.';
-
-
-COMMENT ON COLUMN bugnotificationrecipient.reason_header IS 'The reason this person is receiving this notification (the value for the X-Launchpad-Message-Rationale header).';
-
-
-COMMENT ON COLUMN bugnotificationrecipient.reason_body IS 'A line of text describing the reason this person is receiving this notification (to be included in the email message).';
-
-
-CREATE SEQUENCE bugnotificationrecipient_id_seq
+COMMENT ON TABLE public.bugnotificationrecipient IS 'The recipient for a bug notification.';
+
+
+COMMENT ON COLUMN public.bugnotificationrecipient.bug_notification IS 'The notification this recipient should get.';
+
+
+COMMENT ON COLUMN public.bugnotificationrecipient.person IS 'The person who should receive this notification.';
+
+
+COMMENT ON COLUMN public.bugnotificationrecipient.reason_header IS 'The reason this person is receiving this notification (the value for the X-Launchpad-Message-Rationale header).';
+
+
+COMMENT ON COLUMN public.bugnotificationrecipient.reason_body IS 'A line of text describing the reason this person is receiving this notification (to be included in the email message).';
+
+
+CREATE SEQUENCE public.bugnotificationrecipient_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE bugnotificationrecipient_id_seq OWNED BY bugnotificationrecipient.id;
-
-
-CREATE TABLE bugnotificationrecipientarchive (
+ALTER SEQUENCE public.bugnotificationrecipient_id_seq OWNED BY public.bugnotificationrecipient.id;
+
+
+CREATE TABLE public.bugsubscription (
     id integer NOT NULL,
-    bug_notification integer,
-    person integer,
-    reason_header text,
-    reason_body text
+    person integer NOT NULL,
+    bug integer NOT NULL,
+    date_created timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL,
+    subscribed_by integer NOT NULL,
+    bug_notification_level integer DEFAULT 40 NOT NULL
 );
 
 
-CREATE SEQUENCE bugsubscription_id_seq
+COMMENT ON TABLE public.bugsubscription IS 'A subscription by a Person to a bug.';
+
+
+COMMENT ON COLUMN public.bugsubscription.bug_notification_level IS 'The level of notifications which the Person will receive from this subscription.';
+
+
+CREATE SEQUENCE public.bugsubscription_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE bugsubscription_id_seq OWNED BY bugsubscription.id;
-
-
-CREATE TABLE bugsubscriptionfilter (
+ALTER SEQUENCE public.bugsubscription_id_seq OWNED BY public.bugsubscription.id;
+
+
+CREATE TABLE public.bugsubscriptionfilter (
     id integer NOT NULL,
     structuralsubscription integer,
     find_all_tags boolean NOT NULL,
@@ -6729,100 +5513,97 @@
 );
 
 
-COMMENT ON TABLE bugsubscriptionfilter IS 'A filter with search criteria. Emails are sent only if the affected bug matches the specified parameters. The parameters are the same as those used for bugtask searches.';
-
-
-COMMENT ON COLUMN bugsubscriptionfilter.structuralsubscription IS 'The structural subscription to be filtered.';
-
-
-COMMENT ON COLUMN bugsubscriptionfilter.find_all_tags IS 'If set, search for bugs having all tags specified in BugSubscriptionFilterTag, else search for bugs having any of the tags specified in BugSubscriptionFilterTag.';
-
-
-COMMENT ON COLUMN bugsubscriptionfilter.include_any_tags IS 'If True, include messages for bugs having any tag set.';
-
-
-COMMENT ON COLUMN bugsubscriptionfilter.exclude_any_tags IS 'If True, exclude bugs having any tag set.';
-
-
-COMMENT ON COLUMN bugsubscriptionfilter.other_parameters IS 'Other filter paremeters. Actual filtering is implemented on Python level.';
-
-
-COMMENT ON COLUMN bugsubscriptionfilter.description IS 'A description of the filter, allowing subscribers to note the intent of the filter.';
-
-
-CREATE SEQUENCE bugsubscriptionfilter_id_seq
+COMMENT ON TABLE public.bugsubscriptionfilter IS 'A filter with search criteria. Emails are sent only if the affected bug matches the specified parameters. The parameters are the same as those used for bugtask searches.';
+
+
+COMMENT ON COLUMN public.bugsubscriptionfilter.structuralsubscription IS 'The structural subscription to be filtered.';
+
+
+COMMENT ON COLUMN public.bugsubscriptionfilter.find_all_tags IS 'If set, search for bugs having all tags specified in BugSubscriptionFilterTag, else search for bugs having any of the tags specified in BugSubscriptionFilterTag.';
+
+
+COMMENT ON COLUMN public.bugsubscriptionfilter.include_any_tags IS 'If True, include messages for bugs having any tag set.';
+
+
+COMMENT ON COLUMN public.bugsubscriptionfilter.exclude_any_tags IS 'If True, exclude bugs having any tag set.';
+
+
+COMMENT ON COLUMN public.bugsubscriptionfilter.other_parameters IS 'Other filter paremeters. Actual filtering is implemented on Python level.';
+
+
+COMMENT ON COLUMN public.bugsubscriptionfilter.description IS 'A description of the filter, allowing subscribers to note the intent of the filter.';
+
+
+COMMENT ON COLUMN public.bugsubscriptionfilter.bug_notification_level IS 'The volume and type of bug notifications this filter will allow. The value is an item of the enumeration `BugNotificationLevel`.';
+
+
+CREATE SEQUENCE public.bugsubscriptionfilter_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE bugsubscriptionfilter_id_seq OWNED BY bugsubscriptionfilter.id;
-
-
-CREATE TABLE bugsubscriptionfilterimportance (
-    id integer NOT NULL,
+ALTER SEQUENCE public.bugsubscriptionfilter_id_seq OWNED BY public.bugsubscriptionfilter.id;
+
+
+CREATE TABLE public.bugsubscriptionfilterimportance (
     filter integer NOT NULL,
     importance integer NOT NULL
 );
 
 
-COMMENT ON TABLE bugsubscriptionfilterimportance IS 'Filter a bugsubscription by bug task status.';
-
-
-COMMENT ON COLUMN bugsubscriptionfilterimportance.filter IS 'The subscription filter of this record.';
-
-
-COMMENT ON COLUMN bugsubscriptionfilterimportance.importance IS 'The bug task importance.';
-
-
-CREATE SEQUENCE bugsubscriptionfilterimportance_id_seq
-    START WITH 1
-    INCREMENT BY 1
-    NO MAXVALUE
-    NO MINVALUE
-    CACHE 1;
-
-
-ALTER SEQUENCE bugsubscriptionfilterimportance_id_seq OWNED BY bugsubscriptionfilterimportance.id;
-
-
-CREATE TABLE bugsubscriptionfiltermute (
+COMMENT ON TABLE public.bugsubscriptionfilterimportance IS 'Filter a bugsubscription by bug task status.';
+
+
+COMMENT ON COLUMN public.bugsubscriptionfilterimportance.filter IS 'The subscription filter of this record.';
+
+
+COMMENT ON COLUMN public.bugsubscriptionfilterimportance.importance IS 'The bug task importance.';
+
+
+CREATE TABLE public.bugsubscriptionfilterinformationtype (
+    filter integer NOT NULL,
+    information_type integer NOT NULL
+);
+
+
+CREATE TABLE public.bugsubscriptionfiltermute (
     person integer NOT NULL,
     filter integer NOT NULL,
     date_created timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL
 );
 
 
-CREATE TABLE bugsubscriptionfilterstatus (
-    id integer NOT NULL,
+COMMENT ON TABLE public.bugsubscriptionfiltermute IS 'Mutes for subscription filters.';
+
+
+COMMENT ON COLUMN public.bugsubscriptionfiltermute.person IS 'The person that muted their subscription to this filter.';
+
+
+COMMENT ON COLUMN public.bugsubscriptionfiltermute.filter IS 'The subscription filter of this record';
+
+
+COMMENT ON COLUMN public.bugsubscriptionfiltermute.date_created IS 'The date at which this mute was created.';
+
+
+CREATE TABLE public.bugsubscriptionfilterstatus (
     filter integer NOT NULL,
     status integer NOT NULL
 );
 
 
-COMMENT ON TABLE bugsubscriptionfilterstatus IS 'Filter a bugsubscription by bug task status.';
-
-
-COMMENT ON COLUMN bugsubscriptionfilterstatus.filter IS 'The subscription filter of this record.';
-
-
-COMMENT ON COLUMN bugsubscriptionfilterstatus.status IS 'The bug task status.';
-
-
-CREATE SEQUENCE bugsubscriptionfilterstatus_id_seq
-    START WITH 1
-    INCREMENT BY 1
-    NO MAXVALUE
-    NO MINVALUE
-    CACHE 1;
-
-
-ALTER SEQUENCE bugsubscriptionfilterstatus_id_seq OWNED BY bugsubscriptionfilterstatus.id;
-
-
-CREATE TABLE bugsubscriptionfiltertag (
+COMMENT ON TABLE public.bugsubscriptionfilterstatus IS 'Filter a bugsubscription by bug task status.';
+
+
+COMMENT ON COLUMN public.bugsubscriptionfilterstatus.filter IS 'The subscription filter of this record.';
+
+
+COMMENT ON COLUMN public.bugsubscriptionfilterstatus.status IS 'The bug task status.';
+
+
+CREATE TABLE public.bugsubscriptionfiltertag (
     id integer NOT NULL,
     filter integer NOT NULL,
     tag text NOT NULL,
@@ -6830,41 +5611,41 @@
 );
 
 
-COMMENT ON TABLE bugsubscriptionfiltertag IS 'Filter by bug tag.';
-
-
-COMMENT ON COLUMN bugsubscriptionfiltertag.filter IS 'The subscription filter of this record.';
-
-
-COMMENT ON COLUMN bugsubscriptionfiltertag.tag IS 'A bug tag.';
-
-
-COMMENT ON COLUMN bugsubscriptionfiltertag.include IS 'If True, send only messages for bugs having this tag, else send only messages for bugs which do not have this tag.';
-
-
-CREATE SEQUENCE bugsubscriptionfiltertag_id_seq
-    START WITH 1
-    INCREMENT BY 1
-    NO MAXVALUE
-    NO MINVALUE
-    CACHE 1;
-
-
-ALTER SEQUENCE bugsubscriptionfiltertag_id_seq OWNED BY bugsubscriptionfiltertag.id;
-
-
-CREATE SEQUENCE bugsummary_id_seq
-    START WITH 1
-    INCREMENT BY 1
-    NO MAXVALUE
-    NO MINVALUE
-    CACHE 1;
-
-
-ALTER SEQUENCE bugsummary_id_seq OWNED BY bugsummary.id;
-
-
-CREATE TABLE bugsummaryjournal (
+COMMENT ON TABLE public.bugsubscriptionfiltertag IS 'Filter by bug tag.';
+
+
+COMMENT ON COLUMN public.bugsubscriptionfiltertag.filter IS 'The subscription filter of this record.';
+
+
+COMMENT ON COLUMN public.bugsubscriptionfiltertag.tag IS 'A bug tag.';
+
+
+COMMENT ON COLUMN public.bugsubscriptionfiltertag.include IS 'If True, send only messages for bugs having this tag, else send only messages for bugs which do not have this tag.';
+
+
+CREATE SEQUENCE public.bugsubscriptionfiltertag_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER SEQUENCE public.bugsubscriptionfiltertag_id_seq OWNED BY public.bugsubscriptionfiltertag.id;
+
+
+CREATE SEQUENCE public.bugsummary_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER SEQUENCE public.bugsummary_id_seq OWNED BY public.bugsummary.id;
+
+
+CREATE TABLE public.bugsummaryjournal (
     id integer NOT NULL,
     count integer DEFAULT 0 NOT NULL,
     product integer,
@@ -6878,44 +5659,155 @@
     milestone integer,
     importance integer NOT NULL,
     has_patch boolean NOT NULL,
-    fixed_upstream boolean NOT NULL
-);
-
-
-CREATE SEQUENCE bugsummaryjournal_id_seq
-    START WITH 1
-    INCREMENT BY 1
-    NO MAXVALUE
-    NO MINVALUE
-    CACHE 1;
-
-
-ALTER SEQUENCE bugsummaryjournal_id_seq OWNED BY bugsummaryjournal.id;
-
-
-CREATE SEQUENCE bugtag_id_seq
-    START WITH 1
-    INCREMENT BY 1
-    NO MAXVALUE
-    NO MINVALUE
-    CACHE 1;
-
-
-ALTER SEQUENCE bugtag_id_seq OWNED BY bugtag.id;
-
-
-CREATE SEQUENCE bugtask_id_seq
-    START WITH 1
-    INCREMENT BY 1
-    NO MAXVALUE
-    NO MINVALUE
-    CACHE 1;
-
-
-ALTER SEQUENCE bugtask_id_seq OWNED BY bugtask.id;
-
-
-CREATE TABLE bugtracker (
+    access_policy integer
+);
+
+
+CREATE SEQUENCE public.bugsummaryjournal_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER SEQUENCE public.bugsummaryjournal_id_seq OWNED BY public.bugsummaryjournal.id;
+
+
+CREATE SEQUENCE public.bugtag_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER SEQUENCE public.bugtag_id_seq OWNED BY public.bugtag.id;
+
+
+CREATE TABLE public.bugtask (
+    id integer NOT NULL,
+    bug integer NOT NULL,
+    product integer,
+    distribution integer,
+    distroseries integer,
+    sourcepackagename integer,
+    status integer NOT NULL,
+    importance integer DEFAULT 5 NOT NULL,
+    assignee integer,
+    date_assigned timestamp without time zone,
+    datecreated timestamp without time zone DEFAULT timezone('UTC'::text, ('now'::text)::timestamp(6) with time zone),
+    owner integer NOT NULL,
+    milestone integer,
+    bugwatch integer,
+    targetnamecache text,
+    date_confirmed timestamp without time zone,
+    date_inprogress timestamp without time zone,
+    date_closed timestamp without time zone,
+    productseries integer,
+    date_incomplete timestamp without time zone,
+    date_left_new timestamp without time zone,
+    date_triaged timestamp without time zone,
+    date_fix_committed timestamp without time zone,
+    date_fix_released timestamp without time zone,
+    date_left_closed timestamp without time zone,
+    date_milestone_set timestamp without time zone,
+    CONSTRAINT bugtask_assignment_checks CHECK (
+CASE
+    WHEN (product IS NOT NULL) THEN ((((productseries IS NULL) AND (distribution IS NULL)) AND (distroseries IS NULL)) AND (sourcepackagename IS NULL))
+    WHEN (productseries IS NOT NULL) THEN (((distribution IS NULL) AND (distroseries IS NULL)) AND (sourcepackagename IS NULL))
+    WHEN (distribution IS NOT NULL) THEN (distroseries IS NULL)
+    WHEN (distroseries IS NOT NULL) THEN true
+    ELSE false
+END)
+);
+
+
+COMMENT ON TABLE public.bugtask IS 'Links a given Bug to a particular (sourcepackagename, distro) or product.';
+
+
+COMMENT ON COLUMN public.bugtask.bug IS 'The bug that is assigned to this (sourcepackagename, distro) or product.';
+
+
+COMMENT ON COLUMN public.bugtask.product IS 'The product in which this bug shows up.';
+
+
+COMMENT ON COLUMN public.bugtask.distribution IS 'The distro of the named sourcepackage.';
+
+
+COMMENT ON COLUMN public.bugtask.sourcepackagename IS 'The name of the sourcepackage in which this bug shows up.';
+
+
+COMMENT ON COLUMN public.bugtask.status IS 'The general health of the bug, e.g. Accepted, Rejected, etc.';
+
+
+COMMENT ON COLUMN public.bugtask.importance IS 'The importance of fixing the bug.';
+
+
+COMMENT ON COLUMN public.bugtask.assignee IS 'The person who has been assigned to fix this bug in this product or (sourcepackagename, distro)';
+
+
+COMMENT ON COLUMN public.bugtask.date_assigned IS 'The date on which the bug in this (sourcepackagename, distro) or product was assigned to someone to fix';
+
+
+COMMENT ON COLUMN public.bugtask.datecreated IS 'A timestamp for the creation of this bug assignment. Note that this is not the date the bug was created (though it might be), it''s the date the bug was assigned to this product, which could have come later.';
+
+
+COMMENT ON COLUMN public.bugtask.milestone IS 'A way to mark a bug for grouping purposes, e.g. to say it needs to be fixed by version 1.2';
+
+
+COMMENT ON COLUMN public.bugtask.bugwatch IS 'This column allows us to link a bug
+task to a bug watch. In other words, we are connecting the state of the task
+to the state of the bug in a different bug tracking system. To the best of
+our ability we''ll try and keep the bug task syncronised with the state of
+the remote bug watch.';
+
+
+COMMENT ON COLUMN public.bugtask.targetnamecache IS 'A cached value of the target name of this bugtask, to make it easier to sort and search on the target name.';
+
+
+COMMENT ON COLUMN public.bugtask.date_confirmed IS 'The date when this bug transitioned from an unconfirmed status to a confirmed one. If the state regresses to a one that logically occurs before Confirmed, e.g., Unconfirmed, this date is cleared.';
+
+
+COMMENT ON COLUMN public.bugtask.date_inprogress IS 'The date on which this bug transitioned from not being in progress to a state >= In Progress. If the status moves back to a pre-In Progress state, this date is cleared';
+
+
+COMMENT ON COLUMN public.bugtask.date_closed IS 'The date when this bug transitioned to a resolved state, e.g., Rejected, Fix Released, etc. If the state changes back to a pre-closed state, this date is cleared';
+
+
+COMMENT ON COLUMN public.bugtask.productseries IS 'The product series to which the bug is targeted';
+
+
+COMMENT ON COLUMN public.bugtask.date_left_new IS 'The date when this bug first transitioned out of the NEW status.';
+
+
+COMMENT ON COLUMN public.bugtask.date_triaged IS 'The date when this bug transitioned to a status >= TRIAGED.';
+
+
+COMMENT ON COLUMN public.bugtask.date_fix_committed IS 'The date when this bug transitioned to a status >= FIXCOMMITTED.';
+
+
+COMMENT ON COLUMN public.bugtask.date_fix_released IS 'The date when this bug transitioned to a FIXRELEASED status.';
+
+
+COMMENT ON COLUMN public.bugtask.date_left_closed IS 'The date when this bug last transitioned out of a CLOSED status.';
+
+
+COMMENT ON COLUMN public.bugtask.date_milestone_set IS 'The date when this bug was targed to the milestone that is currently set.';
+
+
+CREATE SEQUENCE public.bugtask_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER SEQUENCE public.bugtask_id_seq OWNED BY public.bugtask.id;
+
+
+CREATE TABLE public.bugtracker (
     id integer NOT NULL,
     bugtrackertype integer NOT NULL,
     name text NOT NULL,
@@ -6929,82 +5821,82 @@
     block_comment_pushing boolean DEFAULT false NOT NULL,
     has_lp_plugin boolean,
     active boolean DEFAULT true NOT NULL,
-    CONSTRAINT valid_name CHECK (valid_name(name))
+    CONSTRAINT valid_name CHECK (public.valid_name(name))
 );
 
 
-COMMENT ON TABLE bugtracker IS 'A bug tracker in some other project. Malone allows us to link Malone bugs with bugs recorded in other bug tracking systems, and to keep the status of the relevant bug task in sync with the status in that upstream bug tracker. So, for example, you might note that Malone bug #43224 is the same as a bug in the Apache bugzilla, number 534536. Then when the upstream guys mark that bug fixed in their bugzilla, Malone know that the bug is fixed upstream.';
-
-
-COMMENT ON COLUMN bugtracker.bugtrackertype IS 'The type of bug tracker, a pointer to the table of bug tracker types. Currently we know about debbugs and bugzilla bugtrackers, and plan to support roundup and sourceforge as well.';
-
-
-COMMENT ON COLUMN bugtracker.name IS 'The unique name of this bugtracker, allowing us to refer to it directly.';
-
-
-COMMENT ON COLUMN bugtracker.title IS 'A title for the bug tracker, used in listings of all the bug trackers and also displayed at the top of the descriptive page for the bug tracker.';
-
-
-COMMENT ON COLUMN bugtracker.summary IS 'A brief summary of this bug tracker, which might for example list any interesting policies regarding the use of the bug tracker. The summary is displayed in bold at the top of the bug tracker page.';
-
-
-COMMENT ON COLUMN bugtracker.baseurl IS 'The base URL for this bug tracker. Using our knowledge of the bugtrackertype, and the details in the BugWatch table we are then able to calculate relative URLs for relevant pages in the bug tracker based on this baseurl.';
-
-
-COMMENT ON COLUMN bugtracker.owner IS 'The person who created this bugtracker entry and who thus has permission to modify it. Ideally we would like this to be the person who coordinates the running of the actual bug tracker upstream.';
-
-
-COMMENT ON COLUMN bugtracker.contactdetails IS 'The contact details of the people responsible for that bug tracker. This allows us to coordinate the syncing of bugs to and from that bug tracker with the responsible people on the other side.';
-
-
-COMMENT ON COLUMN bugtracker.version IS 'The version of the bug tracker software being used.';
-
-
-COMMENT ON COLUMN bugtracker.block_comment_pushing IS 'Whether to block pushing comments to the bug tracker. Having a value of false means that we will push the comments if the bug tracker supports it.';
-
-
-COMMENT ON COLUMN bugtracker.has_lp_plugin IS 'Whether we have confirmed that the Launchpad plugin was installed on the bug tracker, the last time checkwatches was run.';
-
-
-CREATE SEQUENCE bugtracker_id_seq
+COMMENT ON TABLE public.bugtracker IS 'A bug tracker in some other project. Malone allows us to link Malone bugs with bugs recorded in other bug tracking systems, and to keep the status of the relevant bug task in sync with the status in that upstream bug tracker. So, for example, you might note that Malone bug #43224 is the same as a bug in the Apache bugzilla, number 534536. Then when the upstream guys mark that bug fixed in their bugzilla, Malone know that the bug is fixed upstream.';
+
+
+COMMENT ON COLUMN public.bugtracker.bugtrackertype IS 'The type of bug tracker, a pointer to the table of bug tracker types. Currently we know about debbugs and bugzilla bugtrackers, and plan to support roundup and sourceforge as well.';
+
+
+COMMENT ON COLUMN public.bugtracker.name IS 'The unique name of this bugtracker, allowing us to refer to it directly.';
+
+
+COMMENT ON COLUMN public.bugtracker.title IS 'A title for the bug tracker, used in listings of all the bug trackers and also displayed at the top of the descriptive page for the bug tracker.';
+
+
+COMMENT ON COLUMN public.bugtracker.summary IS 'A brief summary of this bug tracker, which might for example list any interesting policies regarding the use of the bug tracker. The summary is displayed in bold at the top of the bug tracker page.';
+
+
+COMMENT ON COLUMN public.bugtracker.baseurl IS 'The base URL for this bug tracker. Using our knowledge of the bugtrackertype, and the details in the BugWatch table we are then able to calculate relative URLs for relevant pages in the bug tracker based on this baseurl.';
+
+
+COMMENT ON COLUMN public.bugtracker.owner IS 'The person who created this bugtracker entry and who thus has permission to modify it. Ideally we would like this to be the person who coordinates the running of the actual bug tracker upstream.';
+
+
+COMMENT ON COLUMN public.bugtracker.contactdetails IS 'The contact details of the people responsible for that bug tracker. This allows us to coordinate the syncing of bugs to and from that bug tracker with the responsible people on the other side.';
+
+
+COMMENT ON COLUMN public.bugtracker.version IS 'The version of the bug tracker software being used.';
+
+
+COMMENT ON COLUMN public.bugtracker.block_comment_pushing IS 'Whether to block pushing comments to the bug tracker. Having a value of false means that we will push the comments if the bug tracker supports it.';
+
+
+COMMENT ON COLUMN public.bugtracker.has_lp_plugin IS 'Whether we have confirmed that the Launchpad plugin was installed on the bug tracker, the last time checkwatches was run.';
+
+
+CREATE SEQUENCE public.bugtracker_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE bugtracker_id_seq OWNED BY bugtracker.id;
-
-
-CREATE TABLE bugtrackeralias (
+ALTER SEQUENCE public.bugtracker_id_seq OWNED BY public.bugtracker.id;
+
+
+CREATE TABLE public.bugtrackeralias (
     id integer NOT NULL,
     bugtracker integer NOT NULL,
     base_url text NOT NULL
 );
 
 
-COMMENT ON TABLE bugtrackeralias IS 'A bugtracker alias is a URL that also refers to the same bugtracker as the master bugtracker. For example, a bugtracker might be accessible as both http://www.bugsrus.com/ and http://bugsrus.com/. A bugtracker can have many aliases, and all of them are checked to prevents users registering duplicate bugtrackers inadvertently.';
-
-
-COMMENT ON COLUMN bugtrackeralias.bugtracker IS 'The master bugtracker that this alias refers to.';
-
-
-COMMENT ON COLUMN bugtrackeralias.base_url IS 'Another base URL for this bug tracker. See BugTracker.baseurl.';
-
-
-CREATE SEQUENCE bugtrackeralias_id_seq
+COMMENT ON TABLE public.bugtrackeralias IS 'A bugtracker alias is a URL that also refers to the same bugtracker as the master bugtracker. For example, a bugtracker might be accessible as both http://www.bugsrus.com/ and http://bugsrus.com/. A bugtracker can have many aliases, and all of them are checked to prevents users registering duplicate bugtrackers inadvertently.';
+
+
+COMMENT ON COLUMN public.bugtrackeralias.bugtracker IS 'The master bugtracker that this alias refers to.';
+
+
+COMMENT ON COLUMN public.bugtrackeralias.base_url IS 'Another base URL for this bug tracker. See BugTracker.baseurl.';
+
+
+CREATE SEQUENCE public.bugtrackeralias_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE bugtrackeralias_id_seq OWNED BY bugtrackeralias.id;
-
-
-CREATE TABLE bugtrackercomponent (
+ALTER SEQUENCE public.bugtrackeralias_id_seq OWNED BY public.bugtrackeralias.id;
+
+
+CREATE TABLE public.bugtrackercomponent (
     id integer NOT NULL,
     name text NOT NULL,
     is_visible boolean DEFAULT true NOT NULL,
@@ -7016,66 +5908,66 @@
 );
 
 
-COMMENT ON TABLE bugtrackercomponent IS 'A software component in a remote bug tracker, which can be linked to the corresponding source package in a distribution using this table.';
-
-
-COMMENT ON COLUMN bugtrackercomponent.name IS 'The name of the component as registered in the remote bug tracker.';
-
-
-COMMENT ON COLUMN bugtrackercomponent.is_visible IS 'Whether to display or hide the item in the Launchpad user interface.';
-
-
-COMMENT ON COLUMN bugtrackercomponent.is_custom IS 'Whether the item was added by a user in Launchpad or is kept in sync with the remote bug tracker.';
-
-
-COMMENT ON COLUMN bugtrackercomponent.component_group IS 'The product or other higher level category used by the remote bug tracker to group projects, if any.';
-
-
-COMMENT ON COLUMN bugtrackercomponent.distribution IS 'Link to the distribution for the associated source package.  This can be NULL if no ling has been established.';
-
-
-COMMENT ON COLUMN bugtrackercomponent.source_package_name IS 'The text name of the source package in a distribution that corresponds to this component.  This can be NULL if no link has been established yet.';
-
-
-CREATE SEQUENCE bugtrackercomponent_id_seq
+COMMENT ON TABLE public.bugtrackercomponent IS 'A software component in a remote bug tracker, which can be linked to the corresponding source package in a distribution using this table.';
+
+
+COMMENT ON COLUMN public.bugtrackercomponent.name IS 'The name of the component as registered in the remote bug tracker.';
+
+
+COMMENT ON COLUMN public.bugtrackercomponent.is_visible IS 'Whether to display or hide the item in the Launchpad user interface.';
+
+
+COMMENT ON COLUMN public.bugtrackercomponent.is_custom IS 'Whether the item was added by a user in Launchpad or is kept in sync with the remote bug tracker.';
+
+
+COMMENT ON COLUMN public.bugtrackercomponent.component_group IS 'The product or other higher level category used by the remote bug tracker to group projects, if any.';
+
+
+COMMENT ON COLUMN public.bugtrackercomponent.distribution IS 'Link to the distribution for the associated source package.  This can be NULL if no ling has been established.';
+
+
+COMMENT ON COLUMN public.bugtrackercomponent.source_package_name IS 'The text name of the source package in a distribution that corresponds to this component.  This can be NULL if no link has been established yet.';
+
+
+CREATE SEQUENCE public.bugtrackercomponent_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE bugtrackercomponent_id_seq OWNED BY bugtrackercomponent.id;
-
-
-CREATE TABLE bugtrackercomponentgroup (
+ALTER SEQUENCE public.bugtrackercomponent_id_seq OWNED BY public.bugtrackercomponent.id;
+
+
+CREATE TABLE public.bugtrackercomponentgroup (
     id integer NOT NULL,
     name text NOT NULL,
     bug_tracker integer NOT NULL
 );
 
 
-COMMENT ON TABLE bugtrackercomponentgroup IS 'A collection of components as modeled in a remote bug tracker, often referred to as a product.  Some bug trackers do not categorize software components this way, so they will have a single default component group that all components belong to.';
-
-
-COMMENT ON COLUMN bugtrackercomponentgroup.name IS 'The product or category name used in the remote bug tracker for grouping components.';
-
-
-COMMENT ON COLUMN bugtrackercomponentgroup.bug_tracker IS 'The external bug tracker this component group belongs to.';
-
-
-CREATE SEQUENCE bugtrackercomponentgroup_id_seq
+COMMENT ON TABLE public.bugtrackercomponentgroup IS 'A collection of components as modeled in a remote bug tracker, often referred to as a product.  Some bug trackers do not categorize software components this way, so they will have a single default component group that all components belong to.';
+
+
+COMMENT ON COLUMN public.bugtrackercomponentgroup.name IS 'The product or category name used in the remote bug tracker for grouping components.';
+
+
+COMMENT ON COLUMN public.bugtrackercomponentgroup.bug_tracker IS 'The external bug tracker this component group belongs to.';
+
+
+CREATE SEQUENCE public.bugtrackercomponentgroup_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE bugtrackercomponentgroup_id_seq OWNED BY bugtrackercomponentgroup.id;
-
-
-CREATE TABLE bugtrackerperson (
+ALTER SEQUENCE public.bugtrackercomponentgroup_id_seq OWNED BY public.bugtrackercomponentgroup.id;
+
+
+CREATE TABLE public.bugtrackerperson (
     id integer NOT NULL,
     date_created timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL,
     bugtracker integer NOT NULL,
@@ -7084,33 +5976,33 @@
 );
 
 
-COMMENT ON TABLE bugtrackerperson IS 'A mapping from a user in an external bug tracker to a Person record in Launchpad. This is used when we can''t get an email address from the bug tracker.';
-
-
-COMMENT ON COLUMN bugtrackerperson.date_created IS 'When was this mapping added.';
-
-
-COMMENT ON COLUMN bugtrackerperson.bugtracker IS 'The external bug tracker in which this user has an account.';
-
-
-COMMENT ON COLUMN bugtrackerperson.person IS 'The Person record in Launchpad this user corresponds to.';
-
-
-COMMENT ON COLUMN bugtrackerperson.name IS 'The (within the bug tracker) unique username in the external bug tracker.';
-
-
-CREATE SEQUENCE bugtrackerperson_id_seq
+COMMENT ON TABLE public.bugtrackerperson IS 'A mapping from a user in an external bug tracker to a Person record in Launchpad. This is used when we can''t get an email address from the bug tracker.';
+
+
+COMMENT ON COLUMN public.bugtrackerperson.date_created IS 'When was this mapping added.';
+
+
+COMMENT ON COLUMN public.bugtrackerperson.bugtracker IS 'The external bug tracker in which this user has an account.';
+
+
+COMMENT ON COLUMN public.bugtrackerperson.person IS 'The Person record in Launchpad this user corresponds to.';
+
+
+COMMENT ON COLUMN public.bugtrackerperson.name IS 'The (within the bug tracker) unique username in the external bug tracker.';
+
+
+CREATE SEQUENCE public.bugtrackerperson_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE bugtrackerperson_id_seq OWNED BY bugtrackerperson.id;
-
-
-CREATE TABLE bugwatch (
+ALTER SEQUENCE public.bugtrackerperson_id_seq OWNED BY public.bugtrackerperson.id;
+
+
+CREATE TABLE public.bugwatch (
     id integer NOT NULL,
     bug integer NOT NULL,
     bugtracker integer NOT NULL,
@@ -7127,30 +6019,30 @@
 );
 
 
-COMMENT ON COLUMN bugwatch.last_error_type IS 'The type of error which last prevented this entry from being updated. Legal values are defined by the BugWatchErrorType enumeration.';
-
-
-COMMENT ON COLUMN bugwatch.remote_importance IS 'The importance of the bug as returned by the remote server. This will be converted into a Launchpad BugTaskImportance value.';
-
-
-COMMENT ON COLUMN bugwatch.remote_lp_bug_id IS 'The bug in Launchpad that the remote bug is pointing at. This can be different than the BugWatch.bug column, since the same remote bug can be linked from multiple bugs in Launchpad, but the remote bug can only link to a single bug in Launchpad. The main use case for this column is to avoid having to query the remote bug tracker for this information, in order to decide whether we need to give this information to the remote bug tracker.';
-
-
-COMMENT ON COLUMN bugwatch.next_check IS 'The time after which the watch should next be checked. Note that this does not denote an exact schedule for the next check since checkwatches only runs periodically.';
-
-
-CREATE SEQUENCE bugwatch_id_seq
+COMMENT ON COLUMN public.bugwatch.last_error_type IS 'The type of error which last prevented this entry from being updated. Legal values are defined by the BugWatchErrorType enumeration.';
+
+
+COMMENT ON COLUMN public.bugwatch.remote_importance IS 'The importance of the bug as returned by the remote server. This will be converted into a Launchpad BugTaskImportance value.';
+
+
+COMMENT ON COLUMN public.bugwatch.remote_lp_bug_id IS 'The bug in Launchpad that the remote bug is pointing at. This can be different than the BugWatch.bug column, since the same remote bug can be linked from multiple bugs in Launchpad, but the remote bug can only link to a single bug in Launchpad. The main use case for this column is to avoid having to query the remote bug tracker for this information, in order to decide whether we need to give this information to the remote bug tracker.';
+
+
+COMMENT ON COLUMN public.bugwatch.next_check IS 'The time after which the watch should next be checked. Note that this does not denote an exact schedule for the next check since checkwatches only runs periodically.';
+
+
+CREATE SEQUENCE public.bugwatch_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE bugwatch_id_seq OWNED BY bugwatch.id;
-
-
-CREATE TABLE bugwatchactivity (
+ALTER SEQUENCE public.bugwatch_id_seq OWNED BY public.bugwatch.id;
+
+
+CREATE TABLE public.bugwatchactivity (
     id integer NOT NULL,
     bug_watch integer NOT NULL,
     activity_date timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL,
@@ -7158,44 +6050,43 @@
     message text,
     oops_id text
 )
-WITH (fillfactor=100);
-
-
-COMMENT ON TABLE bugwatchactivity IS 'This table contains a record of each update for a given bug watch. This allows us to track whether a given update was successful or not and, if not, the details of the error which caused the update to fail.';
-
-
-COMMENT ON COLUMN bugwatchactivity.bug_watch IS 'The bug_watch to which this activity entry relates.';
-
-
-COMMENT ON COLUMN bugwatchactivity.activity_date IS 'The datetime at which the activity occurred.';
-
-
-COMMENT ON COLUMN bugwatchactivity.result IS 'The result of the update. Legal values are defined in the BugWatchErrorType enumeration. An update is considered successful if its error_type is NULL.';
-
-
-COMMENT ON COLUMN bugwatchactivity.message IS 'The message (if any) associated with the update.';
-
-
-COMMENT ON COLUMN bugwatchactivity.oops_id IS 'The OOPS id, if any, associated with the error that caused the update to fail.';
-
-
-CREATE SEQUENCE bugwatchactivity_id_seq
+WITH (fillfactor='100');
+
+
+COMMENT ON TABLE public.bugwatchactivity IS 'This table contains a record of each update for a given bug watch. This allows us to track whether a given update was successful or not and, if not, the details of the error which caused the update to fail.';
+
+
+COMMENT ON COLUMN public.bugwatchactivity.bug_watch IS 'The bug_watch to which this activity entry relates.';
+
+
+COMMENT ON COLUMN public.bugwatchactivity.activity_date IS 'The datetime at which the activity occurred.';
+
+
+COMMENT ON COLUMN public.bugwatchactivity.result IS 'The result of the update. Legal values are defined in the BugWatchErrorType enumeration. An update is considered successful if its error_type is NULL.';
+
+
+COMMENT ON COLUMN public.bugwatchactivity.message IS 'The message (if any) associated with the update.';
+
+
+COMMENT ON COLUMN public.bugwatchactivity.oops_id IS 'The OOPS id, if any, associated with the error that caused the update to fail.';
+
+
+CREATE SEQUENCE public.bugwatchactivity_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE bugwatchactivity_id_seq OWNED BY bugwatchactivity.id;
-
-
-CREATE TABLE builder (
+ALTER SEQUENCE public.bugwatchactivity_id_seq OWNED BY public.bugwatchactivity.id;
+
+
+CREATE TABLE public.builder (
     id integer NOT NULL,
-    processor integer NOT NULL,
+    processor integer,
     name text NOT NULL,
     title text NOT NULL,
-    description text NOT NULL,
     owner integer NOT NULL,
     speedindex integer,
     builderok boolean NOT NULL,
@@ -7207,191 +6098,157 @@
     vm_host text,
     active boolean DEFAULT true NOT NULL,
     failure_count integer DEFAULT 0 NOT NULL,
-    CONSTRAINT valid_absolute_url CHECK (valid_absolute_url(url))
+    version text,
+    clean_status integer DEFAULT 1 NOT NULL,
+    vm_reset_protocol integer,
+    date_clean_status_changed timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL,
+    CONSTRAINT valid_absolute_url CHECK (public.valid_absolute_url(url))
 );
 
 
-COMMENT ON TABLE builder IS 'Builder: This table stores the build-slave registry and status information as: name, url, trusted, builderok, builderaction, failnotes.';
-
-
-COMMENT ON COLUMN builder.speedindex IS 'A relative measure of the speed of this builder. If NULL, we do not yet have a speedindex for the builder else it is the number of seconds needed to perform a reference build';
-
-
-COMMENT ON COLUMN builder.builderok IS 'Should a builder fail for any reason, from out-of-disk-space to not responding to the buildd master, the builderok flag is set to false and the failnotes column is filled with a reason.';
-
-
-COMMENT ON COLUMN builder.failnotes IS 'This column gets filled out with a textual description of how/why a builder has failed. If the builderok column is true then the value in this column is irrelevant and should be treated as NULL or empty.';
-
-
-COMMENT ON COLUMN builder.virtualized IS 'Whether or not the builder is a virtual Xen builder. Packages coming via ubuntu workflow are trusted to build on non-Xen and do not need facist behaviour to be built. Other packages like ppa/grumpy incoming packages can contain malicious code, so are unstrusted and build in a Xen virtual machine.';
-
-
-COMMENT ON COLUMN builder.url IS 'The url to the build slave. There may be more than one build slave on a given host so this url includes the port number to use. The default port number for a build slave is 8221';
-
-
-COMMENT ON COLUMN builder.manual IS 'Whether or not builder was manual mode, i.e., collect any result from the it, but do not dispach anything to it automatically.';
-
-
-COMMENT ON COLUMN builder.vm_host IS 'The virtual machine host associated to this builder. It should be empty for "native" builders (old fashion or architectures not yet supported by XEN).';
-
-
-COMMENT ON COLUMN builder.active IS 'Whether to present or not the builder in the public list of builders avaialble. It is used to hide transient or defunct builders while they get fixed.';
-
-
-COMMENT ON COLUMN builder.failure_count IS 'The number of consecutive failures on this builder.  Is reset to zero after a sucessful dispatch.';
-
-
-CREATE SEQUENCE builder_id_seq
+COMMENT ON TABLE public.builder IS 'Builder: This table stores the build-slave registry and status information as: name, url, trusted, builderok, builderaction, failnotes.';
+
+
+COMMENT ON COLUMN public.builder.speedindex IS 'A relative measure of the speed of this builder. If NULL, we do not yet have a speedindex for the builder else it is the number of seconds needed to perform a reference build';
+
+
+COMMENT ON COLUMN public.builder.builderok IS 'Should a builder fail for any reason, from out-of-disk-space to not responding to the buildd master, the builderok flag is set to false and the failnotes column is filled with a reason.';
+
+
+COMMENT ON COLUMN public.builder.failnotes IS 'This column gets filled out with a textual description of how/why a builder has failed. If the builderok column is true then the value in this column is irrelevant and should be treated as NULL or empty.';
+
+
+COMMENT ON COLUMN public.builder.virtualized IS 'Whether or not the builder is a virtual Xen builder. Packages coming via ubuntu workflow are trusted to build on non-Xen and do not need facist behaviour to be built. Other packages like ppa/grumpy incoming packages can contain malicious code, so are unstrusted and build in a Xen virtual machine.';
+
+
+COMMENT ON COLUMN public.builder.url IS 'The url to the build slave. There may be more than one build slave on a given host so this url includes the port number to use. The default port number for a build slave is 8221';
+
+
+COMMENT ON COLUMN public.builder.manual IS 'Whether or not builder was manual mode, i.e., collect any result from the it, but do not dispach anything to it automatically.';
+
+
+COMMENT ON COLUMN public.builder.vm_host IS 'The virtual machine host associated to this builder. It should be empty for "native" builders (old fashion or architectures not yet supported by XEN).';
+
+
+COMMENT ON COLUMN public.builder.active IS 'Whether to present or not the builder in the public list of builders avaialble. It is used to hide transient or defunct builders while they get fixed.';
+
+
+COMMENT ON COLUMN public.builder.failure_count IS 'The number of consecutive failures on this builder.  Is reset to zero after a sucessful dispatch.';
+
+
+COMMENT ON COLUMN public.builder.version IS 'The version of launchpad-buildd on the slave.';
+
+
+CREATE SEQUENCE public.builder_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE builder_id_seq OWNED BY builder.id;
-
-
-CREATE TABLE buildfarmjob (
+ALTER SEQUENCE public.builder_id_seq OWNED BY public.builder.id;
+
+
+CREATE TABLE public.builderprocessor (
+    builder integer NOT NULL,
+    processor integer NOT NULL
+);
+
+
+CREATE TABLE public.buildfarmjob (
     id integer NOT NULL,
-    processor integer,
-    virtualized boolean,
     date_created timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL,
-    date_started timestamp without time zone,
     date_finished timestamp without time zone,
-    date_first_dispatched timestamp without time zone,
     builder integer,
     status integer NOT NULL,
-    log integer,
     job_type integer NOT NULL,
-    failure_count integer DEFAULT 0 NOT NULL,
-    CONSTRAINT started_if_finished CHECK (((date_finished IS NULL) OR (date_started IS NOT NULL)))
-);
-
-
-COMMENT ON TABLE buildfarmjob IS 'BuildFarmJob: This table stores the information common to all jobs on the Launchpad build farm.';
-
-
-COMMENT ON COLUMN buildfarmjob.processor IS 'Points to the required processor target for this job, or null.';
-
-
-COMMENT ON COLUMN buildfarmjob.virtualized IS 'The virtualization setting required by this build farm job, or null.';
-
-
-COMMENT ON COLUMN buildfarmjob.date_created IS 'When the build farm job record was created.';
-
-
-COMMENT ON COLUMN buildfarmjob.date_started IS 'When the build farm job started being processed.';
-
-
-COMMENT ON COLUMN buildfarmjob.date_finished IS 'When the build farm job finished being processed.';
-
-
-COMMENT ON COLUMN buildfarmjob.date_first_dispatched IS 'The instant the build was dispatched the first time. This value will not get overridden if the build is retried.';
-
-
-COMMENT ON COLUMN buildfarmjob.builder IS 'Points to the builder which processed this build farm job.';
-
-
-COMMENT ON COLUMN buildfarmjob.status IS 'Stores the current build status.';
-
-
-COMMENT ON COLUMN buildfarmjob.log IS 'Points to the log for this build farm job file stored in librarian.';
-
-
-COMMENT ON COLUMN buildfarmjob.job_type IS 'The type of build farm job to which this record corresponds.';
-
-
-COMMENT ON COLUMN buildfarmjob.failure_count IS 'The number of consecutive failures on this job.  If excessive, the job may be terminated.';
-
-
-CREATE SEQUENCE buildfarmjob_id_seq
-    START WITH 1
-    INCREMENT BY 1
-    NO MAXVALUE
-    NO MINVALUE
-    CACHE 1;
-
-
-ALTER SEQUENCE buildfarmjob_id_seq OWNED BY buildfarmjob.id;
-
-
-CREATE TABLE buildpackagejob (
-    id integer NOT NULL,
-    job integer NOT NULL,
-    build integer NOT NULL
-);
-
-
-CREATE SEQUENCE buildpackagejob_id_seq
-    START WITH 1
-    INCREMENT BY 1
-    NO MAXVALUE
-    NO MINVALUE
-    CACHE 1;
-
-
-ALTER SEQUENCE buildpackagejob_id_seq OWNED BY buildpackagejob.id;
-
-
-CREATE TABLE buildqueue (
+    archive integer
+);
+
+
+COMMENT ON TABLE public.buildfarmjob IS 'BuildFarmJob: This table stores the information common to all jobs on the Launchpad build farm.';
+
+
+COMMENT ON COLUMN public.buildfarmjob.date_created IS 'When the build farm job record was created.';
+
+
+COMMENT ON COLUMN public.buildfarmjob.date_finished IS 'When the build farm job finished being processed.';
+
+
+COMMENT ON COLUMN public.buildfarmjob.builder IS 'Points to the builder which processed this build farm job.';
+
+
+COMMENT ON COLUMN public.buildfarmjob.status IS 'Stores the current build status.';
+
+
+COMMENT ON COLUMN public.buildfarmjob.job_type IS 'The type of build farm job to which this record corresponds.';
+
+
+CREATE SEQUENCE public.buildfarmjob_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER SEQUENCE public.buildfarmjob_id_seq OWNED BY public.buildfarmjob.id;
+
+
+CREATE TABLE public.buildqueue (
     id integer NOT NULL,
     builder integer,
     logtail text,
     lastscore integer,
     manual boolean DEFAULT false NOT NULL,
-    job integer NOT NULL,
-    job_type integer DEFAULT 1 NOT NULL,
     estimated_duration interval DEFAULT '00:00:00'::interval NOT NULL,
     processor integer,
-    virtualized boolean
+    virtualized boolean NOT NULL,
+    build_farm_job integer NOT NULL,
+    status integer NOT NULL,
+    date_started timestamp without time zone
 );
 
 
-COMMENT ON TABLE buildqueue IS 'BuildQueue: The queue of jobs in progress/scheduled to run on the Soyuz build farm.';
-
-
-COMMENT ON COLUMN buildqueue.builder IS 'The builder assigned to this build. Some builds will have a builder assigned to queue them up; some will be building on the specified builder already; others will not have a builder yet (NULL) and will be waiting to be assigned into a builder''s queue';
-
-
-COMMENT ON COLUMN buildqueue.logtail IS 'The tail end of the log of the current build. This is updated regularly as the buildd master polls the buildd slaves. Once the build is complete; the full log will be lodged with the librarian and linked into the build table.';
-
-
-COMMENT ON COLUMN buildqueue.lastscore IS 'The last score ascribed to this build record. This can be used in the UI among other places.';
-
-
-COMMENT ON COLUMN buildqueue.manual IS 'Indicates if the current record was or not rescored manually, if so it get skipped from the auto-score procedure.';
-
-
-COMMENT ON COLUMN buildqueue.job IS 'Foreign key to the `Job` table row with the generic job data.';
-
-
-COMMENT ON COLUMN buildqueue.job_type IS 'Type of job (enumeration value), enables us to find/query the correct table with the data specific to this type of job.';
-
-
-COMMENT ON COLUMN buildqueue.estimated_duration IS 'Estimated job duration, based on previous running times of comparable jobs.';
-
-
-COMMENT ON COLUMN buildqueue.processor IS 'The processor required by the associated build farm job.';
-
-
-COMMENT ON COLUMN buildqueue.virtualized IS 'The virtualization setting required by the associated build farm job.';
-
-
-CREATE SEQUENCE buildqueue_id_seq
+COMMENT ON TABLE public.buildqueue IS 'BuildQueue: The queue of jobs in progress/scheduled to run on the Soyuz build farm.';
+
+
+COMMENT ON COLUMN public.buildqueue.builder IS 'The builder assigned to this build. Some builds will have a builder assigned to queue them up; some will be building on the specified builder already; others will not have a builder yet (NULL) and will be waiting to be assigned into a builder''s queue';
+
+
+COMMENT ON COLUMN public.buildqueue.logtail IS 'The tail end of the log of the current build. This is updated regularly as the buildd master polls the buildd slaves. Once the build is complete; the full log will be lodged with the librarian and linked into the build table.';
+
+
+COMMENT ON COLUMN public.buildqueue.lastscore IS 'The last score ascribed to this build record. This can be used in the UI among other places.';
+
+
+COMMENT ON COLUMN public.buildqueue.manual IS 'Indicates if the current record was or not rescored manually, if so it get skipped from the auto-score procedure.';
+
+
+COMMENT ON COLUMN public.buildqueue.estimated_duration IS 'Estimated job duration, based on previous running times of comparable jobs.';
+
+
+COMMENT ON COLUMN public.buildqueue.processor IS 'The processor required by the associated build farm job.';
+
+
+COMMENT ON COLUMN public.buildqueue.virtualized IS 'The virtualization setting required by the associated build farm job.';
+
+
+CREATE SEQUENCE public.buildqueue_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE buildqueue_id_seq OWNED BY buildqueue.id;
-
-
-CREATE TABLE codeimport (
+ALTER SEQUENCE public.buildqueue_id_seq OWNED BY public.buildqueue.id;
+
+
+CREATE TABLE public.codeimport (
     id integer NOT NULL,
-    branch integer NOT NULL,
+    branch integer,
     date_created timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL,
     registrant integer NOT NULL,
     rcs_type integer NOT NULL,
@@ -7403,58 +6260,70 @@
     assignee integer,
     update_interval interval,
     url text,
-    CONSTRAINT valid_vcs_details CHECK (CASE WHEN (rcs_type = 1) THEN (((((cvs_root IS NOT NULL) AND (cvs_root <> ''::text)) AND (cvs_module IS NOT NULL)) AND (cvs_module <> ''::text)) AND (url IS NULL)) WHEN (rcs_type = ANY (ARRAY[2, 3])) THEN ((((cvs_root IS NULL) AND (cvs_module IS NULL)) AND (url IS NOT NULL)) AND valid_absolute_url(url)) WHEN (rcs_type = ANY (ARRAY[4, 5, 6])) THEN (((cvs_root IS NULL) AND (cvs_module IS NULL)) AND (url IS NOT NULL)) ELSE false END)
+    git_repository integer,
+    CONSTRAINT one_target_vcs CHECK (((branch IS NOT NULL) <> (git_repository IS NOT NULL))),
+    CONSTRAINT valid_source_target_vcs_pairing CHECK (((branch IS NOT NULL) OR (rcs_type = 4))),
+    CONSTRAINT valid_vcs_details CHECK (
+CASE
+    WHEN (rcs_type = 1) THEN (((((cvs_root IS NOT NULL) AND (cvs_root <> ''::text)) AND (cvs_module IS NOT NULL)) AND (cvs_module <> ''::text)) AND (url IS NULL))
+    WHEN (rcs_type = ANY (ARRAY[2, 3])) THEN ((((cvs_root IS NULL) AND (cvs_module IS NULL)) AND (url IS NOT NULL)) AND public.valid_absolute_url(url))
+    WHEN (rcs_type = ANY (ARRAY[4, 5, 6])) THEN (((cvs_root IS NULL) AND (cvs_module IS NULL)) AND (url IS NOT NULL))
+    ELSE false
+END)
 );
 
 
-COMMENT ON TABLE codeimport IS 'The persistent record of an import from a foreign version control system to Bazaar, from the initial request to the regularly updated import branch.';
-
-
-COMMENT ON COLUMN codeimport.branch IS 'The Bazaar branch produced by the import system.  Always non-NULL: a placeholder branch is created when the import is created.  The import is associated to a Product and Series though the branch.';
-
-
-COMMENT ON COLUMN codeimport.registrant IS 'The person who originally requested this import.';
-
-
-COMMENT ON COLUMN codeimport.rcs_type IS 'The revision control system used by the import source. The value is defined in dbschema.RevisionControlSystems.';
-
-
-COMMENT ON COLUMN codeimport.cvs_root IS 'The $CVSROOT details, probably of the form :pserver:user@host:/path.';
-
-
-COMMENT ON COLUMN codeimport.cvs_module IS 'The module in cvs_root to import, often the name of the project.';
-
-
-COMMENT ON COLUMN codeimport.review_status IS 'Whether this code import request has been reviewed, and whether it was accepted.';
-
-
-COMMENT ON COLUMN codeimport.date_last_successful IS 'When this code import last succeeded. NULL if this import has never succeeded.';
-
-
-COMMENT ON COLUMN codeimport.owner IS 'The person who is currently responsible for keeping the import details up to date, initially set to the registrant. This person can edit some of the details of the code import branch.';
-
-
-COMMENT ON COLUMN codeimport.assignee IS 'The person in charge of delivering this code import and interacting with the owner.';
-
-
-COMMENT ON COLUMN codeimport.update_interval IS 'How often should this import be updated. If NULL, defaults to a system-wide value set by the Launchpad administrators.';
-
-
-COMMENT ON COLUMN codeimport.url IS 'The URL of the foreign VCS branch for this import.';
-
-
-CREATE SEQUENCE codeimport_id_seq
+COMMENT ON TABLE public.codeimport IS 'The persistent record of an import from a foreign version control system to Bazaar, from the initial request to the regularly updated import branch.';
+
+
+COMMENT ON COLUMN public.codeimport.branch IS 'The Bazaar branch produced by the import system.  Always non-NULL: a placeholder branch is created when the import is created.  The import is associated to a Product and Series though the branch.';
+
+
+COMMENT ON COLUMN public.codeimport.registrant IS 'The person who originally requested this import.';
+
+
+COMMENT ON COLUMN public.codeimport.rcs_type IS 'The revision control system used by the import source. The value is defined in dbschema.RevisionControlSystems.';
+
+
+COMMENT ON COLUMN public.codeimport.cvs_root IS 'The $CVSROOT details, probably of the form :pserver:user@host:/path.';
+
+
+COMMENT ON COLUMN public.codeimport.cvs_module IS 'The module in cvs_root to import, often the name of the project.';
+
+
+COMMENT ON COLUMN public.codeimport.review_status IS 'Whether this code import request has been reviewed, and whether it was accepted.';
+
+
+COMMENT ON COLUMN public.codeimport.date_last_successful IS 'When this code import last succeeded. NULL if this import has never succeeded.';
+
+
+COMMENT ON COLUMN public.codeimport.owner IS 'The person who is currently responsible for keeping the import details up to date, initially set to the registrant. This person can edit some of the details of the code import branch.';
+
+
+COMMENT ON COLUMN public.codeimport.assignee IS 'The person in charge of delivering this code import and interacting with the owner.';
+
+
+COMMENT ON COLUMN public.codeimport.update_interval IS 'How often should this import be updated. If NULL, defaults to a system-wide value set by the Launchpad administrators.';
+
+
+COMMENT ON COLUMN public.codeimport.url IS 'The URL of the foreign VCS branch for this import.';
+
+
+COMMENT ON COLUMN public.codeimport.git_repository IS 'The Git repository produced by the import system, if applicable.  A placeholder repository is created when the import is created.  The import is associated with a target through the repository.';
+
+
+CREATE SEQUENCE public.codeimport_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE codeimport_id_seq OWNED BY codeimport.id;
-
-
-CREATE TABLE codeimportevent (
+ALTER SEQUENCE public.codeimport_id_seq OWNED BY public.codeimport.id;
+
+
+CREATE TABLE public.codeimportevent (
     id integer NOT NULL,
     date_created timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL,
     entry_type integer NOT NULL,
@@ -7464,33 +6333,33 @@
 );
 
 
-COMMENT ON TABLE codeimportevent IS 'A record of events in the code import system.  Rows in this table are created by triggers on other code import tables.';
-
-
-COMMENT ON COLUMN codeimportevent.entry_type IS 'The type of event that is recorded by this entry. Legal values are defined by the CodeImportEventType enumeration.';
-
-
-COMMENT ON COLUMN codeimportevent.code_import IS 'The code import that was associated to this event, if any and if it has not been deleted.';
-
-
-COMMENT ON COLUMN codeimportevent.person IS 'The user who caused the event, if the event is not automatically generated.';
-
-
-COMMENT ON COLUMN codeimportevent.machine IS 'The code import machine that was concerned by this event, if any.';
-
-
-CREATE SEQUENCE codeimportevent_id_seq
+COMMENT ON TABLE public.codeimportevent IS 'A record of events in the code import system.  Rows in this table are created by triggers on other code import tables.';
+
+
+COMMENT ON COLUMN public.codeimportevent.entry_type IS 'The type of event that is recorded by this entry. Legal values are defined by the CodeImportEventType enumeration.';
+
+
+COMMENT ON COLUMN public.codeimportevent.code_import IS 'The code import that was associated to this event, if any and if it has not been deleted.';
+
+
+COMMENT ON COLUMN public.codeimportevent.person IS 'The user who caused the event, if the event is not automatically generated.';
+
+
+COMMENT ON COLUMN public.codeimportevent.machine IS 'The code import machine that was concerned by this event, if any.';
+
+
+CREATE SEQUENCE public.codeimportevent_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE codeimportevent_id_seq OWNED BY codeimportevent.id;
-
-
-CREATE TABLE codeimporteventdata (
+ALTER SEQUENCE public.codeimportevent_id_seq OWNED BY public.codeimportevent.id;
+
+
+CREATE TABLE public.codeimporteventdata (
     id integer NOT NULL,
     event integer,
     data_type integer NOT NULL,
@@ -7498,30 +6367,30 @@
 );
 
 
-COMMENT ON TABLE codeimporteventdata IS 'Additional data associated to a particular code import event.';
-
-
-COMMENT ON COLUMN codeimporteventdata.event IS 'The event the data is associated to.';
-
-
-COMMENT ON COLUMN codeimporteventdata.data_type IS 'The type of additional data, from the CodeImportEventDataType enumeration.';
-
-
-COMMENT ON COLUMN codeimporteventdata.data_value IS 'The value of the additional data.  A string.';
-
-
-CREATE SEQUENCE codeimporteventdata_id_seq
+COMMENT ON TABLE public.codeimporteventdata IS 'Additional data associated to a particular code import event.';
+
+
+COMMENT ON COLUMN public.codeimporteventdata.event IS 'The event the data is associated to.';
+
+
+COMMENT ON COLUMN public.codeimporteventdata.data_type IS 'The type of additional data, from the CodeImportEventDataType enumeration.';
+
+
+COMMENT ON COLUMN public.codeimporteventdata.data_value IS 'The value of the additional data.  A string.';
+
+
+CREATE SEQUENCE public.codeimporteventdata_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE codeimporteventdata_id_seq OWNED BY codeimporteventdata.id;
-
-
-CREATE TABLE codeimportjob (
+ALTER SEQUENCE public.codeimporteventdata_id_seq OWNED BY public.codeimporteventdata.id;
+
+
+CREATE TABLE public.codeimportjob (
     id integer NOT NULL,
     date_created timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL,
     code_import integer NOT NULL,
@@ -7533,52 +6402,58 @@
     heartbeat timestamp without time zone,
     logtail text,
     date_started timestamp without time zone,
-    CONSTRAINT valid_state CHECK (CASE WHEN (state = 10) THEN (((((machine IS NULL) AND (ordering IS NULL)) AND (heartbeat IS NULL)) AND (date_started IS NULL)) AND (logtail IS NULL)) WHEN (state = 20) THEN (((((machine IS NOT NULL) AND (ordering IS NOT NULL)) AND (heartbeat IS NULL)) AND (date_started IS NULL)) AND (logtail IS NULL)) WHEN (state = 30) THEN (((((machine IS NOT NULL) AND (ordering IS NULL)) AND (heartbeat IS NOT NULL)) AND (date_started IS NOT NULL)) AND (logtail IS NOT NULL)) ELSE false END)
+    CONSTRAINT valid_state CHECK (
+CASE
+    WHEN (state = 10) THEN (((((machine IS NULL) AND (ordering IS NULL)) AND (heartbeat IS NULL)) AND (date_started IS NULL)) AND (logtail IS NULL))
+    WHEN (state = 20) THEN (((((machine IS NOT NULL) AND (ordering IS NOT NULL)) AND (heartbeat IS NULL)) AND (date_started IS NULL)) AND (logtail IS NULL))
+    WHEN (state = 30) THEN (((((machine IS NOT NULL) AND (ordering IS NULL)) AND (heartbeat IS NOT NULL)) AND (date_started IS NOT NULL)) AND (logtail IS NOT NULL))
+    ELSE false
+END)
 );
 
 
-COMMENT ON TABLE codeimportjob IS 'A pending or active code import job.  There is always such a row for any active import, but it will not run until date_due is in the past.';
-
-
-COMMENT ON COLUMN codeimportjob.code_import IS 'The code import that is being worked upon.';
-
-
-COMMENT ON COLUMN codeimportjob.machine IS 'The machine job is currently scheduled to run on, or where the job is currently running.';
-
-
-COMMENT ON COLUMN codeimportjob.date_due IS 'When the import should happen.';
-
-
-COMMENT ON COLUMN codeimportjob.state IS 'One of PENDING (waiting until its due or a machine is online), SCHEDULED (assigned to a machine, but not yet running) or RUNNING (actually in the process of being imported now).';
-
-
-COMMENT ON COLUMN codeimportjob.requesting_user IS 'The user who requested the import, if any. Set if and only if reason = REQUEST.';
-
-
-COMMENT ON COLUMN codeimportjob.ordering IS 'A measure of how urgent the job is -- queue entries with lower "ordering" should be processed first, or in other works "ORDER BY ordering" returns the most import jobs first.';
-
-
-COMMENT ON COLUMN codeimportjob.heartbeat IS 'While the job is running, this field should be updated frequently to indicate that the import job hasn''t crashed.';
-
-
-COMMENT ON COLUMN codeimportjob.logtail IS 'The last few lines of output produced by the running job. It should be updated at the same time as the heartbeat.';
-
-
-COMMENT ON COLUMN codeimportjob.date_started IS 'When the import began to be processed.';
-
-
-CREATE SEQUENCE codeimportjob_id_seq
+COMMENT ON TABLE public.codeimportjob IS 'A pending or active code import job.  There is always such a row for any active import, but it will not run until date_due is in the past.';
+
+
+COMMENT ON COLUMN public.codeimportjob.code_import IS 'The code import that is being worked upon.';
+
+
+COMMENT ON COLUMN public.codeimportjob.machine IS 'The machine job is currently scheduled to run on, or where the job is currently running.';
+
+
+COMMENT ON COLUMN public.codeimportjob.date_due IS 'When the import should happen.';
+
+
+COMMENT ON COLUMN public.codeimportjob.state IS 'One of PENDING (waiting until its due or a machine is online), SCHEDULED (assigned to a machine, but not yet running) or RUNNING (actually in the process of being imported now).';
+
+
+COMMENT ON COLUMN public.codeimportjob.requesting_user IS 'The user who requested the import, if any. Set if and only if reason = REQUEST.';
+
+
+COMMENT ON COLUMN public.codeimportjob.ordering IS 'A measure of how urgent the job is -- queue entries with lower "ordering" should be processed first, or in other works "ORDER BY ordering" returns the most import jobs first.';
+
+
+COMMENT ON COLUMN public.codeimportjob.heartbeat IS 'While the job is running, this field should be updated frequently to indicate that the import job hasn''t crashed.';
+
+
+COMMENT ON COLUMN public.codeimportjob.logtail IS 'The last few lines of output produced by the running job. It should be updated at the same time as the heartbeat.';
+
+
+COMMENT ON COLUMN public.codeimportjob.date_started IS 'When the import began to be processed.';
+
+
+CREATE SEQUENCE public.codeimportjob_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE codeimportjob_id_seq OWNED BY codeimportjob.id;
-
-
-CREATE TABLE codeimportmachine (
+ALTER SEQUENCE public.codeimportjob_id_seq OWNED BY public.codeimportjob.id;
+
+
+CREATE TABLE public.codeimportmachine (
     id integer NOT NULL,
     date_created timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL,
     hostname text NOT NULL,
@@ -7587,30 +6462,30 @@
 );
 
 
-COMMENT ON TABLE codeimportmachine IS 'The record of a machine capable of performing jobs for the code import system.';
-
-
-COMMENT ON COLUMN codeimportmachine.hostname IS 'The (unique) hostname of the machine.';
-
-
-COMMENT ON COLUMN codeimportmachine.state IS 'Whether the controller daemon on this machine is offline, online, or quiescing (running but not accepting new jobs).';
-
-
-COMMENT ON COLUMN codeimportmachine.heartbeat IS 'When the code-import-controller daemon was last known to be running on this machine. If it is not updated for a long time the machine state will change to offline.';
-
-
-CREATE SEQUENCE codeimportmachine_id_seq
+COMMENT ON TABLE public.codeimportmachine IS 'The record of a machine capable of performing jobs for the code import system.';
+
+
+COMMENT ON COLUMN public.codeimportmachine.hostname IS 'The (unique) hostname of the machine.';
+
+
+COMMENT ON COLUMN public.codeimportmachine.state IS 'Whether the controller daemon on this machine is offline, online, or quiescing (running but not accepting new jobs).';
+
+
+COMMENT ON COLUMN public.codeimportmachine.heartbeat IS 'When the code-import-controller daemon was last known to be running on this machine. If it is not updated for a long time the machine state will change to offline.';
+
+
+CREATE SEQUENCE public.codeimportmachine_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE codeimportmachine_id_seq OWNED BY codeimportmachine.id;
-
-
-CREATE TABLE codeimportresult (
+ALTER SEQUENCE public.codeimportmachine_id_seq OWNED BY public.codeimportmachine.id;
+
+
+CREATE TABLE public.codeimportresult (
     id integer NOT NULL,
     date_created timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL,
     code_import integer,
@@ -7623,39 +6498,54 @@
 );
 
 
-COMMENT ON TABLE codeimportresult IS 'A completed code import job.';
-
-
-COMMENT ON COLUMN codeimportresult.code_import IS 'The code import for which the job was run.';
-
-
-COMMENT ON COLUMN codeimportresult.machine IS 'The machine the job ran on.';
-
-
-COMMENT ON COLUMN codeimportresult.log_excerpt IS 'The last few lines of the partial log, in case it is set.';
-
-
-COMMENT ON COLUMN codeimportresult.log_file IS 'A partial log of the job for users to see. It is normally only recorded if the job failed in a step that interacts with the remote repository. If a job was successful, or failed in a houskeeping step, the log file would not contain information useful to the user.';
-
-
-COMMENT ON COLUMN codeimportresult.status IS 'How the job ended. Success, some kind of failure, or some kind of interruption before completion.';
-
-
-COMMENT ON COLUMN codeimportresult.date_job_started IS 'When the job started to run (date_created is when it finished).';
-
-
-CREATE SEQUENCE codeimportresult_id_seq
+COMMENT ON TABLE public.codeimportresult IS 'A completed code import job.';
+
+
+COMMENT ON COLUMN public.codeimportresult.code_import IS 'The code import for which the job was run.';
+
+
+COMMENT ON COLUMN public.codeimportresult.machine IS 'The machine the job ran on.';
+
+
+COMMENT ON COLUMN public.codeimportresult.log_excerpt IS 'The last few lines of the partial log, in case it is set.';
+
+
+COMMENT ON COLUMN public.codeimportresult.log_file IS 'A partial log of the job for users to see. It is normally only recorded if the job failed in a step that interacts with the remote repository. If a job was successful, or failed in a houskeeping step, the log file would not contain information useful to the user.';
+
+
+COMMENT ON COLUMN public.codeimportresult.status IS 'How the job ended. Success, some kind of failure, or some kind of interruption before completion.';
+
+
+COMMENT ON COLUMN public.codeimportresult.date_job_started IS 'When the job started to run (date_created is when it finished).';
+
+
+CREATE SEQUENCE public.codeimportresult_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE codeimportresult_id_seq OWNED BY codeimportresult.id;
-
-
-CREATE TABLE codereviewmessage (
+ALTER SEQUENCE public.codeimportresult_id_seq OWNED BY public.codeimportresult.id;
+
+
+CREATE TABLE public.codereviewinlinecomment (
+    previewdiff integer NOT NULL,
+    person integer NOT NULL,
+    comment integer NOT NULL,
+    comments text NOT NULL
+);
+
+
+CREATE TABLE public.codereviewinlinecommentdraft (
+    previewdiff integer NOT NULL,
+    person integer NOT NULL,
+    comments text NOT NULL
+);
+
+
+CREATE TABLE public.codereviewmessage (
     id integer NOT NULL,
     branch_merge_proposal integer NOT NULL,
     message integer NOT NULL,
@@ -7664,33 +6554,33 @@
 );
 
 
-COMMENT ON TABLE codereviewmessage IS 'A message that is part of a code review discussion.';
-
-
-COMMENT ON COLUMN codereviewmessage.branch_merge_proposal IS 'The merge proposal that is being discussed.';
-
-
-COMMENT ON COLUMN codereviewmessage.message IS 'The actual message.';
-
-
-COMMENT ON COLUMN codereviewmessage.vote IS 'The reviewer''s vote for this message.';
-
-
-COMMENT ON COLUMN codereviewmessage.vote_tag IS 'A short description of the vote';
-
-
-CREATE SEQUENCE codereviewmessage_id_seq
+COMMENT ON TABLE public.codereviewmessage IS 'A message that is part of a code review discussion.';
+
+
+COMMENT ON COLUMN public.codereviewmessage.branch_merge_proposal IS 'The merge proposal that is being discussed.';
+
+
+COMMENT ON COLUMN public.codereviewmessage.message IS 'The actual message.';
+
+
+COMMENT ON COLUMN public.codereviewmessage.vote IS 'The reviewer''s vote for this message.';
+
+
+COMMENT ON COLUMN public.codereviewmessage.vote_tag IS 'A short description of the vote';
+
+
+CREATE SEQUENCE public.codereviewmessage_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE codereviewmessage_id_seq OWNED BY codereviewmessage.id;
-
-
-CREATE TABLE codereviewvote (
+ALTER SEQUENCE public.codereviewmessage_id_seq OWNED BY public.codereviewmessage.id;
+
+
+CREATE TABLE public.codereviewvote (
     id integer NOT NULL,
     branch_merge_proposal integer NOT NULL,
     reviewer integer NOT NULL,
@@ -7701,43 +6591,73 @@
 );
 
 
-COMMENT ON TABLE codereviewvote IS 'Reference to a person''s last vote in a code review discussion.';
-
-
-COMMENT ON COLUMN codereviewvote.branch_merge_proposal IS 'The BranchMergeProposal for the code review.';
-
-
-COMMENT ON COLUMN codereviewvote.reviewer IS 'The person performing the review.';
-
-
-COMMENT ON COLUMN codereviewvote.review_type IS 'The aspect of the code being reviewed.';
-
-
-COMMENT ON COLUMN codereviewvote.registrant IS 'The person who registered this vote';
-
-
-COMMENT ON COLUMN codereviewvote.vote_message IS 'The message associated with the vote';
-
-
-COMMENT ON COLUMN codereviewvote.date_created IS 'The date this vote reference was created';
-
-
-CREATE SEQUENCE codereviewvote_id_seq
+COMMENT ON TABLE public.codereviewvote IS 'Reference to a person''s last vote in a code review discussion.';
+
+
+COMMENT ON COLUMN public.codereviewvote.branch_merge_proposal IS 'The BranchMergeProposal for the code review.';
+
+
+COMMENT ON COLUMN public.codereviewvote.reviewer IS 'The person performing the review.';
+
+
+COMMENT ON COLUMN public.codereviewvote.review_type IS 'The aspect of the code being reviewed.';
+
+
+COMMENT ON COLUMN public.codereviewvote.registrant IS 'The person who registered this vote';
+
+
+COMMENT ON COLUMN public.codereviewvote.vote_message IS 'The message associated with the vote';
+
+
+COMMENT ON COLUMN public.codereviewvote.date_created IS 'The date this vote reference was created';
+
+
+CREATE SEQUENCE public.codereviewvote_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE codereviewvote_id_seq OWNED BY codereviewvote.id;
-
-
-CREATE VIEW combinedbugsummary AS
-    SELECT bugsummary.id, bugsummary.count, bugsummary.product, bugsummary.productseries, bugsummary.distribution, bugsummary.distroseries, bugsummary.sourcepackagename, bugsummary.viewed_by, bugsummary.tag, bugsummary.status, bugsummary.milestone, bugsummary.importance, bugsummary.has_patch, bugsummary.fixed_upstream FROM bugsummary UNION ALL SELECT (- bugsummaryjournal.id) AS id, bugsummaryjournal.count, bugsummaryjournal.product, bugsummaryjournal.productseries, bugsummaryjournal.distribution, bugsummaryjournal.distroseries, bugsummaryjournal.sourcepackagename, bugsummaryjournal.viewed_by, bugsummaryjournal.tag, bugsummaryjournal.status, bugsummaryjournal.milestone, bugsummaryjournal.importance, bugsummaryjournal.has_patch, bugsummaryjournal.fixed_upstream FROM bugsummaryjournal;
-
-
-CREATE TABLE commercialsubscription (
+ALTER SEQUENCE public.codereviewvote_id_seq OWNED BY public.codereviewvote.id;
+
+
+CREATE VIEW public.combinedbugsummary AS
+ SELECT bugsummary.id,
+    bugsummary.count,
+    bugsummary.product,
+    bugsummary.productseries,
+    bugsummary.distribution,
+    bugsummary.distroseries,
+    bugsummary.sourcepackagename,
+    bugsummary.viewed_by,
+    bugsummary.tag,
+    bugsummary.status,
+    bugsummary.milestone,
+    bugsummary.importance,
+    bugsummary.has_patch,
+    bugsummary.access_policy
+   FROM public.bugsummary
+UNION ALL
+ SELECT (- bugsummaryjournal.id) AS id,
+    bugsummaryjournal.count,
+    bugsummaryjournal.product,
+    bugsummaryjournal.productseries,
+    bugsummaryjournal.distribution,
+    bugsummaryjournal.distroseries,
+    bugsummaryjournal.sourcepackagename,
+    bugsummaryjournal.viewed_by,
+    bugsummaryjournal.tag,
+    bugsummaryjournal.status,
+    bugsummaryjournal.milestone,
+    bugsummaryjournal.importance,
+    bugsummaryjournal.has_patch,
+    bugsummaryjournal.access_policy
+   FROM public.bugsummaryjournal;
+
+
+CREATE TABLE public.commercialsubscription (
     id integer NOT NULL,
     date_created timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL,
     date_last_modified timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL,
@@ -7752,62 +6672,79 @@
 );
 
 
-COMMENT ON TABLE commercialsubscription IS 'A Commercial Subscription entry for a project.  Projects with licenses of Other/Proprietary must purchase a subscription in order to use Launchpad.';
-
-
-COMMENT ON COLUMN commercialsubscription.date_created IS 'The date this subscription was created in Launchpad.';
-
-
-COMMENT ON COLUMN commercialsubscription.date_last_modified IS 'The date this subscription was last modified.';
-
-
-COMMENT ON COLUMN commercialsubscription.date_starts IS 'The beginning date for this subscription.  It is invalid until that date.';
-
-
-COMMENT ON COLUMN commercialsubscription.date_expires IS 'The expiration date for this subscription.  It is invalid after that date.';
-
-
-COMMENT ON COLUMN commercialsubscription.status IS 'The current status.  One of: SUBSCRIBED, LAPSED, SUSPENDED.';
-
-
-COMMENT ON COLUMN commercialsubscription.product IS 'The product this subscription enables.';
-
-
-COMMENT ON COLUMN commercialsubscription.registrant IS 'The person who created this subscription.';
-
-
-COMMENT ON COLUMN commercialsubscription.purchaser IS 'The person who purchased this subscription.';
-
-
-COMMENT ON COLUMN commercialsubscription.whiteboard IS 'A place for administrators to store comments related to this subscription.';
-
-
-COMMENT ON COLUMN commercialsubscription.sales_system_id IS 'A reference in the external sales system (e.g. Salesforce) that can be used to identify this subscription.';
-
-
-CREATE SEQUENCE commercialsubscription_id_seq
-    START WITH 1
-    INCREMENT BY 1
-    NO MAXVALUE
-    NO MINVALUE
-    CACHE 1;
-
-
-ALTER SEQUENCE commercialsubscription_id_seq OWNED BY commercialsubscription.id;
-
-
-CREATE SEQUENCE component_id_seq
-    START WITH 1
-    INCREMENT BY 1
-    NO MAXVALUE
-    NO MINVALUE
-    CACHE 1;
-
-
-ALTER SEQUENCE component_id_seq OWNED BY component.id;
-
-
-CREATE TABLE componentselection (
+COMMENT ON TABLE public.commercialsubscription IS 'A Commercial Subscription entry for a project.  Projects with licenses of Other/Proprietary must purchase a subscription in order to use Launchpad.';
+
+
+COMMENT ON COLUMN public.commercialsubscription.date_created IS 'The date this subscription was created in Launchpad.';
+
+
+COMMENT ON COLUMN public.commercialsubscription.date_last_modified IS 'The date this subscription was last modified.';
+
+
+COMMENT ON COLUMN public.commercialsubscription.date_starts IS 'The beginning date for this subscription.  It is invalid until that date.';
+
+
+COMMENT ON COLUMN public.commercialsubscription.date_expires IS 'The expiration date for this subscription.  It is invalid after that date.';
+
+
+COMMENT ON COLUMN public.commercialsubscription.status IS 'The current status.  One of: SUBSCRIBED, LAPSED, SUSPENDED.';
+
+
+COMMENT ON COLUMN public.commercialsubscription.product IS 'The product this subscription enables.';
+
+
+COMMENT ON COLUMN public.commercialsubscription.registrant IS 'The person who created this subscription.';
+
+
+COMMENT ON COLUMN public.commercialsubscription.purchaser IS 'The person who purchased this subscription.';
+
+
+COMMENT ON COLUMN public.commercialsubscription.whiteboard IS 'A place for administrators to store comments related to this subscription.';
+
+
+COMMENT ON COLUMN public.commercialsubscription.sales_system_id IS 'A reference in the external sales system (e.g. Salesforce) that can be used to identify this subscription.';
+
+
+CREATE SEQUENCE public.commercialsubscription_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER SEQUENCE public.commercialsubscription_id_seq OWNED BY public.commercialsubscription.id;
+
+
+CREATE TABLE public.component (
+    id integer NOT NULL,
+    name text NOT NULL,
+    description text,
+    CONSTRAINT valid_name CHECK (public.valid_name(name))
+);
+
+
+COMMENT ON TABLE public.component IS 'Known components in Launchpad';
+
+
+COMMENT ON COLUMN public.component.name IS 'Component name text';
+
+
+COMMENT ON COLUMN public.component.description IS 'Description of this component.';
+
+
+CREATE SEQUENCE public.component_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER SEQUENCE public.component_id_seq OWNED BY public.component.id;
+
+
+CREATE TABLE public.componentselection (
     id integer NOT NULL,
     distroseries integer NOT NULL,
     component integer NOT NULL,
@@ -7815,55 +6752,55 @@
 );
 
 
-COMMENT ON TABLE componentselection IS 'Allowed components in a given distroseries.';
-
-
-COMMENT ON COLUMN componentselection.distroseries IS 'Refers to the distroseries in question.';
-
-
-COMMENT ON COLUMN componentselection.component IS 'Refers to the component in qestion.';
-
-
-CREATE SEQUENCE componentselection_id_seq
+COMMENT ON TABLE public.componentselection IS 'Allowed components in a given distroseries.';
+
+
+COMMENT ON COLUMN public.componentselection.distroseries IS 'Refers to the distroseries in question.';
+
+
+COMMENT ON COLUMN public.componentselection.component IS 'Refers to the component in qestion.';
+
+
+CREATE SEQUENCE public.componentselection_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE componentselection_id_seq OWNED BY componentselection.id;
-
-
-CREATE TABLE continent (
+ALTER SEQUENCE public.componentselection_id_seq OWNED BY public.componentselection.id;
+
+
+CREATE TABLE public.continent (
     id integer NOT NULL,
     code text NOT NULL,
     name text NOT NULL
 )
-WITH (fillfactor=100);
-
-
-COMMENT ON TABLE continent IS 'A continent in this huge world.';
-
-
-COMMENT ON COLUMN continent.code IS 'A two-letter code for a continent.';
-
-
-COMMENT ON COLUMN continent.name IS 'The name of the continent.';
-
-
-CREATE SEQUENCE continent_id_seq
+WITH (fillfactor='100');
+
+
+COMMENT ON TABLE public.continent IS 'A continent in this huge world.';
+
+
+COMMENT ON COLUMN public.continent.code IS 'A two-letter code for a continent.';
+
+
+COMMENT ON COLUMN public.continent.name IS 'The name of the continent.';
+
+
+CREATE SEQUENCE public.continent_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE continent_id_seq OWNED BY continent.id;
-
-
-CREATE TABLE country (
+ALTER SEQUENCE public.continent_id_seq OWNED BY public.continent.id;
+
+
+CREATE TABLE public.country (
     id integer NOT NULL,
     iso3166code2 character(2) NOT NULL,
     iso3166code3 character(3) NOT NULL,
@@ -7872,21 +6809,21 @@
     description text,
     continent integer NOT NULL
 )
-WITH (fillfactor=100);
-
-
-CREATE SEQUENCE country_id_seq
+WITH (fillfactor='100');
+
+
+CREATE SEQUENCE public.country_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE country_id_seq OWNED BY country.id;
-
-
-CREATE TABLE customlanguagecode (
+ALTER SEQUENCE public.country_id_seq OWNED BY public.country.id;
+
+
+CREATE TABLE public.customlanguagecode (
     id integer NOT NULL,
     product integer,
     distribution integer,
@@ -7898,71 +6835,71 @@
 );
 
 
-COMMENT ON TABLE customlanguagecode IS 'Overrides translation importer''s interpretation of language codes where needed.';
-
-
-COMMENT ON COLUMN customlanguagecode.product IS 'Product for which this custom language code applies (alternative to distribution + source package name).';
-
-
-COMMENT ON COLUMN customlanguagecode.distribution IS 'Distribution in which this custom language code applies (if not a product).';
-
-
-COMMENT ON COLUMN customlanguagecode.sourcepackagename IS 'Source package name to which this custom language code applies; goes with distribution.';
-
-
-COMMENT ON COLUMN customlanguagecode.language_code IS 'Custom language code; need not be for a real language, and typically not for a "useful" language.';
-
-
-COMMENT ON COLUMN customlanguagecode.language IS 'Language to which code really refers in this context, or NULL if files with this code are to be rejected.';
-
-
-CREATE SEQUENCE customlanguagecode_id_seq
+COMMENT ON TABLE public.customlanguagecode IS 'Overrides translation importer''s interpretation of language codes where needed.';
+
+
+COMMENT ON COLUMN public.customlanguagecode.product IS 'Product for which this custom language code applies (alternative to distribution + source package name).';
+
+
+COMMENT ON COLUMN public.customlanguagecode.distribution IS 'Distribution in which this custom language code applies (if not a product).';
+
+
+COMMENT ON COLUMN public.customlanguagecode.sourcepackagename IS 'Source package name to which this custom language code applies; goes with distribution.';
+
+
+COMMENT ON COLUMN public.customlanguagecode.language_code IS 'Custom language code; need not be for a real language, and typically not for a "useful" language.';
+
+
+COMMENT ON COLUMN public.customlanguagecode.language IS 'Language to which code really refers in this context, or NULL if files with this code are to be rejected.';
+
+
+CREATE SEQUENCE public.customlanguagecode_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE customlanguagecode_id_seq OWNED BY customlanguagecode.id;
-
-
-CREATE TABLE cve (
+ALTER SEQUENCE public.customlanguagecode_id_seq OWNED BY public.customlanguagecode.id;
+
+
+CREATE TABLE public.cve (
     id integer NOT NULL,
     sequence text NOT NULL,
     status integer NOT NULL,
     description text NOT NULL,
     datecreated timestamp without time zone DEFAULT timezone('UTC'::text, ('now'::text)::timestamp(6) with time zone) NOT NULL,
     datemodified timestamp without time zone DEFAULT timezone('UTC'::text, ('now'::text)::timestamp(6) with time zone) NOT NULL,
-    fti ts2.tsvector,
-    CONSTRAINT valid_cve_ref CHECK (valid_cve(sequence))
+    fti public.ts2_tsvector,
+    CONSTRAINT valid_cve_ref CHECK (public.valid_cve(sequence))
 );
 
 
-COMMENT ON TABLE cve IS 'A CVE Entry. The formal database of CVE entries is available at http://cve.mitre.org/ and we sync that database into Launchpad on a regular basis.';
-
-
-COMMENT ON COLUMN cve.sequence IS 'The official CVE entry number. It takes the form XXXX-XXXX where the first four digits are a year indicator, like 2004, and the latter four are the sequence number of the vulnerability in that year.';
-
-
-COMMENT ON COLUMN cve.status IS 'The current status of the CVE. The values are documented in dbschema.CVEState, and are Entry, Candidate, and Deprecated.';
-
-
-COMMENT ON COLUMN cve.datemodified IS 'The last time this CVE entry changed in some way - including addition or modification of references.';
-
-
-CREATE SEQUENCE cve_id_seq
+COMMENT ON TABLE public.cve IS 'A CVE Entry. The formal database of CVE entries is available at http://cve.mitre.org/ and we sync that database into Launchpad on a regular basis.';
+
+
+COMMENT ON COLUMN public.cve.sequence IS 'The official CVE entry number. It takes the form XXXX-XXXX where the first four digits are a year indicator, like 2004, and the latter four are the sequence number of the vulnerability in that year.';
+
+
+COMMENT ON COLUMN public.cve.status IS 'The current status of the CVE. The values are documented in dbschema.CVEState, and are Entry, Candidate, and Deprecated.';
+
+
+COMMENT ON COLUMN public.cve.datemodified IS 'The last time this CVE entry changed in some way - including addition or modification of references.';
+
+
+CREATE SEQUENCE public.cve_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE cve_id_seq OWNED BY cve.id;
-
-
-CREATE TABLE cvereference (
+ALTER SEQUENCE public.cve_id_seq OWNED BY public.cve.id;
+
+
+CREATE TABLE public.cvereference (
     id integer NOT NULL,
     cve integer NOT NULL,
     source text NOT NULL,
@@ -7972,44 +6909,44 @@
 );
 
 
-COMMENT ON TABLE cvereference IS 'A reference in the CVE system that shows what outside tracking numbers are associated with the CVE. These are tracked in the CVE database and extracted from the daily XML dump that we fetch.';
-
-
-COMMENT ON COLUMN cvereference.source IS 'The SOURCE of the CVE reference. This is a text string, like XF or BUGTRAQ or MSKB. Each string indicates a different kind of reference. The list of known types is documented on the CVE web site. At some future date we might turn this into an enum rather than a text, but for the moment we prefer to keep it fluid and just suck in what CVE gives us. This means that CVE can add new source types without us having to update our code.';
-
-
-COMMENT ON COLUMN cvereference.content IS 'The content of the ref in the CVE database. This is sometimes a comment, sometimes a description, sometimes a bug number... it is not predictable.';
-
-
-COMMENT ON COLUMN cvereference.url IS 'The URL to this reference out there on the web, if it was present in the CVE database.';
-
-
-CREATE SEQUENCE cvereference_id_seq
+COMMENT ON TABLE public.cvereference IS 'A reference in the CVE system that shows what outside tracking numbers are associated with the CVE. These are tracked in the CVE database and extracted from the daily XML dump that we fetch.';
+
+
+COMMENT ON COLUMN public.cvereference.source IS 'The SOURCE of the CVE reference. This is a text string, like XF or BUGTRAQ or MSKB. Each string indicates a different kind of reference. The list of known types is documented on the CVE web site. At some future date we might turn this into an enum rather than a text, but for the moment we prefer to keep it fluid and just suck in what CVE gives us. This means that CVE can add new source types without us having to update our code.';
+
+
+COMMENT ON COLUMN public.cvereference.content IS 'The content of the ref in the CVE database. This is sometimes a comment, sometimes a description, sometimes a bug number... it is not predictable.';
+
+
+COMMENT ON COLUMN public.cvereference.url IS 'The URL to this reference out there on the web, if it was present in the CVE database.';
+
+
+CREATE SEQUENCE public.cvereference_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE cvereference_id_seq OWNED BY cvereference.id;
-
-
-CREATE TABLE databasecpustats (
+ALTER SEQUENCE public.cvereference_id_seq OWNED BY public.cvereference.id;
+
+
+CREATE TABLE public.databasecpustats (
     date_created timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL,
     username text NOT NULL,
     cpu integer NOT NULL
 )
-WITH (fillfactor=100);
-
-
-COMMENT ON TABLE databasecpustats IS 'Snapshots of CPU utilization per database username.';
-
-
-COMMENT ON COLUMN databasecpustats.cpu IS '% CPU utilization * 100, as reported by ps -o cp';
-
-
-CREATE TABLE databasediskutilization (
+WITH (fillfactor='100');
+
+
+COMMENT ON TABLE public.databasecpustats IS 'Snapshots of CPU utilization per database username.';
+
+
+COMMENT ON COLUMN public.databasecpustats.cpu IS '% CPU utilization * 100, as reported by ps -o cp';
+
+
+CREATE TABLE public.databasediskutilization (
     date_created timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL,
     namespace text NOT NULL,
     name text NOT NULL,
@@ -8027,29 +6964,29 @@
     free_space bigint NOT NULL,
     free_percent double precision NOT NULL
 )
-WITH (fillfactor=100);
-
-
-CREATE TABLE databasereplicationlag (
+WITH (fillfactor='100');
+
+
+CREATE TABLE public.databasereplicationlag (
     node integer NOT NULL,
     lag interval NOT NULL,
     updated timestamp without time zone DEFAULT timezone('UTC'::text, now())
 );
 
 
-COMMENT ON TABLE databasereplicationlag IS 'A cached snapshot of database replication lag between our master Slony node and its slaves.';
-
-
-COMMENT ON COLUMN databasereplicationlag.node IS 'The Slony node number identifying the slave database.';
-
-
-COMMENT ON COLUMN databasereplicationlag.lag IS 'lag time.';
-
-
-COMMENT ON COLUMN databasereplicationlag.updated IS 'When this value was updated.';
-
-
-CREATE TABLE databasetablestats (
+COMMENT ON TABLE public.databasereplicationlag IS 'A cached snapshot of database replication lag between our master Slony node and its slaves.';
+
+
+COMMENT ON COLUMN public.databasereplicationlag.node IS 'The Slony node number identifying the slave database.';
+
+
+COMMENT ON COLUMN public.databasereplicationlag.lag IS 'lag time.';
+
+
+COMMENT ON COLUMN public.databasereplicationlag.updated IS 'When this value was updated.';
+
+
+CREATE TABLE public.databasetablestats (
     date_created timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL,
     schemaname name NOT NULL,
     relname name NOT NULL,
@@ -8068,13 +7005,13 @@
     last_analyze timestamp with time zone,
     last_autoanalyze timestamp with time zone
 )
-WITH (fillfactor=100);
-
-
-COMMENT ON TABLE databasetablestats IS 'Snapshots of pg_stat_user_tables to let us calculate arbitrary deltas';
-
-
-CREATE TABLE diff (
+WITH (fillfactor='100');
+
+
+COMMENT ON TABLE public.databasetablestats IS 'Snapshots of pg_stat_user_tables to let us calculate arbitrary deltas';
+
+
+CREATE TABLE public.diff (
     id integer NOT NULL,
     diff_text integer,
     diff_lines_count integer,
@@ -8084,36 +7021,36 @@
 );
 
 
-COMMENT ON TABLE diff IS 'Information common to static or preview diffs';
-
-
-COMMENT ON COLUMN diff.diff_text IS 'The library copy of the fulltext of the diff';
-
-
-COMMENT ON COLUMN diff.diff_lines_count IS 'The number of lines in the diff';
-
-
-COMMENT ON COLUMN diff.diffstat IS 'Statistics about the diff';
-
-
-COMMENT ON COLUMN diff.added_lines_count IS 'The number of lines added in the diff.';
-
-
-COMMENT ON COLUMN diff.removed_lines_count IS 'The number of lines removed in the diff';
-
-
-CREATE SEQUENCE diff_id_seq
+COMMENT ON TABLE public.diff IS 'Information common to static or preview diffs';
+
+
+COMMENT ON COLUMN public.diff.diff_text IS 'The library copy of the fulltext of the diff';
+
+
+COMMENT ON COLUMN public.diff.diff_lines_count IS 'The number of lines in the diff';
+
+
+COMMENT ON COLUMN public.diff.diffstat IS 'Statistics about the diff';
+
+
+COMMENT ON COLUMN public.diff.added_lines_count IS 'The number of lines added in the diff.';
+
+
+COMMENT ON COLUMN public.diff.removed_lines_count IS 'The number of lines removed in the diff';
+
+
+CREATE SEQUENCE public.diff_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE diff_id_seq OWNED BY diff.id;
-
-
-CREATE TABLE distribution (
+ALTER SEQUENCE public.diff_id_seq OWNED BY public.diff.id;
+
+
+CREATE TABLE public.distribution (
     id integer NOT NULL,
     name text NOT NULL,
     title text NOT NULL,
@@ -8128,18 +7065,16 @@
     bug_supervisor integer,
     official_malone boolean DEFAULT false NOT NULL,
     official_rosetta boolean DEFAULT false NOT NULL,
-    security_contact integer,
     driver integer,
     translation_focus integer,
     mirror_admin integer NOT NULL,
-    upload_admin integer,
     upload_sender text,
     date_created timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL,
     homepage_content text,
     icon integer,
     mugshot integer,
     logo integer,
-    fti ts2.tsvector,
+    fti public.ts2_tsvector,
     official_answers boolean DEFAULT false NOT NULL,
     language_pack_admin integer,
     official_blueprints boolean DEFAULT false NOT NULL,
@@ -8153,120 +7088,135 @@
     translations_usage integer DEFAULT 10 NOT NULL,
     registrant integer NOT NULL,
     package_derivatives_email text,
+    redirect_release_uploads boolean DEFAULT false NOT NULL,
+    development_series_alias text,
+    official_packages boolean DEFAULT false NOT NULL,
+    supports_ppas boolean DEFAULT false NOT NULL,
+    supports_mirrors boolean DEFAULT false NOT NULL,
+    vcs integer,
     CONSTRAINT only_launchpad_has_expiration CHECK (((enable_bug_expiration IS FALSE) OR (official_malone IS TRUE))),
-    CONSTRAINT valid_name CHECK (valid_name(name))
+    CONSTRAINT valid_name CHECK (public.valid_name(name))
 );
 
 
-COMMENT ON TABLE distribution IS 'Distribution: A soyuz distribution. A distribution is a collection of DistroSeries. Distributions often group together policy and may be referred to by a name such as "Ubuntu" or "Debian"';
-
-
-COMMENT ON COLUMN distribution.name IS 'The unique name of the distribution as a short lowercase name suitable for use in a URL.';
-
-
-COMMENT ON COLUMN distribution.title IS 'The title of the distribution. More a "display name" as it were. E.g. "Ubuntu" or "Debian GNU/Linux"';
-
-
-COMMENT ON COLUMN distribution.description IS 'A description of the distribution. More detailed than the title, this column may also contain information about the project this distribution is run by.';
-
-
-COMMENT ON COLUMN distribution.domainname IS 'The domain name of the distribution. This may be used both for linking to the distribution and for context-related stuff.';
-
-
-COMMENT ON COLUMN distribution.owner IS 'The person in launchpad who is in ultimate-charge of this distribution within launchpad.';
-
-
-COMMENT ON COLUMN distribution.displayname IS 'A short, well-capitalised
+COMMENT ON TABLE public.distribution IS 'Distribution: A soyuz distribution. A distribution is a collection of DistroSeries. Distributions often group together policy and may be referred to by a name such as "Ubuntu" or "Debian"';
+
+
+COMMENT ON COLUMN public.distribution.name IS 'The unique name of the distribution as a short lowercase name suitable for use in a URL.';
+
+
+COMMENT ON COLUMN public.distribution.title IS 'The title of the distribution. More a "display name" as it were. E.g. "Ubuntu" or "Debian GNU/Linux"';
+
+
+COMMENT ON COLUMN public.distribution.description IS 'A description of the distribution. More detailed than the title, this column may also contain information about the project this distribution is run by.';
+
+
+COMMENT ON COLUMN public.distribution.domainname IS 'The domain name of the distribution. This may be used both for linking to the distribution and for context-related stuff.';
+
+
+COMMENT ON COLUMN public.distribution.owner IS 'The person in launchpad who is in ultimate-charge of this distribution within launchpad.';
+
+
+COMMENT ON COLUMN public.distribution.displayname IS 'A short, well-capitalised
 name for this distribution that is not required to be unique but in almost
 all cases would be so.';
 
 
-COMMENT ON COLUMN distribution.summary IS 'A single paragraph that
+COMMENT ON COLUMN public.distribution.summary IS 'A single paragraph that
 summarises the highlights of this distribution. It should be no longer than
 240 characters, although this is not enforced in the database.';
 
 
-COMMENT ON COLUMN distribution.members IS 'Person or team with upload and commit priviledges relating to this distribution. Other rights may be assigned to this role in the future.';
-
-
-COMMENT ON COLUMN distribution.translationgroup IS 'The translation group that is responsible for all translation work in this distribution.';
-
-
-COMMENT ON COLUMN distribution.translationpermission IS 'The level of openness of this distribution''s translation process. The enum lists different approaches to translation, from the very open (anybody can edit any translation in any language) to the completely closed (only designated translators can make any changes at all).';
-
-
-COMMENT ON COLUMN distribution.bug_supervisor IS 'Person who is responsible for managing bugs on this distribution.';
-
-
-COMMENT ON COLUMN distribution.official_malone IS 'Whether or not this distribution uses Malone for an official bug tracker.';
-
-
-COMMENT ON COLUMN distribution.official_rosetta IS 'Whether or not this distribution uses Rosetta for its official translation team and coordination.';
-
-
-COMMENT ON COLUMN distribution.security_contact IS 'The person or team who handles security-related issues in the distribution.';
-
-
-COMMENT ON COLUMN distribution.driver IS 'The team or person responsible for approving goals for each release in the distribution. This should usually be a very small team because the Distribution driver can approve items for backporting to past releases as well as the current release under development. Each distroseries has its own driver too, so you can have the small superset in the Distribution driver, and then specific teams per distroseries for backporting, for example, or for the current release management team on the current development focus release.';
-
-
-COMMENT ON COLUMN distribution.translation_focus IS 'The DistroSeries that should get the translation effort focus.';
-
-
-COMMENT ON COLUMN distribution.mirror_admin IS 'Person or team with privileges to mark a mirror as official.';
-
-
-COMMENT ON COLUMN distribution.upload_admin IS 'Person foreign key which have access to modify the queue ui. If NULL, we fall back to launchpad admin members';
-
-
-COMMENT ON COLUMN distribution.upload_sender IS 'The email address (and name) of the default sender used by the upload processor. If NULL, we fall back to the default sender in the launchpad config.';
-
-
-COMMENT ON COLUMN distribution.homepage_content IS 'A home page for this distribution in the Launchpad.';
-
-
-COMMENT ON COLUMN distribution.icon IS 'The library file alias to a small image to be used as an icon whenever we are referring to a distribution.';
-
-
-COMMENT ON COLUMN distribution.mugshot IS 'The library file alias of a mugshot image to display as the branding of a distribution, on its home page.';
-
-
-COMMENT ON COLUMN distribution.logo IS 'The library file alias of a smaller version of this distributions''s mugshot.';
-
-
-COMMENT ON COLUMN distribution.official_answers IS 'Whether or not this product upstream uses Answers officialy.';
-
-
-COMMENT ON COLUMN distribution.language_pack_admin IS 'The Person or Team that handle language packs for the distro release.';
-
-
-COMMENT ON COLUMN distribution.enable_bug_expiration IS 'Indicates whether automatic bug expiration is enabled.';
-
-
-COMMENT ON COLUMN distribution.bug_reporting_guidelines IS 'Guidelines to the end user for reporting bugs on this distribution.';
-
-
-COMMENT ON COLUMN distribution.reviewer_whiteboard IS 'A whiteboard for Launchpad admins, registry experts and the project owners to capture the state of current issues with the project.';
-
-
-COMMENT ON COLUMN distribution.max_bug_heat IS 'The highest heat value across bugs for this distribution.';
-
-
-COMMENT ON COLUMN distribution.bug_reported_acknowledgement IS 'A message of acknowledgement to display to a bug reporter after they''ve reported a new bug.';
-
-
-CREATE SEQUENCE distribution_id_seq
+COMMENT ON COLUMN public.distribution.members IS 'Person or team with upload and commit priviledges relating to this distribution. Other rights may be assigned to this role in the future.';
+
+
+COMMENT ON COLUMN public.distribution.translationgroup IS 'The translation group that is responsible for all translation work in this distribution.';
+
+
+COMMENT ON COLUMN public.distribution.translationpermission IS 'The level of openness of this distribution''s translation process. The enum lists different approaches to translation, from the very open (anybody can edit any translation in any language) to the completely closed (only designated translators can make any changes at all).';
+
+
+COMMENT ON COLUMN public.distribution.bug_supervisor IS 'Person who is responsible for managing bugs on this distribution.';
+
+
+COMMENT ON COLUMN public.distribution.official_malone IS 'Whether or not this distribution uses Malone for an official bug tracker.';
+
+
+COMMENT ON COLUMN public.distribution.official_rosetta IS 'Whether or not this distribution uses Rosetta for its official translation team and coordination.';
+
+
+COMMENT ON COLUMN public.distribution.driver IS 'The team or person responsible for approving goals for each release in the distribution. This should usually be a very small team because the Distribution driver can approve items for backporting to past releases as well as the current release under development. Each distroseries has its own driver too, so you can have the small superset in the Distribution driver, and then specific teams per distroseries for backporting, for example, or for the current release management team on the current development focus release.';
+
+
+COMMENT ON COLUMN public.distribution.translation_focus IS 'The DistroSeries that should get the translation effort focus.';
+
+
+COMMENT ON COLUMN public.distribution.mirror_admin IS 'Person or team with privileges to mark a mirror as official.';
+
+
+COMMENT ON COLUMN public.distribution.upload_sender IS 'The email address (and name) of the default sender used by the upload processor. If NULL, we fall back to the default sender in the launchpad config.';
+
+
+COMMENT ON COLUMN public.distribution.homepage_content IS 'A home page for this distribution in the Launchpad.';
+
+
+COMMENT ON COLUMN public.distribution.icon IS 'The library file alias to a small image to be used as an icon whenever we are referring to a distribution.';
+
+
+COMMENT ON COLUMN public.distribution.mugshot IS 'The library file alias of a mugshot image to display as the branding of a distribution, on its home page.';
+
+
+COMMENT ON COLUMN public.distribution.logo IS 'The library file alias of a smaller version of this distributions''s mugshot.';
+
+
+COMMENT ON COLUMN public.distribution.official_answers IS 'Whether or not this product upstream uses Answers officialy.';
+
+
+COMMENT ON COLUMN public.distribution.language_pack_admin IS 'The Person or Team that handle language packs for the distro release.';
+
+
+COMMENT ON COLUMN public.distribution.enable_bug_expiration IS 'Indicates whether automatic bug expiration is enabled.';
+
+
+COMMENT ON COLUMN public.distribution.bug_reporting_guidelines IS 'Guidelines to the end user for reporting bugs on this distribution.';
+
+
+COMMENT ON COLUMN public.distribution.reviewer_whiteboard IS 'A whiteboard for Launchpad admins, registry experts and the project owners to capture the state of current issues with the project.';
+
+
+COMMENT ON COLUMN public.distribution.max_bug_heat IS 'The highest heat value across bugs for this distribution.';
+
+
+COMMENT ON COLUMN public.distribution.bug_reported_acknowledgement IS 'A message of acknowledgement to display to a bug reporter after they''ve reported a new bug.';
+
+
+COMMENT ON COLUMN public.distribution.registrant IS 'The person in launchpad who registered this distribution.';
+
+
+COMMENT ON COLUMN public.distribution.package_derivatives_email IS 'The optional email address template to use when sending emails about package updates in a distributrion. The string {package_name} in the template will be replaced with the actual package name being updated.';
+
+
+COMMENT ON COLUMN public.distribution.redirect_release_uploads IS 'Whether uploads to the release pocket of this distribution should be redirected to the proposed pocket instead.';
+
+
+COMMENT ON COLUMN public.distribution.development_series_alias IS 'If set, an alias for the current development series in this distribution.';
+
+
+COMMENT ON COLUMN public.distribution.vcs IS 'An enumeration specifying the default version control system for this distribution.';
+
+
+CREATE SEQUENCE public.distribution_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE distribution_id_seq OWNED BY distribution.id;
-
-
-CREATE TABLE distributionjob (
+ALTER SEQUENCE public.distribution_id_seq OWNED BY public.distribution.id;
+
+
+CREATE TABLE public.distributionjob (
     id integer NOT NULL,
     job integer NOT NULL,
     distribution integer NOT NULL,
@@ -8276,33 +7226,33 @@
 );
 
 
-COMMENT ON TABLE distributionjob IS 'Contains references to jobs to be run on distributions.';
-
-
-COMMENT ON COLUMN distributionjob.distribution IS 'The distribution to be acted on.';
-
-
-COMMENT ON COLUMN distributionjob.distroseries IS 'The distroseries to be acted on.';
-
-
-COMMENT ON COLUMN distributionjob.job_type IS 'The type of job';
-
-
-COMMENT ON COLUMN distributionjob.json_data IS 'A JSON struct containing data for the job.';
-
-
-CREATE SEQUENCE distributionjob_id_seq
+COMMENT ON TABLE public.distributionjob IS 'Contains references to jobs to be run on distributions.';
+
+
+COMMENT ON COLUMN public.distributionjob.distribution IS 'The distribution to be acted on.';
+
+
+COMMENT ON COLUMN public.distributionjob.distroseries IS 'The distroseries to be acted on.';
+
+
+COMMENT ON COLUMN public.distributionjob.job_type IS 'The type of job';
+
+
+COMMENT ON COLUMN public.distributionjob.json_data IS 'A JSON struct containing data for the job.';
+
+
+CREATE SEQUENCE public.distributionjob_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE distributionjob_id_seq OWNED BY distributionjob.id;
-
-
-CREATE TABLE distributionmirror (
+ALTER SEQUENCE public.distributionjob_id_seq OWNED BY public.distributionjob.id;
+
+
+CREATE TABLE public.distributionmirror (
     id integer NOT NULL,
     distribution integer NOT NULL,
     name text NOT NULL,
@@ -8324,85 +7274,85 @@
     reviewer integer,
     country_dns_mirror boolean DEFAULT false NOT NULL,
     CONSTRAINT one_or_more_urls CHECK ((((http_base_url IS NOT NULL) OR (ftp_base_url IS NOT NULL)) OR (rsync_base_url IS NOT NULL))),
-    CONSTRAINT valid_ftp_base_url CHECK (valid_absolute_url(ftp_base_url)),
-    CONSTRAINT valid_http_base_url CHECK (valid_absolute_url(http_base_url)),
-    CONSTRAINT valid_name CHECK (valid_name(name)),
-    CONSTRAINT valid_rsync_base_url CHECK (valid_absolute_url(rsync_base_url))
+    CONSTRAINT valid_ftp_base_url CHECK (public.valid_absolute_url(ftp_base_url)),
+    CONSTRAINT valid_http_base_url CHECK (public.valid_absolute_url(http_base_url)),
+    CONSTRAINT valid_name CHECK (public.valid_name(name)),
+    CONSTRAINT valid_rsync_base_url CHECK (public.valid_absolute_url(rsync_base_url))
 );
 
 
-COMMENT ON TABLE distributionmirror IS 'A mirror of a given distribution.';
-
-
-COMMENT ON COLUMN distributionmirror.distribution IS 'The distribution to which the mirror refers to.';
-
-
-COMMENT ON COLUMN distributionmirror.name IS 'The unique name of the mirror.';
-
-
-COMMENT ON COLUMN distributionmirror.http_base_url IS 'The HTTP URL used to access the mirror.';
-
-
-COMMENT ON COLUMN distributionmirror.ftp_base_url IS 'The FTP URL used to access the mirror.';
-
-
-COMMENT ON COLUMN distributionmirror.rsync_base_url IS 'The Rsync URL used to access the mirror.';
-
-
-COMMENT ON COLUMN distributionmirror.displayname IS 'The displayname of the mirror.';
-
-
-COMMENT ON COLUMN distributionmirror.description IS 'A description of the mirror.';
-
-
-COMMENT ON COLUMN distributionmirror.owner IS 'The owner of the mirror.';
-
-
-COMMENT ON COLUMN distributionmirror.speed IS 'The speed of the mirror''s Internet link.';
-
-
-COMMENT ON COLUMN distributionmirror.country IS 'The country where the mirror is located.';
-
-
-COMMENT ON COLUMN distributionmirror.content IS 'The content that is mirrored.';
-
-
-COMMENT ON COLUMN distributionmirror.official_candidate IS 'Is the mirror a candidate for becoming an official mirror?';
-
-
-COMMENT ON COLUMN distributionmirror.enabled IS 'Is this mirror enabled?';
-
-
-COMMENT ON COLUMN distributionmirror.date_created IS 'The date and time the mirror was created.';
-
-
-COMMENT ON COLUMN distributionmirror.whiteboard IS 'Notes on the current status of the mirror';
-
-
-COMMENT ON COLUMN distributionmirror.status IS 'This mirror''s status.';
-
-
-COMMENT ON COLUMN distributionmirror.date_reviewed IS 'The date and time the mirror was reviewed.';
-
-
-COMMENT ON COLUMN distributionmirror.reviewer IS 'The person who reviewed the mirror.';
-
-
-COMMENT ON COLUMN distributionmirror.country_dns_mirror IS 'Is the mirror a country DNS mirror?';
-
-
-CREATE SEQUENCE distributionmirror_id_seq
+COMMENT ON TABLE public.distributionmirror IS 'A mirror of a given distribution.';
+
+
+COMMENT ON COLUMN public.distributionmirror.distribution IS 'The distribution to which the mirror refers to.';
+
+
+COMMENT ON COLUMN public.distributionmirror.name IS 'The unique name of the mirror.';
+
+
+COMMENT ON COLUMN public.distributionmirror.http_base_url IS 'The HTTP URL used to access the mirror.';
+
+
+COMMENT ON COLUMN public.distributionmirror.ftp_base_url IS 'The FTP URL used to access the mirror.';
+
+
+COMMENT ON COLUMN public.distributionmirror.rsync_base_url IS 'The Rsync URL used to access the mirror.';
+
+
+COMMENT ON COLUMN public.distributionmirror.displayname IS 'The displayname of the mirror.';
+
+
+COMMENT ON COLUMN public.distributionmirror.description IS 'A description of the mirror.';
+
+
+COMMENT ON COLUMN public.distributionmirror.owner IS 'The owner of the mirror.';
+
+
+COMMENT ON COLUMN public.distributionmirror.speed IS 'The speed of the mirror''s Internet link.';
+
+
+COMMENT ON COLUMN public.distributionmirror.country IS 'The country where the mirror is located.';
+
+
+COMMENT ON COLUMN public.distributionmirror.content IS 'The content that is mirrored.';
+
+
+COMMENT ON COLUMN public.distributionmirror.official_candidate IS 'Is the mirror a candidate for becoming an official mirror?';
+
+
+COMMENT ON COLUMN public.distributionmirror.enabled IS 'Is this mirror enabled?';
+
+
+COMMENT ON COLUMN public.distributionmirror.date_created IS 'The date and time the mirror was created.';
+
+
+COMMENT ON COLUMN public.distributionmirror.whiteboard IS 'Notes on the current status of the mirror';
+
+
+COMMENT ON COLUMN public.distributionmirror.status IS 'This mirror''s status.';
+
+
+COMMENT ON COLUMN public.distributionmirror.date_reviewed IS 'The date and time the mirror was reviewed.';
+
+
+COMMENT ON COLUMN public.distributionmirror.reviewer IS 'The person who reviewed the mirror.';
+
+
+COMMENT ON COLUMN public.distributionmirror.country_dns_mirror IS 'Is the mirror a country DNS mirror?';
+
+
+CREATE SEQUENCE public.distributionmirror_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE distributionmirror_id_seq OWNED BY distributionmirror.id;
-
-
-CREATE TABLE distributionsourcepackage (
+ALTER SEQUENCE public.distributionmirror_id_seq OWNED BY public.distributionmirror.id;
+
+
+CREATE TABLE public.distributionsourcepackage (
     id integer NOT NULL,
     distribution integer NOT NULL,
     sourcepackagename integer NOT NULL,
@@ -8417,45 +7367,45 @@
 );
 
 
-COMMENT ON TABLE distributionsourcepackage IS 'Representing a sourcepackage in a distribution across all distribution series.';
-
-
-COMMENT ON COLUMN distributionsourcepackage.bug_reporting_guidelines IS 'Guidelines to the end user for reporting bugs on a particular a source package in a distribution.';
-
-
-COMMENT ON COLUMN distributionsourcepackage.max_bug_heat IS 'The highest heat value across bugs for this source package. NULL means it has not yet been calculated.';
-
-
-COMMENT ON COLUMN distributionsourcepackage.bug_reported_acknowledgement IS 'A message of acknowledgement to display to a bug reporter after they''ve reported a new bug.';
-
-
-COMMENT ON COLUMN distributionsourcepackage.total_bug_heat IS 'Sum of bug heat matching the package distribution and sourcepackagename. NULL means it has not yet been calculated.';
-
-
-COMMENT ON COLUMN distributionsourcepackage.bug_count IS 'Number of bugs matching the package distribution and sourcepackagename. NULL means it has not yet been calculated.';
-
-
-COMMENT ON COLUMN distributionsourcepackage.po_message_count IS 'Number of translations matching the package distribution and sourcepackagename. NULL means it has not yet been calculated.';
-
-
-COMMENT ON COLUMN distributionsourcepackage.is_upstream_link_allowed IS 'Whether an upstream link may be added if it does not already exist.';
-
-
-COMMENT ON COLUMN distributionsourcepackage.enable_bugfiling_duplicate_search IS 'Enable/disable a search for posiible duplicates when a bug is filed.';
-
-
-CREATE SEQUENCE distributionsourcepackage_id_seq
+COMMENT ON TABLE public.distributionsourcepackage IS 'Representing a sourcepackage in a distribution across all distribution series.';
+
+
+COMMENT ON COLUMN public.distributionsourcepackage.bug_reporting_guidelines IS 'Guidelines to the end user for reporting bugs on a particular a source package in a distribution.';
+
+
+COMMENT ON COLUMN public.distributionsourcepackage.max_bug_heat IS 'The highest heat value across bugs for this source package. NULL means it has not yet been calculated.';
+
+
+COMMENT ON COLUMN public.distributionsourcepackage.bug_reported_acknowledgement IS 'A message of acknowledgement to display to a bug reporter after they''ve reported a new bug.';
+
+
+COMMENT ON COLUMN public.distributionsourcepackage.total_bug_heat IS 'Sum of bug heat matching the package distribution and sourcepackagename. NULL means it has not yet been calculated.';
+
+
+COMMENT ON COLUMN public.distributionsourcepackage.bug_count IS 'Number of bugs matching the package distribution and sourcepackagename. NULL means it has not yet been calculated.';
+
+
+COMMENT ON COLUMN public.distributionsourcepackage.po_message_count IS 'Number of translations matching the package distribution and sourcepackagename. NULL means it has not yet been calculated.';
+
+
+COMMENT ON COLUMN public.distributionsourcepackage.is_upstream_link_allowed IS 'Whether an upstream link may be added if it does not already exist.';
+
+
+COMMENT ON COLUMN public.distributionsourcepackage.enable_bugfiling_duplicate_search IS 'Enable/disable a search for posiible duplicates when a bug is filed.';
+
+
+CREATE SEQUENCE public.distributionsourcepackage_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE distributionsourcepackage_id_seq OWNED BY distributionsourcepackage.id;
-
-
-CREATE TABLE distributionsourcepackagecache (
+ALTER SEQUENCE public.distributionsourcepackage_id_seq OWNED BY public.distributionsourcepackage.id;
+
+
+CREATE TABLE public.distributionsourcepackagecache (
     id integer NOT NULL,
     distribution integer NOT NULL,
     sourcepackagename integer NOT NULL,
@@ -8463,73 +7413,227 @@
     binpkgnames text,
     binpkgsummaries text,
     binpkgdescriptions text,
-    fti ts2.tsvector,
+    fti public.ts2_tsvector,
     changelog text,
-    archive integer NOT NULL
-);
-
-
-COMMENT ON TABLE distributionsourcepackagecache IS 'A cache of the text associated with binary and source packages in the distribution. This table allows for fast queries to find a source packagename that matches a given text.';
-
-
-COMMENT ON COLUMN distributionsourcepackagecache.distribution IS 'The distribution in which we are checking.';
-
-
-COMMENT ON COLUMN distributionsourcepackagecache.sourcepackagename IS 'The source package name for which we are caching details.';
-
-
-COMMENT ON COLUMN distributionsourcepackagecache.name IS 'The source package name itself. This is just a copy of the value of sourcepackagename.name. We have it here so it can be part of the full text index.';
-
-
-COMMENT ON COLUMN distributionsourcepackagecache.binpkgnames IS 'The binary package names of binary packages generated from these source packages across all architectures.';
-
-
-COMMENT ON COLUMN distributionsourcepackagecache.binpkgsummaries IS 'The aggregated summaries of all the binary packages generated from these source packages in this distribution.';
-
-
-COMMENT ON COLUMN distributionsourcepackagecache.binpkgdescriptions IS 'The aggregated description of all the binary packages generated from these source packages in this distribution.';
-
-
-COMMENT ON COLUMN distributionsourcepackagecache.changelog IS 'A concatenation of the source package release changelogs for this source package, where the status is not REMOVED.';
-
-
-COMMENT ON COLUMN distributionsourcepackagecache.archive IS 'The archive where the source is published.';
-
-
-CREATE SEQUENCE distributionsourcepackagecache_id_seq
-    START WITH 1
-    INCREMENT BY 1
-    NO MAXVALUE
-    NO MINVALUE
-    CACHE 1;
-
-
-ALTER SEQUENCE distributionsourcepackagecache_id_seq OWNED BY distributionsourcepackagecache.id;
-
-
-CREATE SEQUENCE distroarchseries_id_seq
-    START WITH 1
-    INCREMENT BY 1
-    NO MAXVALUE
-    NO MINVALUE
-    CACHE 1;
-
-
-ALTER SEQUENCE distroarchseries_id_seq OWNED BY distroarchseries.id;
-
-
-CREATE SEQUENCE distroseries_id_seq
-    START WITH 1
-    INCREMENT BY 1
-    NO MAXVALUE
-    NO MINVALUE
-    CACHE 1;
-
-
-ALTER SEQUENCE distroseries_id_seq OWNED BY distroseries.id;
-
-
-CREATE TABLE distroseriesdifference (
+    archive integer
+);
+
+
+COMMENT ON TABLE public.distributionsourcepackagecache IS 'A cache of the text associated with binary and source packages in the distribution. This table allows for fast queries to find a source packagename that matches a given text.';
+
+
+COMMENT ON COLUMN public.distributionsourcepackagecache.distribution IS 'The distribution in which we are checking.';
+
+
+COMMENT ON COLUMN public.distributionsourcepackagecache.sourcepackagename IS 'The source package name for which we are caching details.';
+
+
+COMMENT ON COLUMN public.distributionsourcepackagecache.name IS 'The source package name itself. This is just a copy of the value of sourcepackagename.name. We have it here so it can be part of the full text index.';
+
+
+COMMENT ON COLUMN public.distributionsourcepackagecache.binpkgnames IS 'The binary package names of binary packages generated from these source packages across all architectures.';
+
+
+COMMENT ON COLUMN public.distributionsourcepackagecache.binpkgsummaries IS 'The aggregated summaries of all the binary packages generated from these source packages in this distribution.';
+
+
+COMMENT ON COLUMN public.distributionsourcepackagecache.binpkgdescriptions IS 'The aggregated description of all the binary packages generated from these source packages in this distribution.';
+
+
+COMMENT ON COLUMN public.distributionsourcepackagecache.changelog IS 'A concatenation of the source package release changelogs for this source package, where the status is not REMOVED.';
+
+
+COMMENT ON COLUMN public.distributionsourcepackagecache.archive IS 'The archive where the source is published.';
+
+
+CREATE SEQUENCE public.distributionsourcepackagecache_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER SEQUENCE public.distributionsourcepackagecache_id_seq OWNED BY public.distributionsourcepackagecache.id;
+
+
+CREATE TABLE public.distroarchseries (
+    id integer NOT NULL,
+    distroseries integer NOT NULL,
+    architecturetag text NOT NULL,
+    owner integer NOT NULL,
+    official boolean NOT NULL,
+    package_count integer DEFAULT 0 NOT NULL,
+    date_created timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL,
+    enabled boolean DEFAULT true NOT NULL,
+    processor integer NOT NULL,
+    CONSTRAINT valid_architecturetag CHECK (public.valid_name(architecturetag))
+);
+
+
+COMMENT ON TABLE public.distroarchseries IS 'DistroArchSeries: A soyuz distribution release for a given architecture. A distroseries runs on various architectures. The distroarchseries groups that architecture-specific stuff.';
+
+
+COMMENT ON COLUMN public.distroarchseries.distroseries IS 'The distribution which this distroarchseries is part of.';
+
+
+COMMENT ON COLUMN public.distroarchseries.architecturetag IS 'The name of this architecture in the context of this specific distro release. For example, some distributions might label amd64 as amd64, others might call is x86_64. This information is used, for example, in determining the names of the actual package files... such as the "amd64" part of "apache2_2.0.56-1_amd64.deb"';
+
+
+COMMENT ON COLUMN public.distroarchseries.official IS 'Whether or not this architecture or "port" is an official release. If it is not official then you may not be able to install it or get all the packages for it.';
+
+
+COMMENT ON COLUMN public.distroarchseries.package_count IS 'A cache of the number of binary packages published in this distro arch release. The count only includes packages published in the release pocket.';
+
+
+COMMENT ON COLUMN public.distroarchseries.enabled IS 'Whether to allow build creation and publishing for this DistroArchSeries.';
+
+
+COMMENT ON COLUMN public.distroarchseries.processor IS 'A link to the Processor table, giving the architecture of this DistroArchSeries.';
+
+
+CREATE SEQUENCE public.distroarchseries_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER SEQUENCE public.distroarchseries_id_seq OWNED BY public.distroarchseries.id;
+
+
+CREATE TABLE public.distroseries (
+    id integer NOT NULL,
+    distribution integer NOT NULL,
+    name text NOT NULL,
+    title text NOT NULL,
+    description text NOT NULL,
+    version text NOT NULL,
+    releasestatus integer NOT NULL,
+    datereleased timestamp without time zone,
+    parent_series integer,
+    registrant integer NOT NULL,
+    summary text NOT NULL,
+    displayname text NOT NULL,
+    datelastlangpack timestamp without time zone,
+    messagecount integer DEFAULT 0 NOT NULL,
+    nominatedarchindep integer,
+    changeslist text,
+    binarycount integer DEFAULT 0 NOT NULL,
+    sourcecount integer DEFAULT 0 NOT NULL,
+    driver integer,
+    date_created timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL,
+    hide_all_translations boolean DEFAULT true NOT NULL,
+    defer_translation_imports boolean DEFAULT true NOT NULL,
+    language_pack_base integer,
+    language_pack_delta integer,
+    language_pack_proposed integer,
+    language_pack_full_export_requested boolean DEFAULT false NOT NULL,
+    backports_not_automatic boolean DEFAULT false NOT NULL,
+    include_long_descriptions boolean DEFAULT true NOT NULL,
+    proposed_not_automatic boolean DEFAULT false NOT NULL,
+    publishing_options text,
+    CONSTRAINT valid_language_pack_delta CHECK (((language_pack_base IS NOT NULL) OR (language_pack_delta IS NULL))),
+    CONSTRAINT valid_name CHECK (public.valid_name(name)),
+    CONSTRAINT valid_version CHECK (public.sane_version(version))
+);
+
+
+COMMENT ON TABLE public.distroseries IS 'DistroSeries: A soyuz distribution release. A DistroSeries is a given version of a distribution. E.g. "Warty" "Hoary" "Sarge" etc.';
+
+
+COMMENT ON COLUMN public.distroseries.distribution IS 'The distribution which contains this distroseries.';
+
+
+COMMENT ON COLUMN public.distroseries.name IS 'The unique name of the distroseries. This is a short name in lower case and would be used in sources.list configuration and in generated URLs. E.g. "warty" "sarge" "sid"';
+
+
+COMMENT ON COLUMN public.distroseries.title IS 'The display-name title of the distroseries E.g. "Warty Warthog"';
+
+
+COMMENT ON COLUMN public.distroseries.description IS 'The long detailed description of the release. This may describe the focus of the release or other related information.';
+
+
+COMMENT ON COLUMN public.distroseries.version IS 'The version of the release. E.g. warty would be "4.10" and hoary would be "5.4"';
+
+
+COMMENT ON COLUMN public.distroseries.releasestatus IS 'The current release status of this distroseries. E.g. "pre-release freeze" or "released"';
+
+
+COMMENT ON COLUMN public.distroseries.datereleased IS 'The date on which this distroseries was released. (obviously only valid for released distributions)';
+
+
+COMMENT ON COLUMN public.distroseries.parent_series IS 'The parent distroseries on which this distribution is based. This is related to the inheritance stuff.';
+
+
+COMMENT ON COLUMN public.distroseries.registrant IS 'The user who registered this distroseries.';
+
+
+COMMENT ON COLUMN public.distroseries.summary IS 'A brief summary of the distro release. This will be displayed in bold at the top of the distroseries page, above the distroseries description. It should include any high points that are particularly important to draw to the attention of users.';
+
+
+COMMENT ON COLUMN public.distroseries.datelastlangpack IS 'The date we last generated a base language pack for this release. Language update packs for this release will only include translations added after that date.';
+
+
+COMMENT ON COLUMN public.distroseries.messagecount IS 'This is a cached value and may be a few hours out of sync with reality. It should, however, be in sync with the values in DistroSeriesLanguage, and should never be updated separately. The total number of translation messages in this distro release, as per IRosettaStats.';
+
+
+COMMENT ON COLUMN public.distroseries.nominatedarchindep IS 'This is the DistroArchSeries nominated to build architecture independent packages within this DistroRelase, it is mandatory for buildable distroseries, i.e., Auto Build System will avoid to create build jobs for a DistroSeries with no nominatedarchindep, but the database model allow us to do it (for non-buildable DistroSeries). See further info in NominatedArchIndep specification.';
+
+
+COMMENT ON COLUMN public.distroseries.changeslist IS 'The email address (name name) of the changes announcement list for this distroseries. If NULL, no announcement mail will be sent.';
+
+
+COMMENT ON COLUMN public.distroseries.binarycount IS 'A cache of the number of distinct binary package names published in this distro release.';
+
+
+COMMENT ON COLUMN public.distroseries.sourcecount IS 'A cache of the number of distinct source package names published in this distro release.';
+
+
+COMMENT ON COLUMN public.distroseries.driver IS 'This is a person or team who can act as a driver for this specific release - note that the distribution drivers can also set goals for any release.';
+
+
+COMMENT ON COLUMN public.distroseries.hide_all_translations IS 'Whether we should hid
+e all available translations for this distro release to non admin users.';
+
+
+COMMENT ON COLUMN public.distroseries.defer_translation_imports IS 'Don''t accept PO imports for this release just now.';
+
+
+COMMENT ON COLUMN public.distroseries.language_pack_base IS 'Current full export language pack for this distribution release.';
+
+
+COMMENT ON COLUMN public.distroseries.language_pack_delta IS 'Current language pack update based on language_pack_base information.';
+
+
+COMMENT ON COLUMN public.distroseries.language_pack_proposed IS 'Either a full or update language pack being tested to be used in language_pack_base or language_pack_delta.';
+
+
+COMMENT ON COLUMN public.distroseries.language_pack_full_export_requested IS 'Whether next language pack export should be a full export or an update.';
+
+
+COMMENT ON COLUMN public.distroseries.include_long_descriptions IS 'Include long descriptions in Packages rather than in Translation-en.';
+
+
+COMMENT ON COLUMN public.distroseries.proposed_not_automatic IS 'Whether the -proposed pocket is set NotAutomatic and ButAutomaticUpgrades so that apt does not offer users upgrades into -proposed, but does offer upgrades within it.';
+
+
+COMMENT ON COLUMN public.distroseries.publishing_options IS 'A JSON object containing options modifying the publisher''s behaviour for this series.';
+
+
+CREATE SEQUENCE public.distroseries_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER SEQUENCE public.distroseries_id_seq OWNED BY public.distroseries.id;
+
+
+CREATE TABLE public.distroseriesdifference (
     id integer NOT NULL,
     derived_series integer NOT NULL,
     source_package_name integer NOT NULL,
@@ -8537,85 +7641,88 @@
     status integer NOT NULL,
     difference_type integer NOT NULL,
     parent_package_diff integer,
-    source_version debversion,
-    parent_source_version debversion,
-    base_version debversion,
+    source_version public.debversion,
+    parent_source_version public.debversion,
+    base_version public.debversion,
     parent_series integer NOT NULL,
-    CONSTRAINT valid_base_version CHECK (valid_debian_version((base_version)::text)),
-    CONSTRAINT valid_parent_source_version CHECK (valid_debian_version((parent_source_version)::text)),
-    CONSTRAINT valid_source_version CHECK (valid_debian_version((source_version)::text))
+    CONSTRAINT valid_base_version CHECK (public.valid_debian_version((base_version)::text)),
+    CONSTRAINT valid_parent_source_version CHECK (public.valid_debian_version((parent_source_version)::text)),
+    CONSTRAINT valid_source_version CHECK (public.valid_debian_version((source_version)::text))
 );
 
 
-COMMENT ON TABLE distroseriesdifference IS 'A difference of versions for a package in a derived distroseries and its parent distroseries.';
-
-
-COMMENT ON COLUMN distroseriesdifference.derived_series IS 'The derived distroseries with the difference from its parent.';
-
-
-COMMENT ON COLUMN distroseriesdifference.source_package_name IS 'The name of the source package which is different in the two series.';
-
-
-COMMENT ON COLUMN distroseriesdifference.package_diff IS 'The most recent package diff that was created for the base version to derived version.';
-
-
-COMMENT ON COLUMN distroseriesdifference.status IS 'A distroseries difference can be needing attention, ignored or resolved.';
-
-
-COMMENT ON COLUMN distroseriesdifference.difference_type IS 'The type of difference that this record represents - a package unique to the derived series, or missing, or in both.';
-
-
-COMMENT ON COLUMN distroseriesdifference.parent_package_diff IS 'The most recent package diff that was created for the base version to the parent version.';
-
-
-COMMENT ON COLUMN distroseriesdifference.source_version IS 'The version of the package in the derived series.';
-
-
-COMMENT ON COLUMN distroseriesdifference.parent_source_version IS 'The version of the package in the parent series.';
-
-
-COMMENT ON COLUMN distroseriesdifference.base_version IS 'The common base version of the package for the derived and parent series.';
-
-
-CREATE SEQUENCE distroseriesdifference_id_seq
+COMMENT ON TABLE public.distroseriesdifference IS 'A difference of versions for a package in a derived distroseries and its parent distroseries.';
+
+
+COMMENT ON COLUMN public.distroseriesdifference.derived_series IS 'The derived distroseries with the difference from its parent.';
+
+
+COMMENT ON COLUMN public.distroseriesdifference.source_package_name IS 'The name of the source package which is different in the two series.';
+
+
+COMMENT ON COLUMN public.distroseriesdifference.package_diff IS 'The most recent package diff that was created for the base version to derived version.';
+
+
+COMMENT ON COLUMN public.distroseriesdifference.status IS 'A distroseries difference can be needing attention, ignored or resolved.';
+
+
+COMMENT ON COLUMN public.distroseriesdifference.difference_type IS 'The type of difference that this record represents - a package unique to the derived series, or missing, or in both.';
+
+
+COMMENT ON COLUMN public.distroseriesdifference.parent_package_diff IS 'The most recent package diff that was created for the base version to the parent version.';
+
+
+COMMENT ON COLUMN public.distroseriesdifference.source_version IS 'The version of the package in the derived series.';
+
+
+COMMENT ON COLUMN public.distroseriesdifference.parent_source_version IS 'The version of the package in the parent series.';
+
+
+COMMENT ON COLUMN public.distroseriesdifference.base_version IS 'The common base version of the package for the derived and parent series.';
+
+
+COMMENT ON COLUMN public.distroseriesdifference.parent_series IS 'The parent distroseries with the difference from its child.';
+
+
+CREATE SEQUENCE public.distroseriesdifference_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE distroseriesdifference_id_seq OWNED BY distroseriesdifference.id;
-
-
-CREATE TABLE distroseriesdifferencemessage (
+ALTER SEQUENCE public.distroseriesdifference_id_seq OWNED BY public.distroseriesdifference.id;
+
+
+CREATE TABLE public.distroseriesdifferencemessage (
     id integer NOT NULL,
     distro_series_difference integer NOT NULL,
     message integer NOT NULL
 );
 
 
-COMMENT ON TABLE distroseriesdifferencemessage IS 'A message/comment on a distro series difference.';
-
-
-COMMENT ON COLUMN distroseriesdifferencemessage.distro_series_difference IS 'The distro series difference for this comment.';
-
-
-COMMENT ON COLUMN distroseriesdifferencemessage.message IS 'The comment for the distro series difference.';
-
-
-CREATE SEQUENCE distroseriesdifferencemessage_id_seq
+COMMENT ON TABLE public.distroseriesdifferencemessage IS 'A message/comment on a distro series difference.';
+
+
+COMMENT ON COLUMN public.distroseriesdifferencemessage.distro_series_difference IS 'The distro series difference for this comment.';
+
+
+COMMENT ON COLUMN public.distroseriesdifferencemessage.message IS 'The comment for the distro series difference.';
+
+
+CREATE SEQUENCE public.distroseriesdifferencemessage_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE distroseriesdifferencemessage_id_seq OWNED BY distroseriesdifferencemessage.id;
-
-
-CREATE TABLE distroserieslanguage (
+ALTER SEQUENCE public.distroseriesdifferencemessage_id_seq OWNED BY public.distroseriesdifferencemessage.id;
+
+
+CREATE TABLE public.distroserieslanguage (
     id integer NOT NULL,
     distroseries integer,
     language integer,
@@ -8628,39 +7735,39 @@
 );
 
 
-COMMENT ON TABLE distroserieslanguage IS 'A cache of the current translation status of that language across an entire distroseries.';
-
-
-COMMENT ON COLUMN distroserieslanguage.currentcount IS 'As per IRosettaStats.';
-
-
-COMMENT ON COLUMN distroserieslanguage.updatescount IS 'As per IRosettaStats.';
-
-
-COMMENT ON COLUMN distroserieslanguage.rosettacount IS 'As per IRosettaStats.';
-
-
-COMMENT ON COLUMN distroserieslanguage.contributorcount IS 'The total number of contributors to the translation of this distroseries into this language.';
-
-
-COMMENT ON COLUMN distroserieslanguage.dateupdated IS 'The date these statistucs were last updated.';
-
-
-COMMENT ON COLUMN distroserieslanguage.unreviewed_count IS 'As per IRosettaStats.';
-
-
-CREATE SEQUENCE distroserieslanguage_id_seq
+COMMENT ON TABLE public.distroserieslanguage IS 'A cache of the current translation status of that language across an entire distroseries.';
+
+
+COMMENT ON COLUMN public.distroserieslanguage.currentcount IS 'As per IRosettaStats.';
+
+
+COMMENT ON COLUMN public.distroserieslanguage.updatescount IS 'As per IRosettaStats.';
+
+
+COMMENT ON COLUMN public.distroserieslanguage.rosettacount IS 'As per IRosettaStats.';
+
+
+COMMENT ON COLUMN public.distroserieslanguage.contributorcount IS 'The total number of contributors to the translation of this distroseries into this language.';
+
+
+COMMENT ON COLUMN public.distroserieslanguage.dateupdated IS 'The date these statistucs were last updated.';
+
+
+COMMENT ON COLUMN public.distroserieslanguage.unreviewed_count IS 'As per IRosettaStats.';
+
+
+CREATE SEQUENCE public.distroserieslanguage_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE distroserieslanguage_id_seq OWNED BY distroserieslanguage.id;
-
-
-CREATE TABLE distroseriespackagecache (
+ALTER SEQUENCE public.distroserieslanguage_id_seq OWNED BY public.distroserieslanguage.id;
+
+
+CREATE TABLE public.distroseriespackagecache (
     id integer NOT NULL,
     distroseries integer NOT NULL,
     binarypackagename integer NOT NULL,
@@ -8669,47 +7776,47 @@
     description text,
     summaries text,
     descriptions text,
-    fti ts2.tsvector,
+    fti public.ts2_tsvector,
     archive integer NOT NULL
 );
 
 
-COMMENT ON TABLE distroseriespackagecache IS 'A cache of the text associated with binary packages in the distroseries. This table allows for fast queries to find a binary packagename that matches a given text.';
-
-
-COMMENT ON COLUMN distroseriespackagecache.distroseries IS 'The distroseries in which we are checking.';
-
-
-COMMENT ON COLUMN distroseriespackagecache.binarypackagename IS 'The binary package name for which we are caching details.';
-
-
-COMMENT ON COLUMN distroseriespackagecache.name IS 'The binary package name itself. This is just a copy of the value of binarypackagename.name. We have it here so it can be part of the full text index.';
-
-
-COMMENT ON COLUMN distroseriespackagecache.summary IS 'A single summary for one of the binary packages of this name in this distroseries. We could potentially have binary packages in different architectures with the same name and different summaries, so this is a way of collapsing to one arbitrarily-chosen one, for display purposes. The chances of actually having different summaries and descriptions is pretty small. It could happen, though, because of the way package superseding works when a package does not build on a specific architecture.';
-
-
-COMMENT ON COLUMN distroseriespackagecache.summaries IS 'The aggregated summaries of all the binary packages with this name in this distroseries.';
-
-
-COMMENT ON COLUMN distroseriespackagecache.descriptions IS 'The aggregated description of all the binary packages with this name in this distroseries.';
-
-
-COMMENT ON COLUMN distroseriespackagecache.archive IS 'The archive where the binary is published.';
-
-
-CREATE SEQUENCE distroseriespackagecache_id_seq
+COMMENT ON TABLE public.distroseriespackagecache IS 'A cache of the text associated with binary packages in the distroseries. This table allows for fast queries to find a binary packagename that matches a given text.';
+
+
+COMMENT ON COLUMN public.distroseriespackagecache.distroseries IS 'The distroseries in which we are checking.';
+
+
+COMMENT ON COLUMN public.distroseriespackagecache.binarypackagename IS 'The binary package name for which we are caching details.';
+
+
+COMMENT ON COLUMN public.distroseriespackagecache.name IS 'The binary package name itself. This is just a copy of the value of binarypackagename.name. We have it here so it can be part of the full text index.';
+
+
+COMMENT ON COLUMN public.distroseriespackagecache.summary IS 'A single summary for one of the binary packages of this name in this distroseries. We could potentially have binary packages in different architectures with the same name and different summaries, so this is a way of collapsing to one arbitrarily-chosen one, for display purposes. The chances of actually having different summaries and descriptions is pretty small. It could happen, though, because of the way package superseding works when a package does not build on a specific architecture.';
+
+
+COMMENT ON COLUMN public.distroseriespackagecache.summaries IS 'The aggregated summaries of all the binary packages with this name in this distroseries.';
+
+
+COMMENT ON COLUMN public.distroseriespackagecache.descriptions IS 'The aggregated description of all the binary packages with this name in this distroseries.';
+
+
+COMMENT ON COLUMN public.distroseriespackagecache.archive IS 'The archive where the binary is published.';
+
+
+CREATE SEQUENCE public.distroseriespackagecache_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE distroseriespackagecache_id_seq OWNED BY distroseriespackagecache.id;
-
-
-CREATE TABLE distroseriesparent (
+ALTER SEQUENCE public.distroseriespackagecache_id_seq OWNED BY public.distroseriespackagecache.id;
+
+
+CREATE TABLE public.distroseriesparent (
     id integer NOT NULL,
     derived_series integer NOT NULL,
     parent_series integer NOT NULL,
@@ -8717,135 +7824,70 @@
     is_overlay boolean DEFAULT false NOT NULL,
     component integer,
     pocket integer,
-    ordering integer DEFAULT 1 NOT NULL
+    ordering integer DEFAULT 1 NOT NULL,
+    inherit_overrides boolean DEFAULT false NOT NULL
 );
 
 
-CREATE SEQUENCE distroseriesparent_id_seq
+COMMENT ON TABLE public.distroseriesparent IS 'A list of all the derived distroseries for a parent series.';
+
+
+COMMENT ON COLUMN public.distroseriesparent.derived_series IS 'The derived distroseries';
+
+
+COMMENT ON COLUMN public.distroseriesparent.parent_series IS 'The parent distroseries';
+
+
+COMMENT ON COLUMN public.distroseriesparent.initialized IS 'Whether or not the derived series was initialized by copying packages from the parent.';
+
+
+COMMENT ON COLUMN public.distroseriesparent.is_overlay IS 'Whether or not the derived series is an overlay over the parent series.';
+
+
+COMMENT ON COLUMN public.distroseriesparent.component IS 'The component for this overlay.';
+
+
+COMMENT ON COLUMN public.distroseriesparent.pocket IS 'The pocket for this overlay.';
+
+
+COMMENT ON COLUMN public.distroseriesparent.ordering IS 'The parent ordering. Parents are ordered in ascending order starting from 1.';
+
+
+CREATE SEQUENCE public.distroseriesparent_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE distroseriesparent_id_seq OWNED BY distroseriesparent.id;
-
-
-CREATE TABLE emailaddress (
+ALTER SEQUENCE public.distroseriesparent_id_seq OWNED BY public.distroseriesparent.id;
+
+
+CREATE TABLE public.emailaddress (
     id integer NOT NULL,
     email text NOT NULL,
-    person integer,
+    person integer NOT NULL,
     status integer NOT NULL,
-    date_created timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL,
-    account integer,
-    CONSTRAINT emailaddress__is_linked__chk CHECK (((person IS NOT NULL) OR (account IS NOT NULL)))
-);
-
-
-COMMENT ON COLUMN emailaddress.email IS 'An email address used by a Person. The email address is stored in a casesensitive way, but must be case insensitivly unique.';
-
-
-CREATE SEQUENCE emailaddress_id_seq
-    START WITH 1
-    INCREMENT BY 1
-    NO MAXVALUE
-    NO MINVALUE
-    CACHE 1;
-
-
-ALTER SEQUENCE emailaddress_id_seq OWNED BY emailaddress.id;
-
-
-CREATE TABLE entitlement (
-    id integer NOT NULL,
-    person integer,
-    entitlement_type integer NOT NULL,
-    quota integer NOT NULL,
-    amount_used integer DEFAULT 0 NOT NULL,
-    date_starts timestamp without time zone,
-    date_expires timestamp without time zone,
-    registrant integer,
-    date_created timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL,
-    approved_by integer,
-    date_approved timestamp without time zone,
-    state integer DEFAULT 30 NOT NULL,
-    whiteboard text,
-    is_dirty boolean DEFAULT true NOT NULL,
-    distribution integer,
-    product integer,
-    project integer,
-    CONSTRAINT only_one_target CHECK ((null_count(ARRAY[person, product, project, distribution]) = 3))
-);
-
-
-COMMENT ON TABLE entitlement IS 'Entitlements and usage of privileged features.';
-
-
-COMMENT ON COLUMN entitlement.person IS 'The person to which the entitlements apply.';
-
-
-COMMENT ON COLUMN entitlement.entitlement_type IS 'The type of this entitlement (e.g. private bug).';
-
-
-COMMENT ON COLUMN entitlement.quota IS 'Number of this entitlement allowed.';
-
-
-COMMENT ON COLUMN entitlement.amount_used IS 'Quantity of this entitlement allocation that is used.';
-
-
-COMMENT ON COLUMN entitlement.date_starts IS 'When this entitlement becomes active.';
-
-
-COMMENT ON COLUMN entitlement.date_expires IS 'When this entitlement expires.';
-
-
-COMMENT ON COLUMN entitlement.registrant IS 'The person (admin) who registered this entitlement.  It is NULL if imported directly from an external sales system.';
-
-
-COMMENT ON COLUMN entitlement.date_created IS 'Creation date of entitlement.';
-
-
-COMMENT ON COLUMN entitlement.approved_by IS 'The person who approved this entitlement.  It is NULL if imported directly from an external sales system.';
-
-
-COMMENT ON COLUMN entitlement.date_approved IS 'Approval date of entitlement.  It is NULL if imported directly from an external sales system.';
-
-
-COMMENT ON COLUMN entitlement.state IS 'The state (REQUESTED, ACTIVE, INACTIVE) of the entitlement.';
-
-
-COMMENT ON COLUMN entitlement.whiteboard IS 'A place for administrator notes.';
-
-
-COMMENT ON COLUMN entitlement.is_dirty IS 'This entitlement has been modified and the state needst to be updated on the external system.';
-
-
-COMMENT ON COLUMN entitlement.distribution IS 'The distribution to which this entitlement applies.';
-
-
-COMMENT ON COLUMN entitlement.product IS 'The product to which this entitlement applies.';
-
-
-COMMENT ON COLUMN entitlement.project IS 'The project to which this entitlement applies.';
-
-
-CREATE SEQUENCE entitlement_id_seq
-    START WITH 1
-    INCREMENT BY 1
-    NO MAXVALUE
-    NO MINVALUE
-    CACHE 1;
-
-
-ALTER SEQUENCE entitlement_id_seq OWNED BY entitlement.id;
-
-
-CREATE VIEW exclusivelocks AS
-    SELECT alllocks.procpid, alllocks.usename, alllocks.age, alllocks.relname, alllocks.mode, alllocks.granted, alllocks.current_query FROM alllocks WHERE (alllocks.mode !~~ '%Share%'::text);
-
-
-CREATE TABLE faq (
+    date_created timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL
+);
+
+
+COMMENT ON COLUMN public.emailaddress.email IS 'An email address used by a Person. The email address is stored in a casesensitive way, but must be case insensitivly unique.';
+
+
+CREATE SEQUENCE public.emailaddress_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER SEQUENCE public.emailaddress_id_seq OWNED BY public.emailaddress.id;
+
+
+CREATE TABLE public.faq (
     id integer NOT NULL,
     title text NOT NULL,
     tags text,
@@ -8856,81 +7898,81 @@
     date_created timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL,
     last_updated_by integer,
     date_last_updated timestamp without time zone,
-    fti ts2.tsvector,
+    fti public.ts2_tsvector,
     CONSTRAINT product_or_distro CHECK (((product IS NULL) <> (distribution IS NULL)))
 );
 
 
-COMMENT ON TABLE faq IS 'A technical document containing the answer to a common question.';
-
-
-COMMENT ON COLUMN faq.id IS 'The FAQ document sequence number.';
-
-
-COMMENT ON COLUMN faq.title IS 'The document title.';
-
-
-COMMENT ON COLUMN faq.tags IS 'White-space separated list of tags.';
-
-
-COMMENT ON COLUMN faq.content IS 'The content of FAQ. It can also contain a short summary and a link.';
-
-
-COMMENT ON COLUMN faq.product IS 'The product to which this document is
+COMMENT ON TABLE public.faq IS 'A technical document containing the answer to a common question.';
+
+
+COMMENT ON COLUMN public.faq.id IS 'The FAQ document sequence number.';
+
+
+COMMENT ON COLUMN public.faq.title IS 'The document title.';
+
+
+COMMENT ON COLUMN public.faq.tags IS 'White-space separated list of tags.';
+
+
+COMMENT ON COLUMN public.faq.content IS 'The content of FAQ. It can also contain a short summary and a link.';
+
+
+COMMENT ON COLUMN public.faq.product IS 'The product to which this document is
 related. Either "product" or "distribution" must be set.';
 
 
-COMMENT ON COLUMN faq.distribution IS 'The distribution to which this document
+COMMENT ON COLUMN public.faq.distribution IS 'The distribution to which this document
 is related. Either "product" or "distribution" must be set.';
 
 
-COMMENT ON COLUMN faq.owner IS 'The person who created the document.';
-
-
-COMMENT ON COLUMN faq.date_created IS 'The datetime when the document was created.';
-
-
-COMMENT ON COLUMN faq.last_updated_by IS 'The person who last modified the document.';
-
-
-COMMENT ON COLUMN faq.date_last_updated IS 'The datetime when the document was last modified.';
-
-
-CREATE SEQUENCE faq_id_seq
+COMMENT ON COLUMN public.faq.owner IS 'The person who created the document.';
+
+
+COMMENT ON COLUMN public.faq.date_created IS 'The datetime when the document was created.';
+
+
+COMMENT ON COLUMN public.faq.last_updated_by IS 'The person who last modified the document.';
+
+
+COMMENT ON COLUMN public.faq.date_last_updated IS 'The datetime when the document was last modified.';
+
+
+CREATE SEQUENCE public.faq_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE faq_id_seq OWNED BY faq.id;
-
-
-CREATE TABLE featuredproject (
+ALTER SEQUENCE public.faq_id_seq OWNED BY public.faq.id;
+
+
+CREATE TABLE public.featuredproject (
     id integer NOT NULL,
     pillar_name integer NOT NULL
 );
 
 
-COMMENT ON TABLE featuredproject IS 'A list of featured projects. This table is really just a list of pillarname IDs, if a project''s pillar name is in this list then it is a featured project and will be listed on the Launchpad home page.';
-
-
-COMMENT ON COLUMN featuredproject.pillar_name IS 'A reference to PillarName.id';
-
-
-CREATE SEQUENCE featuredproject_id_seq
+COMMENT ON TABLE public.featuredproject IS 'A list of featured projects. This table is really just a list of pillarname IDs, if a project''s pillar name is in this list then it is a featured project and will be listed on the Launchpad home page.';
+
+
+COMMENT ON COLUMN public.featuredproject.pillar_name IS 'A reference to PillarName.id';
+
+
+CREATE SEQUENCE public.featuredproject_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE featuredproject_id_seq OWNED BY featuredproject.id;
-
-
-CREATE TABLE featureflag (
+ALTER SEQUENCE public.featuredproject_id_seq OWNED BY public.featuredproject.id;
+
+
+CREATE TABLE public.featureflag (
     scope text NOT NULL,
     priority integer NOT NULL,
     flag text NOT NULL,
@@ -8939,21 +7981,21 @@
 );
 
 
-COMMENT ON TABLE featureflag IS 'Configuration that varies by the active scope and that 
+COMMENT ON TABLE public.featureflag IS 'Configuration that varies by the active scope and that 
 can be changed without restarting Launchpad
 <https://dev.launchpad.net/LEP/FeatureFlags>';
 
 
-COMMENT ON COLUMN featureflag.scope IS 'Scope in which this setting is active';
-
-
-COMMENT ON COLUMN featureflag.priority IS 'Higher priority flags override lower';
-
-
-COMMENT ON COLUMN featureflag.flag IS 'Name of the flag being controlled';
-
-
-CREATE TABLE featureflagchangelogentry (
+COMMENT ON COLUMN public.featureflag.scope IS 'Scope in which this setting is active';
+
+
+COMMENT ON COLUMN public.featureflag.priority IS 'Higher priority flags override lower';
+
+
+COMMENT ON COLUMN public.featureflag.flag IS 'Name of the flag being controlled';
+
+
+CREATE TABLE public.featureflagchangelogentry (
     id integer NOT NULL,
     date_changed timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL,
     diff text NOT NULL,
@@ -8962,63 +8004,435 @@
 );
 
 
-CREATE SEQUENCE featureflagchangelogentry_id_seq
+COMMENT ON TABLE public.featureflagchangelogentry IS 'A record of changes to the FeatureFlag table.';
+
+
+COMMENT ON COLUMN public.featureflagchangelogentry.date_changed IS 'The timestamp for when the change was made';
+
+
+COMMENT ON COLUMN public.featureflagchangelogentry.diff IS 'A unified diff of the change.';
+
+
+COMMENT ON COLUMN public.featureflagchangelogentry.comment IS 'A comment explaining the change.';
+
+
+COMMENT ON COLUMN public.featureflagchangelogentry.person IS 'The person who made this change.';
+
+
+CREATE SEQUENCE public.featureflagchangelogentry_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE featureflagchangelogentry_id_seq OWNED BY featureflagchangelogentry.id;
-
-
-CREATE TABLE flatpackagesetinclusion (
+ALTER SEQUENCE public.featureflagchangelogentry_id_seq OWNED BY public.featureflagchangelogentry.id;
+
+
+CREATE TABLE public.flatpackagesetinclusion (
     id integer NOT NULL,
     parent integer NOT NULL,
     child integer NOT NULL
 );
 
 
-COMMENT ON TABLE flatpackagesetinclusion IS 'In order to facilitate the querying of set-subset relationships an expanded or flattened representation of the set-subset hierarchy is provided by this table.';
-
-
-COMMENT ON COLUMN flatpackagesetinclusion.parent IS 'The package set that is (directly or indirectly) including a subset.';
-
-
-COMMENT ON COLUMN flatpackagesetinclusion.child IS 'The package set that is being included as a subset.';
-
-
-CREATE SEQUENCE flatpackagesetinclusion_id_seq
+COMMENT ON TABLE public.flatpackagesetinclusion IS 'In order to facilitate the querying of set-subset relationships an expanded or flattened representation of the set-subset hierarchy is provided by this table.';
+
+
+COMMENT ON COLUMN public.flatpackagesetinclusion.parent IS 'The package set that is (directly or indirectly) including a subset.';
+
+
+COMMENT ON COLUMN public.flatpackagesetinclusion.child IS 'The package set that is being included as a subset.';
+
+
+CREATE SEQUENCE public.flatpackagesetinclusion_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE flatpackagesetinclusion_id_seq OWNED BY flatpackagesetinclusion.id;
-
-
-CREATE TABLE fticache (
+ALTER SEQUENCE public.flatpackagesetinclusion_id_seq OWNED BY public.flatpackagesetinclusion.id;
+
+
+CREATE TABLE public.fticache (
     id integer NOT NULL,
     tablename text NOT NULL,
     columns text NOT NULL
 );
 
 
-CREATE SEQUENCE fticache_id_seq
-    START WITH 1
-    INCREMENT BY 1
-    NO MAXVALUE
-    NO MINVALUE
-    CACHE 1;
-
-
-ALTER SEQUENCE fticache_id_seq OWNED BY fticache.id;
-
-
-CREATE TABLE gpgkey (
+CREATE SEQUENCE public.fticache_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER SEQUENCE public.fticache_id_seq OWNED BY public.fticache.id;
+
+
+CREATE TABLE public.garbojobstate (
+    name text NOT NULL,
+    json_data text
+);
+
+
+COMMENT ON TABLE public.garbojobstate IS 'Contains persistent state for named garbo jobs.';
+
+
+COMMENT ON COLUMN public.garbojobstate.name IS 'The name of the job.';
+
+
+COMMENT ON COLUMN public.garbojobstate.json_data IS 'A JSON struct containing data for the job.';
+
+
+CREATE TABLE public.gitactivity (
+    id integer NOT NULL,
+    repository integer NOT NULL,
+    date_changed timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL,
+    changer integer NOT NULL,
+    changee integer,
+    what_changed integer NOT NULL,
+    old_value text,
+    new_value text
+);
+
+
+COMMENT ON TABLE public.gitactivity IS 'An activity log entry for a Git repository.';
+
+
+COMMENT ON COLUMN public.gitactivity.repository IS 'The repository that this log entry is for.';
+
+
+COMMENT ON COLUMN public.gitactivity.date_changed IS 'The time when this change happened.';
+
+
+COMMENT ON COLUMN public.gitactivity.changer IS 'The user who made this change.';
+
+
+COMMENT ON COLUMN public.gitactivity.changee IS 'The person or team that this change was applied to.';
+
+
+COMMENT ON COLUMN public.gitactivity.what_changed IS 'The property of the repository that changed.';
+
+
+COMMENT ON COLUMN public.gitactivity.old_value IS 'JSON object representing the value before the change.';
+
+
+COMMENT ON COLUMN public.gitactivity.new_value IS 'JSON object representing the value after the change.';
+
+
+CREATE SEQUENCE public.gitactivity_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER SEQUENCE public.gitactivity_id_seq OWNED BY public.gitactivity.id;
+
+
+CREATE TABLE public.gitjob (
+    job integer NOT NULL,
+    repository integer,
+    job_type integer NOT NULL,
+    json_data text
+);
+
+
+COMMENT ON TABLE public.gitjob IS 'Contains references to jobs that are executed for a Git repository.';
+
+
+COMMENT ON COLUMN public.gitjob.job IS 'A reference to a Job row that has all the common job details.';
+
+
+COMMENT ON COLUMN public.gitjob.repository IS 'The repository that this job is for.';
+
+
+COMMENT ON COLUMN public.gitjob.job_type IS 'The type of job, such as a ref scan.';
+
+
+COMMENT ON COLUMN public.gitjob.json_data IS 'Data that is specific to a particular job type.';
+
+
+CREATE TABLE public.gitref (
+    repository integer NOT NULL,
+    path text NOT NULL,
+    commit_sha1 character(40) NOT NULL,
+    object_type integer NOT NULL,
+    author integer,
+    author_date timestamp without time zone,
+    committer integer,
+    committer_date timestamp without time zone,
+    commit_message text
+);
+
+
+COMMENT ON TABLE public.gitref IS 'A reference in a Git repository.';
+
+
+COMMENT ON COLUMN public.gitref.repository IS 'The repository containing this reference.';
+
+
+COMMENT ON COLUMN public.gitref.path IS 'The full path of the reference, e.g. refs/heads/master.';
+
+
+COMMENT ON COLUMN public.gitref.commit_sha1 IS 'The SHA-1 hash of the object pointed to by this reference.';
+
+
+COMMENT ON COLUMN public.gitref.object_type IS 'The type of object pointed to by this reference.';
+
+
+COMMENT ON COLUMN public.gitref.author IS 'The author of the commit pointed to by this reference.';
+
+
+COMMENT ON COLUMN public.gitref.author_date IS 'The author date of the commit pointed to by this reference.';
+
+
+COMMENT ON COLUMN public.gitref.committer IS 'The committer of the commit pointed to by this reference.';
+
+
+COMMENT ON COLUMN public.gitref.committer_date IS 'The committer date of the commit pointed to by this reference.';
+
+
+COMMENT ON COLUMN public.gitref.commit_message IS 'The commit message of the commit pointed to by this reference.';
+
+
+CREATE TABLE public.gitrepository (
+    id integer NOT NULL,
+    date_created timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL,
+    date_last_modified timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL,
+    registrant integer NOT NULL,
+    owner integer NOT NULL,
+    project integer,
+    distribution integer,
+    sourcepackagename integer,
+    name text NOT NULL,
+    information_type integer NOT NULL,
+    owner_default boolean DEFAULT false NOT NULL,
+    target_default boolean DEFAULT false NOT NULL,
+    access_policy integer,
+    access_grants integer[],
+    description text,
+    reviewer integer,
+    default_branch text,
+    repository_type integer NOT NULL,
+    CONSTRAINT default_implies_target CHECK ((((project IS NOT NULL) OR (distribution IS NOT NULL)) OR ((NOT owner_default) AND (NOT target_default)))),
+    CONSTRAINT one_container CHECK ((((project IS NULL) OR (distribution IS NULL)) AND ((distribution IS NULL) = (sourcepackagename IS NULL)))),
+    CONSTRAINT valid_name CHECK (public.valid_git_repository_name(name))
+);
+
+
+COMMENT ON TABLE public.gitrepository IS 'Git repository';
+
+
+COMMENT ON COLUMN public.gitrepository.registrant IS 'The user who registered the repository.';
+
+
+COMMENT ON COLUMN public.gitrepository.owner IS 'The owner of the repository.';
+
+
+COMMENT ON COLUMN public.gitrepository.project IS 'The project that this repository belongs to.';
+
+
+COMMENT ON COLUMN public.gitrepository.distribution IS 'The distribution that this repository belongs to.';
+
+
+COMMENT ON COLUMN public.gitrepository.sourcepackagename IS 'The source package that this repository belongs to.';
+
+
+COMMENT ON COLUMN public.gitrepository.name IS 'The name of this repository.';
+
+
+COMMENT ON COLUMN public.gitrepository.information_type IS 'Enum describing what type of information is stored, such as type of private or security related data, and used to determine how to apply an access policy.';
+
+
+COMMENT ON COLUMN public.gitrepository.owner_default IS 'True if this repository is the default for its owner and target.';
+
+
+COMMENT ON COLUMN public.gitrepository.target_default IS 'True if this repository is the default for its target.';
+
+
+COMMENT ON COLUMN public.gitrepository.description IS 'A short description of this repository.';
+
+
+COMMENT ON COLUMN public.gitrepository.reviewer IS 'The reviewer (person or) team are able to transition merge proposals targeted at the repository through the CODE_APPROVED state.';
+
+
+COMMENT ON COLUMN public.gitrepository.default_branch IS 'The reference path of this repository''s default branch, or "HEAD".';
+
+
+COMMENT ON COLUMN public.gitrepository.repository_type IS 'Repositories are currently one of HOSTED (1) or IMPORTED (3).';
+
+
+CREATE SEQUENCE public.gitrepository_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER SEQUENCE public.gitrepository_id_seq OWNED BY public.gitrepository.id;
+
+
+CREATE TABLE public.gitrule (
+    id integer NOT NULL,
+    repository integer NOT NULL,
+    "position" integer NOT NULL,
+    ref_pattern text NOT NULL,
+    creator integer NOT NULL,
+    date_created timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL,
+    date_last_modified timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL
+);
+
+
+COMMENT ON TABLE public.gitrule IS 'An access rule for a Git repository.';
+
+
+COMMENT ON COLUMN public.gitrule.repository IS 'The repository that this rule is for.';
+
+
+COMMENT ON COLUMN public.gitrule."position" IS 'The position of this rule in its repository''s rule order.';
+
+
+COMMENT ON COLUMN public.gitrule.ref_pattern IS 'The pattern of references matched by this rule.';
+
+
+COMMENT ON COLUMN public.gitrule.creator IS 'The user who created this rule.';
+
+
+COMMENT ON COLUMN public.gitrule.date_created IS 'The time when this rule was created.';
+
+
+COMMENT ON COLUMN public.gitrule.date_last_modified IS 'The time when this rule was last modified.';
+
+
+CREATE SEQUENCE public.gitrule_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER SEQUENCE public.gitrule_id_seq OWNED BY public.gitrule.id;
+
+
+CREATE TABLE public.gitrulegrant (
+    id integer NOT NULL,
+    repository integer NOT NULL,
+    rule integer NOT NULL,
+    grantee_type integer NOT NULL,
+    grantee integer,
+    can_create boolean DEFAULT false NOT NULL,
+    can_push boolean DEFAULT false NOT NULL,
+    can_force_push boolean DEFAULT false NOT NULL,
+    grantor integer NOT NULL,
+    date_created timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL,
+    date_last_modified timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL,
+    CONSTRAINT has_grantee CHECK (((grantee_type = 2) = (grantee IS NOT NULL)))
+);
+
+
+COMMENT ON TABLE public.gitrulegrant IS 'An access grant for a Git repository rule.';
+
+
+COMMENT ON COLUMN public.gitrulegrant.repository IS 'The repository that this grant is for.';
+
+
+COMMENT ON COLUMN public.gitrulegrant.rule IS 'The rule that this grant is for.';
+
+
+COMMENT ON COLUMN public.gitrulegrant.grantee_type IS 'The type of entity being granted access.';
+
+
+COMMENT ON COLUMN public.gitrulegrant.grantee IS 'The person or team being granted access.';
+
+
+COMMENT ON COLUMN public.gitrulegrant.can_create IS 'Whether creating references is allowed.';
+
+
+COMMENT ON COLUMN public.gitrulegrant.can_push IS 'Whether pushing references is allowed.';
+
+
+COMMENT ON COLUMN public.gitrulegrant.can_force_push IS 'Whether force-pushing references is allowed.';
+
+
+COMMENT ON COLUMN public.gitrulegrant.grantor IS 'The user who created this grant.';
+
+
+COMMENT ON COLUMN public.gitrulegrant.date_created IS 'The time when this grant was created.';
+
+
+COMMENT ON COLUMN public.gitrulegrant.date_last_modified IS 'The time when this grant was last modified.';
+
+
+CREATE SEQUENCE public.gitrulegrant_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER SEQUENCE public.gitrulegrant_id_seq OWNED BY public.gitrulegrant.id;
+
+
+CREATE TABLE public.gitsubscription (
+    id integer NOT NULL,
+    person integer NOT NULL,
+    repository integer NOT NULL,
+    date_created timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL,
+    notification_level integer DEFAULT 1 NOT NULL,
+    max_diff_lines integer,
+    review_level integer DEFAULT 0 NOT NULL,
+    subscribed_by integer NOT NULL,
+    paths text
+);
+
+
+COMMENT ON TABLE public.gitsubscription IS 'An association between a person or team and a Git repository.';
+
+
+COMMENT ON COLUMN public.gitsubscription.person IS 'The person or team associated with the repository.';
+
+
+COMMENT ON COLUMN public.gitsubscription.repository IS 'The repository associated with the person or team.';
+
+
+COMMENT ON COLUMN public.gitsubscription.notification_level IS 'The level of email the person wants to receive from repository updates.';
+
+
+COMMENT ON COLUMN public.gitsubscription.max_diff_lines IS 'If the generated diff for a revision is larger than this number, then the diff is not sent in the notification email.';
+
+
+COMMENT ON COLUMN public.gitsubscription.review_level IS 'The level of email the person wants to receive from review activity.';
+
+
+COMMENT ON COLUMN public.gitsubscription.subscribed_by IS 'The person who created this subscription.';
+
+
+COMMENT ON COLUMN public.gitsubscription.paths IS 'A JSON-encoded list of patterns matching subscribed reference paths.';
+
+
+CREATE SEQUENCE public.gitsubscription_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER SEQUENCE public.gitsubscription_id_seq OWNED BY public.gitsubscription.id;
+
+
+CREATE TABLE public.gpgkey (
     id integer NOT NULL,
     owner integer NOT NULL,
     keyid text NOT NULL,
@@ -9028,44 +8442,44 @@
     keysize integer NOT NULL,
     can_encrypt boolean DEFAULT false NOT NULL,
     date_created timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL,
-    CONSTRAINT valid_fingerprint CHECK (valid_fingerprint(fingerprint)),
-    CONSTRAINT valid_keyid CHECK (valid_keyid(keyid))
+    CONSTRAINT valid_fingerprint CHECK (public.valid_fingerprint(fingerprint)),
+    CONSTRAINT valid_keyid CHECK (public.valid_keyid(keyid))
 );
 
 
-COMMENT ON TABLE gpgkey IS 'A GPG key belonging to a Person';
-
-
-COMMENT ON COLUMN gpgkey.keyid IS 'The 8 character GPG key id, uppercase and no whitespace';
-
-
-COMMENT ON COLUMN gpgkey.fingerprint IS 'The 40 character GPG fingerprint, uppercase and no whitespace';
-
-
-COMMENT ON COLUMN gpgkey.active IS 'True if this key is active for use in Launchpad context, false could be deactivated by user or revoked in the global key ring.';
-
-
-COMMENT ON COLUMN gpgkey.algorithm IS 'The algorithm used to generate this key. Valid values defined in dbschema.GPGKeyAlgorithms';
-
-
-COMMENT ON COLUMN gpgkey.keysize IS 'Size of the key in bits, as reported by GPG. We may refuse to deal with keysizes < 768 bits in the future.';
-
-
-COMMENT ON COLUMN gpgkey.can_encrypt IS 'Whether the key has been validated for use in encryption (as opposed to just signing)';
-
-
-CREATE SEQUENCE gpgkey_id_seq
+COMMENT ON TABLE public.gpgkey IS 'A GPG key belonging to a Person';
+
+
+COMMENT ON COLUMN public.gpgkey.keyid IS 'The 8 character GPG key id, uppercase and no whitespace';
+
+
+COMMENT ON COLUMN public.gpgkey.fingerprint IS 'The 40 character GPG fingerprint, uppercase and no whitespace';
+
+
+COMMENT ON COLUMN public.gpgkey.active IS 'True if this key is active for use in Launchpad context, false could be deactivated by user or revoked in the global key ring.';
+
+
+COMMENT ON COLUMN public.gpgkey.algorithm IS 'The algorithm used to generate this key. Valid values defined in dbschema.GPGKeyAlgorithms';
+
+
+COMMENT ON COLUMN public.gpgkey.keysize IS 'Size of the key in bits, as reported by GPG. We may refuse to deal with keysizes < 768 bits in the future.';
+
+
+COMMENT ON COLUMN public.gpgkey.can_encrypt IS 'Whether the key has been validated for use in encryption (as opposed to just signing)';
+
+
+CREATE SEQUENCE public.gpgkey_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE gpgkey_id_seq OWNED BY gpgkey.id;
-
-
-CREATE TABLE hwdevice (
+ALTER SEQUENCE public.gpgkey_id_seq OWNED BY public.gpgkey.id;
+
+
+CREATE TABLE public.hwdevice (
     id integer NOT NULL,
     bus_vendor_id integer NOT NULL,
     bus_product_id text NOT NULL,
@@ -9075,36 +8489,36 @@
 );
 
 
-COMMENT ON TABLE hwdevice IS 'Basic information on devices.';
-
-
-COMMENT ON COLUMN hwdevice.bus_vendor_id IS 'A reference to a HWVendorID record.';
-
-
-COMMENT ON COLUMN hwdevice.bus_product_id IS 'The bus product ID of a device';
-
-
-COMMENT ON COLUMN hwdevice.variant IS 'An optional additional description for a device that shares its vendor and product ID with another, technically different, device.';
-
-
-COMMENT ON COLUMN hwdevice.name IS 'The human readable product name of the device.';
-
-
-COMMENT ON COLUMN hwdevice.submissions IS 'The number of submissions that contain this device.';
-
-
-CREATE SEQUENCE hwdevice_id_seq
+COMMENT ON TABLE public.hwdevice IS 'Basic information on devices.';
+
+
+COMMENT ON COLUMN public.hwdevice.bus_vendor_id IS 'A reference to a HWVendorID record.';
+
+
+COMMENT ON COLUMN public.hwdevice.bus_product_id IS 'The bus product ID of a device';
+
+
+COMMENT ON COLUMN public.hwdevice.variant IS 'An optional additional description for a device that shares its vendor and product ID with another, technically different, device.';
+
+
+COMMENT ON COLUMN public.hwdevice.name IS 'The human readable product name of the device.';
+
+
+COMMENT ON COLUMN public.hwdevice.submissions IS 'The number of submissions that contain this device.';
+
+
+CREATE SEQUENCE public.hwdevice_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE hwdevice_id_seq OWNED BY hwdevice.id;
-
-
-CREATE TABLE hwdeviceclass (
+ALTER SEQUENCE public.hwdevice_id_seq OWNED BY public.hwdevice.id;
+
+
+CREATE TABLE public.hwdeviceclass (
     id integer NOT NULL,
     device integer NOT NULL,
     main_class integer NOT NULL,
@@ -9112,57 +8526,57 @@
 );
 
 
-COMMENT ON TABLE hwdeviceclass IS 'Capabilities of a device.';
-
-
-COMMENT ON COLUMN hwdeviceclass.device IS 'A reference to a device.';
-
-
-COMMENT ON COLUMN hwdeviceclass.main_class IS 'The main class of a device. Legal values are defined by the HWMainClass enumeration.';
-
-
-COMMENT ON COLUMN hwdeviceclass.sub_class IS 'The sub-class of a device. Legal values are defined by the HWSubClass enumeration.';
-
-
-CREATE SEQUENCE hwdeviceclass_id_seq
+COMMENT ON TABLE public.hwdeviceclass IS 'Capabilities of a device.';
+
+
+COMMENT ON COLUMN public.hwdeviceclass.device IS 'A reference to a device.';
+
+
+COMMENT ON COLUMN public.hwdeviceclass.main_class IS 'The main class of a device. Legal values are defined by the HWMainClass enumeration.';
+
+
+COMMENT ON COLUMN public.hwdeviceclass.sub_class IS 'The sub-class of a device. Legal values are defined by the HWSubClass enumeration.';
+
+
+CREATE SEQUENCE public.hwdeviceclass_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE hwdeviceclass_id_seq OWNED BY hwdeviceclass.id;
-
-
-CREATE TABLE hwdevicedriverlink (
+ALTER SEQUENCE public.hwdeviceclass_id_seq OWNED BY public.hwdeviceclass.id;
+
+
+CREATE TABLE public.hwdevicedriverlink (
     id integer NOT NULL,
     device integer NOT NULL,
     driver integer
 );
 
 
-COMMENT ON TABLE hwdevicedriverlink IS 'Combinations of devices and drivers mentioned in submissions.';
-
-
-COMMENT ON COLUMN hwdevicedriverlink.device IS 'The device controlled by the driver.';
-
-
-COMMENT ON COLUMN hwdevicedriverlink.driver IS 'The driver controlling the device.';
-
-
-CREATE SEQUENCE hwdevicedriverlink_id_seq
+COMMENT ON TABLE public.hwdevicedriverlink IS 'Combinations of devices and drivers mentioned in submissions.';
+
+
+COMMENT ON COLUMN public.hwdevicedriverlink.device IS 'The device controlled by the driver.';
+
+
+COMMENT ON COLUMN public.hwdevicedriverlink.driver IS 'The driver controlling the device.';
+
+
+CREATE SEQUENCE public.hwdevicedriverlink_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE hwdevicedriverlink_id_seq OWNED BY hwdevicedriverlink.id;
-
-
-CREATE TABLE hwdevicenamevariant (
+ALTER SEQUENCE public.hwdevicedriverlink_id_seq OWNED BY public.hwdevicedriverlink.id;
+
+
+CREATE TABLE public.hwdevicenamevariant (
     id integer NOT NULL,
     vendor_name integer NOT NULL,
     product_name text NOT NULL,
@@ -9171,33 +8585,33 @@
 );
 
 
-COMMENT ON TABLE hwdevicenamevariant IS 'Alternative vendor and product names of devices.';
-
-
-COMMENT ON COLUMN hwdevicenamevariant.vendor_name IS 'The alternative vendor name.';
-
-
-COMMENT ON COLUMN hwdevicenamevariant.product_name IS 'The alternative product name.';
-
-
-COMMENT ON COLUMN hwdevicenamevariant.device IS 'The device named by this alternative vendor and product names.';
-
-
-COMMENT ON COLUMN hwdevicenamevariant.submissions IS 'The number of submissions containing this alternative vendor and product name.';
-
-
-CREATE SEQUENCE hwdevicenamevariant_id_seq
+COMMENT ON TABLE public.hwdevicenamevariant IS 'Alternative vendor and product names of devices.';
+
+
+COMMENT ON COLUMN public.hwdevicenamevariant.vendor_name IS 'The alternative vendor name.';
+
+
+COMMENT ON COLUMN public.hwdevicenamevariant.product_name IS 'The alternative product name.';
+
+
+COMMENT ON COLUMN public.hwdevicenamevariant.device IS 'The device named by this alternative vendor and product names.';
+
+
+COMMENT ON COLUMN public.hwdevicenamevariant.submissions IS 'The number of submissions containing this alternative vendor and product name.';
+
+
+CREATE SEQUENCE public.hwdevicenamevariant_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE hwdevicenamevariant_id_seq OWNED BY hwdevicenamevariant.id;
-
-
-CREATE TABLE hwdmihandle (
+ALTER SEQUENCE public.hwdevicenamevariant_id_seq OWNED BY public.hwdevicenamevariant.id;
+
+
+CREATE TABLE public.hwdmihandle (
     id integer NOT NULL,
     handle integer NOT NULL,
     type integer NOT NULL,
@@ -9205,27 +8619,27 @@
 );
 
 
-COMMENT ON TABLE hwdmihandle IS 'A DMI Handle appearing in the DMI data of a submission.';
-
-
-COMMENT ON COLUMN hwdmihandle.handle IS 'The ID of the handle.';
-
-
-COMMENT ON COLUMN hwdmihandle.type IS 'The type of the handle.';
-
-
-CREATE SEQUENCE hwdmihandle_id_seq
+COMMENT ON TABLE public.hwdmihandle IS 'A DMI Handle appearing in the DMI data of a submission.';
+
+
+COMMENT ON COLUMN public.hwdmihandle.handle IS 'The ID of the handle.';
+
+
+COMMENT ON COLUMN public.hwdmihandle.type IS 'The type of the handle.';
+
+
+CREATE SEQUENCE public.hwdmihandle_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE hwdmihandle_id_seq OWNED BY hwdmihandle.id;
-
-
-CREATE TABLE hwdmivalue (
+ALTER SEQUENCE public.hwdmihandle_id_seq OWNED BY public.hwdmihandle.id;
+
+
+CREATE TABLE public.hwdmivalue (
     id integer NOT NULL,
     key text,
     value text,
@@ -9233,30 +8647,30 @@
 );
 
 
-COMMENT ON TABLE hwdmivalue IS 'Key/value pairs of DMI data of a handle.';
-
-
-COMMENT ON COLUMN hwdmivalue.key IS 'The key.';
-
-
-COMMENT ON COLUMN hwdmivalue.value IS 'The value';
-
-
-COMMENT ON COLUMN hwdmivalue.handle IS 'The handle to which this key/value pair belongs.';
-
-
-CREATE SEQUENCE hwdmivalue_id_seq
+COMMENT ON TABLE public.hwdmivalue IS 'Key/value pairs of DMI data of a handle.';
+
+
+COMMENT ON COLUMN public.hwdmivalue.key IS 'The key.';
+
+
+COMMENT ON COLUMN public.hwdmivalue.value IS 'The value';
+
+
+COMMENT ON COLUMN public.hwdmivalue.handle IS 'The handle to which this key/value pair belongs.';
+
+
+CREATE SEQUENCE public.hwdmivalue_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE hwdmivalue_id_seq OWNED BY hwdmivalue.id;
-
-
-CREATE TABLE hwdriver (
+ALTER SEQUENCE public.hwdmivalue_id_seq OWNED BY public.hwdmivalue.id;
+
+
+CREATE TABLE public.hwdriver (
     id integer NOT NULL,
     package_name text,
     name text NOT NULL,
@@ -9264,47 +8678,53 @@
 );
 
 
-COMMENT ON TABLE hwdriver IS 'Information about a driver for a device';
-
-
-COMMENT ON COLUMN hwdriver.package_name IS 'The Debian package name a driver is a part of';
-
-
-COMMENT ON COLUMN hwdriver.name IS 'The name of a driver.';
-
-
-CREATE SEQUENCE hwdriver_id_seq
+COMMENT ON TABLE public.hwdriver IS 'Information about a driver for a device';
+
+
+COMMENT ON COLUMN public.hwdriver.package_name IS 'The Debian package name a driver is a part of';
+
+
+COMMENT ON COLUMN public.hwdriver.name IS 'The name of a driver.';
+
+
+CREATE SEQUENCE public.hwdriver_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE hwdriver_id_seq OWNED BY hwdriver.id;
-
-
-CREATE VIEW hwdrivernames AS
-    SELECT DISTINCT ON (hwdriver.name) hwdriver.id, hwdriver.name FROM hwdriver ORDER BY hwdriver.name, hwdriver.id;
-
-
-COMMENT ON VIEW hwdrivernames IS 'A view returning the distinct driver names stored in HWDriver.';
-
-
-COMMENT ON COLUMN hwdrivernames.name IS 'The name of a driver.';
-
-
-CREATE VIEW hwdriverpackagenames AS
-    SELECT DISTINCT ON (hwdriver.package_name) hwdriver.id, hwdriver.package_name FROM hwdriver ORDER BY hwdriver.package_name, hwdriver.id;
-
-
-COMMENT ON VIEW hwdriverpackagenames IS 'A view returning the distinct Debian package names stored in HWDriver.';
-
-
-COMMENT ON COLUMN hwdriverpackagenames.package_name IS 'The Debian package name a driver is a part of.';
-
-
-CREATE TABLE hwsubmission (
+ALTER SEQUENCE public.hwdriver_id_seq OWNED BY public.hwdriver.id;
+
+
+CREATE VIEW public.hwdrivernames AS
+ SELECT DISTINCT ON (hwdriver.name) hwdriver.id,
+    hwdriver.name
+   FROM public.hwdriver
+  ORDER BY hwdriver.name, hwdriver.id;
+
+
+COMMENT ON VIEW public.hwdrivernames IS 'A view returning the distinct driver names stored in HWDriver.';
+
+
+COMMENT ON COLUMN public.hwdrivernames.name IS 'The name of a driver.';
+
+
+CREATE VIEW public.hwdriverpackagenames AS
+ SELECT DISTINCT ON (hwdriver.package_name) hwdriver.id,
+    hwdriver.package_name
+   FROM public.hwdriver
+  ORDER BY hwdriver.package_name, hwdriver.id;
+
+
+COMMENT ON VIEW public.hwdriverpackagenames IS 'A view returning the distinct Debian package names stored in HWDriver.';
+
+
+COMMENT ON COLUMN public.hwdriverpackagenames.package_name IS 'The Debian package name a driver is a part of.';
+
+
+CREATE TABLE public.hwsubmission (
     id integer NOT NULL,
     date_created timestamp without time zone NOT NULL,
     date_submitted timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL,
@@ -9321,78 +8741,78 @@
 );
 
 
-COMMENT ON TABLE hwsubmission IS 'Raw HWDB submission data';
-
-
-COMMENT ON COLUMN hwsubmission.date_created IS 'Date and time of the submission (generated by the client).';
-
-
-COMMENT ON COLUMN hwsubmission.date_submitted IS 'Date and time of the submission (generated by the server).';
-
-
-COMMENT ON COLUMN hwsubmission.format IS 'The format version of the submitted data, as given by the HWDB client. See HWSubmissionFormat for valid values.';
-
-
-COMMENT ON COLUMN hwsubmission.status IS 'The status of the submission. See HWSubmissionProcessingStatus for valid values.';
-
-
-COMMENT ON COLUMN hwsubmission.private IS 'If false, the submitter allows public access to the data. If true, the data may be used only for statistical purposes.';
-
-
-COMMENT ON COLUMN hwsubmission.contactable IS 'If True, the submitter agrees to be contacted by upstream developers and package maintainers for tests etc.';
-
-
-COMMENT ON COLUMN hwsubmission.submission_key IS 'A unique submission ID.';
-
-
-COMMENT ON COLUMN hwsubmission.owner IS 'A reference to the Person table: The owner/submitter of the data.';
-
-
-COMMENT ON COLUMN hwsubmission.distroarchseries IS 'A reference to the distroarchseries of the submission. This value is null, if the submitted values for distribution, distroseries and architecture do not match an existing entry in the Distroarchseries table.';
-
-
-COMMENT ON COLUMN hwsubmission.raw_submission IS 'A reference to a row of LibraryFileAlias. The library file contains the raw submission data.';
-
-
-COMMENT ON COLUMN hwsubmission.system_fingerprint IS 'A reference to an entry of the HWDBSystemFingerPrint table. This table stores the system name as returned by HAL (system.vendor, system.product)';
-
-
-COMMENT ON COLUMN hwsubmission.raw_emailaddress IS 'The email address of the submitter.';
-
-
-CREATE SEQUENCE hwsubmission_id_seq
+COMMENT ON TABLE public.hwsubmission IS 'Raw HWDB submission data';
+
+
+COMMENT ON COLUMN public.hwsubmission.date_created IS 'Date and time of the submission (generated by the client).';
+
+
+COMMENT ON COLUMN public.hwsubmission.date_submitted IS 'Date and time of the submission (generated by the server).';
+
+
+COMMENT ON COLUMN public.hwsubmission.format IS 'The format version of the submitted data, as given by the HWDB client. See HWSubmissionFormat for valid values.';
+
+
+COMMENT ON COLUMN public.hwsubmission.status IS 'The status of the submission. See HWSubmissionProcessingStatus for valid values.';
+
+
+COMMENT ON COLUMN public.hwsubmission.private IS 'If false, the submitter allows public access to the data. If true, the data may be used only for statistical purposes.';
+
+
+COMMENT ON COLUMN public.hwsubmission.contactable IS 'If True, the submitter agrees to be contacted by upstream developers and package maintainers for tests etc.';
+
+
+COMMENT ON COLUMN public.hwsubmission.submission_key IS 'A unique submission ID.';
+
+
+COMMENT ON COLUMN public.hwsubmission.owner IS 'A reference to the Person table: The owner/submitter of the data.';
+
+
+COMMENT ON COLUMN public.hwsubmission.distroarchseries IS 'A reference to the distroarchseries of the submission. This value is null, if the submitted values for distribution, distroseries and architecture do not match an existing entry in the Distroarchseries table.';
+
+
+COMMENT ON COLUMN public.hwsubmission.raw_submission IS 'A reference to a row of LibraryFileAlias. The library file contains the raw submission data.';
+
+
+COMMENT ON COLUMN public.hwsubmission.system_fingerprint IS 'A reference to an entry of the HWDBSystemFingerPrint table. This table stores the system name as returned by HAL (system.vendor, system.product)';
+
+
+COMMENT ON COLUMN public.hwsubmission.raw_emailaddress IS 'The email address of the submitter.';
+
+
+CREATE SEQUENCE public.hwsubmission_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE hwsubmission_id_seq OWNED BY hwsubmission.id;
-
-
-CREATE TABLE hwsubmissionbug (
+ALTER SEQUENCE public.hwsubmission_id_seq OWNED BY public.hwsubmission.id;
+
+
+CREATE TABLE public.hwsubmissionbug (
     id integer NOT NULL,
     submission integer NOT NULL,
     bug integer NOT NULL
 );
 
 
-COMMENT ON TABLE hwsubmissionbug IS 'Link bugs to HWDB submissions';
-
-
-CREATE SEQUENCE hwsubmissionbug_id_seq
+COMMENT ON TABLE public.hwsubmissionbug IS 'Link bugs to HWDB submissions';
+
+
+CREATE SEQUENCE public.hwsubmissionbug_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE hwsubmissionbug_id_seq OWNED BY hwsubmissionbug.id;
-
-
-CREATE TABLE hwsubmissiondevice (
+ALTER SEQUENCE public.hwsubmissionbug_id_seq OWNED BY public.hwsubmissionbug.id;
+
+
+CREATE TABLE public.hwsubmissiondevice (
     id integer NOT NULL,
     device_driver_link integer NOT NULL,
     submission integer NOT NULL,
@@ -9401,56 +8821,56 @@
 );
 
 
-COMMENT ON TABLE hwsubmissiondevice IS 'Links between devices and submissions.';
-
-
-COMMENT ON COLUMN hwsubmissiondevice.device_driver_link IS 'The combination (device, driver) mentioned in a submission.';
-
-
-COMMENT ON COLUMN hwsubmissiondevice.submission IS 'The submission mentioning this (device, driver) combination.';
-
-
-COMMENT ON COLUMN hwsubmissiondevice.parent IS 'The parent device of this device.';
-
-
-COMMENT ON COLUMN hwsubmissiondevice.hal_device_id IS 'The ID of the HAL node of this device in the submitted data.';
-
-
-CREATE SEQUENCE hwsubmissiondevice_id_seq
+COMMENT ON TABLE public.hwsubmissiondevice IS 'Links between devices and submissions.';
+
+
+COMMENT ON COLUMN public.hwsubmissiondevice.device_driver_link IS 'The combination (device, driver) mentioned in a submission.';
+
+
+COMMENT ON COLUMN public.hwsubmissiondevice.submission IS 'The submission mentioning this (device, driver) combination.';
+
+
+COMMENT ON COLUMN public.hwsubmissiondevice.parent IS 'The parent device of this device.';
+
+
+COMMENT ON COLUMN public.hwsubmissiondevice.hal_device_id IS 'The ID of the HAL node of this device in the submitted data.';
+
+
+CREATE SEQUENCE public.hwsubmissiondevice_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE hwsubmissiondevice_id_seq OWNED BY hwsubmissiondevice.id;
-
-
-CREATE TABLE hwsystemfingerprint (
+ALTER SEQUENCE public.hwsubmissiondevice_id_seq OWNED BY public.hwsubmissiondevice.id;
+
+
+CREATE TABLE public.hwsystemfingerprint (
     id integer NOT NULL,
     fingerprint text NOT NULL
 );
 
 
-COMMENT ON TABLE hwsystemfingerprint IS 'A distinct list of "fingerprints" (HAL system.name, system.vendor) from raw submission data';
-
-
-COMMENT ON COLUMN hwsystemfingerprint.fingerprint IS 'The fingerprint';
-
-
-CREATE SEQUENCE hwsystemfingerprint_id_seq
+COMMENT ON TABLE public.hwsystemfingerprint IS 'A distinct list of "fingerprints" (HAL system.name, system.vendor) from raw submission data';
+
+
+COMMENT ON COLUMN public.hwsystemfingerprint.fingerprint IS 'The fingerprint';
+
+
+CREATE SEQUENCE public.hwsystemfingerprint_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE hwsystemfingerprint_id_seq OWNED BY hwsystemfingerprint.id;
-
-
-CREATE TABLE hwtest (
+ALTER SEQUENCE public.hwsystemfingerprint_id_seq OWNED BY public.hwsystemfingerprint.id;
+
+
+CREATE TABLE public.hwtest (
     id integer NOT NULL,
     namespace text,
     name text NOT NULL,
@@ -9458,27 +8878,27 @@
 );
 
 
-COMMENT ON TABLE hwtest IS 'General information about a device test.';
-
-
-COMMENT ON COLUMN hwtest.namespace IS 'The namespace of a test.';
-
-
-COMMENT ON COLUMN hwtest.name IS 'The name of a test.';
-
-
-CREATE SEQUENCE hwtest_id_seq
+COMMENT ON TABLE public.hwtest IS 'General information about a device test.';
+
+
+COMMENT ON COLUMN public.hwtest.namespace IS 'The namespace of a test.';
+
+
+COMMENT ON COLUMN public.hwtest.name IS 'The name of a test.';
+
+
+CREATE SEQUENCE public.hwtest_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE hwtest_id_seq OWNED BY hwtest.id;
-
-
-CREATE TABLE hwtestanswer (
+ALTER SEQUENCE public.hwtest_id_seq OWNED BY public.hwtest.id;
+
+
+CREATE TABLE public.hwtestanswer (
     id integer NOT NULL,
     test integer NOT NULL,
     choice integer,
@@ -9492,63 +8912,63 @@
 );
 
 
-COMMENT ON TABLE hwtestanswer IS 'The answer for a test from a submission. This can be either a multiple choice selection or a numerical value. Exactly one of the columns choice, intval, floatval must be non-null.';
-
-
-COMMENT ON COLUMN hwtestanswer.test IS 'The test answered by this answer.';
-
-
-COMMENT ON COLUMN hwtestanswer.choice IS 'The selected value of a multiple choice test.';
-
-
-COMMENT ON COLUMN hwtestanswer.intval IS 'The integer result of a test with a numerical result.';
-
-
-COMMENT ON COLUMN hwtestanswer.floatval IS 'The double precision floating point number result of a test with a numerical result.';
-
-
-COMMENT ON COLUMN hwtestanswer.unit IS 'The physical unit of a test with a numerical result.';
-
-
-CREATE SEQUENCE hwtestanswer_id_seq
+COMMENT ON TABLE public.hwtestanswer IS 'The answer for a test from a submission. This can be either a multiple choice selection or a numerical value. Exactly one of the columns choice, intval, floatval must be non-null.';
+
+
+COMMENT ON COLUMN public.hwtestanswer.test IS 'The test answered by this answer.';
+
+
+COMMENT ON COLUMN public.hwtestanswer.choice IS 'The selected value of a multiple choice test.';
+
+
+COMMENT ON COLUMN public.hwtestanswer.intval IS 'The integer result of a test with a numerical result.';
+
+
+COMMENT ON COLUMN public.hwtestanswer.floatval IS 'The double precision floating point number result of a test with a numerical result.';
+
+
+COMMENT ON COLUMN public.hwtestanswer.unit IS 'The physical unit of a test with a numerical result.';
+
+
+CREATE SEQUENCE public.hwtestanswer_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE hwtestanswer_id_seq OWNED BY hwtestanswer.id;
-
-
-CREATE TABLE hwtestanswerchoice (
+ALTER SEQUENCE public.hwtestanswer_id_seq OWNED BY public.hwtestanswer.id;
+
+
+CREATE TABLE public.hwtestanswerchoice (
     id integer NOT NULL,
     choice text NOT NULL,
     test integer NOT NULL
 );
 
 
-COMMENT ON TABLE hwtestanswerchoice IS 'Choice values of multiple choice tests/questions.';
-
-
-COMMENT ON COLUMN hwtestanswerchoice.choice IS 'The choice value.';
-
-
-COMMENT ON COLUMN hwtestanswerchoice.test IS 'The test this choice belongs to.';
-
-
-CREATE SEQUENCE hwtestanswerchoice_id_seq
+COMMENT ON TABLE public.hwtestanswerchoice IS 'Choice values of multiple choice tests/questions.';
+
+
+COMMENT ON COLUMN public.hwtestanswerchoice.choice IS 'The choice value.';
+
+
+COMMENT ON COLUMN public.hwtestanswerchoice.test IS 'The test this choice belongs to.';
+
+
+CREATE SEQUENCE public.hwtestanswerchoice_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE hwtestanswerchoice_id_seq OWNED BY hwtestanswerchoice.id;
-
-
-CREATE TABLE hwtestanswercount (
+ALTER SEQUENCE public.hwtestanswerchoice_id_seq OWNED BY public.hwtestanswerchoice.id;
+
+
+CREATE TABLE public.hwtestanswercount (
     id integer NOT NULL,
     test integer NOT NULL,
     distroarchseries integer,
@@ -9561,96 +8981,96 @@
 );
 
 
-COMMENT ON TABLE hwtestanswercount IS 'Accumulated results of tests. Either the column choice or the columns average and sum_square must be non-null.';
-
-
-COMMENT ON COLUMN hwtestanswercount.test IS 'The test.';
-
-
-COMMENT ON COLUMN hwtestanswercount.distroarchseries IS 'The distroarchseries for which results are accumulated,';
-
-
-COMMENT ON COLUMN hwtestanswercount.choice IS 'The choice value of a multiple choice test.';
-
-
-COMMENT ON COLUMN hwtestanswercount.average IS 'The average value of the result of a numerical test.';
-
-
-COMMENT ON COLUMN hwtestanswercount.sum_square IS 'The sum of the squares of the results of a numerical test.';
-
-
-COMMENT ON COLUMN hwtestanswercount.unit IS 'The physical unit of a numerical test result.';
-
-
-COMMENT ON COLUMN hwtestanswercount.num_answers IS 'The number of submissions from which the result is accumulated.';
-
-
-CREATE SEQUENCE hwtestanswercount_id_seq
-    START WITH 1
-    INCREMENT BY 1
-    NO MAXVALUE
-    NO MINVALUE
-    CACHE 1;
-
-
-ALTER SEQUENCE hwtestanswercount_id_seq OWNED BY hwtestanswercount.id;
-
-
-CREATE TABLE hwtestanswercountdevice (
-    id integer NOT NULL,
-    answer integer NOT NULL,
-    device_driver integer NOT NULL
-);
-
-
-COMMENT ON TABLE hwtestanswercountdevice IS 'Association of accumulated test results and device/driver combinations.';
-
-
-COMMENT ON COLUMN hwtestanswercountdevice.answer IS 'The test answer.';
-
-
-COMMENT ON COLUMN hwtestanswercountdevice.device_driver IS 'The device/driver combination.';
-
-
-CREATE SEQUENCE hwtestanswercountdevice_id_seq
-    START WITH 1
-    INCREMENT BY 1
-    NO MAXVALUE
-    NO MINVALUE
-    CACHE 1;
-
-
-ALTER SEQUENCE hwtestanswercountdevice_id_seq OWNED BY hwtestanswercountdevice.id;
-
-
-CREATE TABLE hwtestanswerdevice (
-    id integer NOT NULL,
-    answer integer NOT NULL,
-    device_driver integer NOT NULL
-);
-
-
-COMMENT ON TABLE hwtestanswerdevice IS 'Association of test results and device/driver combinations.';
-
-
-COMMENT ON COLUMN hwtestanswerdevice.answer IS 'The test answer.';
-
-
-COMMENT ON COLUMN hwtestanswerdevice.device_driver IS 'The device/driver combination.';
-
-
-CREATE SEQUENCE hwtestanswerdevice_id_seq
-    START WITH 1
-    INCREMENT BY 1
-    NO MAXVALUE
-    NO MINVALUE
-    CACHE 1;
-
-
-ALTER SEQUENCE hwtestanswerdevice_id_seq OWNED BY hwtestanswerdevice.id;
-
-
-CREATE TABLE hwvendorid (
+COMMENT ON TABLE public.hwtestanswercount IS 'Accumulated results of tests. Either the column choice or the columns average and sum_square must be non-null.';
+
+
+COMMENT ON COLUMN public.hwtestanswercount.test IS 'The test.';
+
+
+COMMENT ON COLUMN public.hwtestanswercount.distroarchseries IS 'The distroarchseries for which results are accumulated,';
+
+
+COMMENT ON COLUMN public.hwtestanswercount.choice IS 'The choice value of a multiple choice test.';
+
+
+COMMENT ON COLUMN public.hwtestanswercount.average IS 'The average value of the result of a numerical test.';
+
+
+COMMENT ON COLUMN public.hwtestanswercount.sum_square IS 'The sum of the squares of the results of a numerical test.';
+
+
+COMMENT ON COLUMN public.hwtestanswercount.unit IS 'The physical unit of a numerical test result.';
+
+
+COMMENT ON COLUMN public.hwtestanswercount.num_answers IS 'The number of submissions from which the result is accumulated.';
+
+
+CREATE SEQUENCE public.hwtestanswercount_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER SEQUENCE public.hwtestanswercount_id_seq OWNED BY public.hwtestanswercount.id;
+
+
+CREATE TABLE public.hwtestanswercountdevice (
+    id integer NOT NULL,
+    answer integer NOT NULL,
+    device_driver integer NOT NULL
+);
+
+
+COMMENT ON TABLE public.hwtestanswercountdevice IS 'Association of accumulated test results and device/driver combinations.';
+
+
+COMMENT ON COLUMN public.hwtestanswercountdevice.answer IS 'The test answer.';
+
+
+COMMENT ON COLUMN public.hwtestanswercountdevice.device_driver IS 'The device/driver combination.';
+
+
+CREATE SEQUENCE public.hwtestanswercountdevice_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER SEQUENCE public.hwtestanswercountdevice_id_seq OWNED BY public.hwtestanswercountdevice.id;
+
+
+CREATE TABLE public.hwtestanswerdevice (
+    id integer NOT NULL,
+    answer integer NOT NULL,
+    device_driver integer NOT NULL
+);
+
+
+COMMENT ON TABLE public.hwtestanswerdevice IS 'Association of test results and device/driver combinations.';
+
+
+COMMENT ON COLUMN public.hwtestanswerdevice.answer IS 'The test answer.';
+
+
+COMMENT ON COLUMN public.hwtestanswerdevice.device_driver IS 'The device/driver combination.';
+
+
+CREATE SEQUENCE public.hwtestanswerdevice_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER SEQUENCE public.hwtestanswerdevice_id_seq OWNED BY public.hwtestanswerdevice.id;
+
+
+CREATE TABLE public.hwvendorid (
     id integer NOT NULL,
     bus integer NOT NULL,
     vendor_id_for_bus text NOT NULL,
@@ -9658,50 +9078,50 @@
 );
 
 
-COMMENT ON TABLE hwvendorid IS 'Associates tuples (bus, vendor ID for this bus) with vendor names.';
-
-
-COMMENT ON COLUMN hwvendorid.bus IS 'The bus.';
-
-
-COMMENT ON COLUMN hwvendorid.vendor_id_for_bus IS 'The ID of a vendor for the bus given by column `bus`';
-
-
-CREATE SEQUENCE hwvendorid_id_seq
+COMMENT ON TABLE public.hwvendorid IS 'Associates tuples (bus, vendor ID for this bus) with vendor names.';
+
+
+COMMENT ON COLUMN public.hwvendorid.bus IS 'The bus.';
+
+
+COMMENT ON COLUMN public.hwvendorid.vendor_id_for_bus IS 'The ID of a vendor for the bus given by column `bus`';
+
+
+CREATE SEQUENCE public.hwvendorid_id_seq
     START WITH 1
     INCREMENT BY 1
+    NO MINVALUE
     NO MAXVALUE
-    NO MINVALUE
     CACHE 1;
 
 
-ALTER SEQUENCE hwvendorid_id_seq OWNED BY hwvendorid.id;
-
-
-CREATE TABLE hwvendorname (
+ALTER SEQUENCE public.hwvendorid_id_seq OWNED BY public.hwvendorid.id;
+
+
+CREATE TABLE public.hwvendorname (
     id integer NOT NULL,
     name text NOT NULL
 );
 
 
-COMMENT ON TABLE hwvendorname IS 'A list of hardware vendor names.';
-
-
-COMMENT ON COLUMN hwvendorname.name IS 'The name of a vendor.';
-
-
-CREATE SEQUENCE hwvendorname_id_seq
+COMMENT ON TABLE public.hwvendorname IS 'A list of hardware vendor names.';
+
+
+COMMENT ON COLUMN public.hwvendorname.name IS 'The name of a vendor.';
+
+
+CREATE SEQUENCE public.h

Follow ups