Make PG's "NOT NULL"s and attnotnull ("is_nullable") conform to SQL-2011

Started by Vitaly Burovoyalmost 10 years ago9 messages
#1Vitaly Burovoy
vitaly.burovoy@gmail.com
1 attachment(s)

Hello, Hackers!

TODO list has an entry "Move NOT NULL constraint information to
pg_constraint" with four links and without two with the newest
work[1]/messages/by-id/1343682669-sup-2532@alvh.no-ip.org[2]/messages/by-id/20160109030002.GA671800@alvherre.pgsql.

I rebased the patch from [2]/messages/by-id/20160109030002.GA671800@alvherre.pgsql (in attachment). At least it applies
cleanly on top of c477e84fe2471cb675234fce75cd6bb4bc2cf481 and does
not generate a core dump during "make check". There are no tests for
it and it fails "make check" (by difference) which leads inability to
run "make check-world".

But before starting working on it I had a look at the SQL-2011
standard (ISO/IEC 9075-2)[3]http://www.wiscorp.com/sql20nn.zip and found that:

1. A name for a "NOT NULL" constraint <NNC> can be given by a table
definition (subcl. 11.4, "Format"->"column constraint definition").
2. The standard splits NNC and CHECK constraints (subcl. 11.4,
"Format"-> "column constraint")
3. A _descriptor_ of a column must include a "nullability
characteristic" (subcl. 11.4 GR 4.d and 4.L).
4. At the same time the _descriptor_ of the column must include an
_indication_ whether the column is defined as "NOT NULL" or not (near
subcl. 4.13 Note 41) and a name of the constraint.
5. "Nullability characteristic" is set only by nondeferrable
constraints (subcl. 4.13) but there can be several constraints which
have influence on it (e.g. PK + CHECK but without NNC => is_nullable).
6. If an SQL-implementation can deduce CHECK constraint and/or DOMAIN
constraint to "column IS NULL" can never be TRUE it can claim support
for the feature "T101. Enhanced nullability determination" (subcl.
4.13, Note 38). See also (subcl. 6.35 SR 4.b)
7. NNC can be "deferrable" via "constraint characteristics" which are
set in addition to "column constraint" (i.e. the column can be "NOT
NULL" _and_ not "is_nullable").
8. NNC is an _equivalent_ to a table CHECK constraint (subcl. 11.4 SR 17.a).
9. There is no way to set NNC for a table except "... ALTER COLUMN ...
SET NOT NULL" clause (subcl. 11.6).
10. "... ALTER COLUMN ... SET NOT NULL" clause doesn't allow to
specify name of the constraint (subcl. 11.15).
11. There is no way to specify more than one NNC per column via "SET
NOT NULL" (subcl. 11.15 GR 1)
12. At the same time in (subcl. 4.13) mentioned there can be "at least
one NNC" (may be via inheritance?).
13. "... ALTER COLUMN ... SET NOT NULL" _must_ add a table CHECK
constraint (subcl. 11.15 GR 1.d).
14. "DROP NOT NULL" clause must drop cascading all NNC, but leave
other constraints that may affect "nullability characteristic" (subcl.
11.16 GR 1.*).
15. PK can have NULL values if its "constraint characteristics" is "deferrable".
16. There is no mention of "NOT NULL" constraints in the (ISO/IEC
9075-11) at all.

===
Shortcuts:
subcl: Subclause
GR: General Rule
SR: Syntax Rule

Conclusion:
I. NNC implies CHECK constraints (p.13) but it is not a constraint
itself (p.4, p.9, p.13, p.16; opposite to p.2)
II. CHECK constraint does not imply NNC but it has influence on
"attnotnull" (deep check of CHECK constraints allows to move the
feature "T101" to the supporting features list).
III. "pg_attribute" table should have an "attnotnullid oid" as an
indicator of "NOT NULL" (p.4) and points to a CHECK constraint; It is
in addition to a "Nullability characteristic" "attnotnull" (p.3).
IV. "pg_constraint" should have a column "connotnullkey int2[]" as a
"list of the nullable columns" which references to
"pg_attribute.attnum" for fast checking whether a column is still
nullable after deleting/updating constraints or not. Array is
necessary for cases like "CHECK ((col1 IS NOT NULL) AND (col2 IS NOT
NULL))" and for nondeferrable PKs.
V. Inherited tables inherit CHECK constraints (from p.I), but that
constraints are not written to the "attnotnullid" (from p.II) even if
they have NULL values.
VI. "pg_constraint" _can_ have a column "connotnullpure BOOLEAN" to
skip CHECK constraints which define "NOT NULL" only (for one or
several columns) because a row has already checked for NULLs via
"attnotnull" just before ExecRelCheck is executed.
VII. "connotnullkey" is NULL for deferrable and "NOT VALID" constraints.
VIII. "connotnullkey" is recalculated after "VALIDATE CONSTRAINT" is done.
IX. "attnotnull" is recalculated if a constraint with nonempty
"connotnullkey" is inserted, deleted or "connotnullkey" is changed.
X. Pure CHECK constraint doesn't do full scan if the appropriate
table's column(s) has(ve) "attnotnull" as "TRUE".
XI. pg_dump shows "NOT NULL" iff "attnotnullid IS NOT NULL" and skip
CHECK statement with oid matched with attnotnullid.

What do you think about that design?

P.S.:
Since the SQL standard defines that "col NOT NULL" as an equivalent to
"CHECK (col IS NOT NULL)" (p.8) what to do with that behavior:

postgres=# create type t as (x int);
CREATE TYPE
postgres=# SELECT v, v IS NOT NULL AS should_be_in_table FROM
(VALUES('(1)'::t),('()'),(NULL)) AS x(v);
v | should_be_in_table
-----+--------------------
(1) | t
() | f
| f
(3 rows)

"attnotnull" in such case is stricter, like "CHECK (col IS DISTINCT FROM NULL)".

Should such values (with NULL in each attribute of a composite type)
violate NOT NULL constraints?

===
[1]: /messages/by-id/1343682669-sup-2532@alvh.no-ip.org
[2]: /messages/by-id/20160109030002.GA671800@alvherre.pgsql
[3]: http://www.wiscorp.com/sql20nn.zip

Attachments:

catalog-notnull-2-c477e84.patchapplication/octet-stream; name=catalog-notnull-2-c477e84.patchDownload
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 392eb70..de84b77 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -3802,6 +3802,51 @@ SELECT * FROM parent WHERE key = 2400;
       </listitem>
      </varlistentry>
 
+     <varlistentry id="guc-force-parallel-mode" xreflabel="force_parallel_mode">
+      <term><varname>force_parallel_mode</varname> (<type>enum</type>)
+      <indexterm>
+       <primary><varname>force_parallel_mode</> configuration parameter</primary>
+      </indexterm>
+      </term>
+      <listitem>
+       <para>
+        Allows the use of parallel queries for testing purposes even in cases
+        where no performance benefit is expected.
+        The allowed values of <varname>force_parallel_mode</> are
+        <literal>off</> (use parallel mode only when it is expected to improve
+        performance), <literal>on</> (force parallel query for all queries
+        for which it is thought to be safe), and <literal>regress</> (like
+        on, but with additional behavior changes to facilitate automated
+        regression testing).
+       </para>
+
+       <para>
+        More specifically, setting this value to <literal>on</> will add
+        a <literal>Gather</> node to the top of any query plan for which this
+        appears to be safe, so that the query runs inside of a parallel worker.
+        Even when a parallel worker is not available or cannot be used,
+        operations such as starting a subtransaction that would be prohibited
+        in a parallel query context will be prohibited unless the planner
+        believes that this will cause the query to fail.  If failures or
+        unexpected results occur when this option is set, some functions used
+        by the query may need to be marked <literal>PARALLEL UNSAFE</literal>
+        (or, possibly, <literal>PARALLEL RESTRICTED</literal>).
+       </para>
+
+       <para>
+        Setting this value to <literal>regress</> has all of the same effects
+        as setting it to <literal>on</> plus some additional effect that are
+        intended to facilitate automated regression testing.  Normally,
+        messages from a parallel worker are prefixed with a context line,
+        but a setting of <literal>regress</> suppresses this to guarantee
+        reproducible results.  Also, the <literal>Gather</> nodes added to
+        plans by this setting are hidden from the <literal>EXPLAIN</> output
+        so that the output matches what would be obtained if this setting
+        were turned <literal>off</>.
+       </para>
+      </listitem>
+     </varlistentry>
+
      </variablelist>
     </sect2>
    </sect1>
diff --git a/doc/src/sgml/ddl.sgml b/doc/src/sgml/ddl.sgml
index 2adeeff..6a3b622 100644
--- a/doc/src/sgml/ddl.sgml
+++ b/doc/src/sgml/ddl.sgml
@@ -495,8 +495,8 @@ CREATE TABLE products (
    </indexterm>
 
    <para>
-    Unique constraints ensure that the data contained in a column or a
-    group of columns is unique with respect to all the rows in the
+    Unique constraints ensure that the data contained in a column, or a
+    group of columns, is unique among all the rows in the
     table.  The syntax is:
 <programlisting>
 CREATE TABLE products (
@@ -518,8 +518,8 @@ CREATE TABLE products (
    </para>
 
    <para>
-    If a unique constraint refers to a group of columns, the columns
-    are listed separated by commas:
+    To define a unique constraint for a group of columns, write it as a
+    table constraint with the column names separated by commas:
 <programlisting>
 CREATE TABLE example (
     a integer,
@@ -546,9 +546,10 @@ CREATE TABLE products (
 
    <para>
     Adding a unique constraint will automatically create a unique B-tree
-    index on the column or group of columns used in the constraint.
-    A uniqueness constraint on only some rows can be enforced by creating
-    a <link linkend="indexes-partial">partial index</link>.
+    index on the column or group of columns listed in the constraint.
+    A uniqueness restriction covering only some rows cannot be written as
+    a unique constraint, but it is possible to enforce such a restriction by
+    creating a unique <link linkend="indexes-partial">partial index</link>.
    </para>
 
    <indexterm>
@@ -557,10 +558,10 @@ CREATE TABLE products (
    </indexterm>
 
    <para>
-    In general, a unique constraint is violated when there is more than
+    In general, a unique constraint is violated if there is more than
     one row in the table where the values of all of the
     columns included in the constraint are equal.
-    However, two null values are not considered equal in this
+    However, two null values are never considered equal in this
     comparison.  That means even in the presence of a
     unique constraint it is possible to store duplicate
     rows that contain a null value in at least one of the constrained
@@ -584,8 +585,9 @@ CREATE TABLE products (
    </indexterm>
 
    <para>
-    Technically, a primary key constraint is simply a combination of a
-    unique constraint and a not-null constraint.  So, the following
+    A primary key constraint indicates that a column, or group of columns,
+    can be used as a unique identifier for rows in the table.  This
+    requires that the values be both unique and not null.  So, the following
     two table definitions accept the same data:
 <programlisting>
 CREATE TABLE products (
@@ -605,7 +607,7 @@ CREATE TABLE products (
    </para>
 
    <para>
-    Primary keys can also constrain more than one column; the syntax
+    Primary keys can span more than one column; the syntax
     is similar to unique constraints:
 <programlisting>
 CREATE TABLE example (
@@ -618,31 +620,31 @@ CREATE TABLE example (
    </para>
 
    <para>
-    A primary key indicates that a column or group of columns can be
-    used as a unique identifier for rows in the table.  (This is a
-    direct consequence of the definition of a primary key.  Note that
-    a unique constraint does not, by itself, provide a unique identifier
-    because it does not exclude null values.)  This is useful both for
-    documentation purposes and for client applications.  For example,
-    a GUI application that allows modifying row values probably needs
-    to know the primary key of a table to be able to identify rows
-    uniquely.
-   </para>
-
-   <para>
     Adding a primary key will automatically create a unique B-tree index
-    on the column or group of columns used in the primary key.
+    on the column or group of columns listed in the primary key, and will
+    force the column(s) to be marked <literal>NOT NULL</>.
    </para>
 
    <para>
     A table can have at most one primary key.  (There can be any number
-    of unique and not-null constraints, which are functionally the same
-    thing, but only one can be identified as the primary key.)
+    of unique and not-null constraints, which are functionally almost the
+    same thing, but only one can be identified as the primary key.)
     Relational database theory
     dictates that every table must have a primary key.  This rule is
     not enforced by <productname>PostgreSQL</productname>, but it is
     usually best to follow it.
    </para>
+
+   <para>
+    Primary keys are useful both for
+    documentation purposes and for client applications.  For example,
+    a GUI application that allows modifying row values probably needs
+    to know the primary key of a table to be able to identify rows
+    uniquely.  There are also various ways in which the database system
+    makes use of a primary key if one has been declared; for example,
+    the primary key defines the default target column(s) for foreign keys
+    referencing its table.
+   </para>
   </sect2>
 
   <sect2 id="ddl-constraints-fk">
diff --git a/doc/src/sgml/ref/create_table.sgml b/doc/src/sgml/ref/create_table.sgml
index f0c94d5..cd234db 100644
--- a/doc/src/sgml/ref/create_table.sgml
+++ b/doc/src/sgml/ref/create_table.sgml
@@ -506,25 +506,25 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI
     <term><literal>PRIMARY KEY ( <replaceable class="PARAMETER">column_name</replaceable> [, ... ] )</> (table constraint)</term>
     <listitem>
      <para>
-      The primary key constraint specifies that a column or columns of a table
-      can contain only unique (non-duplicate), nonnull values.
-      Technically, <literal>PRIMARY KEY</literal> is merely a
-      combination of <literal>UNIQUE</> and <literal>NOT NULL</>, but
-      identifying a set of columns as primary key also provides
-      metadata about the design of the schema, as a primary key
-      implies that other tables
-      can rely on this set of columns as a unique identifier for rows.
-     </para>
-
-     <para>
-      Only one primary key can be specified for a table, whether as a
+      The <literal>PRIMARY KEY</> constraint specifies that a column or
+      columns of a table can contain only unique (non-duplicate), nonnull
+      values. Only one primary key can be specified for a table, whether as a
       column constraint or a table constraint.
      </para>
 
      <para>
       The primary key constraint should name a set of columns that is
-      different from other sets of columns named by any unique
-      constraint defined for the same table.
+      different from the set of columns named by any unique
+      constraint defined for the same table.  (Otherwise, the unique
+      constraint is redundant and will be discarded.)
+     </para>
+
+     <para>
+      <literal>PRIMARY KEY</literal> enforces the same data constraints as
+      a combination of <literal>UNIQUE</> and <literal>NOT NULL</>, but
+      identifying a set of columns as the primary key also provides metadata
+      about the design of the schema, since a primary key implies that other
+      tables can rely on this set of columns as a unique identifier for rows.
      </para>
     </listitem>
    </varlistentry>
diff --git a/doc/src/sgml/release-9.1.sgml b/doc/src/sgml/release-9.1.sgml
index f5dab31..4ab11e2 100644
--- a/doc/src/sgml/release-9.1.sgml
+++ b/doc/src/sgml/release-9.1.sgml
@@ -1,6 +1,506 @@
 <!-- doc/src/sgml/release-9.1.sgml -->
 <!-- See header comment in release.sgml about typical markup -->
 
+ <sect1 id="release-9-1-20">
+  <title>Release 9.1.20</title>
+
+  <note>
+  <title>Release Date</title>
+  <simpara>2016-02-11</simpara>
+  </note>
+
+  <para>
+   This release contains a variety of fixes from 9.1.19.
+   For information about new features in the 9.1 major release, see
+   <xref linkend="release-9-1">.
+  </para>
+
+  <sect2>
+   <title>Migration to Version 9.1.20</title>
+
+   <para>
+    A dump/restore is not required for those running 9.1.X.
+   </para>
+
+   <para>
+    However, if you are upgrading from a version earlier than 9.1.16,
+    see <xref linkend="release-9-1-16">.
+   </para>
+
+  </sect2>
+
+  <sect2>
+   <title>Changes</title>
+
+   <itemizedlist>
+
+    <listitem>
+     <para>
+      Perform an immediate shutdown if the <filename>postmaster.pid</> file
+      is removed (Tom Lane)
+     </para>
+
+     <para>
+      The postmaster now checks every minute or so
+      that <filename>postmaster.pid</> is still there and still contains its
+      own PID.  If not, it performs an immediate shutdown, as though it had
+      received <systemitem>SIGQUIT</>.  The main motivation for this change
+      is to ensure that failed buildfarm runs will get cleaned up without
+      manual intervention; but it also serves to limit the bad effects if a
+      DBA forcibly removes <filename>postmaster.pid</> and then starts a new
+      postmaster.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      In <literal>SERIALIZABLE</> transaction isolation mode, serialization
+      anomalies could be missed due to race conditions during insertions
+      (Kevin Grittner, Thomas Munro)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix failure to emit appropriate WAL records when doing <literal>ALTER
+      TABLE ... SET TABLESPACE</> for unlogged relations (Michael Paquier,
+      Andres Freund)
+     </para>
+
+     <para>
+      Even though the relation's data is unlogged, the move must be logged or
+      the relation will be inaccessible after a standby is promoted to master.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix possible misinitialization of unlogged relations at the end of
+      crash recovery (Andres Freund, Michael Paquier)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix <command>ALTER COLUMN TYPE</> to reconstruct inherited check
+      constraints properly (Tom Lane)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix <command>REASSIGN OWNED</> to change ownership of composite types
+      properly (&Aacute;lvaro Herrera)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix <command>REASSIGN OWNED</> and <command>ALTER OWNER</> to correctly
+      update granted-permissions lists when changing owners of data types,
+      foreign data wrappers, or foreign servers (Bruce Momjian,
+      &Aacute;lvaro Herrera)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix <command>REASSIGN OWNED</> to ignore foreign user mappings,
+      rather than fail (&Aacute;lvaro Herrera)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Add more defenses against bad planner cost estimates for GIN index
+      scans when the index's internal statistics are very out-of-date
+      (Tom Lane)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Make planner cope with hypothetical GIN indexes suggested by an index
+      advisor plug-in (Julien Rouhaud)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix dumping of whole-row Vars in <literal>ROW()</>
+      and <literal>VALUES()</> lists (Tom Lane)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix possible internal overflow in <type>numeric</> division
+      (Dean Rasheed)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix enforcement of restrictions inside parentheses within regular
+      expression lookahead constraints (Tom Lane)
+     </para>
+
+     <para>
+      Lookahead constraints aren't allowed to contain backrefs, and
+      parentheses within them are always considered non-capturing, according
+      to the manual.  However, the code failed to handle these cases properly
+      inside a parenthesized subexpression, and would give unexpected
+      results.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Conversion of regular expressions to indexscan bounds could produce
+      incorrect bounds from regexps containing lookahead constraints
+      (Tom Lane)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix regular-expression compiler to handle loops of constraint arcs
+      (Tom Lane)
+     </para>
+
+     <para>
+      The code added for CVE-2007-4772 was both incomplete, in that it didn't
+      handle loops involving more than one state, and incorrect, in that it
+      could cause assertion failures (though there seem to be no bad
+      consequences of that in a non-assert build).  Multi-state loops would
+      cause the compiler to run until the query was canceled or it reached
+      the too-many-states error condition.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Improve memory-usage accounting in regular-expression compiler
+      (Tom Lane)
+     </para>
+
+     <para>
+      This causes the code to emit <quote>regular expression is too
+      complex</> errors in some cases that previously used unreasonable
+      amounts of time and memory.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Improve performance of regular-expression compiler (Tom Lane)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Make <literal>%h</> and <literal>%r</> escapes
+      in <varname>log_line_prefix</> work for messages emitted due
+      to <varname>log_connections</> (Tom Lane)
+     </para>
+
+     <para>
+      Previously, <literal>%h</>/<literal>%r</> started to work just after a
+      new session had emitted the <quote>connection received</> log message;
+      now they work for that message too.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      On Windows, ensure the shared-memory mapping handle gets closed in
+      child processes that don't need it (Tom Lane, Amit Kapila)
+     </para>
+
+     <para>
+      This oversight resulted in failure to recover from crashes
+      whenever <varname>logging_collector</> is turned on.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix possible failure to detect socket EOF in non-blocking mode on
+      Windows (Tom Lane)
+     </para>
+
+     <para>
+      It's not entirely clear whether this problem can happen in pre-9.5
+      branches, but if it did, the symptom would be that a walsender process
+      would wait indefinitely rather than noticing a loss of connection.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Avoid leaking a token handle during SSPI authentication
+      (Christian Ullrich)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      In <application>psql</>, ensure that <application>libreadline</>'s idea
+      of the screen size is updated when the terminal window size changes
+      (Merlin Moncure)
+     </para>
+
+     <para>
+      Previously, <application>libreadline</> did not notice if the window
+      was resized during query output, leading to strange behavior during
+      later input of multiline queries.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix <application>psql</>'s <literal>\det</> command to interpret its
+      pattern argument the same way as other <literal>\d</> commands with
+      potentially schema-qualified patterns do (Reece Hart)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Avoid possible crash in <application>psql</>'s <literal>\c</> command
+      when previous connection was via Unix socket and command specifies a
+      new hostname and same username (Tom Lane)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      In <literal>pg_ctl start -w</>, test child process status directly
+      rather than relying on heuristics (Tom Lane, Michael Paquier)
+     </para>
+
+     <para>
+      Previously, <application>pg_ctl</> relied on an assumption that the new
+      postmaster would always create <filename>postmaster.pid</> within five
+      seconds.  But that can fail on heavily-loaded systems,
+      causing <application>pg_ctl</> to report incorrectly that the
+      postmaster failed to start.
+     </para>
+
+     <para>
+      Except on Windows, this change also means that a <literal>pg_ctl start
+      -w</> done immediately after another such command will now reliably
+      fail, whereas previously it would report success if done within two
+      seconds of the first command.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      In <literal>pg_ctl start -w</>, don't attempt to use a wildcard listen
+      address to connect to the postmaster (Kondo Yuta)
+     </para>
+
+     <para>
+      On Windows, <application>pg_ctl</> would fail to detect postmaster
+      startup if <varname>listen_addresses</> is set to <literal>0.0.0.0</>
+      or <literal>::</>, because it would try to use that value verbatim as
+      the address to connect to, which doesn't work.  Instead assume
+      that <literal>127.0.0.1</> or <literal>::1</>, respectively, is the
+      right thing to use.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      In <application>pg_ctl</> on Windows, check service status to decide
+      where to send output, rather than checking if standard output is a
+      terminal (Michael Paquier)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      In <application>pg_dump</> and <application>pg_basebackup</>, adopt
+      the GNU convention for handling tar-archive members exceeding 8GB
+      (Tom Lane)
+     </para>
+
+     <para>
+      The POSIX standard for <literal>tar</> file format does not allow
+      archive member files to exceed 8GB, but most modern implementations
+      of <application>tar</> support an extension that fixes that.  Adopt
+      this extension so that <application>pg_dump</> with <option>-Ft</> no
+      longer fails on tables with more than 8GB of data, and so
+      that <application>pg_basebackup</> can handle files larger than 8GB.
+      In addition, fix some portability issues that could cause failures for
+      members between 4GB and 8GB on some platforms.  Potentially these
+      problems could cause unrecoverable data loss due to unreadable backup
+      files.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix assorted corner-case bugs in <application>pg_dump</>'s processing
+      of extension member objects (Tom Lane)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Make <application>pg_dump</> mark a view's triggers as needing to be
+      processed after its rule, to prevent possible failure during
+      parallel <application>pg_restore</> (Tom Lane)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Ensure that relation option values are properly quoted
+      in <application>pg_dump</> (Kouhei Sutou, Tom Lane)
+     </para>
+
+     <para>
+      A reloption value that isn't a simple identifier or number could lead
+      to dump/reload failures due to syntax errors in CREATE statements
+      issued by <application>pg_dump</>.  This is not an issue with any
+      reloption currently supported by core <productname>PostgreSQL</>, but
+      extensions could allow reloptions that cause the problem.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix <application>pg_upgrade</>'s file-copying code to handle errors
+      properly on Windows (Bruce Momjian)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Install guards in <application>pgbench</> against corner-case overflow
+      conditions during evaluation of script-specified division or modulo
+      operators (Fabien Coelho, Michael Paquier)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Prevent certain <application>PL/Java</> parameters from being set by
+      non-superusers (Noah Misch)
+     </para>
+
+     <para>
+      This change mitigates a <application>PL/Java</> security bug
+      (CVE-2016-0766), which was fixed in <application>PL/Java</> by marking
+      these parameters as superuser-only.  To fix the security hazard for
+      sites that update <productname>PostgreSQL</> more frequently
+      than <application>PL/Java</>, make the core code aware of them also.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Improve <application>libpq</>'s handling of out-of-memory situations
+      (Michael Paquier, Amit Kapila, Heikki Linnakangas)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix order of arguments
+      in <application>ecpg</>-generated <literal>typedef</> statements
+      (Michael Meskes)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Use <literal>%g</> not <literal>%f</> format
+      in <application>ecpg</>'s <function>PGTYPESnumeric_from_double()</>
+      (Tom Lane)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix <application>ecpg</>-supplied header files to not contain comments
+      continued from a preprocessor directive line onto the next line
+      (Michael Meskes)
+     </para>
+
+     <para>
+      Such a comment is rejected by <application>ecpg</>.  It's not yet clear
+      whether <application>ecpg</> itself should be changed.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Ensure that <filename>contrib/pgcrypto</>'s <function>crypt()</>
+      function can be interrupted by query cancel (Andreas Karlsson)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Accept <application>flex</> versions later than 2.5.x
+      (Tom Lane, Michael Paquier)
+     </para>
+
+     <para>
+      Now that flex 2.6.0 has been released, the version checks in our build
+      scripts needed to be adjusted.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Install our <filename>missing</> script where PGXS builds can find it
+      (Jim Nasby)
+     </para>
+
+     <para>
+      This allows sane behavior in a PGXS build done on a machine where build
+      tools such as <application>bison</> are missing.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Ensure that <filename>dynloader.h</> is included in the installed
+      header files in MSVC builds (Bruce Momjian, Michael Paquier)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Add variant regression test expected-output file to match behavior of
+      current <application>libxml2</> (Tom Lane)
+     </para>
+
+     <para>
+      The fix for <application>libxml2</>'s CVE-2015-7499 causes it not to
+      output error context reports in some cases where it used to do so.
+      This seems to be a bug, but we'll probably have to live with it for
+      some time, so work around it.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Update time zone data files to <application>tzdata</> release 2016a for
+      DST law changes in Cayman Islands, Metlakatla, and Trans-Baikal
+      Territory (Zabaykalsky Krai), plus historical corrections for Pakistan.
+     </para>
+    </listitem>
+
+   </itemizedlist>
+
+  </sect2>
+ </sect1>
+
  <sect1 id="release-9-1-19">
   <title>Release 9.1.19</title>
 
diff --git a/doc/src/sgml/release-9.2.sgml b/doc/src/sgml/release-9.2.sgml
index bee0c9e..78154cb 100644
--- a/doc/src/sgml/release-9.2.sgml
+++ b/doc/src/sgml/release-9.2.sgml
@@ -1,6 +1,537 @@
 <!-- doc/src/sgml/release-9.2.sgml -->
 <!-- See header comment in release.sgml about typical markup -->
 
+ <sect1 id="release-9-2-15">
+  <title>Release 9.2.15</title>
+
+  <note>
+  <title>Release Date</title>
+  <simpara>2016-02-11</simpara>
+  </note>
+
+  <para>
+   This release contains a variety of fixes from 9.2.14.
+   For information about new features in the 9.2 major release, see
+   <xref linkend="release-9-2">.
+  </para>
+
+  <sect2>
+   <title>Migration to Version 9.2.15</title>
+
+   <para>
+    A dump/restore is not required for those running 9.2.X.
+   </para>
+
+   <para>
+    However, if you are upgrading from a version earlier than 9.2.11,
+    see <xref linkend="release-9-2-11">.
+   </para>
+
+  </sect2>
+
+  <sect2>
+   <title>Changes</title>
+
+   <itemizedlist>
+
+    <listitem>
+     <para>
+      Perform an immediate shutdown if the <filename>postmaster.pid</> file
+      is removed (Tom Lane)
+     </para>
+
+     <para>
+      The postmaster now checks every minute or so
+      that <filename>postmaster.pid</> is still there and still contains its
+      own PID.  If not, it performs an immediate shutdown, as though it had
+      received <systemitem>SIGQUIT</>.  The main motivation for this change
+      is to ensure that failed buildfarm runs will get cleaned up without
+      manual intervention; but it also serves to limit the bad effects if a
+      DBA forcibly removes <filename>postmaster.pid</> and then starts a new
+      postmaster.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      In <literal>SERIALIZABLE</> transaction isolation mode, serialization
+      anomalies could be missed due to race conditions during insertions
+      (Kevin Grittner, Thomas Munro)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix failure to emit appropriate WAL records when doing <literal>ALTER
+      TABLE ... SET TABLESPACE</> for unlogged relations (Michael Paquier,
+      Andres Freund)
+     </para>
+
+     <para>
+      Even though the relation's data is unlogged, the move must be logged or
+      the relation will be inaccessible after a standby is promoted to master.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix possible misinitialization of unlogged relations at the end of
+      crash recovery (Andres Freund, Michael Paquier)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix <command>ALTER COLUMN TYPE</> to reconstruct inherited check
+      constraints properly (Tom Lane)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix <command>REASSIGN OWNED</> to change ownership of composite types
+      properly (&Aacute;lvaro Herrera)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix <command>REASSIGN OWNED</> and <command>ALTER OWNER</> to correctly
+      update granted-permissions lists when changing owners of data types,
+      foreign data wrappers, or foreign servers (Bruce Momjian,
+      &Aacute;lvaro Herrera)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix <command>REASSIGN OWNED</> to ignore foreign user mappings,
+      rather than fail (&Aacute;lvaro Herrera)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Add more defenses against bad planner cost estimates for GIN index
+      scans when the index's internal statistics are very out-of-date
+      (Tom Lane)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Make planner cope with hypothetical GIN indexes suggested by an index
+      advisor plug-in (Julien Rouhaud)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix dumping of whole-row Vars in <literal>ROW()</>
+      and <literal>VALUES()</> lists (Tom Lane)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix possible internal overflow in <type>numeric</> division
+      (Dean Rasheed)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix enforcement of restrictions inside parentheses within regular
+      expression lookahead constraints (Tom Lane)
+     </para>
+
+     <para>
+      Lookahead constraints aren't allowed to contain backrefs, and
+      parentheses within them are always considered non-capturing, according
+      to the manual.  However, the code failed to handle these cases properly
+      inside a parenthesized subexpression, and would give unexpected
+      results.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Conversion of regular expressions to indexscan bounds could produce
+      incorrect bounds from regexps containing lookahead constraints
+      (Tom Lane)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix regular-expression compiler to handle loops of constraint arcs
+      (Tom Lane)
+     </para>
+
+     <para>
+      The code added for CVE-2007-4772 was both incomplete, in that it didn't
+      handle loops involving more than one state, and incorrect, in that it
+      could cause assertion failures (though there seem to be no bad
+      consequences of that in a non-assert build).  Multi-state loops would
+      cause the compiler to run until the query was canceled or it reached
+      the too-many-states error condition.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Improve memory-usage accounting in regular-expression compiler
+      (Tom Lane)
+     </para>
+
+     <para>
+      This causes the code to emit <quote>regular expression is too
+      complex</> errors in some cases that previously used unreasonable
+      amounts of time and memory.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Improve performance of regular-expression compiler (Tom Lane)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Make <literal>%h</> and <literal>%r</> escapes
+      in <varname>log_line_prefix</> work for messages emitted due
+      to <varname>log_connections</> (Tom Lane)
+     </para>
+
+     <para>
+      Previously, <literal>%h</>/<literal>%r</> started to work just after a
+      new session had emitted the <quote>connection received</> log message;
+      now they work for that message too.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      On Windows, ensure the shared-memory mapping handle gets closed in
+      child processes that don't need it (Tom Lane, Amit Kapila)
+     </para>
+
+     <para>
+      This oversight resulted in failure to recover from crashes
+      whenever <varname>logging_collector</> is turned on.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix possible failure to detect socket EOF in non-blocking mode on
+      Windows (Tom Lane)
+     </para>
+
+     <para>
+      It's not entirely clear whether this problem can happen in pre-9.5
+      branches, but if it did, the symptom would be that a walsender process
+      would wait indefinitely rather than noticing a loss of connection.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Avoid leaking a token handle during SSPI authentication
+      (Christian Ullrich)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      In <application>psql</>, ensure that <application>libreadline</>'s idea
+      of the screen size is updated when the terminal window size changes
+      (Merlin Moncure)
+     </para>
+
+     <para>
+      Previously, <application>libreadline</> did not notice if the window
+      was resized during query output, leading to strange behavior during
+      later input of multiline queries.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix <application>psql</>'s <literal>\det</> command to interpret its
+      pattern argument the same way as other <literal>\d</> commands with
+      potentially schema-qualified patterns do (Reece Hart)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Avoid possible crash in <application>psql</>'s <literal>\c</> command
+      when previous connection was via Unix socket and command specifies a
+      new hostname and same username (Tom Lane)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      In <literal>pg_ctl start -w</>, test child process status directly
+      rather than relying on heuristics (Tom Lane, Michael Paquier)
+     </para>
+
+     <para>
+      Previously, <application>pg_ctl</> relied on an assumption that the new
+      postmaster would always create <filename>postmaster.pid</> within five
+      seconds.  But that can fail on heavily-loaded systems,
+      causing <application>pg_ctl</> to report incorrectly that the
+      postmaster failed to start.
+     </para>
+
+     <para>
+      Except on Windows, this change also means that a <literal>pg_ctl start
+      -w</> done immediately after another such command will now reliably
+      fail, whereas previously it would report success if done within two
+      seconds of the first command.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      In <literal>pg_ctl start -w</>, don't attempt to use a wildcard listen
+      address to connect to the postmaster (Kondo Yuta)
+     </para>
+
+     <para>
+      On Windows, <application>pg_ctl</> would fail to detect postmaster
+      startup if <varname>listen_addresses</> is set to <literal>0.0.0.0</>
+      or <literal>::</>, because it would try to use that value verbatim as
+      the address to connect to, which doesn't work.  Instead assume
+      that <literal>127.0.0.1</> or <literal>::1</>, respectively, is the
+      right thing to use.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      In <application>pg_ctl</> on Windows, check service status to decide
+      where to send output, rather than checking if standard output is a
+      terminal (Michael Paquier)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      In <application>pg_dump</> and <application>pg_basebackup</>, adopt
+      the GNU convention for handling tar-archive members exceeding 8GB
+      (Tom Lane)
+     </para>
+
+     <para>
+      The POSIX standard for <literal>tar</> file format does not allow
+      archive member files to exceed 8GB, but most modern implementations
+      of <application>tar</> support an extension that fixes that.  Adopt
+      this extension so that <application>pg_dump</> with <option>-Ft</> no
+      longer fails on tables with more than 8GB of data, and so
+      that <application>pg_basebackup</> can handle files larger than 8GB.
+      In addition, fix some portability issues that could cause failures for
+      members between 4GB and 8GB on some platforms.  Potentially these
+      problems could cause unrecoverable data loss due to unreadable backup
+      files.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix assorted corner-case bugs in <application>pg_dump</>'s processing
+      of extension member objects (Tom Lane)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Make <application>pg_dump</> mark a view's triggers as needing to be
+      processed after its rule, to prevent possible failure during
+      parallel <application>pg_restore</> (Tom Lane)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Ensure that relation option values are properly quoted
+      in <application>pg_dump</> (Kouhei Sutou, Tom Lane)
+     </para>
+
+     <para>
+      A reloption value that isn't a simple identifier or number could lead
+      to dump/reload failures due to syntax errors in CREATE statements
+      issued by <application>pg_dump</>.  This is not an issue with any
+      reloption currently supported by core <productname>PostgreSQL</>, but
+      extensions could allow reloptions that cause the problem.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix <application>pg_upgrade</>'s file-copying code to handle errors
+      properly on Windows (Bruce Momjian)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Install guards in <application>pgbench</> against corner-case overflow
+      conditions during evaluation of script-specified division or modulo
+      operators (Fabien Coelho, Michael Paquier)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix failure to localize messages emitted
+      by <application>pg_receivexlog</> and <application>pg_recvlogical</>
+      (Ioseph Kim)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Avoid dump/reload problems when using both <application>plpython2</>
+      and <application>plpython3</> (Tom Lane)
+     </para>
+
+     <para>
+      In principle, both versions of <application>PL/Python</> can be used in
+      the same database, though not in the same session (because the two
+      versions of <application>libpython</> cannot safely be used concurrently).
+      However, <application>pg_restore</> and <application>pg_upgrade</> both
+      do things that can fall foul of the same-session restriction.  Work
+      around that by changing the timing of the check.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix <application>PL/Python</> regression tests to pass with Python 3.5
+      (Peter Eisentraut)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Prevent certain <application>PL/Java</> parameters from being set by
+      non-superusers (Noah Misch)
+     </para>
+
+     <para>
+      This change mitigates a <application>PL/Java</> security bug
+      (CVE-2016-0766), which was fixed in <application>PL/Java</> by marking
+      these parameters as superuser-only.  To fix the security hazard for
+      sites that update <productname>PostgreSQL</> more frequently
+      than <application>PL/Java</>, make the core code aware of them also.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Improve <application>libpq</>'s handling of out-of-memory situations
+      (Michael Paquier, Amit Kapila, Heikki Linnakangas)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix order of arguments
+      in <application>ecpg</>-generated <literal>typedef</> statements
+      (Michael Meskes)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Use <literal>%g</> not <literal>%f</> format
+      in <application>ecpg</>'s <function>PGTYPESnumeric_from_double()</>
+      (Tom Lane)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix <application>ecpg</>-supplied header files to not contain comments
+      continued from a preprocessor directive line onto the next line
+      (Michael Meskes)
+     </para>
+
+     <para>
+      Such a comment is rejected by <application>ecpg</>.  It's not yet clear
+      whether <application>ecpg</> itself should be changed.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Ensure that <filename>contrib/pgcrypto</>'s <function>crypt()</>
+      function can be interrupted by query cancel (Andreas Karlsson)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Accept <application>flex</> versions later than 2.5.x
+      (Tom Lane, Michael Paquier)
+     </para>
+
+     <para>
+      Now that flex 2.6.0 has been released, the version checks in our build
+      scripts needed to be adjusted.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Install our <filename>missing</> script where PGXS builds can find it
+      (Jim Nasby)
+     </para>
+
+     <para>
+      This allows sane behavior in a PGXS build done on a machine where build
+      tools such as <application>bison</> are missing.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Ensure that <filename>dynloader.h</> is included in the installed
+      header files in MSVC builds (Bruce Momjian, Michael Paquier)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Add variant regression test expected-output file to match behavior of
+      current <application>libxml2</> (Tom Lane)
+     </para>
+
+     <para>
+      The fix for <application>libxml2</>'s CVE-2015-7499 causes it not to
+      output error context reports in some cases where it used to do so.
+      This seems to be a bug, but we'll probably have to live with it for
+      some time, so work around it.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Update time zone data files to <application>tzdata</> release 2016a for
+      DST law changes in Cayman Islands, Metlakatla, and Trans-Baikal
+      Territory (Zabaykalsky Krai), plus historical corrections for Pakistan.
+     </para>
+    </listitem>
+
+   </itemizedlist>
+
+  </sect2>
+ </sect1>
+
  <sect1 id="release-9-2-14">
   <title>Release 9.2.14</title>
 
diff --git a/doc/src/sgml/release-9.3.sgml b/doc/src/sgml/release-9.3.sgml
index b637908..0f4907d 100644
--- a/doc/src/sgml/release-9.3.sgml
+++ b/doc/src/sgml/release-9.3.sgml
@@ -1,6 +1,616 @@
 <!-- doc/src/sgml/release-9.3.sgml -->
 <!-- See header comment in release.sgml about typical markup -->
 
+ <sect1 id="release-9-3-11">
+  <title>Release 9.3.11</title>
+
+  <note>
+  <title>Release Date</title>
+  <simpara>2016-02-11</simpara>
+  </note>
+
+  <para>
+   This release contains a variety of fixes from 9.3.10.
+   For information about new features in the 9.3 major release, see
+   <xref linkend="release-9-3">.
+  </para>
+
+  <sect2>
+   <title>Migration to Version 9.3.11</title>
+
+   <para>
+    A dump/restore is not required for those running 9.3.X.
+   </para>
+
+   <para>
+    However, if you are upgrading from a version earlier than 9.3.9,
+    see <xref linkend="release-9-3-9">.
+   </para>
+
+  </sect2>
+
+  <sect2>
+   <title>Changes</title>
+
+   <itemizedlist>
+
+    <listitem>
+     <para>
+      Perform an immediate shutdown if the <filename>postmaster.pid</> file
+      is removed (Tom Lane)
+     </para>
+
+     <para>
+      The postmaster now checks every minute or so
+      that <filename>postmaster.pid</> is still there and still contains its
+      own PID.  If not, it performs an immediate shutdown, as though it had
+      received <systemitem>SIGQUIT</>.  The main motivation for this change
+      is to ensure that failed buildfarm runs will get cleaned up without
+      manual intervention; but it also serves to limit the bad effects if a
+      DBA forcibly removes <filename>postmaster.pid</> and then starts a new
+      postmaster.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      In <literal>SERIALIZABLE</> transaction isolation mode, serialization
+      anomalies could be missed due to race conditions during insertions
+      (Kevin Grittner, Thomas Munro)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix failure to emit appropriate WAL records when doing <literal>ALTER
+      TABLE ... SET TABLESPACE</> for unlogged relations (Michael Paquier,
+      Andres Freund)
+     </para>
+
+     <para>
+      Even though the relation's data is unlogged, the move must be logged or
+      the relation will be inaccessible after a standby is promoted to master.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix possible misinitialization of unlogged relations at the end of
+      crash recovery (Andres Freund, Michael Paquier)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Ensure walsender slots are fully re-initialized when being re-used
+      (Magnus Hagander)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix <command>ALTER COLUMN TYPE</> to reconstruct inherited check
+      constraints properly (Tom Lane)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix <command>REASSIGN OWNED</> to change ownership of composite types
+      properly (&Aacute;lvaro Herrera)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix <command>REASSIGN OWNED</> and <command>ALTER OWNER</> to correctly
+      update granted-permissions lists when changing owners of data types,
+      foreign data wrappers, or foreign servers (Bruce Momjian,
+      &Aacute;lvaro Herrera)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix <command>REASSIGN OWNED</> to ignore foreign user mappings,
+      rather than fail (&Aacute;lvaro Herrera)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix possible crash after doing query rewrite for an updatable view
+      (Stephen Frost)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix planner's handling of <literal>LATERAL</> references (Tom
+      Lane)
+     </para>
+
+     <para>
+      This fixes some corner cases that led to <quote>failed to build any
+      N-way joins</> or <quote>could not devise a query plan</> planner
+      failures.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Add more defenses against bad planner cost estimates for GIN index
+      scans when the index's internal statistics are very out-of-date
+      (Tom Lane)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Make planner cope with hypothetical GIN indexes suggested by an index
+      advisor plug-in (Julien Rouhaud)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Speed up generation of unique table aliases in <command>EXPLAIN</> and
+      rule dumping, and ensure that generated aliases do not
+      exceed <literal>NAMEDATALEN</> (Tom Lane)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix dumping of whole-row Vars in <literal>ROW()</>
+      and <literal>VALUES()</> lists (Tom Lane)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix possible internal overflow in <type>numeric</> division
+      (Dean Rasheed)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix enforcement of restrictions inside parentheses within regular
+      expression lookahead constraints (Tom Lane)
+     </para>
+
+     <para>
+      Lookahead constraints aren't allowed to contain backrefs, and
+      parentheses within them are always considered non-capturing, according
+      to the manual.  However, the code failed to handle these cases properly
+      inside a parenthesized subexpression, and would give unexpected
+      results.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Conversion of regular expressions to indexscan bounds could produce
+      incorrect bounds from regexps containing lookahead constraints
+      (Tom Lane)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix regular-expression compiler to handle loops of constraint arcs
+      (Tom Lane)
+     </para>
+
+     <para>
+      The code added for CVE-2007-4772 was both incomplete, in that it didn't
+      handle loops involving more than one state, and incorrect, in that it
+      could cause assertion failures (though there seem to be no bad
+      consequences of that in a non-assert build).  Multi-state loops would
+      cause the compiler to run until the query was canceled or it reached
+      the too-many-states error condition.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Improve memory-usage accounting in regular-expression compiler
+      (Tom Lane)
+     </para>
+
+     <para>
+      This causes the code to emit <quote>regular expression is too
+      complex</> errors in some cases that previously used unreasonable
+      amounts of time and memory.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Improve performance of regular-expression compiler (Tom Lane)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Make <literal>%h</> and <literal>%r</> escapes
+      in <varname>log_line_prefix</> work for messages emitted due
+      to <varname>log_connections</> (Tom Lane)
+     </para>
+
+     <para>
+      Previously, <literal>%h</>/<literal>%r</> started to work just after a
+      new session had emitted the <quote>connection received</> log message;
+      now they work for that message too.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      On Windows, ensure the shared-memory mapping handle gets closed in
+      child processes that don't need it (Tom Lane, Amit Kapila)
+     </para>
+
+     <para>
+      This oversight resulted in failure to recover from crashes
+      whenever <varname>logging_collector</> is turned on.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix possible failure to detect socket EOF in non-blocking mode on
+      Windows (Tom Lane)
+     </para>
+
+     <para>
+      It's not entirely clear whether this problem can happen in pre-9.5
+      branches, but if it did, the symptom would be that a walsender process
+      would wait indefinitely rather than noticing a loss of connection.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Avoid leaking a token handle during SSPI authentication
+      (Christian Ullrich)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      In <application>psql</>, ensure that <application>libreadline</>'s idea
+      of the screen size is updated when the terminal window size changes
+      (Merlin Moncure)
+     </para>
+
+     <para>
+      Previously, <application>libreadline</> did not notice if the window
+      was resized during query output, leading to strange behavior during
+      later input of multiline queries.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix <application>psql</>'s <literal>\det</> command to interpret its
+      pattern argument the same way as other <literal>\d</> commands with
+      potentially schema-qualified patterns do (Reece Hart)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Avoid possible crash in <application>psql</>'s <literal>\c</> command
+      when previous connection was via Unix socket and command specifies a
+      new hostname and same username (Tom Lane)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      In <literal>pg_ctl start -w</>, test child process status directly
+      rather than relying on heuristics (Tom Lane, Michael Paquier)
+     </para>
+
+     <para>
+      Previously, <application>pg_ctl</> relied on an assumption that the new
+      postmaster would always create <filename>postmaster.pid</> within five
+      seconds.  But that can fail on heavily-loaded systems,
+      causing <application>pg_ctl</> to report incorrectly that the
+      postmaster failed to start.
+     </para>
+
+     <para>
+      Except on Windows, this change also means that a <literal>pg_ctl start
+      -w</> done immediately after another such command will now reliably
+      fail, whereas previously it would report success if done within two
+      seconds of the first command.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      In <literal>pg_ctl start -w</>, don't attempt to use a wildcard listen
+      address to connect to the postmaster (Kondo Yuta)
+     </para>
+
+     <para>
+      On Windows, <application>pg_ctl</> would fail to detect postmaster
+      startup if <varname>listen_addresses</> is set to <literal>0.0.0.0</>
+      or <literal>::</>, because it would try to use that value verbatim as
+      the address to connect to, which doesn't work.  Instead assume
+      that <literal>127.0.0.1</> or <literal>::1</>, respectively, is the
+      right thing to use.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      In <application>pg_ctl</> on Windows, check service status to decide
+      where to send output, rather than checking if standard output is a
+      terminal (Michael Paquier)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      In <application>pg_dump</> and <application>pg_basebackup</>, adopt
+      the GNU convention for handling tar-archive members exceeding 8GB
+      (Tom Lane)
+     </para>
+
+     <para>
+      The POSIX standard for <literal>tar</> file format does not allow
+      archive member files to exceed 8GB, but most modern implementations
+      of <application>tar</> support an extension that fixes that.  Adopt
+      this extension so that <application>pg_dump</> with <option>-Ft</> no
+      longer fails on tables with more than 8GB of data, and so
+      that <application>pg_basebackup</> can handle files larger than 8GB.
+      In addition, fix some portability issues that could cause failures for
+      members between 4GB and 8GB on some platforms.  Potentially these
+      problems could cause unrecoverable data loss due to unreadable backup
+      files.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix assorted corner-case bugs in <application>pg_dump</>'s processing
+      of extension member objects (Tom Lane)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Make <application>pg_dump</> mark a view's triggers as needing to be
+      processed after its rule, to prevent possible failure during
+      parallel <application>pg_restore</> (Tom Lane)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Ensure that relation option values are properly quoted
+      in <application>pg_dump</> (Kouhei Sutou, Tom Lane)
+     </para>
+
+     <para>
+      A reloption value that isn't a simple identifier or number could lead
+      to dump/reload failures due to syntax errors in CREATE statements
+      issued by <application>pg_dump</>.  This is not an issue with any
+      reloption currently supported by core <productname>PostgreSQL</>, but
+      extensions could allow reloptions that cause the problem.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Avoid repeated password prompts during parallel <application>pg_dump</>
+      (Zeus Kronion)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix <application>pg_upgrade</>'s file-copying code to handle errors
+      properly on Windows (Bruce Momjian)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Install guards in <application>pgbench</> against corner-case overflow
+      conditions during evaluation of script-specified division or modulo
+      operators (Fabien Coelho, Michael Paquier)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix failure to localize messages emitted
+      by <application>pg_receivexlog</> and <application>pg_recvlogical</>
+      (Ioseph Kim)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Avoid dump/reload problems when using both <application>plpython2</>
+      and <application>plpython3</> (Tom Lane)
+     </para>
+
+     <para>
+      In principle, both versions of <application>PL/Python</> can be used in
+      the same database, though not in the same session (because the two
+      versions of <application>libpython</> cannot safely be used concurrently).
+      However, <application>pg_restore</> and <application>pg_upgrade</> both
+      do things that can fall foul of the same-session restriction.  Work
+      around that by changing the timing of the check.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix <application>PL/Python</> regression tests to pass with Python 3.5
+      (Peter Eisentraut)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix premature clearing of <application>libpq</>'s input buffer when
+      socket EOF is seen (Tom Lane)
+     </para>
+
+     <para>
+      This mistake caused <application>libpq</> to sometimes not report the
+      backend's final error message before reporting <quote>server closed the
+      connection unexpectedly</>.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Prevent certain <application>PL/Java</> parameters from being set by
+      non-superusers (Noah Misch)
+     </para>
+
+     <para>
+      This change mitigates a <application>PL/Java</> security bug
+      (CVE-2016-0766), which was fixed in <application>PL/Java</> by marking
+      these parameters as superuser-only.  To fix the security hazard for
+      sites that update <productname>PostgreSQL</> more frequently
+      than <application>PL/Java</>, make the core code aware of them also.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Improve <application>libpq</>'s handling of out-of-memory situations
+      (Michael Paquier, Amit Kapila, Heikki Linnakangas)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix order of arguments
+      in <application>ecpg</>-generated <literal>typedef</> statements
+      (Michael Meskes)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Use <literal>%g</> not <literal>%f</> format
+      in <application>ecpg</>'s <function>PGTYPESnumeric_from_double()</>
+      (Tom Lane)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix <application>ecpg</>-supplied header files to not contain comments
+      continued from a preprocessor directive line onto the next line
+      (Michael Meskes)
+     </para>
+
+     <para>
+      Such a comment is rejected by <application>ecpg</>.  It's not yet clear
+      whether <application>ecpg</> itself should be changed.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Fix <function>hstore_to_json_loose()</>'s test for whether
+      an <type>hstore</> value can be converted to a JSON number (Tom Lane)
+     </para>
+
+     <para>
+      Previously this function could be fooled by non-alphanumeric trailing
+      characters, leading to emitting syntactically-invalid JSON.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Ensure that <filename>contrib/pgcrypto</>'s <function>crypt()</>
+      function can be interrupted by query cancel (Andreas Karlsson)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Accept <application>flex</> versions later than 2.5.x
+      (Tom Lane, Michael Paquier)
+     </para>
+
+     <para>
+      Now that flex 2.6.0 has been released, the version checks in our build
+      scripts needed to be adjusted.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Improve reproducibility of build output by ensuring filenames are given
+      to the linker in a fixed order (Christoph Berg)
+     </para>
+
+     <para>
+      This avoids possible bitwise differences in the produced executable
+      files from one build to the next.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Install our <filename>missing</> script where PGXS builds can find it
+      (Jim Nasby)
+     </para>
+
+     <para>
+      This allows sane behavior in a PGXS build done on a machine where build
+      tools such as <application>bison</> are missing.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Ensure that <filename>dynloader.h</> is included in the installed
+      header files in MSVC builds (Bruce Momjian, Michael Paquier)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Add variant regression test expected-output file to match behavior of
+      current <application>libxml2</> (Tom Lane)
+     </para>
+
+     <para>
+      The fix for <application>libxml2</>'s CVE-2015-7499 causes it not to
+      output error context reports in some cases where it used to do so.
+      This seems to be a bug, but we'll probably have to live with it for
+      some time, so work around it.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Update time zone data files to <application>tzdata</> release 2016a for
+      DST law changes in Cayman Islands, Metlakatla, and Trans-Baikal
+      Territory (Zabaykalsky Krai), plus historical corrections for Pakistan.
+     </para>
+    </listitem>
+
+   </itemizedlist>
+
+  </sect2>
+ </sect1>
+
  <sect1 id="release-9-3-10">
   <title>Release 9.3.10</title>
 
diff --git a/doc/src/sgml/release-9.4.sgml b/doc/src/sgml/release-9.4.sgml
index 2c4c642..7ba54a9 100644
--- a/doc/src/sgml/release-9.4.sgml
+++ b/doc/src/sgml/release-9.4.sgml
@@ -491,16 +491,6 @@ Branch: REL9_1_STABLE [b00c79b5b] 2015-10-16 14:43:18 -0400
      </para>
     </listitem>
 
-<!--
-Author: Tom Lane <tgl@sss.pgh.pa.us>
-Branch: master [b8682a715] 2016-01-26 15:38:33 -0500
-Branch: REL9_5_STABLE [2acb682f6] 2016-01-26 15:38:33 -0500
-Branch: REL9_4_STABLE [2b3983158] 2016-01-26 15:38:33 -0500
-Branch: REL9_3_STABLE [9bbfca8fd] 2016-01-26 15:38:33 -0500
-Branch: REL9_2_STABLE [3a7af9d73] 2016-01-26 15:38:33 -0500
-Branch: REL9_1_STABLE [b043df093] 2016-01-26 15:38:33 -0500
--->
-
     <listitem>
      <para>
       Make <literal>%h</> and <literal>%r</> escapes
@@ -558,16 +548,6 @@ Branch: REL9_1_STABLE [d05103b77] 2016-01-04 17:41:33 -0500
      </para>
     </listitem>
 
-<!--
-Author: Magnus Hagander <magnus@hagander.net>
-Branch: master [6a61d1ff9] 2016-01-14 13:06:03 +0100
-Branch: REL9_5_STABLE [3276ca303] 2016-01-14 13:07:20 +0100
-Branch: REL9_4_STABLE [ab49f87d5] 2016-01-14 13:07:35 +0100
-Branch: REL9_3_STABLE [77d8edcf5] 2016-01-14 13:07:45 +0100
-Branch: REL9_2_STABLE [df0bd5a0f] 2016-01-14 13:07:55 +0100
-Branch: REL9_1_STABLE [b1c0f92eb] 2016-01-14 13:08:10 +0100
--->
-
     <listitem>
      <para>
       Avoid leaking a token handle during SSPI authentication
@@ -605,16 +585,6 @@ Branch: REL9_1_STABLE [db462a44e] 2015-12-17 16:55:51 -0500
      </para>
     </listitem>
 
-<!--
-Author: Tom Lane <tgl@sss.pgh.pa.us>
-Branch: master [7e2247047] 2016-01-29 10:28:02 +0100
-Branch: REL9_5_STABLE [56251f396] 2016-01-29 10:28:02 +0100
-Branch: REL9_4_STABLE [5849b6e32] 2016-01-29 10:28:02 +0100
-Branch: REL9_3_STABLE [db678ca16] 2016-01-29 10:28:03 +0100
-Branch: REL9_2_STABLE [a362cc2e3] 2016-01-29 10:28:03 +0100
-Branch: REL9_1_STABLE [ed5f57218] 2016-01-29 10:28:03 +0100
--->
-
     <listitem>
      <para>
       Fix <application>psql</>'s <literal>\det</> command to interpret its
@@ -699,16 +669,6 @@ Branch: REL9_1_STABLE [87deb55a4] 2015-11-08 17:31:24 -0500
      </para>
     </listitem>
 
-<!--
-Author: Alvaro Herrera <alvherre@alvh.no-ip.org>
-Branch: master [a96761391] 2016-01-07 11:59:08 -0300
-Branch: REL9_5_STABLE [744d01c9a] 2016-01-07 11:59:08 -0300
-Branch: REL9_4_STABLE [c7aca3d45] 2016-01-07 11:59:08 -0300
-Branch: REL9_3_STABLE [74d4009b8] 2016-01-07 11:59:08 -0300
-Branch: REL9_2_STABLE [5c4cbd5d1] 2016-01-07 11:59:08 -0300
-Branch: REL9_1_STABLE [b96f6f444] 2016-01-07 11:59:08 -0300
--->
-
     <listitem>
      <para>
       In <application>pg_ctl</> on Windows, check service status to decide
@@ -750,16 +710,6 @@ Branch: REL9_1_STABLE [6df62ef43] 2015-11-23 00:32:01 -0500
      </para>
     </listitem>
 
-<!--
-Author: Tom Lane <tgl@sss.pgh.pa.us>
-Branch: master [e72d7d853] 2016-01-13 18:55:27 -0500
-Branch: REL9_5_STABLE [c42df2d46] 2016-01-13 18:55:27 -0500
-Branch: REL9_4_STABLE [7393208b5] 2016-01-13 18:55:27 -0500
-Branch: REL9_3_STABLE [b87403f70] 2016-01-13 18:55:27 -0500
-Branch: REL9_2_STABLE [be2b27651] 2016-01-13 18:55:27 -0500
-Branch: REL9_1_STABLE [5108013db] 2016-01-13 18:55:27 -0500
--->
-
     <listitem>
      <para>
       Fix assorted corner-case bugs in <application>pg_dump</>'s processing
@@ -767,29 +717,6 @@ Branch: REL9_1_STABLE [5108013db] 2016-01-13 18:55:27 -0500
      </para>
     </listitem>
 
-<!--
-Author: Alvaro Herrera <alvherre@alvh.no-ip.org>
-Branch: master [df43fcf45] 2016-01-22 20:04:35 -0300
-Branch: REL9_5_STABLE [1e910cf5b] 2016-01-22 20:04:35 -0300
--->
-
-    <listitem>
-     <para>
-      Fix improper quoting of domain constraint names
-      in <application>pg_dump</> (Elvis Pranskevichus)
-     </para>
-    </listitem>
-
-<!--
-Author: Tom Lane <tgl@sss.pgh.pa.us>
-Branch: master [0ed707e9b] 2016-02-04 00:26:10 -0500
-Branch: REL9_5_STABLE [b99dd7170] 2016-02-04 00:26:10 -0500
-Branch: REL9_4_STABLE [411e2b0d5] 2016-02-04 00:26:10 -0500
-Branch: REL9_3_STABLE [aefbc208b] 2016-02-04 00:26:10 -0500
-Branch: REL9_2_STABLE [4f58a7003] 2016-02-04 00:26:10 -0500
-Branch: REL9_1_STABLE [9c704632c] 2016-02-04 00:26:10 -0500
--->
-
     <listitem>
      <para>
       Make <application>pg_dump</> mark a view's triggers as needing to be
@@ -867,16 +794,6 @@ Branch: REL9_1_STABLE [c36064e43] 2015-11-24 17:18:27 -0500
      </para>
     </listitem>
 
-<!--
-Author: Robert Haas <rhaas@postgresql.org>
-Branch: master [64f5edca2] 2016-02-01 08:23:41 -0500
-Branch: REL9_5_STABLE [829757c8a] 2016-02-01 08:26:07 -0500
-Branch: REL9_4_STABLE [c33d1a8d5] 2016-02-03 09:15:29 -0500
-Branch: REL9_3_STABLE [014796aa3] 2016-02-03 09:19:58 -0500
-Branch: REL9_2_STABLE [b63a4f418] 2016-02-03 09:21:44 -0500
-Branch: REL9_1_STABLE [4c8b07d3c] 2016-02-03 09:25:34 -0500
--->
-
     <listitem>
      <para>
       Install guards in <application>pgbench</> against corner-case overflow
@@ -887,19 +804,6 @@ Branch: REL9_1_STABLE [4c8b07d3c] 2016-02-03 09:25:34 -0500
 
 <!--
 Author: Alvaro Herrera <alvherre@alvh.no-ip.org>
-Branch: master [4aecd22d3] 2016-01-05 17:25:12 -0300
-Branch: REL9_5_STABLE [7ef311eb4] 2016-01-05 17:25:12 -0300
--->
-
-    <listitem>
-     <para>
-      Suppress useless warning message when <application>pg_receivexlog</>
-      connects to a pre-9.4 server (Marco Nenciarini)
-     </para>
-    </listitem>
-
-<!--
-Author: Alvaro Herrera <alvherre@alvh.no-ip.org>
 Branch: master [fc995bfdb] 2015-12-28 10:50:35 -0300
 Branch: REL9_5_STABLE Release: REL9_5_0 [c3e068b26] 2015-12-28 10:50:35 -0300
 Branch: REL9_4_STABLE [f98bc20dd] 2015-12-28 10:50:35 -0300
@@ -915,17 +819,6 @@ Branch: REL9_2_STABLE [4fb9e6109] 2015-12-28 10:50:35 -0300
      </para>
     </listitem>
 
-<!--
-Author: Tom Lane <tgl@sss.pgh.pa.us>
-Branch: master [866566a69] 2016-01-11 19:55:39 -0500
-Branch: REL9_5_STABLE [db8fa56d6] 2016-01-11 19:55:39 -0500
-Branch: REL9_4_STABLE [22815752e] 2016-01-11 19:55:40 -0500
-Branch: REL9_3_STABLE [0ddeaba7e] 2016-01-11 19:55:40 -0500
-Branch: REL9_2_STABLE [3843ba510] 2016-01-11 19:55:40 -0500
-Branch: master [fb6fcbd33] 2016-01-11 20:06:36 -0500
-Branch: REL9_5_STABLE [5ef26b8de] 2016-01-11 20:06:47 -0500
--->
-
     <listitem>
      <para>
       Avoid dump/reload problems when using both <application>plpython2</>
@@ -933,15 +826,22 @@ Branch: REL9_5_STABLE [5ef26b8de] 2016-01-11 20:06:47 -0500
      </para>
 
      <para>
-      In principle, both versions of PL/Python can be used in the same
-      database, though not in the same session (because the two versions of
-      <application>libpython</> cannot safely be used concurrently).
+      In principle, both versions of <application>PL/Python</> can be used in
+      the same database, though not in the same session (because the two
+      versions of <application>libpython</> cannot safely be used concurrently).
       However, <application>pg_restore</> and <application>pg_upgrade</> both
       do things that can fall foul of the same-session restriction.  Work
       around that by changing the timing of the check.
      </para>
     </listitem>
 
+    <listitem>
+     <para>
+      Fix <application>PL/Python</> regression tests to pass with Python 3.5
+      (Peter Eisentraut)
+     </para>
+    </listitem>
+
 <!--
 Author: Tom Lane <tgl@sss.pgh.pa.us>
 Branch: master [c40591885] 2015-11-12 13:03:52 -0500
@@ -950,22 +850,6 @@ Branch: REL9_4_STABLE [40879a92b] 2015-11-12 13:03:52 -0500
 Branch: REL9_3_STABLE [db6e8e162] 2015-11-12 13:03:53 -0500
 -->
 
-<!--
-Author: Peter Eisentraut <peter_e@gmx.net>
-Branch: REL9_4_STABLE [f1b898759] 2015-11-14 13:43:43 -0500
-Branch: REL9_3_STABLE [a37ab812c] 2015-11-14 13:44:09 -0500
-Branch: REL9_2_STABLE [82076c1e4] 2015-11-14 13:53:26 -0500
-Author: Tom Lane <tgl@sss.pgh.pa.us>
-Branch: REL9_5_STABLE [a66c1fcdd] 2016-01-08 11:39:28 -0500
--->
-
-    <listitem>
-     <para>
-      Fix PL/Python regression tests to pass with Python 3.5
-      (Peter Eisentraut)
-     </para>
-    </listitem>
-
     <listitem>
      <para>
       Fix premature clearing of <application>libpq</>'s input buffer when
@@ -979,6 +863,21 @@ Branch: REL9_5_STABLE [a66c1fcdd] 2016-01-08 11:39:28 -0500
      </para>
     </listitem>
 
+    <listitem>
+     <para>
+      Prevent certain <application>PL/Java</> parameters from being set by
+      non-superusers (Noah Misch)
+     </para>
+
+     <para>
+      This change mitigates a <application>PL/Java</> security bug
+      (CVE-2016-0766), which was fixed in <application>PL/Java</> by marking
+      these parameters as superuser-only.  To fix the security hazard for
+      sites that update <productname>PostgreSQL</> more frequently
+      than <application>PL/Java</>, make the core code aware of them also.
+     </para>
+    </listitem>
+
 <!--
 Author: Heikki Linnakangas <heikki.linnakangas@iki.fi>
 Branch: master [7b96bf445] 2015-12-14 18:19:10 +0200
@@ -1031,15 +930,6 @@ Branch: REL9_1_STABLE [84387496f] 2015-12-01 11:42:52 -0500
      </para>
     </listitem>
 
-<!--
-Author: Michael Meskes <meskes@postgresql.org>
-Branch: master [7a58d19b0] 2016-02-01 13:21:00 +0100
-Branch: REL9_5_STABLE [40482e606] 2016-02-01 13:20:37 +0100
-Branch: REL9_3_STABLE [0b55fef39] 2016-02-01 13:19:10 +0100
-Branch: REL9_2_STABLE [d9ce5d201] 2016-02-01 13:19:34 +0100
-Branch: REL9_1_STABLE [79782b407] 2016-02-01 13:19:43 +0100
--->
-
     <listitem>
      <para>
       Fix <application>ecpg</>-supplied header files to not contain comments
@@ -1053,14 +943,6 @@ Branch: REL9_1_STABLE [79782b407] 2016-02-01 13:19:43 +0100
      </para>
     </listitem>
 
-<!--
-Author: Tom Lane <tgl@sss.pgh.pa.us>
-Branch: master [e6ecc93a1] 2016-02-03 01:39:48 -0500
-Branch: REL9_5_STABLE [1c291624b] 2016-02-03 01:39:08 -0500
-Branch: REL9_4_STABLE [aa223a037] 2016-02-03 01:39:08 -0500
-Branch: REL9_3_STABLE [1f2b195eb] 2016-02-03 01:39:08 -0500
--->
-
     <listitem>
      <para>
       Fix <function>hstore_to_json_loose()</>'s test for whether
@@ -1090,16 +972,6 @@ Branch: REL9_1_STABLE [1b6102eb7] 2015-12-27 13:03:19 -0300
      </para>
     </listitem>
 
-<!--
-Author: Robert Haas <rhaas@postgresql.org>
-Branch: master [9418d79a7] 2016-02-04 21:17:53 -0500
-Branch: REL9_5_STABLE [453d40817] 2016-02-04 21:17:46 -0500
-Branch: REL9_4_STABLE [1f3294c22] 2016-02-04 21:15:57 -0500
-Branch: master [37c84570b] 2016-02-04 22:27:13 -0500
-Branch: REL9_5_STABLE [d160e2a34] 2016-02-04 22:27:38 -0500
-Branch: REL9_4_STABLE [2099b911d] 2016-02-04 22:27:47 -0500
--->
-
     <listitem>
      <para>
       In <filename>contrib/postgres_fdw</>, fix bugs triggered by use
@@ -1135,27 +1007,6 @@ Branch: REL9_2_STABLE [7f94a5c10] 2015-12-10 10:19:31 -0500
      </para>
     </listitem>
 
-<!--
-Author: Tom Lane <tgl@sss.pgh.pa.us>
-Branch: master [a396144ac] 2016-01-22 11:53:06 -0500
-Branch: REL9_5_STABLE [47acf3add] 2016-01-22 11:53:06 -0500
--->
-
-    <listitem>
-     <para>
-      Fix ill-advised restriction of <literal>NAMEDATALEN</> to be less
-      than 256 (Robert Haas, Tom Lane)
-     </para>
-    </listitem>
-
-<!--
-Author: Tom Lane <tgl@sss.pgh.pa.us>
-Branch: master [3343ea9e8] 2016-01-05 15:47:05 -0500
-Branch: REL9_5_STABLE [8805af088] 2016-01-05 15:47:05 -0500
-Branch: REL9_4_STABLE [8c558b2e9] 2016-01-05 15:47:05 -0500
-Branch: REL9_3_STABLE [6d899f098] 2016-01-05 15:47:05 -0500
--->
-
     <listitem>
      <para>
       Improve reproducibility of build output by ensuring filenames are given
@@ -1190,20 +1041,10 @@ Branch: REL9_1_STABLE [2a37a103b] 2015-12-11 16:14:48 -0500
      </para>
     </listitem>
 
-<!--
-Author: Bruce Momjian <bruce@momjian.us>
-Branch: master [216d56843] 2016-01-19 23:30:29 -0500
-Branch: REL9_5_STABLE [34bda20ae] 2016-01-19 23:30:29 -0500
-Branch: REL9_4_STABLE [8b3d52801] 2016-01-19 23:30:29 -0500
-Branch: REL9_3_STABLE [7a47262ce] 2016-01-19 23:30:28 -0500
-Branch: REL9_2_STABLE [49d65e857] 2016-01-19 23:30:28 -0500
-Branch: REL9_1_STABLE [b1bc38144] 2016-01-19 23:30:28 -0500
--->
-
     <listitem>
      <para>
       Ensure that <filename>dynloader.h</> is included in the installed
-      header files in MSVC builds (Michael Paquier)
+      header files in MSVC builds (Bruce Momjian, Michael Paquier)
      </para>
     </listitem>
 
@@ -1231,16 +1072,6 @@ Branch: REL9_1_STABLE [386dcd539] 2015-12-11 19:08:40 -0500
      </para>
     </listitem>
 
-<!--
-Author: Tom Lane <tgl@sss.pgh.pa.us>
-Branch: master [a73311e52] 2016-02-05 10:59:09 -0500
-Branch: REL9_5_STABLE [37e694632] 2016-02-05 10:59:21 -0500
-Branch: REL9_4_STABLE [31b792f61] 2016-02-05 10:59:26 -0500
-Branch: REL9_3_STABLE [9a3475b84] 2016-02-05 10:59:31 -0500
-Branch: REL9_2_STABLE [32f17a2e7] 2016-02-05 10:59:35 -0500
-Branch: REL9_1_STABLE [6887d72d0] 2016-02-05 10:59:39 -0500
--->
-
     <listitem>
      <para>
       Update time zone data files to <application>tzdata</> release 2016a for
diff --git a/doc/src/sgml/release-9.5.sgml b/doc/src/sgml/release-9.5.sgml
index f47b7c2..6639be5 100644
--- a/doc/src/sgml/release-9.5.sgml
+++ b/doc/src/sgml/release-9.5.sgml
@@ -1,6 +1,403 @@
 <!-- doc/src/sgml/release-9.5.sgml -->
 <!-- See header comment in release.sgml about typical markup -->
 
+ <sect1 id="release-9-5-1">
+  <title>Release 9.5.1</title>
+
+  <note>
+  <title>Release Date</title>
+  <simpara>2016-02-11</simpara>
+  </note>
+
+  <para>
+   This release contains a variety of fixes from 9.5.0.
+   For information about new features in the 9.5 major release, see
+   <xref linkend="release-9-5">.
+  </para>
+
+  <sect2>
+   <title>Migration to Version 9.5.1</title>
+
+   <para>
+    A dump/restore is not required for those running 9.5.X.
+   </para>
+  </sect2>
+
+  <sect2>
+   <title>Changes</title>
+
+   <itemizedlist>
+
+<!--
+Author: Tom Lane <tgl@sss.pgh.pa.us>
+Branch: master [f867ce551] 2016-02-07 12:29:32 -0500
+Branch: REL9_5_STABLE [129db3cbe] 2016-02-07 12:29:17 -0500
+-->
+
+    <listitem>
+     <para>
+      Fix an oversight that caused hash joins to miss joining to some tuples
+      of the inner relation in rare cases (Tomas Vondra, Tom Lane)
+     </para>
+    </listitem>
+
+<!--
+Author: Tom Lane <tgl@sss.pgh.pa.us>
+Branch: master [b8682a715] 2016-01-26 15:38:33 -0500
+Branch: REL9_5_STABLE [2acb682f6] 2016-01-26 15:38:33 -0500
+Branch: REL9_4_STABLE [2b3983158] 2016-01-26 15:38:33 -0500
+Branch: REL9_3_STABLE [9bbfca8fd] 2016-01-26 15:38:33 -0500
+Branch: REL9_2_STABLE [3a7af9d73] 2016-01-26 15:38:33 -0500
+Branch: REL9_1_STABLE [b043df093] 2016-01-26 15:38:33 -0500
+-->
+
+    <listitem>
+     <para>
+      Make <literal>%h</> and <literal>%r</> escapes
+      in <varname>log_line_prefix</> work for messages emitted due
+      to <varname>log_connections</> (Tom Lane)
+     </para>
+
+     <para>
+      Previously, <literal>%h</>/<literal>%r</> started to work just after a
+      new session had emitted the <quote>connection received</> log message;
+      now they work for that message too.
+     </para>
+    </listitem>
+
+<!--
+Author: Magnus Hagander <magnus@hagander.net>
+Branch: master [6a61d1ff9] 2016-01-14 13:06:03 +0100
+Branch: REL9_5_STABLE [3276ca303] 2016-01-14 13:07:20 +0100
+Branch: REL9_4_STABLE [ab49f87d5] 2016-01-14 13:07:35 +0100
+Branch: REL9_3_STABLE [77d8edcf5] 2016-01-14 13:07:45 +0100
+Branch: REL9_2_STABLE [df0bd5a0f] 2016-01-14 13:07:55 +0100
+Branch: REL9_1_STABLE [b1c0f92eb] 2016-01-14 13:08:10 +0100
+-->
+
+    <listitem>
+     <para>
+      Avoid leaking a token handle during SSPI authentication
+      (Christian Ullrich)
+     </para>
+    </listitem>
+
+<!--
+Author: Tom Lane <tgl@sss.pgh.pa.us>
+Branch: master [7e2247047] 2016-01-29 10:28:02 +0100
+Branch: REL9_5_STABLE [56251f396] 2016-01-29 10:28:02 +0100
+Branch: REL9_4_STABLE [5849b6e32] 2016-01-29 10:28:02 +0100
+Branch: REL9_3_STABLE [db678ca16] 2016-01-29 10:28:03 +0100
+Branch: REL9_2_STABLE [a362cc2e3] 2016-01-29 10:28:03 +0100
+Branch: REL9_1_STABLE [ed5f57218] 2016-01-29 10:28:03 +0100
+-->
+
+    <listitem>
+     <para>
+      Fix <application>psql</>'s <literal>\det</> command to interpret its
+      pattern argument the same way as other <literal>\d</> commands with
+      potentially schema-qualified patterns do (Reece Hart)
+     </para>
+    </listitem>
+
+<!--
+Author: Alvaro Herrera <alvherre@alvh.no-ip.org>
+Branch: master [a96761391] 2016-01-07 11:59:08 -0300
+Branch: REL9_5_STABLE [744d01c9a] 2016-01-07 11:59:08 -0300
+Branch: REL9_4_STABLE [c7aca3d45] 2016-01-07 11:59:08 -0300
+Branch: REL9_3_STABLE [74d4009b8] 2016-01-07 11:59:08 -0300
+Branch: REL9_2_STABLE [5c4cbd5d1] 2016-01-07 11:59:08 -0300
+Branch: REL9_1_STABLE [b96f6f444] 2016-01-07 11:59:08 -0300
+-->
+
+    <listitem>
+     <para>
+      In <application>pg_ctl</> on Windows, check service status to decide
+      where to send output, rather than checking if standard output is a
+      terminal (Michael Paquier)
+     </para>
+    </listitem>
+
+<!--
+Author: Tom Lane <tgl@sss.pgh.pa.us>
+Branch: master [e72d7d853] 2016-01-13 18:55:27 -0500
+Branch: REL9_5_STABLE [c42df2d46] 2016-01-13 18:55:27 -0500
+Branch: REL9_4_STABLE [7393208b5] 2016-01-13 18:55:27 -0500
+Branch: REL9_3_STABLE [b87403f70] 2016-01-13 18:55:27 -0500
+Branch: REL9_2_STABLE [be2b27651] 2016-01-13 18:55:27 -0500
+Branch: REL9_1_STABLE [5108013db] 2016-01-13 18:55:27 -0500
+-->
+
+    <listitem>
+     <para>
+      Fix assorted corner-case bugs in <application>pg_dump</>'s processing
+      of extension member objects (Tom Lane)
+     </para>
+    </listitem>
+
+<!--
+Author: Alvaro Herrera <alvherre@alvh.no-ip.org>
+Branch: master [df43fcf45] 2016-01-22 20:04:35 -0300
+Branch: REL9_5_STABLE [1e910cf5b] 2016-01-22 20:04:35 -0300
+-->
+
+    <listitem>
+     <para>
+      Fix improper quoting of domain constraint names
+      in <application>pg_dump</> (Elvis Pranskevichus)
+     </para>
+    </listitem>
+
+<!--
+Author: Tom Lane <tgl@sss.pgh.pa.us>
+Branch: master [0ed707e9b] 2016-02-04 00:26:10 -0500
+Branch: REL9_5_STABLE [b99dd7170] 2016-02-04 00:26:10 -0500
+Branch: REL9_4_STABLE [411e2b0d5] 2016-02-04 00:26:10 -0500
+Branch: REL9_3_STABLE [aefbc208b] 2016-02-04 00:26:10 -0500
+Branch: REL9_2_STABLE [4f58a7003] 2016-02-04 00:26:10 -0500
+Branch: REL9_1_STABLE [9c704632c] 2016-02-04 00:26:10 -0500
+-->
+
+    <listitem>
+     <para>
+      Make <application>pg_dump</> mark a view's triggers as needing to be
+      processed after its rule, to prevent possible failure during
+      parallel <application>pg_restore</> (Tom Lane)
+     </para>
+    </listitem>
+
+<!--
+Author: Robert Haas <rhaas@postgresql.org>
+Branch: master [64f5edca2] 2016-02-01 08:23:41 -0500
+Branch: REL9_5_STABLE [829757c8a] 2016-02-01 08:26:07 -0500
+Branch: REL9_4_STABLE [c33d1a8d5] 2016-02-03 09:15:29 -0500
+Branch: REL9_3_STABLE [014796aa3] 2016-02-03 09:19:58 -0500
+Branch: REL9_2_STABLE [b63a4f418] 2016-02-03 09:21:44 -0500
+Branch: REL9_1_STABLE [4c8b07d3c] 2016-02-03 09:25:34 -0500
+-->
+
+    <listitem>
+     <para>
+      Install guards in <application>pgbench</> against corner-case overflow
+      conditions during evaluation of script-specified division or modulo
+      operators (Fabien Coelho, Michael Paquier)
+     </para>
+    </listitem>
+
+<!--
+Author: Alvaro Herrera <alvherre@alvh.no-ip.org>
+Branch: master [4aecd22d3] 2016-01-05 17:25:12 -0300
+Branch: REL9_5_STABLE [7ef311eb4] 2016-01-05 17:25:12 -0300
+-->
+
+    <listitem>
+     <para>
+      Suppress useless warning message when <application>pg_receivexlog</>
+      connects to a pre-9.4 server (Marco Nenciarini)
+     </para>
+    </listitem>
+
+<!--
+Author: Tom Lane <tgl@sss.pgh.pa.us>
+Branch: master [866566a69] 2016-01-11 19:55:39 -0500
+Branch: REL9_5_STABLE [db8fa56d6] 2016-01-11 19:55:39 -0500
+Branch: REL9_4_STABLE [22815752e] 2016-01-11 19:55:40 -0500
+Branch: REL9_3_STABLE [0ddeaba7e] 2016-01-11 19:55:40 -0500
+Branch: REL9_2_STABLE [3843ba510] 2016-01-11 19:55:40 -0500
+Branch: master [fb6fcbd33] 2016-01-11 20:06:36 -0500
+Branch: REL9_5_STABLE [5ef26b8de] 2016-01-11 20:06:47 -0500
+-->
+
+    <listitem>
+     <para>
+      Avoid dump/reload problems when using both <application>plpython2</>
+      and <application>plpython3</> (Tom Lane)
+     </para>
+
+     <para>
+      In principle, both versions of <application>PL/Python</> can be used in
+      the same database, though not in the same session (because the two
+      versions of <application>libpython</> cannot safely be used concurrently).
+      However, <application>pg_restore</> and <application>pg_upgrade</> both
+      do things that can fall foul of the same-session restriction.  Work
+      around that by changing the timing of the check.
+     </para>
+    </listitem>
+
+<!--
+Author: Peter Eisentraut <peter_e@gmx.net>
+Branch: REL9_4_STABLE [f1b898759] 2015-11-14 13:43:43 -0500
+Branch: REL9_3_STABLE [a37ab812c] 2015-11-14 13:44:09 -0500
+Branch: REL9_2_STABLE [82076c1e4] 2015-11-14 13:53:26 -0500
+Author: Tom Lane <tgl@sss.pgh.pa.us>
+Branch: REL9_5_STABLE [a66c1fcdd] 2016-01-08 11:39:28 -0500
+-->
+
+    <listitem>
+     <para>
+      Fix <application>PL/Python</> regression tests to pass with Python 3.5
+      (Peter Eisentraut)
+     </para>
+    </listitem>
+
+<!--
+Author: Noah Misch <noah@leadboat.com>
+Branch: master [f4aa3a18a] 2016-02-05 20:22:51 -0500
+Branch: REL9_5_STABLE [0089dd34a] 2016-02-05 20:23:04 -0500
+Branch: REL9_4_STABLE [ed6deeb7a] 2016-02-05 20:23:07 -0500
+Branch: REL9_3_STABLE [34e91736b] 2016-02-05 20:23:11 -0500
+Branch: REL9_2_STABLE [de9766d39] 2016-02-05 20:23:14 -0500
+Branch: REL9_1_STABLE [b1f591c50] 2016-02-05 20:23:19 -0500
+-->
+
+    <listitem>
+     <para>
+      Prevent certain <application>PL/Java</> parameters from being set by
+      non-superusers (Noah Misch)
+     </para>
+
+     <para>
+      This change mitigates a <application>PL/Java</> security bug
+      (CVE-2016-0766), which was fixed in <application>PL/Java</> by marking
+      these parameters as superuser-only.  To fix the security hazard for
+      sites that update <productname>PostgreSQL</> more frequently
+      than <application>PL/Java</>, make the core code aware of them also.
+     </para>
+    </listitem>
+
+<!--
+Author: Michael Meskes <meskes@postgresql.org>
+Branch: master [7a58d19b0] 2016-02-01 13:21:00 +0100
+Branch: REL9_5_STABLE [40482e606] 2016-02-01 13:20:37 +0100
+Branch: REL9_3_STABLE [0b55fef39] 2016-02-01 13:19:10 +0100
+Branch: REL9_2_STABLE [d9ce5d201] 2016-02-01 13:19:34 +0100
+Branch: REL9_1_STABLE [79782b407] 2016-02-01 13:19:43 +0100
+-->
+
+    <listitem>
+     <para>
+      Fix <application>ecpg</>-supplied header files to not contain comments
+      continued from a preprocessor directive line onto the next line
+      (Michael Meskes)
+     </para>
+
+     <para>
+      Such a comment is rejected by <application>ecpg</>.  It's not yet clear
+      whether <application>ecpg</> itself should be changed.
+     </para>
+    </listitem>
+
+<!--
+Author: Tom Lane <tgl@sss.pgh.pa.us>
+Branch: master [e6ecc93a1] 2016-02-03 01:39:48 -0500
+Branch: REL9_5_STABLE [1c291624b] 2016-02-03 01:39:08 -0500
+Branch: REL9_4_STABLE [aa223a037] 2016-02-03 01:39:08 -0500
+Branch: REL9_3_STABLE [1f2b195eb] 2016-02-03 01:39:08 -0500
+-->
+
+    <listitem>
+     <para>
+      Fix <function>hstore_to_json_loose()</>'s test for whether
+      an <type>hstore</> value can be converted to a JSON number (Tom Lane)
+     </para>
+
+     <para>
+      Previously this function could be fooled by non-alphanumeric trailing
+      characters, leading to emitting syntactically-invalid JSON.
+     </para>
+    </listitem>
+
+<!--
+Author: Robert Haas <rhaas@postgresql.org>
+Branch: master [9418d79a7] 2016-02-04 21:17:53 -0500
+Branch: REL9_5_STABLE [453d40817] 2016-02-04 21:17:46 -0500
+Branch: REL9_4_STABLE [1f3294c22] 2016-02-04 21:15:57 -0500
+Branch: master [37c84570b] 2016-02-04 22:27:13 -0500
+Branch: REL9_5_STABLE [d160e2a34] 2016-02-04 22:27:38 -0500
+Branch: REL9_4_STABLE [2099b911d] 2016-02-04 22:27:47 -0500
+-->
+
+    <listitem>
+     <para>
+      In <filename>contrib/postgres_fdw</>, fix bugs triggered by use
+      of <literal>tableoid</> in data-modifying commands (Etsuro Fujita,
+      Robert Haas)
+     </para>
+    </listitem>
+
+<!--
+Author: Tom Lane <tgl@sss.pgh.pa.us>
+Branch: master [a396144ac] 2016-01-22 11:53:06 -0500
+Branch: REL9_5_STABLE [47acf3add] 2016-01-22 11:53:06 -0500
+-->
+
+    <listitem>
+     <para>
+      Fix ill-advised restriction of <literal>NAMEDATALEN</> to be less
+      than 256 (Robert Haas, Tom Lane)
+     </para>
+    </listitem>
+
+<!--
+Author: Tom Lane <tgl@sss.pgh.pa.us>
+Branch: master [3343ea9e8] 2016-01-05 15:47:05 -0500
+Branch: REL9_5_STABLE [8805af088] 2016-01-05 15:47:05 -0500
+Branch: REL9_4_STABLE [8c558b2e9] 2016-01-05 15:47:05 -0500
+Branch: REL9_3_STABLE [6d899f098] 2016-01-05 15:47:05 -0500
+-->
+
+    <listitem>
+     <para>
+      Improve reproducibility of build output by ensuring filenames are given
+      to the linker in a fixed order (Christoph Berg)
+     </para>
+
+     <para>
+      This avoids possible bitwise differences in the produced executable
+      files from one build to the next.
+     </para>
+    </listitem>
+
+<!--
+Author: Bruce Momjian <bruce@momjian.us>
+Branch: master [216d56843] 2016-01-19 23:30:29 -0500
+Branch: REL9_5_STABLE [34bda20ae] 2016-01-19 23:30:29 -0500
+Branch: REL9_4_STABLE [8b3d52801] 2016-01-19 23:30:29 -0500
+Branch: REL9_3_STABLE [7a47262ce] 2016-01-19 23:30:28 -0500
+Branch: REL9_2_STABLE [49d65e857] 2016-01-19 23:30:28 -0500
+Branch: REL9_1_STABLE [b1bc38144] 2016-01-19 23:30:28 -0500
+-->
+
+    <listitem>
+     <para>
+      Ensure that <filename>dynloader.h</> is included in the installed
+      header files in MSVC builds (Bruce Momjian, Michael Paquier)
+     </para>
+    </listitem>
+
+<!--
+Author: Tom Lane <tgl@sss.pgh.pa.us>
+Branch: master [a73311e52] 2016-02-05 10:59:09 -0500
+Branch: REL9_5_STABLE [37e694632] 2016-02-05 10:59:21 -0500
+Branch: REL9_4_STABLE [31b792f61] 2016-02-05 10:59:26 -0500
+Branch: REL9_3_STABLE [9a3475b84] 2016-02-05 10:59:31 -0500
+Branch: REL9_2_STABLE [32f17a2e7] 2016-02-05 10:59:35 -0500
+Branch: REL9_1_STABLE [6887d72d0] 2016-02-05 10:59:39 -0500
+-->
+
+    <listitem>
+     <para>
+      Update time zone data files to <application>tzdata</> release 2016a for
+      DST law changes in Cayman Islands, Metlakatla, and Trans-Baikal
+      Territory (Zabaykalsky Krai), plus historical corrections for Pakistan.
+     </para>
+    </listitem>
+
+   </itemizedlist>
+
+  </sect2>
+ </sect1>
+
  <sect1 id="release-9-5">
   <title>Release 9.5</title>
 
diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c
index 8eea092..4f91cd0 100644
--- a/src/backend/access/transam/parallel.c
+++ b/src/backend/access/transam/parallel.c
@@ -22,6 +22,7 @@
 #include "libpq/pqformat.h"
 #include "libpq/pqmq.h"
 #include "miscadmin.h"
+#include "optimizer/planmain.h"
 #include "storage/ipc.h"
 #include "storage/sinval.h"
 #include "storage/spin.h"
@@ -432,6 +433,9 @@ LaunchParallelWorkers(ParallelContext *pcxt)
 	if (pcxt->nworkers == 0)
 		return;
 
+	/* We need to be a lock group leader. */
+	BecomeLockGroupLeader();
+
 	/* If we do have workers, we'd better have a DSM segment. */
 	Assert(pcxt->seg != NULL);
 
@@ -952,6 +956,19 @@ ParallelWorkerMain(Datum main_arg)
 	 */
 
 	/*
+	 * Join locking group.  We must do this before anything that could try
+	 * to acquire a heavyweight lock, because any heavyweight locks acquired
+	 * to this point could block either directly against the parallel group
+	 * leader or against some process which in turn waits for a lock that
+	 * conflicts with the parallel group leader, causing an undetected
+	 * deadlock.  (If we can't join the lock group, the leader has gone away,
+	 * so just exit quietly.)
+	 */
+	if (!BecomeLockGroupMember(fps->parallel_master_pgproc,
+							   fps->parallel_master_pid))
+		return;
+
+	/*
 	 * Load libraries that were loaded by original backend.  We want to do
 	 * this before restoring GUCs, because the libraries might define custom
 	 * variables.
@@ -1063,7 +1080,8 @@ ParallelExtensionTrampoline(dsm_segment *seg, shm_toc *toc)
 static void
 ParallelErrorContext(void *arg)
 {
-	errcontext("parallel worker, PID %d", *(int32 *) arg);
+	if (force_parallel_mode != FORCE_PARALLEL_REGRESS)
+		errcontext("parallel worker, PID %d", *(int32 *) arg);
 }
 
 /*
diff --git a/src/backend/commands/constraint.c b/src/backend/commands/constraint.c
index 26f9114..02b72a3 100644
--- a/src/backend/commands/constraint.c
+++ b/src/backend/commands/constraint.c
@@ -13,13 +13,18 @@
  */
 #include "postgres.h"
 
+#include "access/htup_details.h"
 #include "catalog/index.h"
+#include "catalog/pg_constraint.h"
+#include "commands/constraint.h"
 #include "commands/trigger.h"
 #include "executor/executor.h"
 #include "utils/builtins.h"
 #include "utils/rel.h"
+#include "utils/syscache.h"
 #include "utils/tqual.h"
 
+static char *tryExtractNotNull_internal(Node *node, Relation rel);
 
 /*
  * unique_key_recheck - trigger function to do a deferred uniqueness check.
@@ -193,3 +198,125 @@ unique_key_recheck(PG_FUNCTION_ARGS)
 
 	return PointerGetDatum(NULL);
 }
+
+Constraint *
+createCheckNotNullConstraint(Oid nspid, char *constraint_name,
+							 const char *relname, const char *colname)
+{
+	Constraint *check = makeNode(Constraint);
+	ColumnRef  *colref;
+	NullTest   *nulltest;
+
+	colref = (ColumnRef *) makeNode(ColumnRef);
+	colref->fields = list_make1(makeString(pstrdup(colname)));
+
+	nulltest = (NullTest *) makeNode(NullTest);
+	nulltest->argisrow = false;	/* FIXME -- may be bogus! */
+	nulltest->nulltesttype = IS_NOT_NULL;
+	nulltest->arg = (Expr *) colref;
+
+	check->contype = CONSTR_CHECK;
+	check->location = -1;
+	check->conname = constraint_name ? constraint_name :
+		ChooseConstraintName(relname, colname, "not_null", nspid,
+							 NIL);
+	check->raw_expr = (Node *) nulltest;
+	check->cooked_expr = NULL;
+
+	return check;
+}
+
+/*
+ * Given a CHECK constraint, examine it and determine whether it is CHECK (col
+ * IS NOT NULL).  If it is, return the column name for which it is.  Otherwise
+ * return NULL.
+ */
+char *
+tryExtractNotNullFromCheckConstr(Constraint *constr)
+{
+	char   *retval;
+
+	Assert(constr->contype == CONSTR_CHECK);
+
+	if (constr->raw_expr != NULL)
+	{
+		Assert(constr->cooked_expr == NULL);  // as in heap.c
+		retval = tryExtractNotNull_internal(constr->raw_expr, NULL);
+	}
+	else
+	{
+		Assert(constr->cooked_expr != NULL);  // as in heap.c
+		retval = tryExtractNotNull_internal(stringToNode(constr->cooked_expr), NULL);
+	}
+
+	return retval;
+}
+
+/*
+ * As above, but use a pg_constraint row as input.
+ *
+ * tupdesc is pg_constraint's tuple descriptor, and rel is the relation the
+ * constraint is for.
+ */
+char *
+tryExtractNotNullFromCatalog(HeapTuple constrTup, TupleDesc tupdesc,
+							 Relation rel)
+{
+	Datum	val;
+	bool	isnull;
+	char   *conbin;
+	Node   *node;
+
+	val = SysCacheGetAttr(CONSTROID, constrTup, Anum_pg_constraint_conbin,
+						  &isnull);
+	if (isnull)
+		elog(ERROR, "null conbin for constraint %u",
+			 HeapTupleGetOid(constrTup));
+	conbin = TextDatumGetCString(val);
+	node = (Node *) stringToNode(conbin);
+
+	return tryExtractNotNull_internal(node, rel);
+}
+
+/*
+ * Worker for the above
+ */
+static char *
+tryExtractNotNull_internal(Node *node, Relation rel)
+{
+	if (IsA(node, NullTest))
+	{
+		NullTest *nulltest = (NullTest *) node;
+
+		if (nulltest->nulltesttype == IS_NOT_NULL)
+		{
+			if (IsA(nulltest->arg, ColumnRef))
+			{
+				ColumnRef *colref = (ColumnRef *) nulltest->arg;
+
+				if (list_length(colref->fields) == 1)
+					return strVal(linitial(colref->fields));
+			}
+			if (IsA(nulltest->arg, Var))
+			{
+				Var	   *var = (Var *) nulltest->arg;
+				TupleDesc tupdesc;
+
+				if (!RelationIsValid(rel))
+					elog(ERROR,
+						 "no relation given to extract constraint from");
+				tupdesc = RelationGetDescr(rel);
+				return NameStr(tupdesc->attrs[var->varattno - 1]->attname);
+			}
+		}
+	}
+
+	/*
+	 * XXX Need to check a few more possible wordings of NOT NULL:
+	 *
+	 * - foo IS DISTINCT FROM NULL
+	 * - NOT (foo IS NULL)
+	 */
+
+	return NULL;
+}
diff --git a/src/backend/commands/createas.c b/src/backend/commands/createas.c
index fcb0331..514568e 100644
--- a/src/backend/commands/createas.c
+++ b/src/backend/commands/createas.c
@@ -312,6 +312,7 @@ intorel_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
 	create->inhRelations = NIL;
 	create->ofTypename = NULL;
 	create->constraints = NIL;
+	create->notnullcols = NIL;
 	create->options = into->options;
 	create->oncommit = into->onCommit;
 	create->tablespacename = into->tableSpaceName;
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 25d8ca0..ee13136 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -23,6 +23,7 @@
 #include "foreign/fdwapi.h"
 #include "nodes/nodeFuncs.h"
 #include "optimizer/clauses.h"
+#include "optimizer/planmain.h"
 #include "parser/parsetree.h"
 #include "rewrite/rewriteHandler.h"
 #include "tcop/tcopprot.h"
@@ -572,6 +573,7 @@ void
 ExplainPrintPlan(ExplainState *es, QueryDesc *queryDesc)
 {
 	Bitmapset  *rels_used = NULL;
+	PlanState *ps;
 
 	Assert(queryDesc->plannedstmt != NULL);
 	es->pstmt = queryDesc->plannedstmt;
@@ -580,7 +582,17 @@ ExplainPrintPlan(ExplainState *es, QueryDesc *queryDesc)
 	es->rtable_names = select_rtable_names_for_explain(es->rtable, rels_used);
 	es->deparse_cxt = deparse_context_for_plan_rtable(es->rtable,
 													  es->rtable_names);
-	ExplainNode(queryDesc->planstate, NIL, NULL, NULL, es);
+
+	/*
+	 * Sometimes we mark a Gather node as "invisible", which means that it's
+	 * not displayed in EXPLAIN output.  The purpose of this is to allow
+	 * running regression tests with force_parallel_mode=regress to get the
+	 * same results as running the same tests with force_parallel_mode=off.
+	 */
+	ps = queryDesc->planstate;
+	if (IsA(ps, GatherState) &&((Gather *) ps->plan)->invisible)
+		ps = outerPlanState(ps);
+	ExplainNode(ps, NIL, NULL, NULL, es);
 }
 
 /*
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index eeda3b4..38eacf2 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -47,6 +47,7 @@
 #include "catalog/toasting.h"
 #include "commands/cluster.h"
 #include "commands/comment.h"
+#include "commands/constraint.h"
 #include "commands/defrem.h"
 #include "commands/event_trigger.h"
 #include "commands/policy.h"
@@ -61,7 +62,6 @@
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
 #include "nodes/nodeFuncs.h"
-#include "nodes/parsenodes.h"
 #include "optimizer/clauses.h"
 #include "optimizer/planner.h"
 #include "parser/parse_clause.h"
@@ -270,8 +270,9 @@ struct DropRelationCallbackState
 #define		ATT_FOREIGN_TABLE		0x0020
 
 static void truncate_check_rel(Relation rel);
-static List *MergeAttributes(List *schema, List *supers, char relpersistence,
-				List **supOids, List **supconstr, int *supOidCount);
+static List *MergeAttributes(List *schema, List *notnullcols, List *supers,
+				char relpersistence, List **supOids, List **supconstr,
+				int *supOidCount);
 static bool MergeCheckConstraint(List *constraints, char *name, Node *expr);
 static void MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel);
 static void MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel);
@@ -339,8 +340,9 @@ static void add_column_collation_dependency(Oid relid, int32 attnum, Oid collid)
 static void ATPrepAddOids(List **wqueue, Relation rel, bool recurse,
 			  AlterTableCmd *cmd, LOCKMODE lockmode);
 static ObjectAddress ATExecDropNotNull(Relation rel, const char *colName, LOCKMODE lockmode);
-static ObjectAddress ATExecSetNotNull(AlteredTableInfo *tab, Relation rel,
-				 const char *colName, LOCKMODE lockmode);
+static ObjectAddress ATExecSetNotNull(List **wqueue, AlteredTableInfo *tab,
+				 Relation rel, char *constrname, const char *colName,
+				 LOCKMODE lockmode);
 static ObjectAddress ATExecColumnDefault(Relation rel, const char *colName,
 					Node *newDefault, LOCKMODE lockmode);
 static void ATPrepSetStatistics(Relation rel, const char *colName,
@@ -370,6 +372,11 @@ static ObjectAddress ATAddCheckConstraint(List **wqueue,
 					 Constraint *constr,
 					 bool recurse, bool recursing, bool is_readd,
 					 LOCKMODE lockmode);
+static ObjectAddress ATAddCheckConstraint_internal(List **wqueue,
+					 AlteredTableInfo *tab, Relation rel,
+					 Constraint *constr,
+					 bool recurse, bool recursing, bool is_readd,
+					 bool check_it, LOCKMODE lockmode);
 static ObjectAddress ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
 						  Constraint *fkconstraint, LOCKMODE lockmode);
 static void ATExecDropConstraint(Relation rel, const char *constrName,
@@ -575,7 +582,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
 	 * Look up inheritance ancestors and generate relation schema, including
 	 * inherited attributes.
 	 */
-	schema = MergeAttributes(schema, stmt->inhRelations,
+	schema = MergeAttributes(schema, stmt->notnullcols, stmt->inhRelations,
 							 stmt->relation->relpersistence,
 							 &inheritOids, &old_constraints, &parentOidCount);
 
@@ -1356,6 +1363,8 @@ storage_name(char c)
  * Input arguments:
  * 'schema' is the column/attribute definition for the table. (It's a list
  *		of ColumnDef's.) It is destructively changed.
+ * 'notnullcols' is a list of column names that have NOT NULL constraints.
+ *		Some of these columns may already have is_not_null already set.
  * 'supers' is a list of names (as RangeVar nodes) of parent relations.
  * 'relpersistence' is a persistence type of the table.
  *
@@ -1408,10 +1417,12 @@ storage_name(char c)
  *----------
  */
 static List *
-MergeAttributes(List *schema, List *supers, char relpersistence,
-				List **supOids, List **supconstr, int *supOidCount)
+MergeAttributes(List *schema, List *notnullcols, List *supers,
+				char relpersistence, List **supOids, List **supconstr,
+				int *supOidCount)
 {
 	ListCell   *entry;
+	ListCell   *cell;
 	List	   *inhSchema = NIL;
 	List	   *parentOids = NIL;
 	List	   *constraints = NIL;
@@ -1896,6 +1907,23 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
 	}
 
 	/*
+	 * If we have NOT NULL constraint declarations, set the is_not_null bits
+	 * in the correspoding ColumnDef elements.
+	 */
+	foreach (cell, notnullcols)
+	{
+		char   *colname = lfirst(cell);
+
+		foreach (entry, schema)
+		{
+			ColumnDef *coldef = lfirst(entry);
+
+			if (strcmp(coldef->colname, colname) == 0)
+				coldef->is_not_null = true;
+		}
+	}
+
+	/*
 	 * If we found any conflicting parent default values, check to make sure
 	 * they were overridden by the child.
 	 */
@@ -3479,7 +3507,7 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
 			address = ATExecDropNotNull(rel, cmd->name, lockmode);
 			break;
 		case AT_SetNotNull:		/* ALTER COLUMN SET NOT NULL */
-			address = ATExecSetNotNull(tab, rel, cmd->name, lockmode);
+			address = ATExecSetNotNull(wqueue, tab, rel, NULL, cmd->name, lockmode);
 			break;
 		case AT_SetStatistics:	/* ALTER COLUMN SET STATISTICS */
 			address = ATExecSetStatistics(rel, cmd->name, cmd->def, lockmode);
@@ -5281,13 +5309,14 @@ ATExecDropNotNull(Relation rel, const char *colName, LOCKMODE lockmode)
  * NULL, InvalidObjectAddress is returned.
  */
 static ObjectAddress
-ATExecSetNotNull(AlteredTableInfo *tab, Relation rel,
-				 const char *colName, LOCKMODE lockmode)
+ATExecSetNotNull(List **wqueue, AlteredTableInfo *tab, Relation rel,
+				 char *constrname, const char *colName, LOCKMODE lockmode)
 {
 	HeapTuple	tuple;
 	AttrNumber	attnum;
 	Relation	attr_rel;
 	ObjectAddress address;
+	Constraint *newconstr;
 
 	/*
 	 * lookup the attribute
@@ -5332,6 +5361,20 @@ ATExecSetNotNull(AlteredTableInfo *tab, Relation rel,
 	else
 		address = InvalidObjectAddress;
 
+	/*
+	 * We also need to add a new pg_constraint row.  Use
+	 * ATAddCheckConstraint_internal for that, but let it know that it
+	 * doesn't need to test the constraint; we already informed it above,
+	 * if necessary.
+	 */
+	newconstr = createCheckNotNullConstraint(rel->rd_rel->relnamespace,
+											 constrname,
+											 NameStr(rel->rd_rel->relname),
+											 colName);
+
+	ATAddCheckConstraint_internal(wqueue, tab, rel, newconstr,
+								  true, false, false, true, lockmode);
+
 	InvokeObjectPostAlterHook(RelationRelationId,
 							  RelationGetRelid(rel), attnum);
 
@@ -6108,6 +6151,40 @@ ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
 					 Constraint *constr, bool recurse, bool recursing,
 					 bool is_readd, LOCKMODE lockmode)
 {
+	char *colname;
+	ObjectAddress address;
+
+	/*
+	 * If the constraint we're adding is CHECK (col IS NOT NULL), then we route
+	 * it through ATExecSetNotNull instead of working directly with it; that
+	 * function is responsible for getting back to us to recurse, etc.
+	 *
+	 * The reason for this is to get the attnotnull bit set for the column, and
+	 * also to avoid having a second NOT NULL constraint for a column that
+	 * might already have one.  (XXX is the latter actually a desirable
+	 * property?  Consider inherited tables here.)
+	 */
+	Assert(constr->contype == CONSTR_CHECK);
+
+	colname = tryExtractNotNullFromCheckConstr(constr);
+	if (colname != NULL)
+		address = ATExecSetNotNull(wqueue, tab, rel, constr->conname,
+								   colname, lockmode);
+	else
+		/* Not a single-column NOT NULL constraint -- do the regular dance */
+		address = ATAddCheckConstraint_internal(wqueue, tab, rel, constr,
+												recurse, recursing, is_readd,
+												true, lockmode);
+
+	return address;
+}
+
+static ObjectAddress
+ATAddCheckConstraint_internal(List **wqueue, AlteredTableInfo *tab,
+							  Relation rel, Constraint *constr, bool recurse,
+							  bool recursing, bool is_readd,
+							  bool check_it, LOCKMODE lockmode)
+{
 	List	   *newcons;
 	ListCell   *lcon;
 	List	   *children;
@@ -6214,8 +6291,9 @@ ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
 		childtab = ATGetQueueEntry(wqueue, childrel);
 
 		/* Recurse to child */
-		ATAddCheckConstraint(wqueue, childtab, childrel,
-							 constr, recurse, true, is_readd, lockmode);
+		ATAddCheckConstraint_internal(wqueue, childtab, childrel,
+									  constr, recurse, true, is_readd, check_it,
+									  lockmode);
 
 		heap_close(childrel, NoLock);
 	}
@@ -7681,6 +7759,7 @@ ATExecDropConstraint(Relation rel, const char *constrName,
 	while (HeapTupleIsValid(tuple = systable_getnext(scan)))
 	{
 		ObjectAddress conobj;
+		char		  *colName;
 
 		con = (Form_pg_constraint) GETSTRUCT(tuple);
 
@@ -7694,6 +7773,22 @@ ATExecDropConstraint(Relation rel, const char *constrName,
 					 errmsg("cannot drop inherited constraint \"%s\" of relation \"%s\"",
 							constrName, RelationGetRelationName(rel))));
 
+		if (con->contype == CONSTRAINT_CHECK)
+		{
+			/*
+			 * If it's a CHECK constraint, verify whether it is NOT NULL.
+			 * If it is, then we may need to unset the attnotnull bit as well.
+			 */
+			colName = tryExtractNotNullFromCatalog(tuple,
+												   RelationGetDescr(conrel),
+												   rel);
+			if (colName != NULL)
+			{
+				/* do something! */
+				elog(NOTICE, "colname is %s", colName);
+			}
+		}
+
 		is_no_inherit_constraint = con->connoinherit;
 
 		/*
diff --git a/src/backend/executor/nodeHash.c b/src/backend/executor/nodeHash.c
index 47160e4..9ed09a7 100644
--- a/src/backend/executor/nodeHash.c
+++ b/src/backend/executor/nodeHash.c
@@ -1575,8 +1575,19 @@ ExecHashRemoveNextSkewBucket(HashJoinTable hashtable)
 		if (batchno == hashtable->curbatch)
 		{
 			/* Move the tuple to the main hash table */
-			hashTuple->next = hashtable->buckets[bucketno];
-			hashtable->buckets[bucketno] = hashTuple;
+			HashJoinTuple copyTuple;
+
+			/*
+			 * We must copy the tuple into the dense storage, else it will not
+			 * be found by, eg, ExecHashIncreaseNumBatches.
+			 */
+			copyTuple = (HashJoinTuple) dense_alloc(hashtable, tupleSize);
+			memcpy(copyTuple, hashTuple, tupleSize);
+			pfree(hashTuple);
+
+			copyTuple->next = hashtable->buckets[bucketno];
+			hashtable->buckets[bucketno] = copyTuple;
+
 			/* We have reduced skew space, but overall space doesn't change */
 			hashtable->spaceUsedSkew -= tupleSize;
 		}
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index a8b79fa..e54d174 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -334,6 +334,7 @@ _copyGather(const Gather *from)
 	 */
 	COPY_SCALAR_FIELD(num_workers);
 	COPY_SCALAR_FIELD(single_copy);
+	COPY_SCALAR_FIELD(invisible);
 
 	return newnode;
 }
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index d59b954..3e1c3e6 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -443,6 +443,7 @@ _outGather(StringInfo str, const Gather *node)
 
 	WRITE_INT_FIELD(num_workers);
 	WRITE_BOOL_FIELD(single_copy);
+	WRITE_BOOL_FIELD(invisible);
 }
 
 static void
@@ -1824,6 +1825,7 @@ _outPlannerGlobal(StringInfo str, const PlannerGlobal *node)
 	WRITE_BOOL_FIELD(hasRowSecurity);
 	WRITE_BOOL_FIELD(parallelModeOK);
 	WRITE_BOOL_FIELD(parallelModeNeeded);
+	WRITE_BOOL_FIELD(wholePlanParallelSafe);
 	WRITE_BOOL_FIELD(hasForeignJoin);
 }
 
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 6c46151..e4d41ee 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -2053,6 +2053,7 @@ _readGather(void)
 
 	READ_INT_FIELD(num_workers);
 	READ_BOOL_FIELD(single_copy);
+	READ_BOOL_FIELD(invisible);
 
 	READ_DONE();
 }
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 54ff7f6..6e0db08 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -212,6 +212,10 @@ create_plan(PlannerInfo *root, Path *best_path)
 	/* Recursively process the path tree */
 	plan = create_plan_recurse(root, best_path);
 
+	/* Update parallel safety information if needed. */
+	if (!best_path->parallel_safe)
+		root->glob->wholePlanParallelSafe = false;
+
 	/* Check we successfully assigned all NestLoopParams to plan nodes */
 	if (root->curOuterParams != NIL)
 		elog(ERROR, "failed to assign all NestLoopParams to plan nodes");
@@ -4829,6 +4833,7 @@ make_gather(List *qptlist,
 	plan->righttree = NULL;
 	node->num_workers = nworkers;
 	node->single_copy = single_copy;
+	node->invisible	= false;
 
 	return node;
 }
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index a09b4b5..a3cc274 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -48,10 +48,12 @@
 #include "storage/dsm_impl.h"
 #include "utils/rel.h"
 #include "utils/selfuncs.h"
+#include "utils/syscache.h"
 
 
-/* GUC parameter */
+/* GUC parameters */
 double		cursor_tuple_fraction = DEFAULT_CURSOR_TUPLE_FRACTION;
+int			force_parallel_mode = FORCE_PARALLEL_OFF;
 
 /* Hook for plugins to get control in planner() */
 planner_hook_type planner_hook = NULL;
@@ -230,25 +232,31 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
 		!has_parallel_hazard((Node *) parse, true);
 
 	/*
-	 * glob->parallelModeOK should tell us whether it's necessary to impose
-	 * the parallel mode restrictions, but we don't actually want to impose
-	 * them unless we choose a parallel plan, so that people who mislabel
-	 * their functions but don't use parallelism anyway aren't harmed.
-	 * However, it's useful for testing purposes to be able to force the
-	 * restrictions to be imposed whenever a parallel plan is actually chosen
-	 * or not.
+	 * glob->parallelModeNeeded should tell us whether it's necessary to
+	 * impose the parallel mode restrictions, but we don't actually want to
+	 * impose them unless we choose a parallel plan, so that people who
+	 * mislabel their functions but don't use parallelism anyway aren't
+	 * harmed. But when force_parallel_mode is set, we enable the restrictions
+	 * whenever possible for testing purposes.
 	 *
-	 * (It's been suggested that we should always impose these restrictions
-	 * whenever glob->parallelModeOK is true, so that it's easier to notice
-	 * incorrectly-labeled functions sooner.  That might be the right thing to
-	 * do, but for now I've taken this approach.  We could also control this
-	 * with a GUC.)
+	 * glob->wholePlanParallelSafe should tell us whether it's OK to stick a
+	 * Gather node on top of the entire plan.  However, it only needs to be
+	 * accurate when force_parallel_mode is 'on' or 'regress', so we don't
+	 * bother doing the work otherwise.  The value we set here is just a
+	 * preliminary guess; it may get changed from true to false later, but
+	 * not visca versa.
 	 */
-#ifdef FORCE_PARALLEL_MODE
-	glob->parallelModeNeeded = glob->parallelModeOK;
-#else
-	glob->parallelModeNeeded = false;
-#endif
+	if (force_parallel_mode == FORCE_PARALLEL_OFF || !glob->parallelModeOK)
+	{
+		glob->parallelModeNeeded = false;
+		glob->wholePlanParallelSafe = false;	/* either false or don't care */
+	}
+	else
+	{
+		glob->parallelModeNeeded = true;
+		glob->wholePlanParallelSafe =
+			!has_parallel_hazard((Node *) parse, false);
+	}
 
 	/* Determine what fraction of the plan is likely to be scanned */
 	if (cursorOptions & CURSOR_OPT_FAST_PLAN)
@@ -293,6 +301,35 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
 	}
 
 	/*
+	 * At present, we don't copy subplans to workers.  The presence of a
+	 * subplan in one part of the plan doesn't preclude the use of parallelism
+	 * in some other part of the plan, but it does preclude the possibility of
+	 * regarding the entire plan parallel-safe.
+	 */
+	if (glob->subplans != NULL)
+		glob->wholePlanParallelSafe = false;
+
+	/*
+	 * Optionally add a Gather node for testing purposes, provided this is
+	 * actually a safe thing to do.
+	 */
+	if (glob->wholePlanParallelSafe &&
+		force_parallel_mode != FORCE_PARALLEL_OFF)
+	{
+		Gather	   *gather = makeNode(Gather);
+
+		gather->plan.targetlist = top_plan->targetlist;
+		gather->plan.qual = NIL;
+		gather->plan.lefttree = top_plan;
+		gather->plan.righttree = NULL;
+		gather->num_workers = 1;
+		gather->single_copy = true;
+		gather->invisible = (force_parallel_mode == FORCE_PARALLEL_REGRESS);
+		root->glob->parallelModeNeeded = true;
+		top_plan = &gather->plan;
+	}
+
+	/*
 	 * If any Params were generated, run through the plan tree and compute
 	 * each plan node's extParam/allParam sets.  Ideally we'd merge this into
 	 * set_plan_references' tree traversal, but for now it has to be separate
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index a65b2977..97300ae 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -40,6 +40,7 @@
 #include "catalog/pg_operator.h"
 #include "catalog/pg_type.h"
 #include "commands/comment.h"
+#include "commands/constraint.h"
 #include "commands/defrem.h"
 #include "commands/tablecmds.h"
 #include "commands/tablespace.h"
@@ -80,6 +81,7 @@ typedef struct
 	List	   *ckconstraints;	/* CHECK constraints */
 	List	   *fkconstraints;	/* FOREIGN KEY constraints */
 	List	   *ixconstraints;	/* index-creating constraints */
+	List	   *notnulls;		/* list of column names declared NOT NULL */
 	List	   *inh_indexes;	/* cloned indexes from INCLUDING INDEXES */
 	List	   *blist;			/* "before list" of things to do before
 								 * creating the table */
@@ -105,6 +107,8 @@ typedef struct
 
 static void transformColumnDefinition(CreateStmtContext *cxt,
 						  ColumnDef *column);
+static Constraint *transformNotNullConstraint(CreateStmtContext *cxt,
+						   Constraint *constraint, ColumnDef *column);
 static void transformTableConstraint(CreateStmtContext *cxt,
 						 Constraint *constraint);
 static void transformTableLikeClause(CreateStmtContext *cxt,
@@ -224,6 +228,7 @@ transformCreateStmt(CreateStmt *stmt, const char *queryString)
 	cxt.ckconstraints = NIL;
 	cxt.fkconstraints = NIL;
 	cxt.ixconstraints = NIL;
+	cxt.notnulls = NIL;
 	cxt.inh_indexes = NIL;
 	cxt.blist = NIL;
 	cxt.alist = NIL;
@@ -333,6 +338,7 @@ transformCreateStmt(CreateStmt *stmt, const char *queryString)
 	 */
 	stmt->tableElts = cxt.columns;
 	stmt->constraints = cxt.ckconstraints;
+	stmt->notnullcols = cxt.notnulls;
 
 	result = lappend(cxt.blist, stmt);
 	result = list_concat(result, cxt.alist);
@@ -528,6 +534,9 @@ transformColumnDefinition(CreateStmtContext *cxt, ColumnDef *column)
 
 	foreach(clist, column->constraints)
 	{
+		Constraint *newckconstr;
+		char	   *colname;
+
 		constraint = lfirst(clist);
 		Assert(IsA(constraint, Constraint));
 
@@ -546,6 +555,11 @@ transformColumnDefinition(CreateStmtContext *cxt, ColumnDef *column)
 				break;
 
 			case CONSTR_NOTNULL:
+				/*
+				 * For NOT NULL declarations, we need to mark the column as
+				 * not nullable; and furthermore we need to create a new
+				 * CHECK constraint for this.
+				 */
 				if (saw_nullable && !column->is_not_null)
 					ereport(ERROR,
 							(errcode(ERRCODE_SYNTAX_ERROR),
@@ -554,6 +568,9 @@ transformColumnDefinition(CreateStmtContext *cxt, ColumnDef *column)
 							 parser_errposition(cxt->pstate,
 												constraint->location)));
 				column->is_not_null = TRUE;
+				newckconstr = transformNotNullConstraint(cxt, constraint,
+														 column);
+				cxt->ckconstraints = lappend(cxt->ckconstraints, newckconstr);
 				saw_nullable = true;
 				break;
 
@@ -572,6 +589,21 @@ transformColumnDefinition(CreateStmtContext *cxt, ColumnDef *column)
 
 			case CONSTR_CHECK:
 				cxt->ckconstraints = lappend(cxt->ckconstraints, constraint);
+				/*
+				 * If there is a CHECK (foo IS NOT NULL) constraint
+				 * declaration, we check the column name used in the
+				 * constraint.  If it's the same name as the column being
+				 * defined, simply set the is_not_null flag in the column
+				 * definition; otherwise remember the column name for later.
+				 */
+				colname = tryExtractNotNullFromCheckConstr(constraint);
+				if (colname != NULL)
+				{
+					if (strcmp(colname, column->colname) == 0)
+						column->is_not_null = true;
+					else
+						cxt->notnulls = lappend(cxt->notnulls, colname);
+				}
 				break;
 
 			case CONSTR_PRIMARY:
@@ -663,6 +695,8 @@ transformColumnDefinition(CreateStmtContext *cxt, ColumnDef *column)
 static void
 transformTableConstraint(CreateStmtContext *cxt, Constraint *constraint)
 {
+	char *colname;
+
 	switch (constraint->contype)
 	{
 		case CONSTR_PRIMARY:
@@ -697,6 +731,9 @@ transformTableConstraint(CreateStmtContext *cxt, Constraint *constraint)
 
 		case CONSTR_CHECK:
 			cxt->ckconstraints = lappend(cxt->ckconstraints, constraint);
+			colname = tryExtractNotNullFromCheckConstr(constraint);
+			if (colname != NULL)
+				cxt->notnulls = lappend(cxt->notnulls, colname);
 			break;
 
 		case CONSTR_FOREIGN:
@@ -728,6 +765,30 @@ transformTableConstraint(CreateStmtContext *cxt, Constraint *constraint)
 }
 
 /*
+ * Given a NOT NULL column declaration, transform it into a new Constraint node
+ * representing the equivalent CHECK (col) IS NOT NULL.
+ */
+static Constraint *
+transformNotNullConstraint(CreateStmtContext *cxt, Constraint *constraint,
+						   ColumnDef *column)
+{
+	Constraint *check;
+	Oid		nspid;
+
+	if (cxt->rel)
+		nspid = RelationGetNamespace(cxt->rel);
+	else
+		nspid = RangeVarGetCreationNamespace(cxt->relation);
+
+	check = createCheckNotNullConstraint(nspid,
+										 NULL,
+										 cxt->relation->relname,
+										 column->colname);
+
+	return check;
+}
+
+/*
  * transformTableLikeClause
  *
  * Change the LIKE <srctable> portion of a CREATE TABLE statement into
@@ -2510,6 +2571,7 @@ transformAlterTableStmt(Oid relid, AlterTableStmt *stmt,
 	cxt.ckconstraints = NIL;
 	cxt.fkconstraints = NIL;
 	cxt.ixconstraints = NIL;
+	cxt.notnulls = NIL;
 	cxt.inh_indexes = NIL;
 	cxt.blist = NIL;
 	cxt.alist = NIL;
diff --git a/src/backend/storage/lmgr/README b/src/backend/storage/lmgr/README
index 8898e25..cb9c7d6 100644
--- a/src/backend/storage/lmgr/README
+++ b/src/backend/storage/lmgr/README
@@ -586,6 +586,69 @@ The caller can then send a cancellation signal.  This implements the
 principle that autovacuum has a low locking priority (eg it must not block
 DDL on the table).
 
+Group Locking
+-------------
+
+As if all of that weren't already complicated enough, PostgreSQL now supports
+parallelism (see src/backend/access/transam/README.parallel), which means that
+we might need to resolve deadlocks that occur between gangs of related processes
+rather than individual processes.  This doesn't change the basic deadlock
+detection algorithm very much, but it makes the bookkeeping more complicated.
+
+We choose to regard locks held by processes in the same parallel group as
+non-conflicting.  This means that two processes in a parallel group can hold
+a self-exclusive lock on the same relation at the same time, or one process
+can acquire an AccessShareLock while the other already holds AccessExclusiveLock.
+This might seem dangerous and could be in some cases (more on that below), but
+if we didn't do this then parallel query would be extremely prone to
+self-deadlock.  For example, a parallel query against a relation on which the
+leader had already AccessExclusiveLock would hang, because the workers would
+try to lock the same relation and be blocked by the leader; yet the leader can't
+finish until it receives completion indications from all workers.  An undetected
+deadlock results.  This is far from the only scenario where such a problem
+happens.  The same thing will occur if the leader holds only AccessShareLock,
+the worker seeks AccessShareLock, but between the time the leader attempts to
+acquire the lock and the time the worker attempts to acquire it, some other
+process queues up waiting for an AccessExclusiveLock.  In this case, too, an
+indefinite hang results.
+
+It might seem that we could predict which locks the workers will attempt to
+acquire and ensure before going parallel that those locks would be acquired
+successfully.  But this is very difficult to make work in a general way.  For
+example, a parallel worker's portion of the query plan could involve an
+SQL-callable function which generates a query dynamically, and that query
+might happen to hit a table on which the leader happens to hold
+AccessExcusiveLock.  By imposing enough restrictions on what workers can do,
+we could eventually create a situation where their behavior can be adequately
+restricted, but these restrictions would be fairly onerous, and even then, the
+system required to decide whether the workers will succeed at acquiring the
+necessary locks would be complex and possibly buggy.
+
+So, instead, we take the approach of deciding that locks within a lock group
+do not conflict.  This eliminates the possibility of an undetected deadlock,
+but also opens up some problem cases: if the leader and worker try to do some
+operation at the same time which would ordinarily be prevented by the heavyweight
+lock mechanism, undefined behavior might result.  In practice, the dangers are
+modest.  The leader and worker share the same transaction, snapshot, and combo
+CID hash, and neither can perform any DDL or, indeed, write any data at all.
+Thus, for either to read a table locked exclusively by the other is safe enough.
+Problems would occur if the leader initiated parallelism from a point in the
+code at which it had some backend-private state that made table access from
+another process unsafe, for example after calling SetReindexProcessing and
+before calling ResetReindexProcessing, catastrophe could ensue, because the
+worker won't have that state.  Similarly, problems could occur with certain
+kinds of non-relation locks, such as relation extension locks.  It's no safer
+for two related processes to extend the same relation at the time than for
+unrelated processes to do the same.  However, since parallel mode is strictly
+read-only at present, neither this nor most of the similar cases can arise at
+present.  To allow parallel writes, we'll either need to (1) further enhance
+the deadlock detector to handle those types of locks in a different way than
+other types; or (2) have parallel workers use some other mutual exclusion
+method for such cases; or (3) revise those cases so that they no longer use
+heavyweight locking in the first place (which is not a crazy idea, given that
+such lock acquisitions are not expected to deadlock and that heavyweight lock
+acquisition is fairly slow anyway).
+
 User Locks (Advisory Locks)
 ---------------------------
 
diff --git a/src/backend/storage/lmgr/deadlock.c b/src/backend/storage/lmgr/deadlock.c
index a68aaf6..69f678b 100644
--- a/src/backend/storage/lmgr/deadlock.c
+++ b/src/backend/storage/lmgr/deadlock.c
@@ -38,6 +38,7 @@ typedef struct
 {
 	PGPROC	   *waiter;			/* the waiting process */
 	PGPROC	   *blocker;		/* the process it is waiting for */
+	LOCK	   *lock;			/* the lock it is waiting for */
 	int			pred;			/* workspace for TopoSort */
 	int			link;			/* workspace for TopoSort */
 } EDGE;
@@ -72,6 +73,9 @@ static bool FindLockCycle(PGPROC *checkProc,
 			  EDGE *softEdges, int *nSoftEdges);
 static bool FindLockCycleRecurse(PGPROC *checkProc, int depth,
 					 EDGE *softEdges, int *nSoftEdges);
+static bool FindLockCycleRecurseMember(PGPROC *checkProc,
+						   PGPROC *checkProcLeader,
+						   int depth, EDGE *softEdges, int *nSoftEdges);
 static bool ExpandConstraints(EDGE *constraints, int nConstraints);
 static bool TopoSort(LOCK *lock, EDGE *constraints, int nConstraints,
 		 PGPROC **ordering);
@@ -449,18 +453,15 @@ FindLockCycleRecurse(PGPROC *checkProc,
 					 EDGE *softEdges,	/* output argument */
 					 int *nSoftEdges)	/* output argument */
 {
-	PGPROC	   *proc;
-	PGXACT	   *pgxact;
-	LOCK	   *lock;
-	PROCLOCK   *proclock;
-	SHM_QUEUE  *procLocks;
-	LockMethod	lockMethodTable;
-	PROC_QUEUE *waitQueue;
-	int			queue_size;
-	int			conflictMask;
 	int			i;
-	int			numLockModes,
-				lm;
+	dlist_iter	iter;
+
+	/*
+	 * If this process is a lock group member, check the leader instead. (Note
+	 * that we might be the leader, in which case this is a no-op.)
+	 */
+	if (checkProc->lockGroupLeader != NULL)
+		checkProc = checkProc->lockGroupLeader;
 
 	/*
 	 * Have we already seen this proc?
@@ -494,13 +495,57 @@ FindLockCycleRecurse(PGPROC *checkProc,
 	visitedProcs[nVisitedProcs++] = checkProc;
 
 	/*
-	 * If the proc is not waiting, we have no outgoing waits-for edges.
+	 * If the process is waiting, there is an outgoing waits-for edge to each
+	 * process that blocks it.
 	 */
-	if (checkProc->links.next == NULL)
-		return false;
-	lock = checkProc->waitLock;
-	if (lock == NULL)
-		return false;
+	if (checkProc->links.next != NULL && checkProc->waitLock != NULL &&
+		FindLockCycleRecurseMember(checkProc, checkProc, depth, softEdges,
+								   nSoftEdges))
+		return true;
+
+	/*
+	 * If the process is not waiting, there could still be outgoing waits-for
+	 * edges if it is part of a lock group, because other members of the lock
+	 * group might be waiting even though this process is not.  (Given lock
+	 * groups {A1, A2} and {B1, B2}, if A1 waits for B1 and B2 waits for A2,
+	 * that is a deadlock even neither of B1 and A2 are waiting for anything.)
+	 */
+	dlist_foreach(iter, &checkProc->lockGroupMembers)
+	{
+		PGPROC	   *memberProc;
+
+		memberProc = dlist_container(PGPROC, lockGroupLink, iter.cur);
+
+		if (memberProc->links.next != NULL && memberProc->waitLock != NULL &&
+			memberProc != checkProc &&
+		  FindLockCycleRecurseMember(memberProc, checkProc, depth, softEdges,
+									 nSoftEdges))
+			return true;
+	}
+
+	return false;
+}
+
+static bool
+FindLockCycleRecurseMember(PGPROC *checkProc,
+						   PGPROC *checkProcLeader,
+						   int depth,
+						   EDGE *softEdges,		/* output argument */
+						   int *nSoftEdges)		/* output argument */
+{
+	PGPROC	   *proc;
+	LOCK	   *lock = checkProc->waitLock;
+	PGXACT	   *pgxact;
+	PROCLOCK   *proclock;
+	SHM_QUEUE  *procLocks;
+	LockMethod	lockMethodTable;
+	PROC_QUEUE *waitQueue;
+	int			queue_size;
+	int			conflictMask;
+	int			i;
+	int			numLockModes,
+				lm;
+
 	lockMethodTable = GetLocksMethodTable(lock);
 	numLockModes = lockMethodTable->numLockModes;
 	conflictMask = lockMethodTable->conflictTab[checkProc->waitLockMode];
@@ -516,11 +561,14 @@ FindLockCycleRecurse(PGPROC *checkProc,
 
 	while (proclock)
 	{
+		PGPROC	   *leader;
+
 		proc = proclock->tag.myProc;
 		pgxact = &ProcGlobal->allPgXact[proc->pgprocno];
+		leader = proc->lockGroupLeader == NULL ? proc : proc->lockGroupLeader;
 
-		/* A proc never blocks itself */
-		if (proc != checkProc)
+		/* A proc never blocks itself or any other lock group member */
+		if (leader != checkProcLeader)
 		{
 			for (lm = 1; lm <= numLockModes; lm++)
 			{
@@ -601,10 +649,20 @@ FindLockCycleRecurse(PGPROC *checkProc,
 
 		for (i = 0; i < queue_size; i++)
 		{
-			proc = procs[i];
+			PGPROC	   *leader;
 
-			/* Done when we reach the target proc */
-			if (proc == checkProc)
+			proc = procs[i];
+			leader = proc->lockGroupLeader == NULL ? proc :
+				proc->lockGroupLeader;
+
+			/*
+			 * TopoSort will always return an ordering with group members
+			 * adjacent to each other in the wait queue (see comments
+			 * therein). So, as soon as we reach a process in the same lock
+			 * group as checkProc, we know we've found all the conflicts that
+			 * precede any member of the lock group lead by checkProcLeader.
+			 */
+			if (leader == checkProcLeader)
 				break;
 
 			/* Is there a conflict with this guy's request? */
@@ -625,8 +683,9 @@ FindLockCycleRecurse(PGPROC *checkProc,
 					 * Add this edge to the list of soft edges in the cycle
 					 */
 					Assert(*nSoftEdges < MaxBackends);
-					softEdges[*nSoftEdges].waiter = checkProc;
-					softEdges[*nSoftEdges].blocker = proc;
+					softEdges[*nSoftEdges].waiter = checkProcLeader;
+					softEdges[*nSoftEdges].blocker = leader;
+					softEdges[*nSoftEdges].lock = lock;
 					(*nSoftEdges)++;
 					return true;
 				}
@@ -635,20 +694,52 @@ FindLockCycleRecurse(PGPROC *checkProc,
 	}
 	else
 	{
+		PGPROC	   *lastGroupMember = NULL;
+
 		/* Use the true lock wait queue order */
 		waitQueue = &(lock->waitProcs);
+
+		/*
+		 * Find the last member of the lock group that is present in the wait
+		 * queue.  Anything after this is not a soft lock conflict. If group
+		 * locking is not in use, then we know immediately which process we're
+		 * looking for, but otherwise we've got to search the wait queue to
+		 * find the last process actually present.
+		 */
+		if (checkProc->lockGroupLeader == NULL)
+			lastGroupMember = checkProc;
+		else
+		{
+			proc = (PGPROC *) waitQueue->links.next;
+			queue_size = waitQueue->size;
+			while (queue_size-- > 0)
+			{
+				if (proc->lockGroupLeader == checkProcLeader)
+					lastGroupMember = proc;
+				proc = (PGPROC *) proc->links.next;
+			}
+			Assert(lastGroupMember != NULL);
+		}
+
+		/*
+		 * OK, now rescan (or scan) the queue to identify the soft conflicts.
+		 */
 		queue_size = waitQueue->size;
-
 		proc = (PGPROC *) waitQueue->links.next;
-
 		while (queue_size-- > 0)
 		{
+			PGPROC	   *leader;
+
+			leader = proc->lockGroupLeader == NULL ? proc :
+				proc->lockGroupLeader;
+
 			/* Done when we reach the target proc */
-			if (proc == checkProc)
+			if (proc == lastGroupMember)
 				break;
 
 			/* Is there a conflict with this guy's request? */
-			if ((LOCKBIT_ON(proc->waitLockMode) & conflictMask) != 0)
+			if ((LOCKBIT_ON(proc->waitLockMode) & conflictMask) != 0 &&
+				leader != checkProcLeader)
 			{
 				/* This proc soft-blocks checkProc */
 				if (FindLockCycleRecurse(proc, depth + 1,
@@ -665,8 +756,9 @@ FindLockCycleRecurse(PGPROC *checkProc,
 					 * Add this edge to the list of soft edges in the cycle
 					 */
 					Assert(*nSoftEdges < MaxBackends);
-					softEdges[*nSoftEdges].waiter = checkProc;
-					softEdges[*nSoftEdges].blocker = proc;
+					softEdges[*nSoftEdges].waiter = checkProcLeader;
+					softEdges[*nSoftEdges].blocker = leader;
+					softEdges[*nSoftEdges].lock = lock;
 					(*nSoftEdges)++;
 					return true;
 				}
@@ -711,8 +803,7 @@ ExpandConstraints(EDGE *constraints,
 	 */
 	for (i = nConstraints; --i >= 0;)
 	{
-		PGPROC	   *proc = constraints[i].waiter;
-		LOCK	   *lock = proc->waitLock;
+		LOCK	   *lock = constraints[i].lock;
 
 		/* Did we already make a list for this lock? */
 		for (j = nWaitOrders; --j >= 0;)
@@ -778,7 +869,9 @@ TopoSort(LOCK *lock,
 	PGPROC	   *proc;
 	int			i,
 				j,
+				jj,
 				k,
+				kk,
 				last;
 
 	/* First, fill topoProcs[] array with the procs in their current order */
@@ -798,41 +891,95 @@ TopoSort(LOCK *lock,
 	 * stores its list link in constraints[i].link (note any constraint will
 	 * be in just one list). The array index for the before-proc of the i'th
 	 * constraint is remembered in constraints[i].pred.
+	 *
+	 * Note that it's not necessarily the case that every constraint affects
+	 * this particular wait queue.  Prior to group locking, a process could be
+	 * waiting for at most one lock.  But a lock group can be waiting for
+	 * zero, one, or multiple locks.  Since topoProcs[] is an array of the
+	 * processes actually waiting, while constraints[] is an array of group
+	 * leaders, we've got to scan through topoProcs[] for each constraint,
+	 * checking whether both a waiter and a blocker for that group are
+	 * present.  If so, the constraint is relevant to this wait queue; if not,
+	 * it isn't.
 	 */
 	MemSet(beforeConstraints, 0, queue_size * sizeof(int));
 	MemSet(afterConstraints, 0, queue_size * sizeof(int));
 	for (i = 0; i < nConstraints; i++)
 	{
+		/*
+		 * Find a representative process that is on the lock queue and part of
+		 * the waiting lock group.  This may or may not be the leader, which
+		 * may or may not be waiting at all.  If there are any other processes
+		 * in the same lock group on the queue, set their number of
+		 * beforeConstraints to -1 to indicate that they should be emitted
+		 * with their groupmates rather than considered separately.
+		 */
 		proc = constraints[i].waiter;
-		/* Ignore constraint if not for this lock */
-		if (proc->waitLock != lock)
-			continue;
-		/* Find the waiter proc in the array */
+		Assert(proc != NULL);
+		jj = -1;
 		for (j = queue_size; --j >= 0;)
 		{
-			if (topoProcs[j] == proc)
+			PGPROC	   *waiter = topoProcs[j];
+
+			if (waiter == proc || waiter->lockGroupLeader == proc)
+			{
+				Assert(waiter->waitLock == lock);
+				if (jj == -1)
+					jj = j;
+				else
+				{
+					Assert(beforeConstraints[j] <= 0);
+					beforeConstraints[j] = -1;
+				}
 				break;
+			}
 		}
-		Assert(j >= 0);			/* should have found a match */
-		/* Find the blocker proc in the array */
+
+		/* If no matching waiter, constraint is not relevant to this lock. */
+		if (jj < 0)
+			continue;
+
+		/*
+		 * Similarly, find a representative process that is on the lock queue
+		 * and waiting for the blocking lock group.  Again, this could be the
+		 * leader but does not need to be.
+		 */
 		proc = constraints[i].blocker;
+		Assert(proc != NULL);
+		kk = -1;
 		for (k = queue_size; --k >= 0;)
 		{
-			if (topoProcs[k] == proc)
-				break;
+			PGPROC	   *blocker = topoProcs[k];
+
+			if (blocker == proc || blocker->lockGroupLeader == proc)
+			{
+				Assert(blocker->waitLock == lock);
+				if (kk == -1)
+					kk = k;
+				else
+				{
+					Assert(beforeConstraints[k] <= 0);
+					beforeConstraints[k] = -1;
+				}
+			}
 		}
-		Assert(k >= 0);			/* should have found a match */
-		beforeConstraints[j]++; /* waiter must come before */
+
+		/* If no matching blocker, constraint is not relevant to this lock. */
+		if (kk < 0)
+			continue;
+
+		beforeConstraints[jj]++;	/* waiter must come before */
 		/* add this constraint to list of after-constraints for blocker */
-		constraints[i].pred = j;
-		constraints[i].link = afterConstraints[k];
-		afterConstraints[k] = i + 1;
+		constraints[i].pred = jj;
+		constraints[i].link = afterConstraints[kk];
+		afterConstraints[kk] = i + 1;
 	}
+
 	/*--------------------
 	 * Now scan the topoProcs array backwards.  At each step, output the
-	 * last proc that has no remaining before-constraints, and decrease
-	 * the beforeConstraints count of each of the procs it was constrained
-	 * against.
+	 * last proc that has no remaining before-constraints plus any other
+	 * members of the same lock group; then decrease the beforeConstraints
+	 * count of each of the procs it was constrained against.
 	 * i = index of ordering[] entry we want to output this time
 	 * j = search index for topoProcs[]
 	 * k = temp for scanning constraint list for proc j
@@ -840,8 +987,11 @@ TopoSort(LOCK *lock,
 	 *--------------------
 	 */
 	last = queue_size - 1;
-	for (i = queue_size; --i >= 0;)
+	for (i = queue_size - 1; i >= 0;)
 	{
+		int			c;
+		int			nmatches = 0;
+
 		/* Find next candidate to output */
 		while (topoProcs[last] == NULL)
 			last--;
@@ -850,12 +1000,37 @@ TopoSort(LOCK *lock,
 			if (topoProcs[j] != NULL && beforeConstraints[j] == 0)
 				break;
 		}
+
 		/* If no available candidate, topological sort fails */
 		if (j < 0)
 			return false;
-		/* Output candidate, and mark it done by zeroing topoProcs[] entry */
-		ordering[i] = topoProcs[j];
-		topoProcs[j] = NULL;
+
+		/*
+		 * Output everything in the lock group.  There's no point in outputing
+		 * an ordering where members of the same lock group are not
+		 * consecutive on the wait queue: if some other waiter is between two
+		 * requests that belong to the same group, then either it conflicts
+		 * with both of them and is certainly not a solution; or it conflicts
+		 * with at most one of them and is thus isomorphic to an ordering
+		 * where the group members are consecutive.
+		 */
+		proc = topoProcs[j];
+		if (proc->lockGroupLeader != NULL)
+			proc = proc->lockGroupLeader;
+		Assert(proc != NULL);
+		for (c = 0; c <= last; ++c)
+		{
+			if (topoProcs[c] == proc || (topoProcs[c] != NULL &&
+									  topoProcs[c]->lockGroupLeader == proc))
+			{
+				ordering[i - nmatches] = topoProcs[c];
+				topoProcs[c] = NULL;
+				++nmatches;
+			}
+		}
+		Assert(nmatches > 0);
+		i -= nmatches;
+
 		/* Update beforeConstraints counts of its predecessors */
 		for (k = afterConstraints[j]; k > 0; k = constraints[k - 1].link)
 			beforeConstraints[constraints[k - 1].pred]--;
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 269fe14..e3e9599 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -35,6 +35,7 @@
 #include "access/transam.h"
 #include "access/twophase.h"
 #include "access/twophase_rmgr.h"
+#include "access/xact.h"
 #include "access/xlog.h"
 #include "miscadmin.h"
 #include "pg_trace.h"
@@ -1136,6 +1137,18 @@ SetupLockInTable(LockMethod lockMethodTable, PGPROC *proc,
 	{
 		uint32		partition = LockHashPartition(hashcode);
 
+		/*
+		 * It might seem unsafe to access proclock->groupLeader without a lock,
+		 * but it's not really.  Either we are initializing a proclock on our
+		 * own behalf, in which case our group leader isn't changing because
+		 * the group leader for a process can only ever be changed by the
+		 * process itself; or else we are transferring a fast-path lock to the
+		 * main lock table, in which case that process can't change it's lock
+		 * group leader without first releasing all of its locks (and in
+		 * particular the one we are currently transferring).
+		 */
+		proclock->groupLeader = proc->lockGroupLeader != NULL ?
+			proc->lockGroupLeader : proc;
 		proclock->holdMask = 0;
 		proclock->releaseMask = 0;
 		/* Add proclock to appropriate lists */
@@ -1255,9 +1268,10 @@ RemoveLocalLock(LOCALLOCK *locallock)
  * NOTES:
  *		Here's what makes this complicated: one process's locks don't
  * conflict with one another, no matter what purpose they are held for
- * (eg, session and transaction locks do not conflict).
- * So, we must subtract off our own locks when determining whether the
- * requested new lock conflicts with those already held.
+ * (eg, session and transaction locks do not conflict).  Nor do the locks
+ * of one process in a lock group conflict with those of another process in
+ * the same group.  So, we must subtract off these locks when determining
+ * whether the requested new lock conflicts with those already held.
  */
 int
 LockCheckConflicts(LockMethod lockMethodTable,
@@ -1267,8 +1281,12 @@ LockCheckConflicts(LockMethod lockMethodTable,
 {
 	int			numLockModes = lockMethodTable->numLockModes;
 	LOCKMASK	myLocks;
-	LOCKMASK	otherLocks;
+	int			conflictMask = lockMethodTable->conflictTab[lockmode];
+	int			conflictsRemaining[MAX_LOCKMODES];
+	int			totalConflictsRemaining = 0;
 	int			i;
+	SHM_QUEUE  *procLocks;
+	PROCLOCK   *otherproclock;
 
 	/*
 	 * first check for global conflicts: If no locks conflict with my request,
@@ -1279,40 +1297,91 @@ LockCheckConflicts(LockMethod lockMethodTable,
 	 * type of lock that conflicts with request.   Bitwise compare tells if
 	 * there is a conflict.
 	 */
-	if (!(lockMethodTable->conflictTab[lockmode] & lock->grantMask))
+	if (!(conflictMask & lock->grantMask))
 	{
 		PROCLOCK_PRINT("LockCheckConflicts: no conflict", proclock);
 		return STATUS_OK;
 	}
 
 	/*
-	 * Rats.  Something conflicts.  But it could still be my own lock. We have
-	 * to construct a conflict mask that does not reflect our own locks, but
-	 * only lock types held by other processes.
+	 * Rats.  Something conflicts.  But it could still be my own lock, or
+	 * a lock held by another member of my locking group.  First, figure out
+	 * how many conflicts remain after subtracting out any locks I hold
+	 * myself.
 	 */
 	myLocks = proclock->holdMask;
-	otherLocks = 0;
 	for (i = 1; i <= numLockModes; i++)
 	{
-		int			myHolding = (myLocks & LOCKBIT_ON(i)) ? 1 : 0;
-
-		if (lock->granted[i] > myHolding)
-			otherLocks |= LOCKBIT_ON(i);
+		if ((conflictMask & LOCKBIT_ON(i)) == 0)
+		{
+			conflictsRemaining[i] = 0;
+			continue;
+		}
+		conflictsRemaining[i] = lock->granted[i];
+		if (myLocks & LOCKBIT_ON(i))
+			--conflictsRemaining[i];
+		totalConflictsRemaining += conflictsRemaining[i];
 	}
 
-	/*
-	 * now check again for conflicts.  'otherLocks' describes the types of
-	 * locks held by other processes.  If one of these conflicts with the kind
-	 * of lock that I want, there is a conflict and I have to sleep.
-	 */
-	if (!(lockMethodTable->conflictTab[lockmode] & otherLocks))
+	/* If no conflicts remain, we get the lock. */
+	if (totalConflictsRemaining == 0)
 	{
-		/* no conflict. OK to get the lock */
-		PROCLOCK_PRINT("LockCheckConflicts: resolved", proclock);
+		PROCLOCK_PRINT("LockCheckConflicts: resolved (simple)", proclock);
 		return STATUS_OK;
 	}
 
-	PROCLOCK_PRINT("LockCheckConflicts: conflicting", proclock);
+	/* If no group locking, it's definitely a conflict. */
+	if (proclock->groupLeader == MyProc && MyProc->lockGroupLeader == NULL)
+	{
+		Assert(proclock->tag.myProc == MyProc);
+		PROCLOCK_PRINT("LockCheckConflicts: conflicting (simple)",
+					   proclock);
+		return STATUS_FOUND;
+	}
+
+	/*
+	 * Locks held in conflicting modes by members of our own lock group are
+	 * not real conflicts; we can subtract those out and see if we still have
+	 * a conflict.  This is O(N) in the number of processes holding or awaiting
+	 * locks on this object.  We could improve that by making the shared memory
+	 * state more complex (and larger) but it doesn't seem worth it.
+	 */
+	procLocks = &(lock->procLocks);
+	otherproclock = (PROCLOCK *)
+		SHMQueueNext(procLocks, procLocks, offsetof(PROCLOCK, lockLink));
+	while (otherproclock != NULL)
+	{
+		if (proclock != otherproclock &&
+			proclock->groupLeader == otherproclock->groupLeader &&
+			(otherproclock->holdMask & conflictMask) != 0)
+		{
+			int	intersectMask = otherproclock->holdMask & conflictMask;
+
+			for (i = 1; i <= numLockModes; i++)
+			{
+				if ((intersectMask & LOCKBIT_ON(i)) != 0)
+				{
+					if (conflictsRemaining[i] <= 0)
+						elog(PANIC, "proclocks held do not match lock");
+					conflictsRemaining[i]--;
+					totalConflictsRemaining--;
+				}
+			}
+
+			if (totalConflictsRemaining == 0)
+			{
+				PROCLOCK_PRINT("LockCheckConflicts: resolved (group)",
+							   proclock);
+				return STATUS_OK;
+			}
+		}
+		otherproclock = (PROCLOCK *)
+			SHMQueueNext(procLocks, &otherproclock->lockLink,
+						 offsetof(PROCLOCK, lockLink));
+	}
+
+	/* Nope, it's a real conflict. */
+	PROCLOCK_PRINT("LockCheckConflicts: conflicting (group)", proclock);
 	return STATUS_FOUND;
 }
 
@@ -3095,6 +3164,10 @@ PostPrepare_Locks(TransactionId xid)
 	PROCLOCKTAG proclocktag;
 	int			partition;
 
+	/* Can't prepare a lock group follower. */
+	Assert(MyProc->lockGroupLeader == NULL ||
+		   MyProc->lockGroupLeader == MyProc);
+
 	/* This is a critical section: any error means big trouble */
 	START_CRIT_SECTION();
 
@@ -3239,6 +3312,13 @@ PostPrepare_Locks(TransactionId xid)
 			proclocktag.myProc = newproc;
 
 			/*
+			 * Update groupLeader pointer to point to the new proc.  (We'd
+			 * better not be a member of somebody else's lock group!)
+			 */
+			Assert(proclock->groupLeader == proclock->tag.myProc);
+			proclock->groupLeader = newproc;
+
+			/*
 			 * Update the proclock.  We should not find any existing entry for
 			 * the same hash key, since there can be only one entry for any
 			 * given lock with my own proc.
@@ -3785,6 +3865,8 @@ lock_twophase_recover(TransactionId xid, uint16 info,
 	 */
 	if (!found)
 	{
+		Assert(proc->lockGroupLeader == NULL);
+		proclock->groupLeader = proc;
 		proclock->holdMask = 0;
 		proclock->releaseMask = 0;
 		/* Add proclock to appropriate lists */
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 3690753..084be5a 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -263,6 +263,9 @@ InitProcGlobal(void)
 		/* Initialize myProcLocks[] shared memory queues. */
 		for (j = 0; j < NUM_LOCK_PARTITIONS; j++)
 			SHMQueueInit(&(procs[i].myProcLocks[j]));
+
+		/* Initialize lockGroupMembers list. */
+		dlist_init(&procs[i].lockGroupMembers);
 	}
 
 	/*
@@ -397,6 +400,11 @@ InitProcess(void)
 	MyProc->backendLatestXid = InvalidTransactionId;
 	pg_atomic_init_u32(&MyProc->nextClearXidElem, INVALID_PGPROCNO);
 
+	/* Check that group locking fields are in a proper initial state. */
+	Assert(MyProc->lockGroupLeaderIdentifier == 0);
+	Assert(MyProc->lockGroupLeader == NULL);
+	Assert(dlist_is_empty(&MyProc->lockGroupMembers));
+
 	/*
 	 * Acquire ownership of the PGPROC's latch, so that we can use WaitLatch
 	 * on it.  That allows us to repoint the process latch, which so far
@@ -556,6 +564,11 @@ InitAuxiliaryProcess(void)
 	OwnLatch(&MyProc->procLatch);
 	SwitchToSharedLatch();
 
+	/* Check that group locking fields are in a proper initial state. */
+	Assert(MyProc->lockGroupLeaderIdentifier == 0);
+	Assert(MyProc->lockGroupLeader == NULL);
+	Assert(dlist_is_empty(&MyProc->lockGroupMembers));
+
 	/*
 	 * We might be reusing a semaphore that belonged to a failed process. So
 	 * be careful and reinitialize its value here.  (This is not strictly
@@ -794,6 +807,40 @@ ProcKill(int code, Datum arg)
 		ReplicationSlotRelease();
 
 	/*
+	 * Detach from any lock group of which we are a member.  If the leader
+	 * exist before all other group members, it's PGPROC will remain allocated
+	 * until the last group process exits; that process must return the
+	 * leader's PGPROC to the appropriate list.
+	 */
+	if (MyProc->lockGroupLeader != NULL)
+	{
+		PGPROC	   *leader = MyProc->lockGroupLeader;
+		LWLock	   *leader_lwlock = LockHashPartitionLockByProc(leader);
+
+		LWLockAcquire(leader_lwlock, LW_EXCLUSIVE);
+		Assert(!dlist_is_empty(&leader->lockGroupMembers));
+		dlist_delete(&MyProc->lockGroupLink);
+		if (dlist_is_empty(&leader->lockGroupMembers))
+		{
+			leader->lockGroupLeaderIdentifier = 0;
+			leader->lockGroupLeader = NULL;
+			if (leader != MyProc)
+			{
+				procgloballist = leader->procgloballist;
+
+				/* Leader exited first; return its PGPROC. */
+				SpinLockAcquire(ProcStructLock);
+				leader->links.next = (SHM_QUEUE *) *procgloballist;
+				*procgloballist = leader;
+				SpinLockRelease(ProcStructLock);
+			}
+		}
+		else if (leader != MyProc)
+			MyProc->lockGroupLeader = NULL;
+		LWLockRelease(leader_lwlock);
+	}
+
+	/*
 	 * Reset MyLatch to the process local one.  This is so that signal
 	 * handlers et al can continue using the latch after the shared latch
 	 * isn't ours anymore. After that clear MyProc and disown the shared
@@ -807,9 +854,20 @@ ProcKill(int code, Datum arg)
 	procgloballist = proc->procgloballist;
 	SpinLockAcquire(ProcStructLock);
 
-	/* Return PGPROC structure (and semaphore) to appropriate freelist */
-	proc->links.next = (SHM_QUEUE *) *procgloballist;
-	*procgloballist = proc;
+	/*
+	 * If we're still a member of a locking group, that means we're a leader
+	 * which has somehow exited before its children.  The last remaining child
+	 * will release our PGPROC.  Otherwise, release it now.
+	 */
+	if (proc->lockGroupLeader == NULL)
+	{
+		/* Since lockGroupLeader is NULL, lockGroupMembers should be empty. */
+		Assert(dlist_is_empty(&proc->lockGroupMembers));
+
+		/* Return PGPROC structure (and semaphore) to appropriate freelist */
+		proc->links.next = (SHM_QUEUE *) *procgloballist;
+		*procgloballist = proc;
+	}
 
 	/* Update shared estimate of spins_per_delay */
 	ProcGlobal->spins_per_delay = update_spins_per_delay(ProcGlobal->spins_per_delay);
@@ -942,9 +1000,31 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable)
 	bool		allow_autovacuum_cancel = true;
 	int			myWaitStatus;
 	PGPROC	   *proc;
+	PGPROC	   *leader = MyProc->lockGroupLeader;
 	int			i;
 
 	/*
+	 * If group locking is in use, locks held my members of my locking group
+	 * need to be included in myHeldLocks.
+	 */
+	if (leader != NULL)
+	{
+		SHM_QUEUE  *procLocks = &(lock->procLocks);
+		PROCLOCK   *otherproclock;
+
+		otherproclock = (PROCLOCK *)
+			SHMQueueNext(procLocks, procLocks, offsetof(PROCLOCK, lockLink));
+		while (otherproclock != NULL)
+		{
+			if (otherproclock->groupLeader == leader)
+				myHeldLocks |= otherproclock->holdMask;
+			otherproclock = (PROCLOCK *)
+				SHMQueueNext(procLocks, &otherproclock->lockLink,
+							 offsetof(PROCLOCK, lockLink));
+		}
+	}
+
+	/*
 	 * Determine where to add myself in the wait queue.
 	 *
 	 * Normally I should go at the end of the queue.  However, if I already
@@ -968,6 +1048,15 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable)
 		proc = (PGPROC *) waitQueue->links.next;
 		for (i = 0; i < waitQueue->size; i++)
 		{
+			/*
+			 * If we're part of the same locking group as this waiter, its
+			 * locks neither conflict with ours nor contribute to aheadRequsts.
+			 */
+			if (leader != NULL && leader == proc->lockGroupLeader)
+			{
+				proc = (PGPROC *) proc->links.next;
+				continue;
+			}
 			/* Must he wait for me? */
 			if (lockMethodTable->conflictTab[proc->waitLockMode] & myHeldLocks)
 			{
@@ -1658,3 +1747,66 @@ ProcSendSignal(int pid)
 		SetLatch(&proc->procLatch);
 	}
 }
+
+/*
+ * BecomeLockGroupLeader - designate process as lock group leader
+ *
+ * Once this function has returned, other processes can join the lock group
+ * by calling BecomeLockGroupMember.
+ */
+void
+BecomeLockGroupLeader(void)
+{
+	LWLock	   *leader_lwlock;
+
+	/* If we already did it, we don't need to do it again. */
+	if (MyProc->lockGroupLeader == MyProc)
+		return;
+
+	/* We had better not be a follower. */
+	Assert(MyProc->lockGroupLeader == NULL);
+
+	/* Create single-member group, containing only ourselves. */
+	leader_lwlock = LockHashPartitionLockByProc(MyProc);
+	LWLockAcquire(leader_lwlock, LW_EXCLUSIVE);
+	MyProc->lockGroupLeader = MyProc;
+	MyProc->lockGroupLeaderIdentifier = MyProcPid;
+	dlist_push_head(&MyProc->lockGroupMembers, &MyProc->lockGroupLink);
+	LWLockRelease(leader_lwlock);
+}
+
+/*
+ * BecomeLockGroupMember - designate process as lock group member
+ *
+ * This is pretty straightforward except for the possibility that the leader
+ * whose group we're trying to join might exit before we manage to do so;
+ * and the PGPROC might get recycled for an unrelated process.  To avoid
+ * that, we require the caller to pass the PID of the intended PGPROC as
+ * an interlock.  Returns true if we successfully join the intended lock
+ * group, and false if not.
+ */
+bool
+BecomeLockGroupMember(PGPROC *leader, int pid)
+{
+	LWLock	   *leader_lwlock;
+	bool		ok = false;
+
+	/* Group leader can't become member of group */
+	Assert(MyProc != leader);
+
+	/* PID must be valid. */
+	Assert(pid != 0);
+
+	/* Try to join the group. */
+	leader_lwlock = LockHashPartitionLockByProc(MyProc);
+	LWLockAcquire(leader_lwlock, LW_EXCLUSIVE);
+	if (leader->lockGroupLeaderIdentifier == pid)
+	{
+		ok = true;
+		MyProc->lockGroupLeader = leader;
+		dlist_push_tail(&leader->lockGroupMembers, &MyProc->lockGroupLink);
+	}
+	LWLockRelease(leader_lwlock);
+
+	return ok;
+}
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 90b1eb1..cdbf72c 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -43,8 +43,12 @@ static int DecodeTime(char *str, int fmask, int range,
 static const datetkn *datebsearch(const char *key, const datetkn *base, int nel);
 static int DecodeDate(char *str, int fmask, int *tmask, bool *is2digits,
 		   struct pg_tm * tm);
-static void TrimTrailingZeros(char *str);
-static void AppendSeconds(char *cp, int sec, fsec_t fsec,
+
+#ifndef HAVE_INT64_TIMESTAMP
+static char *TrimTrailingZeros(char *str);
+#endif   /* HAVE_INT64_TIMESTAMP */
+
+static char *AppendSeconds(char *cp, int sec, fsec_t fsec,
 			  int precision, bool fillzeros);
 static void AdjustFractSeconds(double frac, struct pg_tm * tm, fsec_t *fsec,
 				   int scale);
@@ -398,57 +402,121 @@ GetCurrentTimeUsec(struct pg_tm * tm, fsec_t *fsec, int *tzp)
 /* TrimTrailingZeros()
  * ... resulting from printing numbers with full precision.
  *
+ * Returns a pointer to the new end of string.  No NUL terminator is put
+ * there; callers are responsible for NUL terminating str themselves.
+ *
  * Before Postgres 8.4, this always left at least 2 fractional digits,
  * but conversations on the lists suggest this isn't desired
  * since showing '0.10' is misleading with values of precision(1).
  */
-static void
+#ifndef HAVE_INT64_TIMESTAMP
+static char *
 TrimTrailingZeros(char *str)
 {
 	int			len = strlen(str);
 
 	while (len > 1 && *(str + len - 1) == '0' && *(str + len - 2) != '.')
-	{
 		len--;
-		*(str + len) = '\0';
-	}
+	return str + len;
 }
+#endif   /* HAVE_INT64_TIMESTAMP */
 
 /*
- * Append sections and fractional seconds (if any) at *cp.
+ * Append seconds and fractional seconds (if any) at *cp.
+ *
  * precision is the max number of fraction digits, fillzeros says to
  * pad to two integral-seconds digits.
+ *
+ * Returns a pointer to the new end of string.  No NUL terminator is put
+ * there; callers are responsible for NUL terminating str themselves.
+ *
  * Note that any sign is stripped from the input seconds values.
  */
-static void
+static char *
 AppendSeconds(char *cp, int sec, fsec_t fsec, int precision, bool fillzeros)
 {
+	Assert(precision >= 0);
+
+#ifdef HAVE_INT64_TIMESTAMP
+	/* fsec_t is just an int32 */
+
+	if (fillzeros)
+		cp = pg_ltostr_zeropad(cp, Abs(sec), 2);
+	else
+		cp = pg_ltostr(cp, Abs(sec));
+
+	if (fsec != 0)
+	{
+		int32		value = Abs(fsec);
+		char	   *end = &cp[precision + 1];
+		bool		gotnonzero = false;
+
+		*cp++ = '.';
+
+		/*
+		 * Append the fractional seconds part.  Note that we don't want any
+		 * trailing zeros here, so since we're building the number in reverse
+		 * we'll skip appending zeros until we've output a non-zero digit.
+		 */
+		while (precision--)
+		{
+			int32		oldval = value;
+			int32		remainder;
+
+			value /= 10;
+			remainder = oldval - value * 10;
+
+			/* check if we got a non-zero */
+			if (remainder)
+				gotnonzero = true;
+
+			if (gotnonzero)
+				cp[precision] = '0' + remainder;
+			else
+				end = &cp[precision];
+		}
+
+		/*
+		 * If we still have a non-zero value then precision must have not been
+		 * enough to print the number.  We punt the problem to pg_ltostr(),
+		 * which will generate a correct answer in the minimum valid width.
+		 */
+		if (value)
+			return pg_ltostr(cp, Abs(fsec));
+
+		return end;
+	}
+	else
+		return cp;
+#else
+	/* fsec_t is a double */
+
 	if (fsec == 0)
 	{
 		if (fillzeros)
-			sprintf(cp, "%02d", abs(sec));
+			return pg_ltostr_zeropad(cp, Abs(sec), 2);
 		else
-			sprintf(cp, "%d", abs(sec));
+			return pg_ltostr(cp, Abs(sec));
 	}
 	else
 	{
-#ifdef HAVE_INT64_TIMESTAMP
-		if (fillzeros)
-			sprintf(cp, "%02d.%0*d", abs(sec), precision, (int) Abs(fsec));
-		else
-			sprintf(cp, "%d.%0*d", abs(sec), precision, (int) Abs(fsec));
-#else
 		if (fillzeros)
 			sprintf(cp, "%0*.*f", precision + 3, precision, fabs(sec + fsec));
 		else
 			sprintf(cp, "%.*f", precision, fabs(sec + fsec));
-#endif
-		TrimTrailingZeros(cp);
+		return TrimTrailingZeros(cp);
 	}
+#endif   /* HAVE_INT64_TIMESTAMP */
 }
 
-/* Variant of above that's specialized to timestamp case */
-static void
+
+/*
+ * Variant of above that's specialized to timestamp case.
+ *
+ * Returns a pointer to the new end of string.  No NUL terminator is put
+ * there; callers are responsible for NUL terminating str themselves.
+ */
+static char *
 AppendTimestampSeconds(char *cp, struct pg_tm * tm, fsec_t fsec)
 {
 	/*
@@ -459,7 +527,7 @@ AppendTimestampSeconds(char *cp, struct pg_tm * tm, fsec_t fsec)
 	if (tm->tm_year <= 0)
 		fsec = 0;
 #endif
-	AppendSeconds(cp, tm->tm_sec, fsec, MAX_TIMESTAMP_PRECISION, true);
+	return AppendSeconds(cp, tm->tm_sec, fsec, MAX_TIMESTAMP_PRECISION, true);
 }
 
 /*
@@ -3831,9 +3899,12 @@ datebsearch(const char *key, const datetkn *base, int nel)
 }
 
 /* EncodeTimezone()
- *		Append representation of a numeric timezone offset to str.
+ *		Copies representation of a numeric timezone offset to str.
+ *
+ * Returns a pointer to the new end of string.  No NUL terminator is put
+ * there; callers are responsible for NUL terminating str themselves.
  */
-static void
+static char *
 EncodeTimezone(char *str, int tz, int style)
 {
 	int			hour,
@@ -3846,16 +3917,26 @@ EncodeTimezone(char *str, int tz, int style)
 	hour = min / MINS_PER_HOUR;
 	min -= hour * MINS_PER_HOUR;
 
-	str += strlen(str);
 	/* TZ is negated compared to sign we wish to display ... */
 	*str++ = (tz <= 0 ? '+' : '-');
 
 	if (sec != 0)
-		sprintf(str, "%02d:%02d:%02d", hour, min, sec);
+	{
+		str = pg_ltostr_zeropad(str, hour, 2);
+		*str++ = ':';
+		str = pg_ltostr_zeropad(str, min, 2);
+		*str++ = ':';
+		str = pg_ltostr_zeropad(str, sec, 2);
+	}
 	else if (min != 0 || style == USE_XSD_DATES)
-		sprintf(str, "%02d:%02d", hour, min);
+	{
+		str = pg_ltostr_zeropad(str, hour, 2);
+		*str++ = ':';
+		str = pg_ltostr_zeropad(str, min, 2);
+	}
 	else
-		sprintf(str, "%02d", hour);
+		str = pg_ltostr_zeropad(str, hour, 2);
+	return str;
 }
 
 /* EncodeDateOnly()
@@ -3871,48 +3952,70 @@ EncodeDateOnly(struct pg_tm * tm, int style, char *str)
 		case USE_ISO_DATES:
 		case USE_XSD_DATES:
 			/* compatible with ISO date formats */
-			if (tm->tm_year > 0)
-				sprintf(str, "%04d-%02d-%02d",
-						tm->tm_year, tm->tm_mon, tm->tm_mday);
-			else
-				sprintf(str, "%04d-%02d-%02d %s",
-						-(tm->tm_year - 1), tm->tm_mon, tm->tm_mday, "BC");
+			str = pg_ltostr_zeropad(str,
+					(tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
+			*str++ = '-';
+			str = pg_ltostr_zeropad(str, tm->tm_mon, 2);
+			*str++ = '-';
+			str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
 			break;
 
 		case USE_SQL_DATES:
 			/* compatible with Oracle/Ingres date formats */
 			if (DateOrder == DATEORDER_DMY)
-				sprintf(str, "%02d/%02d", tm->tm_mday, tm->tm_mon);
+			{
+				str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
+				*str++ = '/';
+				str = pg_ltostr_zeropad(str, tm->tm_mon, 2);
+			}
 			else
-				sprintf(str, "%02d/%02d", tm->tm_mon, tm->tm_mday);
-			if (tm->tm_year > 0)
-				sprintf(str + 5, "/%04d", tm->tm_year);
-			else
-				sprintf(str + 5, "/%04d %s", -(tm->tm_year - 1), "BC");
+			{
+				str = pg_ltostr_zeropad(str, tm->tm_mon, 2);
+				*str++ = '/';
+				str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
+			}
+			*str++ = '/';
+			str = pg_ltostr_zeropad(str,
+					(tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
 			break;
 
 		case USE_GERMAN_DATES:
 			/* German-style date format */
-			sprintf(str, "%02d.%02d", tm->tm_mday, tm->tm_mon);
-			if (tm->tm_year > 0)
-				sprintf(str + 5, ".%04d", tm->tm_year);
-			else
-				sprintf(str + 5, ".%04d %s", -(tm->tm_year - 1), "BC");
+			str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
+			*str++ = '.';
+			str = pg_ltostr_zeropad(str, tm->tm_mon, 2);
+			*str++ = '.';
+			str = pg_ltostr_zeropad(str,
+					(tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
 			break;
 
 		case USE_POSTGRES_DATES:
 		default:
 			/* traditional date-only style for Postgres */
 			if (DateOrder == DATEORDER_DMY)
-				sprintf(str, "%02d-%02d", tm->tm_mday, tm->tm_mon);
+			{
+				str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
+				*str++ = '-';
+				str = pg_ltostr_zeropad(str, tm->tm_mon, 2);
+			}
 			else
-				sprintf(str, "%02d-%02d", tm->tm_mon, tm->tm_mday);
-			if (tm->tm_year > 0)
-				sprintf(str + 5, "-%04d", tm->tm_year);
-			else
-				sprintf(str + 5, "-%04d %s", -(tm->tm_year - 1), "BC");
+			{
+				str = pg_ltostr_zeropad(str, tm->tm_mon, 2);
+				*str++ = '-';
+				str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
+			}
+			*str++ = '-';
+			str = pg_ltostr_zeropad(str,
+					(tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
 			break;
 	}
+
+	if (tm->tm_year <= 0)
+	{
+		memcpy(str, " BC", 3);	/* Don't copy NUL */
+		str += 3;
+	}
+	*str = '\0';
 }
 
 
@@ -3927,13 +4030,14 @@ EncodeDateOnly(struct pg_tm * tm, int style, char *str)
 void
 EncodeTimeOnly(struct pg_tm * tm, fsec_t fsec, bool print_tz, int tz, int style, char *str)
 {
-	sprintf(str, "%02d:%02d:", tm->tm_hour, tm->tm_min);
-	str += strlen(str);
-
-	AppendSeconds(str, tm->tm_sec, fsec, MAX_TIME_PRECISION, true);
-
+	str = pg_ltostr_zeropad(str, tm->tm_hour, 2);
+	*str++ = ':';
+	str = pg_ltostr_zeropad(str, tm->tm_min, 2);
+	*str++ = ':';
+	str = AppendSeconds(str, tm->tm_sec, fsec, MAX_TIME_PRECISION, true);
 	if (print_tz)
-		EncodeTimezone(str, tz, style);
+		str = EncodeTimezone(str, tz, style);
+	*str = '\0';
 }
 
 
@@ -3971,106 +4075,129 @@ EncodeDateTime(struct pg_tm * tm, fsec_t fsec, bool print_tz, int tz, const char
 		case USE_ISO_DATES:
 		case USE_XSD_DATES:
 			/* Compatible with ISO-8601 date formats */
-
-			if (style == USE_ISO_DATES)
-				sprintf(str, "%04d-%02d-%02d %02d:%02d:",
-						(tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1),
-						tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min);
-			else
-				sprintf(str, "%04d-%02d-%02dT%02d:%02d:",
-						(tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1),
-						tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min);
-
-			AppendTimestampSeconds(str + strlen(str), tm, fsec);
-
+			str = pg_ltostr_zeropad(str,
+					(tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
+			*str++ = '-';
+			str = pg_ltostr_zeropad(str, tm->tm_mon, 2);
+			*str++ = '-';
+			str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
+			*str++ = (style == USE_ISO_DATES) ? ' ' : 'T';
+			str = pg_ltostr_zeropad(str, tm->tm_hour, 2);
+			*str++ = ':';
+			str = pg_ltostr_zeropad(str, tm->tm_min, 2);
+			*str++ = ':';
+			str = AppendTimestampSeconds(str, tm, fsec);
 			if (print_tz)
-				EncodeTimezone(str, tz, style);
-
-			if (tm->tm_year <= 0)
-				sprintf(str + strlen(str), " BC");
+				str = EncodeTimezone(str, tz, style);
 			break;
 
 		case USE_SQL_DATES:
 			/* Compatible with Oracle/Ingres date formats */
-
 			if (DateOrder == DATEORDER_DMY)
-				sprintf(str, "%02d/%02d", tm->tm_mday, tm->tm_mon);
+			{
+				str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
+				*str++ = '/';
+				str = pg_ltostr_zeropad(str, tm->tm_mon, 2);
+			}
 			else
-				sprintf(str, "%02d/%02d", tm->tm_mon, tm->tm_mday);
-
-			sprintf(str + 5, "/%04d %02d:%02d:",
-					(tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1),
-					tm->tm_hour, tm->tm_min);
-
-			AppendTimestampSeconds(str + strlen(str), tm, fsec);
+			{
+				str = pg_ltostr_zeropad(str, tm->tm_mon, 2);
+				*str++ = '/';
+				str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
+			}
+			*str++ = '/';
+			str = pg_ltostr_zeropad(str,
+					(tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
+			*str++ = ' ';
+			str = pg_ltostr_zeropad(str, tm->tm_hour, 2);
+			*str++ = ':';
+			str = pg_ltostr_zeropad(str, tm->tm_min, 2);
+			*str++ = ':';
+			str = AppendTimestampSeconds(str, tm, fsec);
 
 			/*
 			 * Note: the uses of %.*s in this function would be risky if the
 			 * timezone names ever contain non-ASCII characters.  However, all
-			 * TZ abbreviations in the Olson database are plain ASCII.
+			 * TZ abbreviations in the IANA database are plain ASCII.
 			 */
-
 			if (print_tz)
 			{
 				if (tzn)
-					sprintf(str + strlen(str), " %.*s", MAXTZLEN, tzn);
+				{
+					sprintf(str, " %.*s", MAXTZLEN, tzn);
+					str += strlen(str);
+				}
 				else
-					EncodeTimezone(str, tz, style);
+					str = EncodeTimezone(str, tz, style);
 			}
-
-			if (tm->tm_year <= 0)
-				sprintf(str + strlen(str), " BC");
 			break;
 
 		case USE_GERMAN_DATES:
 			/* German variant on European style */
-
-			sprintf(str, "%02d.%02d", tm->tm_mday, tm->tm_mon);
-
-			sprintf(str + 5, ".%04d %02d:%02d:",
-					(tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1),
-					tm->tm_hour, tm->tm_min);
-
-			AppendTimestampSeconds(str + strlen(str), tm, fsec);
+			str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
+			*str++ = '.';
+			str = pg_ltostr_zeropad(str, tm->tm_mon, 2);
+			*str++ = '.';
+			str = pg_ltostr_zeropad(str,
+					(tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
+			*str++ = ' ';
+			str = pg_ltostr_zeropad(str, tm->tm_hour, 2);
+			*str++ = ':';
+			str = pg_ltostr_zeropad(str, tm->tm_min, 2);
+			*str++ = ':';
+			str = AppendTimestampSeconds(str, tm, fsec);
 
 			if (print_tz)
 			{
 				if (tzn)
-					sprintf(str + strlen(str), " %.*s", MAXTZLEN, tzn);
+				{
+					sprintf(str, " %.*s", MAXTZLEN, tzn);
+					str += strlen(str);
+				}
 				else
-					EncodeTimezone(str, tz, style);
+					str = EncodeTimezone(str, tz, style);
 			}
-
-			if (tm->tm_year <= 0)
-				sprintf(str + strlen(str), " BC");
 			break;
 
 		case USE_POSTGRES_DATES:
 		default:
 			/* Backward-compatible with traditional Postgres abstime dates */
-
 			day = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
 			tm->tm_wday = j2day(day);
-
 			memcpy(str, days[tm->tm_wday], 3);
-			strcpy(str + 3, " ");
-
+			str += 3;
+			*str++ = ' ';
 			if (DateOrder == DATEORDER_DMY)
-				sprintf(str + 4, "%02d %3s", tm->tm_mday, months[tm->tm_mon - 1]);
+			{
+				str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
+				*str++ = ' ';
+				memcpy(str, months[tm->tm_mon - 1], 3);
+				str += 3;
+			}
 			else
-				sprintf(str + 4, "%3s %02d", months[tm->tm_mon - 1], tm->tm_mday);
-
-			sprintf(str + 10, " %02d:%02d:", tm->tm_hour, tm->tm_min);
-
-			AppendTimestampSeconds(str + strlen(str), tm, fsec);
-
-			sprintf(str + strlen(str), " %04d",
-					(tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1));
+			{
+				memcpy(str, months[tm->tm_mon - 1], 3);
+				str += 3;
+				*str++ = ' ';
+				str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
+			}
+			*str++ = ' ';
+			str = pg_ltostr_zeropad(str, tm->tm_hour, 2);
+			*str++ = ':';
+			str = pg_ltostr_zeropad(str, tm->tm_min, 2);
+			*str++ = ':';
+			str = AppendTimestampSeconds(str, tm, fsec);
+			*str++ = ' ';
+			str = pg_ltostr_zeropad(str,
+					(tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
 
 			if (print_tz)
 			{
 				if (tzn)
-					sprintf(str + strlen(str), " %.*s", MAXTZLEN, tzn);
+				{
+					sprintf(str, " %.*s", MAXTZLEN, tzn);
+					str += strlen(str);
+				}
 				else
 				{
 					/*
@@ -4079,15 +4206,19 @@ EncodeDateTime(struct pg_tm * tm, fsec_t fsec, bool print_tz, int tz, const char
 					 * avoid formatting something which would be rejected by
 					 * the date/time parser later. - thomas 2001-10-19
 					 */
-					sprintf(str + strlen(str), " ");
-					EncodeTimezone(str, tz, style);
+					*str++ = ' ';
+					str = EncodeTimezone(str, tz, style);
 				}
 			}
-
-			if (tm->tm_year <= 0)
-				sprintf(str + strlen(str), " BC");
 			break;
 	}
+
+	if (tm->tm_year <= 0)
+	{
+		memcpy(str, " BC", 3);	/* Don't copy NUL */
+		str += 3;
+	}
+	*str = '\0';
 }
 
 
@@ -4242,7 +4373,8 @@ EncodeInterval(struct pg_tm * tm, fsec_t fsec, int style, char *str)
 							day_sign, abs(mday),
 							sec_sign, abs(hour), abs(min));
 					cp += strlen(cp);
-					AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true);
+					cp = AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true);
+					*cp = '\0';
 				}
 				else if (has_year_month)
 				{
@@ -4252,13 +4384,15 @@ EncodeInterval(struct pg_tm * tm, fsec_t fsec, int style, char *str)
 				{
 					sprintf(cp, "%d %d:%02d:", mday, hour, min);
 					cp += strlen(cp);
-					AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true);
+					cp = AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true);
+					*cp = '\0';
 				}
 				else
 				{
 					sprintf(cp, "%d:%02d:", hour, min);
 					cp += strlen(cp);
-					AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true);
+					cp = AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true);
+					*cp = '\0';
 				}
 			}
 			break;
@@ -4284,8 +4418,7 @@ EncodeInterval(struct pg_tm * tm, fsec_t fsec, int style, char *str)
 			{
 				if (sec < 0 || fsec < 0)
 					*cp++ = '-';
-				AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, false);
-				cp += strlen(cp);
+				cp = AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, false);
 				*cp++ = 'S';
 				*cp++ = '\0';
 			}
@@ -4311,7 +4444,8 @@ EncodeInterval(struct pg_tm * tm, fsec_t fsec, int style, char *str)
 						(minus ? "-" : (is_before ? "+" : "")),
 						abs(hour), abs(min));
 				cp += strlen(cp);
-				AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true);
+				cp = AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true);
+				*cp = '\0';
 			}
 			break;
 
@@ -4337,8 +4471,7 @@ EncodeInterval(struct pg_tm * tm, fsec_t fsec, int style, char *str)
 				}
 				else if (is_before)
 					*cp++ = '-';
-				AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, false);
-				cp += strlen(cp);
+				cp = AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, false);
 				sprintf(cp, " sec%s",
 						(abs(sec) != 1 || fsec != 0) ? "s" : "");
 				is_zero = FALSE;
diff --git a/src/backend/utils/adt/numutils.c b/src/backend/utils/adt/numutils.c
index 880d304..6b10596 100644
--- a/src/backend/utils/adt/numutils.c
+++ b/src/backend/utils/adt/numutils.c
@@ -227,3 +227,164 @@ pg_lltoa(int64 value, char *a)
 		*a-- = swap;
 	}
 }
+
+
+/*
+ * pg_ltostr_zeropad
+ *		Converts 'value' into a decimal string representation stored at 'str'.
+ *		'minwidth' specifies the minimum width of the result; any extra space
+ *		is filled up by prefixing the number with zeros.
+ *
+ * Returns the ending address of the string result (the last character written
+ * plus 1).  Note that no NUL terminator is written.
+ *
+ * The intended use-case for this function is to build strings that contain
+ * multiple individual numbers, for example:
+ *
+ *	str = pg_ltostr_zeropad(str, hours, 2);
+ *	*str++ = ':';
+ *	str = pg_ltostr_zeropad(str, mins, 2);
+ *	*str++ = ':';
+ *	str = pg_ltostr_zeropad(str, secs, 2);
+ *	*str = '\0';
+ *
+ * Note: Caller must ensure that 'str' points to enough memory to hold the
+ * result.
+ */
+char *
+pg_ltostr_zeropad(char *str, int32 value, int32 minwidth)
+{
+	char	   *start = str;
+	char	   *end = &str[minwidth];
+	int32		num = value;
+
+	Assert(minwidth > 0);
+
+	/*
+	 * Handle negative numbers in a special way.  We can't just write a '-'
+	 * prefix and reverse the sign as that would overflow for INT32_MIN.
+	 */
+	if (num < 0)
+	{
+		*start++ = '-';
+		minwidth--;
+
+		/*
+		 * Build the number starting at the last digit.  Here remainder will
+		 * be a negative number, so we must reverse the sign before adding '0'
+		 * in order to get the correct ASCII digit.
+		 */
+		while (minwidth--)
+		{
+			int32		oldval = num;
+			int32		remainder;
+
+			num /= 10;
+			remainder = oldval - num * 10;
+			start[minwidth] = '0' - remainder;
+		}
+	}
+	else
+	{
+		/* Build the number starting at the last digit */
+		while (minwidth--)
+		{
+			int32		oldval = num;
+			int32		remainder;
+
+			num /= 10;
+			remainder = oldval - num * 10;
+			start[minwidth] = '0' + remainder;
+		}
+	}
+
+	/*
+	 * If minwidth was not high enough to fit the number then num won't have
+	 * been divided down to zero.  We punt the problem to pg_ltostr(), which
+	 * will generate a correct answer in the minimum valid width.
+	 */
+	if (num != 0)
+		return pg_ltostr(str, value);
+
+	/* Otherwise, return last output character + 1 */
+	return end;
+}
+
+/*
+ * pg_ltostr
+ *		Converts 'value' into a decimal string representation stored at 'str'.
+ *
+ * Returns the ending address of the string result (the last character written
+ * plus 1).  Note that no NUL terminator is written.
+ *
+ * The intended use-case for this function is to build strings that contain
+ * multiple individual numbers, for example:
+ *
+ *	str = pg_ltostr(str, a);
+ *	*str++ = ' ';
+ *	str = pg_ltostr(str, b);
+ *	*str = '\0';
+ *
+ * Note: Caller must ensure that 'str' points to enough memory to hold the
+ * result.
+ */
+char *
+pg_ltostr(char *str, int32 value)
+{
+	char	   *start;
+	char	   *end;
+
+	/*
+	 * Handle negative numbers in a special way.  We can't just write a '-'
+	 * prefix and reverse the sign as that would overflow for INT32_MIN.
+	 */
+	if (value < 0)
+	{
+		*str++ = '-';
+
+		/* Mark the position we must reverse the string from. */
+		start = str;
+
+		/* Compute the result string backwards. */
+		do
+		{
+			int32		oldval = value;
+			int32		remainder;
+
+			value /= 10;
+			remainder = oldval - value * 10;
+			/* As above, we expect remainder to be negative. */
+			*str++ = '0' - remainder;
+		} while (value != 0);
+	}
+	else
+	{
+		/* Mark the position we must reverse the string from. */
+		start = str;
+
+		/* Compute the result string backwards. */
+		do
+		{
+			int32		oldval = value;
+			int32		remainder;
+
+			value /= 10;
+			remainder = oldval - value * 10;
+			*str++ = '0' + remainder;
+		} while (value != 0);
+	}
+
+	/* Remember the end+1 and back up 'str' to the last character. */
+	end = str--;
+
+	/* Reverse string. */
+	while (start < str)
+	{
+		char		swap = *start;
+
+		*start++ = *str;
+		*str-- = swap;
+	}
+
+	return end;
+}
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 4efd298..490a090 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -5532,9 +5532,21 @@ get_insert_query_def(Query *query, deparse_context *context)
 			/* Add a WHERE clause (for partial indexes) if given */
 			if (confl->arbiterWhere != NULL)
 			{
+				bool		save_varprefix;
+
+				/*
+				 * Force non-prefixing of Vars, since parser assumes that they
+				 * belong to target relation.  WHERE clause does not use
+				 * InferenceElem, so this is separately required.
+				 */
+				save_varprefix = context->varprefix;
+				context->varprefix = false;
+
 				appendContextKeyword(context, " WHERE ",
 									 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
 				get_rule_expr(confl->arbiterWhere, context, false);
+
+				context->varprefix = save_varprefix;
 			}
 		}
 		else if (confl->constraint != InvalidOid)
@@ -7956,13 +7968,14 @@ get_rule_expr(Node *node, deparse_context *context,
 		case T_InferenceElem:
 			{
 				InferenceElem *iexpr = (InferenceElem *) node;
-				bool		varprefix = context->varprefix;
+				bool		save_varprefix;
 				bool		need_parens;
 
 				/*
 				 * InferenceElem can only refer to target relation, so a
-				 * prefix is never useful.
+				 * prefix is not useful, and indeed would cause parse errors.
 				 */
+				save_varprefix = context->varprefix;
 				context->varprefix = false;
 
 				/*
@@ -7982,7 +7995,7 @@ get_rule_expr(Node *node, deparse_context *context,
 				if (need_parens)
 					appendStringInfoChar(buf, ')');
 
-				context->varprefix = varprefix;
+				context->varprefix = save_varprefix;
 
 				if (iexpr->infercollid)
 					appendStringInfo(buf, " COLLATE %s",
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 66c4791..31a69ca 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -379,6 +379,19 @@ static const struct config_enum_entry huge_pages_options[] = {
 	{NULL, 0, false}
 };
 
+static const struct config_enum_entry force_parallel_mode_options[] = {
+	{"off", FORCE_PARALLEL_OFF, false},
+	{"on", FORCE_PARALLEL_ON, false},
+	{"regress", FORCE_PARALLEL_REGRESS, false},
+	{"true", FORCE_PARALLEL_ON, true},
+	{"false", FORCE_PARALLEL_OFF, true},
+	{"yes", FORCE_PARALLEL_ON, true},
+	{"no", FORCE_PARALLEL_OFF, true},
+	{"1", FORCE_PARALLEL_ON, true},
+	{"0", FORCE_PARALLEL_OFF, true},
+	{NULL, 0, false}
+};
+
 /*
  * Options for enum values stored in other modules
  */
@@ -863,6 +876,7 @@ static struct config_bool ConfigureNamesBool[] =
 		true,
 		NULL, NULL, NULL
 	},
+
 	{
 		{"geqo", PGC_USERSET, QUERY_TUNING_GEQO,
 			gettext_noop("Enables genetic query optimization."),
@@ -3672,6 +3686,16 @@ static struct config_enum ConfigureNamesEnum[] =
 		NULL, NULL, NULL
 	},
 
+	{
+		{"force_parallel_mode", PGC_USERSET, QUERY_TUNING_OTHER,
+			gettext_noop("Forces use of parallel query facilities."),
+			gettext_noop("If possible, run query using a parallel worker and with parallel restrictions.")
+		},
+		&force_parallel_mode,
+		FORCE_PARALLEL_OFF, force_parallel_mode_options,
+		NULL, NULL, NULL
+	},
+
 	/* End-of-list marker */
 	{
 		{NULL, 0, 0, NULL, NULL}, NULL, 0, NULL, NULL, NULL, NULL
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index 029114f..09b2003 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -313,6 +313,7 @@
 #from_collapse_limit = 8
 #join_collapse_limit = 8		# 1 disables collapsing of explicit
 					# JOIN clauses
+#force_parallel_mode = off
 
 
 #------------------------------------------------------------------------------
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 64c2673..d09c6ce 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -6901,7 +6901,35 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
 
 		resetPQExpBuffer(q);
 
-		if (fout->remoteVersion >= 90200)
+		if (fout->remoteVersion >= 90600)
+		{
+			/*
+			 * In 9.6, NOT NULL constraints are in pg_constraint and will be
+			 * dumped as table constraints, so it's unnecessary to dump them
+			 * here.
+			 */
+			appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
+							  "a.attstattarget, a.attstorage, t.typstorage, "
+							  "false as attnotnull, a.atthasdef, a.attisdropped, "
+							  "a.attlen, a.attalign, a.attislocal, "
+				  "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
+						"array_to_string(a.attoptions, ', ') AS attoptions, "
+							  "CASE WHEN a.attcollation <> t.typcollation "
+						   "THEN a.attcollation ELSE 0 END AS attcollation, "
+							  "pg_catalog.array_to_string(ARRAY("
+							  "SELECT pg_catalog.quote_ident(option_name) || "
+							  "' ' || pg_catalog.quote_literal(option_value) "
+						"FROM pg_catalog.pg_options_to_table(attfdwoptions) "
+							  "ORDER BY option_name"
+							  "), E',\n    ') AS attfdwoptions "
+			 "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
+							  "ON a.atttypid = t.oid "
+							  "WHERE a.attrelid = '%u'::pg_catalog.oid "
+							  "AND a.attnum > 0::pg_catalog.int2 "
+							  "ORDER BY a.attrelid, a.attnum",
+							  tbinfo->dobj.catId.oid);
+		}
+		else if (fout->remoteVersion >= 90200)
 		{
 			/*
 			 * attfdwoptions is new in 9.2.
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 90992f2..378c40f 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -53,6 +53,6 @@
  */
 
 /*							yyyymmddN */
-#define CATALOG_VERSION_NO	201602041
+#define CATALOG_VERSION_NO	201602071
 
 #endif
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index c6b4916..1c0ef9a 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -5146,23 +5146,23 @@ DATA(insert OID = 3993 ( dense_rank_final	PGNSP PGUID 12 1 0 2276 0 f f f f f f
 DESCR("aggregate final function");
 
 /* pg_upgrade support */
-DATA(insert OID = 3582 ( binary_upgrade_set_next_pg_type_oid PGNSP PGUID  12 1 0 0 0 f f f f t f v s 1 0 2278 "26" _null_ _null_ _null_ _null_ _null_ binary_upgrade_set_next_pg_type_oid _null_ _null_ _null_ ));
+DATA(insert OID = 3582 ( binary_upgrade_set_next_pg_type_oid PGNSP PGUID  12 1 0 0 0 f f f f t f v r 1 0 2278 "26" _null_ _null_ _null_ _null_ _null_ binary_upgrade_set_next_pg_type_oid _null_ _null_ _null_ ));
 DESCR("for use by pg_upgrade");
-DATA(insert OID = 3584 ( binary_upgrade_set_next_array_pg_type_oid PGNSP PGUID	12 1 0 0 0 f f f f t f v s 1 0 2278 "26" _null_ _null_ _null_ _null_ _null_ binary_upgrade_set_next_array_pg_type_oid _null_ _null_ _null_ ));
+DATA(insert OID = 3584 ( binary_upgrade_set_next_array_pg_type_oid PGNSP PGUID	12 1 0 0 0 f f f f t f v r 1 0 2278 "26" _null_ _null_ _null_ _null_ _null_ binary_upgrade_set_next_array_pg_type_oid _null_ _null_ _null_ ));
 DESCR("for use by pg_upgrade");
-DATA(insert OID = 3585 ( binary_upgrade_set_next_toast_pg_type_oid PGNSP PGUID	12 1 0 0 0 f f f f t f v s 1 0 2278 "26" _null_ _null_ _null_ _null_ _null_ binary_upgrade_set_next_toast_pg_type_oid _null_ _null_ _null_ ));
+DATA(insert OID = 3585 ( binary_upgrade_set_next_toast_pg_type_oid PGNSP PGUID	12 1 0 0 0 f f f f t f v r 1 0 2278 "26" _null_ _null_ _null_ _null_ _null_ binary_upgrade_set_next_toast_pg_type_oid _null_ _null_ _null_ ));
 DESCR("for use by pg_upgrade");
-DATA(insert OID = 3586 ( binary_upgrade_set_next_heap_pg_class_oid PGNSP PGUID	12 1 0 0 0 f f f f t f v s 1 0 2278 "26" _null_ _null_ _null_ _null_ _null_ binary_upgrade_set_next_heap_pg_class_oid _null_ _null_ _null_ ));
+DATA(insert OID = 3586 ( binary_upgrade_set_next_heap_pg_class_oid PGNSP PGUID	12 1 0 0 0 f f f f t f v r 1 0 2278 "26" _null_ _null_ _null_ _null_ _null_ binary_upgrade_set_next_heap_pg_class_oid _null_ _null_ _null_ ));
 DESCR("for use by pg_upgrade");
-DATA(insert OID = 3587 ( binary_upgrade_set_next_index_pg_class_oid PGNSP PGUID  12 1 0 0 0 f f f f t f v s 1 0 2278 "26" _null_ _null_ _null_ _null_ _null_ binary_upgrade_set_next_index_pg_class_oid _null_ _null_ _null_ ));
+DATA(insert OID = 3587 ( binary_upgrade_set_next_index_pg_class_oid PGNSP PGUID  12 1 0 0 0 f f f f t f v r 1 0 2278 "26" _null_ _null_ _null_ _null_ _null_ binary_upgrade_set_next_index_pg_class_oid _null_ _null_ _null_ ));
 DESCR("for use by pg_upgrade");
-DATA(insert OID = 3588 ( binary_upgrade_set_next_toast_pg_class_oid PGNSP PGUID  12 1 0 0 0 f f f f t f v s 1 0 2278 "26" _null_ _null_ _null_ _null_ _null_ binary_upgrade_set_next_toast_pg_class_oid _null_ _null_ _null_ ));
+DATA(insert OID = 3588 ( binary_upgrade_set_next_toast_pg_class_oid PGNSP PGUID  12 1 0 0 0 f f f f t f v r 1 0 2278 "26" _null_ _null_ _null_ _null_ _null_ binary_upgrade_set_next_toast_pg_class_oid _null_ _null_ _null_ ));
 DESCR("for use by pg_upgrade");
-DATA(insert OID = 3589 ( binary_upgrade_set_next_pg_enum_oid PGNSP PGUID  12 1 0 0 0 f f f f t f v s 1 0 2278 "26" _null_ _null_ _null_ _null_ _null_ binary_upgrade_set_next_pg_enum_oid _null_ _null_ _null_ ));
+DATA(insert OID = 3589 ( binary_upgrade_set_next_pg_enum_oid PGNSP PGUID  12 1 0 0 0 f f f f t f v r 1 0 2278 "26" _null_ _null_ _null_ _null_ _null_ binary_upgrade_set_next_pg_enum_oid _null_ _null_ _null_ ));
 DESCR("for use by pg_upgrade");
-DATA(insert OID = 3590 ( binary_upgrade_set_next_pg_authid_oid PGNSP PGUID	12 1 0 0 0 f f f f t f v s 1 0 2278 "26" _null_ _null_ _null_ _null_ _null_ binary_upgrade_set_next_pg_authid_oid _null_ _null_ _null_ ));
+DATA(insert OID = 3590 ( binary_upgrade_set_next_pg_authid_oid PGNSP PGUID	12 1 0 0 0 f f f f t f v r 1 0 2278 "26" _null_ _null_ _null_ _null_ _null_ binary_upgrade_set_next_pg_authid_oid _null_ _null_ _null_ ));
 DESCR("for use by pg_upgrade");
-DATA(insert OID = 3591 ( binary_upgrade_create_empty_extension PGNSP PGUID	12 1 0 0 0 f f f f f f v s 7 0 2278 "25 25 16 25 1028 1009 1009" _null_ _null_ _null_ _null_ _null_ binary_upgrade_create_empty_extension _null_ _null_ _null_ ));
+DATA(insert OID = 3591 ( binary_upgrade_create_empty_extension PGNSP PGUID	12 1 0 0 0 f f f f f f v r 7 0 2278 "25 25 16 25 1028 1009 1009" _null_ _null_ _null_ _null_ _null_ binary_upgrade_create_empty_extension _null_ _null_ _null_ ));
 DESCR("for use by pg_upgrade");
 
 /* replication/origin.h */
diff --git a/src/include/commands/constraint.h b/src/include/commands/constraint.h
new file mode 100644
index 0000000..99799b4
--- /dev/null
+++ b/src/include/commands/constraint.h
@@ -0,0 +1,29 @@
+/*-------------------------------------------------------------------------
+ *
+ * constraint.h
+ *	  PostgreSQL CONSTRAINT support declarations
+ *
+ * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * IDENTIFICATION
+ *	  src/include/commands/constraint.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef CONSTRAINT_H
+#define CONSTRAINT_H
+
+#include "nodes/parsenodes.h"
+#include "utils/relcache.h"
+
+extern Constraint *createCheckNotNullConstraint(Oid nspid,
+							 char *constraint_name, const char *relname,
+							 const char *colname);
+
+extern char *tryExtractNotNullFromCheckConstr(Constraint *constr);
+
+extern char *tryExtractNotNullFromCatalog(HeapTuple constrTup,
+							 TupleDesc tupdesc, Relation rel);
+
+#endif /* CONSTRAINT_H */
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 2fd0629..4ab39fd 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -1735,10 +1735,11 @@ typedef struct VariableShowStmt
  *		Create Table Statement
  *
  * NOTE: in the raw gram.y output, ColumnDef and Constraint nodes are
- * intermixed in tableElts, and constraints is NIL.  After parse analysis,
- * tableElts contains just ColumnDefs, and constraints contains just
- * Constraint nodes (in fact, only CONSTR_CHECK nodes, in the present
- * implementation).
+ * intermixed in tableElts, and constraints and notnullcols are NIL.  After
+ * parse analysis, tableElts contains just ColumnDefs, notnullcols has been
+ * filled with not-nullable column names from various sources, and constraints
+ * contains just Constraint nodes (in fact, only CONSTR_CHECK nodes, in the
+ * present implementation).
  * ----------------------
  */
 
@@ -1751,6 +1752,7 @@ typedef struct CreateStmt
 								 * inhRelation) */
 	TypeName   *ofTypename;		/* OF typename */
 	List	   *constraints;	/* constraints (list of Constraint nodes) */
+	List	   *notnullcols;	/* list of column names with NOT NULL */
 	List	   *options;		/* options from WITH clause */
 	OnCommitAction oncommit;	/* what do we do at COMMIT? */
 	char	   *tablespacename; /* table space to use, or NULL */
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index 55d6bbe..ae224cf 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -775,6 +775,7 @@ typedef struct Gather
 	Plan		plan;
 	int			num_workers;
 	bool		single_copy;
+	bool		invisible;		/* suppress EXPLAIN display (for testing)? */
 } Gather;
 
 /* ----------------
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
index 595438c..96198ae 100644
--- a/src/include/nodes/relation.h
+++ b/src/include/nodes/relation.h
@@ -108,6 +108,9 @@ typedef struct PlannerGlobal
 	bool		parallelModeOK; /* parallel mode potentially OK? */
 
 	bool		parallelModeNeeded;		/* parallel mode actually required? */
+
+	bool		wholePlanParallelSafe;	/* is the entire plan parallel safe? */
+
 	bool		hasForeignJoin;	/* does have a pushed down foreign join */
 } PlannerGlobal;
 
diff --git a/src/include/optimizer/planmain.h b/src/include/optimizer/planmain.h
index 7ae7367..eaa642b 100644
--- a/src/include/optimizer/planmain.h
+++ b/src/include/optimizer/planmain.h
@@ -17,9 +17,18 @@
 #include "nodes/plannodes.h"
 #include "nodes/relation.h"
 
+/* possible values for force_parallel_mode */
+typedef enum
+{
+	FORCE_PARALLEL_OFF,
+	FORCE_PARALLEL_ON,
+	FORCE_PARALLEL_REGRESS
+} ForceParallelMode;
+
 /* GUC parameters */
 #define DEFAULT_CURSOR_TUPLE_FRACTION 0.1
 extern double cursor_tuple_fraction;
+extern int force_parallel_mode;
 
 /* query_planner callback to compute query_pathkeys */
 typedef void (*query_pathkeys_callback) (PlannerInfo *root, void *extra);
diff --git a/src/include/storage/lock.h b/src/include/storage/lock.h
index 43eca86..6b4e365 100644
--- a/src/include/storage/lock.h
+++ b/src/include/storage/lock.h
@@ -346,6 +346,7 @@ typedef struct PROCLOCK
 	PROCLOCKTAG tag;			/* unique identifier of proclock object */
 
 	/* data */
+	PGPROC	   *groupLeader;	/* group leader, or NULL if no lock group */
 	LOCKMASK	holdMask;		/* bitmask for lock types currently held */
 	LOCKMASK	releaseMask;	/* bitmask for lock types to be released */
 	SHM_QUEUE	lockLink;		/* list link in LOCK's list of proclocks */
@@ -457,7 +458,6 @@ typedef enum
 								 * worker */
 } DeadLockState;
 
-
 /*
  * The lockmgr's shared hash tables are partitioned to reduce contention.
  * To determine which partition a given locktag belongs to, compute the tag's
@@ -473,6 +473,17 @@ typedef enum
 	(&MainLWLockArray[LOCK_MANAGER_LWLOCK_OFFSET + (i)].lock)
 
 /*
+ * The deadlock detector needs to be able to access lockGroupLeader and
+ * related fields in the PGPROC, so we arrange for those fields to be protected
+ * by one of the lock hash partition locks.  Since the deadlock detector
+ * acquires all such locks anyway, this makes it safe for it to access these
+ * fields without doing anything extra.  To avoid contention as much as
+ * possible, we map different PGPROCs to different partition locks.
+ */
+#define LockHashPartitionLockByProc(p) \
+	LockHashPartitionLock((p)->pgprocno)
+
+/*
  * function prototypes
  */
 extern void InitLocks(void);
diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h
index 3441288..66ab255 100644
--- a/src/include/storage/proc.h
+++ b/src/include/storage/proc.h
@@ -155,6 +155,15 @@ struct PGPROC
 	bool		fpVXIDLock;		/* are we holding a fast-path VXID lock? */
 	LocalTransactionId fpLocalTransactionId;	/* lxid for fast-path VXID
 												 * lock */
+
+	/*
+	 * Support for lock groups.  Use LockHashPartitionLockByProc to get the
+	 * LWLock protecting these fields.
+	 */
+	int			lockGroupLeaderIdentifier;	/* MyProcPid, if I'm a leader */
+	PGPROC	   *lockGroupLeader;	/* lock group leader, if I'm a follower */
+	dlist_head	lockGroupMembers;	/* list of members, if I'm a leader */
+	dlist_node  lockGroupLink;		/* my member link, if I'm a member */
 };
 
 /* NOTE: "typedef struct PGPROC PGPROC" appears in storage/lock.h. */
@@ -272,4 +281,7 @@ extern void LockErrorCleanup(void);
 extern void ProcWaitForSignal(void);
 extern void ProcSendSignal(int pid);
 
+extern void BecomeLockGroupLeader(void);
+extern bool BecomeLockGroupMember(PGPROC *leader, int pid);
+
 #endif   /* PROC_H */
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index c9be32e..affcc01 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -290,6 +290,8 @@ extern int32 pg_atoi(const char *s, int size, int c);
 extern void pg_itoa(int16 i, char *a);
 extern void pg_ltoa(int32 l, char *a);
 extern void pg_lltoa(int64 ll, char *a);
+extern char *pg_ltostr_zeropad(char *str, int32 value, int32 minwidth);
+extern char *pg_ltostr(char *str, int32 value);
 
 /*
  *		Per-opclass comparison functions for new btrees.  These are
diff --git a/src/test/regress/expected/join.out b/src/test/regress/expected/join.out
index 64f046e..0ac21bb 100644
--- a/src/test/regress/expected/join.out
+++ b/src/test/regress/expected/join.out
@@ -2331,6 +2331,34 @@ select tt1.*, tt2.* from tt2 right join tt1 on tt1.joincol = tt2.joincol;
 reset enable_hashjoin;
 reset enable_nestloop;
 --
+-- regression test for bug #13908 (hash join with skew tuples & nbatch increase)
+--
+set work_mem to '64kB';
+set enable_mergejoin to off;
+explain (costs off)
+select count(*) from tenk1 a, tenk1 b
+  where a.hundred = b.thousand and (b.fivethous % 10) < 10;
+                         QUERY PLAN                         
+------------------------------------------------------------
+ Aggregate
+   ->  Hash Join
+         Hash Cond: (a.hundred = b.thousand)
+         ->  Index Only Scan using tenk1_hundred on tenk1 a
+         ->  Hash
+               ->  Seq Scan on tenk1 b
+                     Filter: ((fivethous % 10) < 10)
+(7 rows)
+
+select count(*) from tenk1 a, tenk1 b
+  where a.hundred = b.thousand and (b.fivethous % 10) < 10;
+ count  
+--------
+ 100000
+(1 row)
+
+reset work_mem;
+reset enable_mergejoin;
+--
 -- regression test for 8.2 bug with improper re-ordering of left joins
 --
 create temp table tt3(f1 int, f2 text);
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 28b061f..2bdba2d 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -2846,7 +2846,7 @@ SELECT definition FROM pg_rules WHERE tablename = 'hats' ORDER BY rulename;
  CREATE RULE hat_nosert AS                                                                  +
      ON INSERT TO hats DO INSTEAD  INSERT INTO hat_data (hat_name, hat_color)               +
    VALUES (new.hat_name, new.hat_color) ON CONFLICT(hat_name COLLATE "C" bpchar_pattern_ops)+
-   WHERE (hat_data.hat_color = 'green'::bpchar) DO NOTHING                                  +
+   WHERE (hat_color = 'green'::bpchar) DO NOTHING                                           +
    RETURNING hat_data.hat_name,                                                             +
      hat_data.hat_color;
 (1 row)
@@ -2871,7 +2871,7 @@ SELECT tablename, rulename, definition FROM pg_rules
  hats      | hat_nosert | CREATE RULE hat_nosert AS                                                                  +
            |            |     ON INSERT TO hats DO INSTEAD  INSERT INTO hat_data (hat_name, hat_color)               +
            |            |   VALUES (new.hat_name, new.hat_color) ON CONFLICT(hat_name COLLATE "C" bpchar_pattern_ops)+
-           |            |   WHERE (hat_data.hat_color = 'green'::bpchar) DO NOTHING                                  +
+           |            |   WHERE (hat_color = 'green'::bpchar) DO NOTHING                                           +
            |            |   RETURNING hat_data.hat_name,                                                             +
            |            |     hat_data.hat_color;
 (1 row)
diff --git a/src/test/regress/sql/join.sql b/src/test/regress/sql/join.sql
index 0358d00..fafbb3f 100644
--- a/src/test/regress/sql/join.sql
+++ b/src/test/regress/sql/join.sql
@@ -464,6 +464,22 @@ reset enable_hashjoin;
 reset enable_nestloop;
 
 --
+-- regression test for bug #13908 (hash join with skew tuples & nbatch increase)
+--
+
+set work_mem to '64kB';
+set enable_mergejoin to off;
+
+explain (costs off)
+select count(*) from tenk1 a, tenk1 b
+  where a.hundred = b.thousand and (b.fivethous % 10) < 10;
+select count(*) from tenk1 a, tenk1 b
+  where a.hundred = b.thousand and (b.fivethous % 10) < 10;
+
+reset work_mem;
+reset enable_mergejoin;
+
+--
 -- regression test for 8.2 bug with improper re-ordering of left joins
 --
 
#2Vitaly Burovoy
vitaly.burovoy@gmail.com
In reply to: Vitaly Burovoy (#1)
1 attachment(s)
Re: Make PG's "NOT NULL"s and attnotnull ("is_nullable") conform to SQL-2011

On 2/7/16, Vitaly Burovoy <vitaly.burovoy@gmail.com> wrote:

Hello, Hackers!

TODO list has an entry "Move NOT NULL constraint information to
pg_constraint" with four links and without two with the newest
work[1][2].

I rebased the patch from [2] (in attachment). At least it applies
cleanly on top of c477e84fe2471cb675234fce75cd6bb4bc2cf481 and does
not generate a core dump during "make check". There are no tests for
it and it fails "make check" (by difference) which leads inability to
run "make check-world".

It seems the file I attached has more than necessary changes.

Please, find a correct patch attached.

===
[1]/messages/by-id/1343682669-sup-2532@alvh.no-ip.org
[2]/messages/by-id/20160109030002.GA671800@alvherre.pgsql

--
Best regards,
Vitaly Burovoy

Attachments:

catalog-notnull-2-c477e84_cleaned.patchapplication/octet-stream; name=catalog-notnull-2-c477e84_cleaned.patchDownload
diff --git a/src/backend/commands/constraint.c b/src/backend/commands/constraint.c
index 26f9114..02b72a3 100644
--- a/src/backend/commands/constraint.c
+++ b/src/backend/commands/constraint.c
@@ -13,13 +13,18 @@
  */
 #include "postgres.h"
 
+#include "access/htup_details.h"
 #include "catalog/index.h"
+#include "catalog/pg_constraint.h"
+#include "commands/constraint.h"
 #include "commands/trigger.h"
 #include "executor/executor.h"
 #include "utils/builtins.h"
 #include "utils/rel.h"
+#include "utils/syscache.h"
 #include "utils/tqual.h"
 
+static char *tryExtractNotNull_internal(Node *node, Relation rel);
 
 /*
  * unique_key_recheck - trigger function to do a deferred uniqueness check.
@@ -193,3 +198,125 @@ unique_key_recheck(PG_FUNCTION_ARGS)
 
 	return PointerGetDatum(NULL);
 }
+
+Constraint *
+createCheckNotNullConstraint(Oid nspid, char *constraint_name,
+							 const char *relname, const char *colname)
+{
+	Constraint *check = makeNode(Constraint);
+	ColumnRef  *colref;
+	NullTest   *nulltest;
+
+	colref = (ColumnRef *) makeNode(ColumnRef);
+	colref->fields = list_make1(makeString(pstrdup(colname)));
+
+	nulltest = (NullTest *) makeNode(NullTest);
+	nulltest->argisrow = false;	/* FIXME -- may be bogus! */
+	nulltest->nulltesttype = IS_NOT_NULL;
+	nulltest->arg = (Expr *) colref;
+
+	check->contype = CONSTR_CHECK;
+	check->location = -1;
+	check->conname = constraint_name ? constraint_name :
+		ChooseConstraintName(relname, colname, "not_null", nspid,
+							 NIL);
+	check->raw_expr = (Node *) nulltest;
+	check->cooked_expr = NULL;
+
+	return check;
+}
+
+/*
+ * Given a CHECK constraint, examine it and determine whether it is CHECK (col
+ * IS NOT NULL).  If it is, return the column name for which it is.  Otherwise
+ * return NULL.
+ */
+char *
+tryExtractNotNullFromCheckConstr(Constraint *constr)
+{
+	char   *retval;
+
+	Assert(constr->contype == CONSTR_CHECK);
+
+	if (constr->raw_expr != NULL)
+	{
+		Assert(constr->cooked_expr == NULL);  // as in heap.c
+		retval = tryExtractNotNull_internal(constr->raw_expr, NULL);
+	}
+	else
+	{
+		Assert(constr->cooked_expr != NULL);  // as in heap.c
+		retval = tryExtractNotNull_internal(stringToNode(constr->cooked_expr), NULL);
+	}
+
+	return retval;
+}
+
+/*
+ * As above, but use a pg_constraint row as input.
+ *
+ * tupdesc is pg_constraint's tuple descriptor, and rel is the relation the
+ * constraint is for.
+ */
+char *
+tryExtractNotNullFromCatalog(HeapTuple constrTup, TupleDesc tupdesc,
+							 Relation rel)
+{
+	Datum	val;
+	bool	isnull;
+	char   *conbin;
+	Node   *node;
+
+	val = SysCacheGetAttr(CONSTROID, constrTup, Anum_pg_constraint_conbin,
+						  &isnull);
+	if (isnull)
+		elog(ERROR, "null conbin for constraint %u",
+			 HeapTupleGetOid(constrTup));
+	conbin = TextDatumGetCString(val);
+	node = (Node *) stringToNode(conbin);
+
+	return tryExtractNotNull_internal(node, rel);
+}
+
+/*
+ * Worker for the above
+ */
+static char *
+tryExtractNotNull_internal(Node *node, Relation rel)
+{
+	if (IsA(node, NullTest))
+	{
+		NullTest *nulltest = (NullTest *) node;
+
+		if (nulltest->nulltesttype == IS_NOT_NULL)
+		{
+			if (IsA(nulltest->arg, ColumnRef))
+			{
+				ColumnRef *colref = (ColumnRef *) nulltest->arg;
+
+				if (list_length(colref->fields) == 1)
+					return strVal(linitial(colref->fields));
+			}
+			if (IsA(nulltest->arg, Var))
+			{
+				Var	   *var = (Var *) nulltest->arg;
+				TupleDesc tupdesc;
+
+				if (!RelationIsValid(rel))
+					elog(ERROR,
+						 "no relation given to extract constraint from");
+				tupdesc = RelationGetDescr(rel);
+				return NameStr(tupdesc->attrs[var->varattno - 1]->attname);
+			}
+		}
+	}
+
+	/*
+	 * XXX Need to check a few more possible wordings of NOT NULL:
+	 *
+	 * - foo IS DISTINCT FROM NULL
+	 * - NOT (foo IS NULL)
+	 */
+
+	return NULL;
+}
diff --git a/src/backend/commands/createas.c b/src/backend/commands/createas.c
index fcb0331..514568e 100644
--- a/src/backend/commands/createas.c
+++ b/src/backend/commands/createas.c
@@ -312,6 +312,7 @@ intorel_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
 	create->inhRelations = NIL;
 	create->ofTypename = NULL;
 	create->constraints = NIL;
+	create->notnullcols = NIL;
 	create->options = into->options;
 	create->oncommit = into->onCommit;
 	create->tablespacename = into->tableSpaceName;
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index eeda3b4..38eacf2 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -47,6 +47,7 @@
 #include "catalog/toasting.h"
 #include "commands/cluster.h"
 #include "commands/comment.h"
+#include "commands/constraint.h"
 #include "commands/defrem.h"
 #include "commands/event_trigger.h"
 #include "commands/policy.h"
@@ -61,7 +62,6 @@
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
 #include "nodes/nodeFuncs.h"
-#include "nodes/parsenodes.h"
 #include "optimizer/clauses.h"
 #include "optimizer/planner.h"
 #include "parser/parse_clause.h"
@@ -270,8 +270,9 @@ struct DropRelationCallbackState
 #define		ATT_FOREIGN_TABLE		0x0020
 
 static void truncate_check_rel(Relation rel);
-static List *MergeAttributes(List *schema, List *supers, char relpersistence,
-				List **supOids, List **supconstr, int *supOidCount);
+static List *MergeAttributes(List *schema, List *notnullcols, List *supers,
+				char relpersistence, List **supOids, List **supconstr,
+				int *supOidCount);
 static bool MergeCheckConstraint(List *constraints, char *name, Node *expr);
 static void MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel);
 static void MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel);
@@ -339,8 +340,9 @@ static void add_column_collation_dependency(Oid relid, int32 attnum, Oid collid)
 static void ATPrepAddOids(List **wqueue, Relation rel, bool recurse,
 			  AlterTableCmd *cmd, LOCKMODE lockmode);
 static ObjectAddress ATExecDropNotNull(Relation rel, const char *colName, LOCKMODE lockmode);
-static ObjectAddress ATExecSetNotNull(AlteredTableInfo *tab, Relation rel,
-				 const char *colName, LOCKMODE lockmode);
+static ObjectAddress ATExecSetNotNull(List **wqueue, AlteredTableInfo *tab,
+				 Relation rel, char *constrname, const char *colName,
+				 LOCKMODE lockmode);
 static ObjectAddress ATExecColumnDefault(Relation rel, const char *colName,
 					Node *newDefault, LOCKMODE lockmode);
 static void ATPrepSetStatistics(Relation rel, const char *colName,
@@ -370,6 +372,11 @@ static ObjectAddress ATAddCheckConstraint(List **wqueue,
 					 Constraint *constr,
 					 bool recurse, bool recursing, bool is_readd,
 					 LOCKMODE lockmode);
+static ObjectAddress ATAddCheckConstraint_internal(List **wqueue,
+					 AlteredTableInfo *tab, Relation rel,
+					 Constraint *constr,
+					 bool recurse, bool recursing, bool is_readd,
+					 bool check_it, LOCKMODE lockmode);
 static ObjectAddress ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
 						  Constraint *fkconstraint, LOCKMODE lockmode);
 static void ATExecDropConstraint(Relation rel, const char *constrName,
@@ -575,7 +582,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
 	 * Look up inheritance ancestors and generate relation schema, including
 	 * inherited attributes.
 	 */
-	schema = MergeAttributes(schema, stmt->inhRelations,
+	schema = MergeAttributes(schema, stmt->notnullcols, stmt->inhRelations,
 							 stmt->relation->relpersistence,
 							 &inheritOids, &old_constraints, &parentOidCount);
 
@@ -1356,6 +1363,8 @@ storage_name(char c)
  * Input arguments:
  * 'schema' is the column/attribute definition for the table. (It's a list
  *		of ColumnDef's.) It is destructively changed.
+ * 'notnullcols' is a list of column names that have NOT NULL constraints.
+ *		Some of these columns may already have is_not_null already set.
  * 'supers' is a list of names (as RangeVar nodes) of parent relations.
  * 'relpersistence' is a persistence type of the table.
  *
@@ -1408,10 +1417,12 @@ storage_name(char c)
  *----------
  */
 static List *
-MergeAttributes(List *schema, List *supers, char relpersistence,
-				List **supOids, List **supconstr, int *supOidCount)
+MergeAttributes(List *schema, List *notnullcols, List *supers,
+				char relpersistence, List **supOids, List **supconstr,
+				int *supOidCount)
 {
 	ListCell   *entry;
+	ListCell   *cell;
 	List	   *inhSchema = NIL;
 	List	   *parentOids = NIL;
 	List	   *constraints = NIL;
@@ -1896,6 +1907,23 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
 	}
 
 	/*
+	 * If we have NOT NULL constraint declarations, set the is_not_null bits
+	 * in the correspoding ColumnDef elements.
+	 */
+	foreach (cell, notnullcols)
+	{
+		char   *colname = lfirst(cell);
+
+		foreach (entry, schema)
+		{
+			ColumnDef *coldef = lfirst(entry);
+
+			if (strcmp(coldef->colname, colname) == 0)
+				coldef->is_not_null = true;
+		}
+	}
+
+	/*
 	 * If we found any conflicting parent default values, check to make sure
 	 * they were overridden by the child.
 	 */
@@ -3479,7 +3507,7 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
 			address = ATExecDropNotNull(rel, cmd->name, lockmode);
 			break;
 		case AT_SetNotNull:		/* ALTER COLUMN SET NOT NULL */
-			address = ATExecSetNotNull(tab, rel, cmd->name, lockmode);
+			address = ATExecSetNotNull(wqueue, tab, rel, NULL, cmd->name, lockmode);
 			break;
 		case AT_SetStatistics:	/* ALTER COLUMN SET STATISTICS */
 			address = ATExecSetStatistics(rel, cmd->name, cmd->def, lockmode);
@@ -5281,13 +5309,14 @@ ATExecDropNotNull(Relation rel, const char *colName, LOCKMODE lockmode)
  * NULL, InvalidObjectAddress is returned.
  */
 static ObjectAddress
-ATExecSetNotNull(AlteredTableInfo *tab, Relation rel,
-				 const char *colName, LOCKMODE lockmode)
+ATExecSetNotNull(List **wqueue, AlteredTableInfo *tab, Relation rel,
+				 char *constrname, const char *colName, LOCKMODE lockmode)
 {
 	HeapTuple	tuple;
 	AttrNumber	attnum;
 	Relation	attr_rel;
 	ObjectAddress address;
+	Constraint *newconstr;
 
 	/*
 	 * lookup the attribute
@@ -5332,6 +5361,20 @@ ATExecSetNotNull(AlteredTableInfo *tab, Relation rel,
 	else
 		address = InvalidObjectAddress;
 
+	/*
+	 * We also need to add a new pg_constraint row.  Use
+	 * ATAddCheckConstraint_internal for that, but let it know that it
+	 * doesn't need to test the constraint; we already informed it above,
+	 * if necessary.
+	 */
+	newconstr = createCheckNotNullConstraint(rel->rd_rel->relnamespace,
+											 constrname,
+											 NameStr(rel->rd_rel->relname),
+											 colName);
+
+	ATAddCheckConstraint_internal(wqueue, tab, rel, newconstr,
+								  true, false, false, true, lockmode);
+
 	InvokeObjectPostAlterHook(RelationRelationId,
 							  RelationGetRelid(rel), attnum);
 
@@ -6108,6 +6151,40 @@ ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
 					 Constraint *constr, bool recurse, bool recursing,
 					 bool is_readd, LOCKMODE lockmode)
 {
+	char *colname;
+	ObjectAddress address;
+
+	/*
+	 * If the constraint we're adding is CHECK (col IS NOT NULL), then we route
+	 * it through ATExecSetNotNull instead of working directly with it; that
+	 * function is responsible for getting back to us to recurse, etc.
+	 *
+	 * The reason for this is to get the attnotnull bit set for the column, and
+	 * also to avoid having a second NOT NULL constraint for a column that
+	 * might already have one.  (XXX is the latter actually a desirable
+	 * property?  Consider inherited tables here.)
+	 */
+	Assert(constr->contype == CONSTR_CHECK);
+
+	colname = tryExtractNotNullFromCheckConstr(constr);
+	if (colname != NULL)
+		address = ATExecSetNotNull(wqueue, tab, rel, constr->conname,
+								   colname, lockmode);
+	else
+		/* Not a single-column NOT NULL constraint -- do the regular dance */
+		address = ATAddCheckConstraint_internal(wqueue, tab, rel, constr,
+												recurse, recursing, is_readd,
+												true, lockmode);
+
+	return address;
+}
+
+static ObjectAddress
+ATAddCheckConstraint_internal(List **wqueue, AlteredTableInfo *tab,
+							  Relation rel, Constraint *constr, bool recurse,
+							  bool recursing, bool is_readd,
+							  bool check_it, LOCKMODE lockmode)
+{
 	List	   *newcons;
 	ListCell   *lcon;
 	List	   *children;
@@ -6214,8 +6291,9 @@ ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
 		childtab = ATGetQueueEntry(wqueue, childrel);
 
 		/* Recurse to child */
-		ATAddCheckConstraint(wqueue, childtab, childrel,
-							 constr, recurse, true, is_readd, lockmode);
+		ATAddCheckConstraint_internal(wqueue, childtab, childrel,
+									  constr, recurse, true, is_readd, check_it,
+									  lockmode);
 
 		heap_close(childrel, NoLock);
 	}
@@ -7681,6 +7759,7 @@ ATExecDropConstraint(Relation rel, const char *constrName,
 	while (HeapTupleIsValid(tuple = systable_getnext(scan)))
 	{
 		ObjectAddress conobj;
+		char		  *colName;
 
 		con = (Form_pg_constraint) GETSTRUCT(tuple);
 
@@ -7694,6 +7773,22 @@ ATExecDropConstraint(Relation rel, const char *constrName,
 					 errmsg("cannot drop inherited constraint \"%s\" of relation \"%s\"",
 							constrName, RelationGetRelationName(rel))));
 
+		if (con->contype == CONSTRAINT_CHECK)
+		{
+			/*
+			 * If it's a CHECK constraint, verify whether it is NOT NULL.
+			 * If it is, then we may need to unset the attnotnull bit as well.
+			 */
+			colName = tryExtractNotNullFromCatalog(tuple,
+												   RelationGetDescr(conrel),
+												   rel);
+			if (colName != NULL)
+			{
+				/* do something! */
+				elog(NOTICE, "colname is %s", colName);
+			}
+		}
+
 		is_no_inherit_constraint = con->connoinherit;
 
 		/*
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index a65b2977..97300ae 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -40,6 +40,7 @@
 #include "catalog/pg_operator.h"
 #include "catalog/pg_type.h"
 #include "commands/comment.h"
+#include "commands/constraint.h"
 #include "commands/defrem.h"
 #include "commands/tablecmds.h"
 #include "commands/tablespace.h"
@@ -80,6 +81,7 @@ typedef struct
 	List	   *ckconstraints;	/* CHECK constraints */
 	List	   *fkconstraints;	/* FOREIGN KEY constraints */
 	List	   *ixconstraints;	/* index-creating constraints */
+	List	   *notnulls;		/* list of column names declared NOT NULL */
 	List	   *inh_indexes;	/* cloned indexes from INCLUDING INDEXES */
 	List	   *blist;			/* "before list" of things to do before
 								 * creating the table */
@@ -105,6 +107,8 @@ typedef struct
 
 static void transformColumnDefinition(CreateStmtContext *cxt,
 						  ColumnDef *column);
+static Constraint *transformNotNullConstraint(CreateStmtContext *cxt,
+						   Constraint *constraint, ColumnDef *column);
 static void transformTableConstraint(CreateStmtContext *cxt,
 						 Constraint *constraint);
 static void transformTableLikeClause(CreateStmtContext *cxt,
@@ -224,6 +228,7 @@ transformCreateStmt(CreateStmt *stmt, const char *queryString)
 	cxt.ckconstraints = NIL;
 	cxt.fkconstraints = NIL;
 	cxt.ixconstraints = NIL;
+	cxt.notnulls = NIL;
 	cxt.inh_indexes = NIL;
 	cxt.blist = NIL;
 	cxt.alist = NIL;
@@ -333,6 +338,7 @@ transformCreateStmt(CreateStmt *stmt, const char *queryString)
 	 */
 	stmt->tableElts = cxt.columns;
 	stmt->constraints = cxt.ckconstraints;
+	stmt->notnullcols = cxt.notnulls;
 
 	result = lappend(cxt.blist, stmt);
 	result = list_concat(result, cxt.alist);
@@ -528,6 +534,9 @@ transformColumnDefinition(CreateStmtContext *cxt, ColumnDef *column)
 
 	foreach(clist, column->constraints)
 	{
+		Constraint *newckconstr;
+		char	   *colname;
+
 		constraint = lfirst(clist);
 		Assert(IsA(constraint, Constraint));
 
@@ -546,6 +555,11 @@ transformColumnDefinition(CreateStmtContext *cxt, ColumnDef *column)
 				break;
 
 			case CONSTR_NOTNULL:
+				/*
+				 * For NOT NULL declarations, we need to mark the column as
+				 * not nullable; and furthermore we need to create a new
+				 * CHECK constraint for this.
+				 */
 				if (saw_nullable && !column->is_not_null)
 					ereport(ERROR,
 							(errcode(ERRCODE_SYNTAX_ERROR),
@@ -554,6 +568,9 @@ transformColumnDefinition(CreateStmtContext *cxt, ColumnDef *column)
 							 parser_errposition(cxt->pstate,
 												constraint->location)));
 				column->is_not_null = TRUE;
+				newckconstr = transformNotNullConstraint(cxt, constraint,
+														 column);
+				cxt->ckconstraints = lappend(cxt->ckconstraints, newckconstr);
 				saw_nullable = true;
 				break;
 
@@ -572,6 +589,21 @@ transformColumnDefinition(CreateStmtContext *cxt, ColumnDef *column)
 
 			case CONSTR_CHECK:
 				cxt->ckconstraints = lappend(cxt->ckconstraints, constraint);
+				/*
+				 * If there is a CHECK (foo IS NOT NULL) constraint
+				 * declaration, we check the column name used in the
+				 * constraint.  If it's the same name as the column being
+				 * defined, simply set the is_not_null flag in the column
+				 * definition; otherwise remember the column name for later.
+				 */
+				colname = tryExtractNotNullFromCheckConstr(constraint);
+				if (colname != NULL)
+				{
+					if (strcmp(colname, column->colname) == 0)
+						column->is_not_null = true;
+					else
+						cxt->notnulls = lappend(cxt->notnulls, colname);
+				}
 				break;
 
 			case CONSTR_PRIMARY:
@@ -663,6 +695,8 @@ transformColumnDefinition(CreateStmtContext *cxt, ColumnDef *column)
 static void
 transformTableConstraint(CreateStmtContext *cxt, Constraint *constraint)
 {
+	char *colname;
+
 	switch (constraint->contype)
 	{
 		case CONSTR_PRIMARY:
@@ -697,6 +731,9 @@ transformTableConstraint(CreateStmtContext *cxt, Constraint *constraint)
 
 		case CONSTR_CHECK:
 			cxt->ckconstraints = lappend(cxt->ckconstraints, constraint);
+			colname = tryExtractNotNullFromCheckConstr(constraint);
+			if (colname != NULL)
+				cxt->notnulls = lappend(cxt->notnulls, colname);
 			break;
 
 		case CONSTR_FOREIGN:
@@ -728,6 +765,30 @@ transformTableConstraint(CreateStmtContext *cxt, Constraint *constraint)
 }
 
 /*
+ * Given a NOT NULL column declaration, transform it into a new Constraint node
+ * representing the equivalent CHECK (col) IS NOT NULL.
+ */
+static Constraint *
+transformNotNullConstraint(CreateStmtContext *cxt, Constraint *constraint,
+						   ColumnDef *column)
+{
+	Constraint *check;
+	Oid		nspid;
+
+	if (cxt->rel)
+		nspid = RelationGetNamespace(cxt->rel);
+	else
+		nspid = RangeVarGetCreationNamespace(cxt->relation);
+
+	check = createCheckNotNullConstraint(nspid,
+										 NULL,
+										 cxt->relation->relname,
+										 column->colname);
+
+	return check;
+}
+
+/*
  * transformTableLikeClause
  *
  * Change the LIKE <srctable> portion of a CREATE TABLE statement into
@@ -2510,6 +2571,7 @@ transformAlterTableStmt(Oid relid, AlterTableStmt *stmt,
 	cxt.ckconstraints = NIL;
 	cxt.fkconstraints = NIL;
 	cxt.ixconstraints = NIL;
+	cxt.notnulls = NIL;
 	cxt.inh_indexes = NIL;
 	cxt.blist = NIL;
 	cxt.alist = NIL;
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 64c2673..d09c6ce 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -6901,7 +6901,35 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
 
 		resetPQExpBuffer(q);
 
-		if (fout->remoteVersion >= 90200)
+		if (fout->remoteVersion >= 90600)
+		{
+			/*
+			 * In 9.6, NOT NULL constraints are in pg_constraint and will be
+			 * dumped as table constraints, so it's unnecessary to dump them
+			 * here.
+			 */
+			appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
+							  "a.attstattarget, a.attstorage, t.typstorage, "
+							  "false as attnotnull, a.atthasdef, a.attisdropped, "
+							  "a.attlen, a.attalign, a.attislocal, "
+				  "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
+						"array_to_string(a.attoptions, ', ') AS attoptions, "
+							  "CASE WHEN a.attcollation <> t.typcollation "
+						   "THEN a.attcollation ELSE 0 END AS attcollation, "
+							  "pg_catalog.array_to_string(ARRAY("
+							  "SELECT pg_catalog.quote_ident(option_name) || "
+							  "' ' || pg_catalog.quote_literal(option_value) "
+						"FROM pg_catalog.pg_options_to_table(attfdwoptions) "
+							  "ORDER BY option_name"
+							  "), E',\n    ') AS attfdwoptions "
+			 "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
+							  "ON a.atttypid = t.oid "
+							  "WHERE a.attrelid = '%u'::pg_catalog.oid "
+							  "AND a.attnum > 0::pg_catalog.int2 "
+							  "ORDER BY a.attrelid, a.attnum",
+							  tbinfo->dobj.catId.oid);
+		}
+		else if (fout->remoteVersion >= 90200)
 		{
 			/*
 			 * attfdwoptions is new in 9.2.
diff --git a/src/include/commands/constraint.h b/src/include/commands/constraint.h
new file mode 100644
index 0000000..99799b4
--- /dev/null
+++ b/src/include/commands/constraint.h
@@ -0,0 +1,29 @@
+/*-------------------------------------------------------------------------
+ *
+ * constraint.h
+ *	  PostgreSQL CONSTRAINT support declarations
+ *
+ * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * IDENTIFICATION
+ *	  src/include/commands/constraint.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef CONSTRAINT_H
+#define CONSTRAINT_H
+
+#include "nodes/parsenodes.h"
+#include "utils/relcache.h"
+
+extern Constraint *createCheckNotNullConstraint(Oid nspid,
+							 char *constraint_name, const char *relname,
+							 const char *colname);
+
+extern char *tryExtractNotNullFromCheckConstr(Constraint *constr);
+
+extern char *tryExtractNotNullFromCatalog(HeapTuple constrTup,
+							 TupleDesc tupdesc, Relation rel);
+
+#endif /* CONSTRAINT_H */
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 2fd0629..4ab39fd 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -1735,10 +1735,11 @@ typedef struct VariableShowStmt
  *		Create Table Statement
  *
  * NOTE: in the raw gram.y output, ColumnDef and Constraint nodes are
- * intermixed in tableElts, and constraints is NIL.  After parse analysis,
- * tableElts contains just ColumnDefs, and constraints contains just
- * Constraint nodes (in fact, only CONSTR_CHECK nodes, in the present
- * implementation).
+ * intermixed in tableElts, and constraints and notnullcols are NIL.  After
+ * parse analysis, tableElts contains just ColumnDefs, notnullcols has been
+ * filled with not-nullable column names from various sources, and constraints
+ * contains just Constraint nodes (in fact, only CONSTR_CHECK nodes, in the
+ * present implementation).
  * ----------------------
  */
 
@@ -1751,6 +1752,7 @@ typedef struct CreateStmt
 								 * inhRelation) */
 	TypeName   *ofTypename;		/* OF typename */
 	List	   *constraints;	/* constraints (list of Constraint nodes) */
+	List	   *notnullcols;	/* list of column names with NOT NULL */
 	List	   *options;		/* options from WITH clause */
 	OnCommitAction oncommit;	/* what do we do at COMMIT? */
 	char	   *tablespacename; /* table space to use, or NULL */
#3Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Vitaly Burovoy (#1)
Re: Make PG's "NOT NULL"s and attnotnull ("is_nullable") conform to SQL-2011

Vitaly Burovoy wrote:

Hi,

But before starting working on it I had a look at the SQL-2011
standard (ISO/IEC 9075-2)[3] and found that:

1. A name for a "NOT NULL" constraint <NNC> can be given by a table
definition (subcl. 11.4, "Format"->"column constraint definition").
2. The standard splits NNC and CHECK constraints (subcl. 11.4,
"Format"-> "column constraint")

Point 2 is where things differ from what I remember; my (possibly
flawed) understanding was that there's no difference between those
things. Many (maybe all) of the things from this point on are probably
fallout from that one change.

III. "pg_attribute" table should have an "attnotnullid oid" as an
indicator of "NOT NULL" (p.4) and points to a CHECK constraint; It is
in addition to a "Nullability characteristic" "attnotnull" (p.3).
IV. "pg_constraint" should have a column "connotnullkey int2[]" as a
"list of the nullable columns" which references to
"pg_attribute.attnum" for fast checking whether a column is still
nullable after deleting/updating constraints or not. Array is
necessary for cases like "CHECK ((col1 IS NOT NULL) AND (col2 IS NOT
NULL))" and for nondeferrable PKs.

I think these points warrant some more consideration. I don't like the
idea that pg_attribute and pg_constraint are both getting considerably
bloated to support this.

P.S.:
Since the SQL standard defines that "col NOT NULL" as an equivalent to
"CHECK (col IS NOT NULL)" (p.8) what to do with that behavior:

postgres=# create type t as (x int);
CREATE TYPE
postgres=# SELECT v, v IS NOT NULL AS should_be_in_table FROM
(VALUES('(1)'::t),('()'),(NULL)) AS x(v);
v | should_be_in_table
-----+--------------------
(1) | t
() | f
| f
(3 rows)

"attnotnull" in such case is stricter, like "CHECK (col IS DISTINCT FROM NULL)".

Should such values (with NULL in each attribute of a composite type)
violate NOT NULL constraints?

I wonder if the standard has a concept of null composite values. If
not, then there is no difference between IS NOT NULL and IS DISTINCT
FROM NULL, which explains why they define NNC in terms of the former.

I think your email was too hard to read because of excessive density,
which would explain the complete lack of response. I haven't had the
chance to work on this topic again, but I encourage you to, if you have
the resources. (TBH I haven't had the chance to study your proposed
design in detail, either).

--
�lvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#4Vitaly Burovoy
vitaly.burovoy@gmail.com
In reply to: Alvaro Herrera (#3)
Re: Make PG's "NOT NULL"s and attnotnull ("is_nullable") conform to SQL-2011

I'm sorry for the late answer.

On 4/27/16, Alvaro Herrera <alvherre@2ndquadrant.com> wrote:

Vitaly Burovoy wrote:

Hi,

But before starting working on it I had a look at the SQL-2011
standard (ISO/IEC 9075-2)[3] and found that:

1. A name for a "NOT NULL" constraint <NNC> can be given by a table
definition (subcl. 11.4, "Format"->"column constraint definition").
2. The standard splits NNC and CHECK constraints (subcl. 11.4,
"Format"-> "column constraint")

Point 2 is where things differ from what I remember; my (possibly
flawed) understanding was that there's no difference between those
things. Many (maybe all) of the things from this point on are probably
fallout from that one change.

It is just mentioning that CHECK constraints have influence on
nullability characteristic, but it differs from NNC.
NNC creates CHECK constraint, but not vice versa. You can create
several CHECK "col IS NOT NULL" constraints, but only one NNC (several
ones by inheritance only?). And DROP NOT NULL should drop only those
CHECK that is linked with NNC (and inherited), but no more (full
explanation is in my initial letter).

III. "pg_attribute" table should have an "attnotnullid oid" as an
indicator of "NOT NULL" (p.4) and points to a CHECK constraint; It is
in addition to a "Nullability characteristic" "attnotnull" (p.3).
IV. "pg_constraint" should have a column "connotnullkey int2[]" as a
"list of the nullable columns" which references to
"pg_attribute.attnum" for fast checking whether a column is still
nullable after deleting/updating constraints or not. Array is
necessary for cases like "CHECK ((col1 IS NOT NULL) AND (col2 IS NOT
NULL))" and for nondeferrable PKs.

I think these points warrant some more consideration. I don't like the
idea that pg_attribute and pg_constraint are both getting considerably
bloated to support this.

Ok, I'm ready for a discussion.

Two additional columns are necessary: one for pointing to an
underlying CHECK constraint (or boolean column whether current CHECK
is NNC or not) and second for fast computation of "attnotnull" (which
means "nullable characteristic") and ability to skip check if
"attnotnull" is set but not triggered (I think it'll improve
performance for inherited tables).

I think placing the first column (attnotnullid) to pg_attribute is
better because you can't have more than one value in it.

The second is obviously should be placed in pg_constraint.

P.S.:
Since the SQL standard defines that "col NOT NULL" as an equivalent to
"CHECK (col IS NOT NULL)" (p.8) what to do with that behavior:

postgres=# create type t as (x int);
CREATE TYPE
postgres=# SELECT v, v IS NOT NULL AS should_be_in_table FROM
(VALUES('(1)'::t),('()'),(NULL)) AS x(v);
v | should_be_in_table
-----+--------------------
(1) | t
() | f
| f
(3 rows)

"attnotnull" in such case is stricter, like "CHECK (col IS DISTINCT FROM
NULL)".

Should such values (with NULL in each attribute of a composite type)
violate NOT NULL constraints?

I wonder if the standard has a concept of null composite values. If
not, then there is no difference between IS NOT NULL and IS DISTINCT
FROM NULL, which explains why they define NNC in terms of the former.

Yes, it has. The PG's composite type is "Row types" (subcl.4.8) in the standard.

The standard also differentiates IS [NOT] NULL and IS [NOT] DISTINCT FROM:

Subcl. 8.8 <null predicate>:
...
1) Let R be the <row value predicand> and let V be the value of R.
2) Case:
a) If V is the null value, then “R IS NULL” is True and
the value of “R IS NOT NULL” is False.
b) Otherwise:
i) The value of “R IS NULL” is
Case:
1) If the value of every field of V is the null value, then True.
2) Otherwise, False.
...

Subcl. 8.15 <distinct predicate>
...
1) Let V1 be the value of <row value predicand 3> and let V2 be the value of <row value predicand 4>.
...
b) If V1 is the null value and V2 is not the null value, or if V1 is not the null value and V2 is the null
value, then the result is True.
...

In subcl.8.8 "each column" is mentioned, in 8.15 if one of value is
the null value and the other is not then nothing more is checked and
True is returned.

I think your email was too hard to read because of excessive density,
which would explain the complete lack of response.

Hmm. I decided it was "silently approved". =)

I haven't had the chance to work on this topic again, but I encourage you to,
if you have the resources.

Thank you, I think I'll find a time for it no earlier than the summer.

(TBH I haven't had the chance to study your proposed design in detail, either).

I hope somebody find a time to study it before someone sends a proposal.

--
Best regards,
Vitaly Burovoy

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#5Tom Lane
tgl@sss.pgh.pa.us
In reply to: Vitaly Burovoy (#4)
Re: Make PG's "NOT NULL"s and attnotnull ("is_nullable") conform to SQL-2011

Vitaly Burovoy <vitaly.burovoy@gmail.com> writes:

On 4/27/16, Alvaro Herrera <alvherre@2ndquadrant.com> wrote:

Point 2 is where things differ from what I remember; my (possibly
flawed) understanding was that there's no difference between those
things. Many (maybe all) of the things from this point on are probably
fallout from that one change.

It is just mentioning that CHECK constraints have influence on
nullability characteristic, but it differs from NNC.
NNC creates CHECK constraint, but not vice versa. You can create
several CHECK "col IS NOT NULL" constraints, but only one NNC (several
ones by inheritance only?). And DROP NOT NULL should drop only those
CHECK that is linked with NNC (and inherited), but no more (full
explanation is in my initial letter).

This seems to me to be a most curious reading of the standard.
SQL:2011 11.4 <column definition> syntax rule 17a says

If a <column constraint definition> is specified that contains
the <column constraint> NOT NULL, then it is equivalent to the
following <table constraint definition>:

CND CHECK ( C IS NOT NULL ) CA

As a rule, when the SQL spec says "equivalent", they do not mean "it's
sort of like this", they mean the effects are indistinguishable. In
particular, I see nothing whatsoever saying that you're not allowed to
write more than one per column.

So I don't like the proposal to add an attnotnullid column to
pg_attribute. What we'd talked about earlier was converting attnotnull
into, effectively, a hint flag saying that there's at least one NOT NULL
constraint attached to the column. That still seems like a good approach
to me. When we're actually ready to throw an error for a null value,
we could root through the table's constraint list for a not-null
constraint name to report. It doesn't matter which one we select, because
constraint application order has never been promised to be deterministic;
and a few extra cycles at that point don't seem like a big problem to me.

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#6David G. Johnston
david.g.johnston@gmail.com
In reply to: Tom Lane (#5)
Re: Make PG's "NOT NULL"s and attnotnull ("is_nullable") conform to SQL-2011

Quick flyby here...

On Tuesday, May 3, 2016, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Vitaly Burovoy <vitaly.burovoy@gmail.com <javascript:;>> writes:

On 4/27/16, Alvaro Herrera <alvherre@2ndquadrant.com <javascript:;>>

wrote:

Point 2 is where things differ from what I remember; my (possibly
flawed) understanding was that there's no difference between those
things. Many (maybe all) of the things from this point on are probably
fallout from that one change.

It is just mentioning that CHECK constraints have influence on
nullability characteristic, but it differs from NNC.
NNC creates CHECK constraint, but not vice versa. You can create
several CHECK "col IS NOT NULL" constraints, but only one NNC (several
ones by inheritance only?). And DROP NOT NULL should drop only those
CHECK that is linked with NNC (and inherited), but no more (full
explanation is in my initial letter).

Either it's one, or it's not...

This seems to me to be a most curious reading of the standard.
SQL:2011 11.4 <column definition> syntax rule 17a says

If a <column constraint definition> is specified that contains
the <column constraint> NOT NULL, then it is equivalent to the
following <table constraint definition>:

CND CHECK ( C IS NOT NULL ) CA

As a rule, when the SQL spec says "equivalent", they do not mean "it's
sort of like this", they mean the effects are indistinguishable. In
particular, I see nothing whatsoever saying that you're not allowed to
write more than one per column.

Does it define how DROP NOT NULL is supposed to behave?

I agree that the behavior of a column NNC is identical to a similar
constraint defined on the table: but if drop not null doesn't impact table
constraints then the concept of perfect equality is already lost.

So I don't like the proposal to add an attnotnullid column to
pg_attribute. What we'd talked about earlier was converting attnotnull
into, effectively, a hint flag saying that there's at least one NOT NULL
constraint attached to the column.

Have we considered making it a table constraint and giving it a name? We
already handle that case without difficulty.

Not looking for a detailed explanation.

David J.

#7David G. Johnston
david.g.johnston@gmail.com
In reply to: Vitaly Burovoy (#1)
Re: Make PG's "NOT NULL"s and attnotnull ("is_nullable") conform to SQL-2011

On Monday, February 8, 2016, Vitaly Burovoy <vitaly.burovoy@gmail.com>
wrote:

12. At the same time in (subcl. 4.13) mentioned there can be "at least
one NNC" (may be via inheritance?).

This is a bit hard to reason about given that our implementation of
inheritance is non-standard.

Are we close to the standard semantics with regard to this particular
dynamic?

David J.

#8Vitaly Burovoy
vitaly.burovoy@gmail.com
In reply to: Tom Lane (#5)
Re: Make PG's "NOT NULL"s and attnotnull ("is_nullable") conform to SQL-2011

On 5/3/16, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Vitaly Burovoy <vitaly.burovoy@gmail.com> writes:

On 4/27/16, Alvaro Herrera <alvherre@2ndquadrant.com> wrote:

Point 2 is where things differ from what I remember; my (possibly
flawed) understanding was that there's no difference between those
things. Many (maybe all) of the things from this point on are probably
fallout from that one change.

It is just mentioning that CHECK constraints have influence on
nullability characteristic, but it differs from NNC.
NNC creates CHECK constraint, but not vice versa. You can create
several CHECK "col IS NOT NULL" constraints, but only one NNC (several
ones by inheritance only?). And DROP NOT NULL should drop only those
CHECK that is linked with NNC (and inherited), but no more (full
explanation is in my initial letter).

This seems to me to be a most curious reading of the standard.
SQL:2011 11.4 <column definition> syntax rule 17a says

If a <column constraint definition> is specified that contains
the <column constraint> NOT NULL, then it is equivalent to the
following <table constraint definition>:

CND CHECK ( C IS NOT NULL ) CA

As a rule, when the SQL spec says "equivalent", they do not mean "it's
sort of like this", they mean the effects are indistinguishable. In
particular, I see nothing whatsoever saying that you're not allowed to
write more than one per column.

1. SQL:2011 4.13 <Columns, fields, and attributes>:

— If C is a column of a base table, then an indication of whether it is
defined as NOT NULL and, if so, the constraint name of the associated table
constraint definition.
NOTE 41 — This indication and the associated constraint name exist for
definitional purposes only and are not exposed through the COLUMNS view
in the Information Schema.

There is only "constraint name", not "constraint names".

2. SQL:2011 11.15 <set column not null clause> General Rule 1:

... If the column descriptor of C does not contain an indication that
C is defined as NOT NULL, then:

And there is no rule 2. I.e. if the column is already set as NOT NULL
you can't specify it as NOT NULL again.

3. SQL:2011 11.15 <set column not null clause> General Rule 1.d:

The following <alter table statement> is executed without further
Access Rule checking:
ALTER TABLE TN ADD CONSTRAINT IDCN CHECK ( CN IS NOT NULL )

So I don't like the proposal to add an attnotnullid column to
pg_attribute.

Why and where to place it?

What we'd talked about earlier was converting attnotnull
into, effectively, a hint flag saying that there's at least one NOT NULL
constraint attached to the column. That still seems like a good approach
to me.

Ok. But not only NOT NULL constraint, but also non-deferrable PK,
CHECK, domains, may be the strictest FK.

When we're actually ready to throw an error for a null value,
we could root through the table's constraint list for a not-null
constraint name to report.

attnotnullid is not for reporting, it is for DROP NOT NULL and
recreating "CREATE TABLE" statements via pg_dump.

It doesn't matter which one we select, because
constraint application order has never been promised to be deterministic;
and a few extra cycles at that point don't seem like a big problem to me.

regards, tom lane

--
Best regards,
Vitaly Burovoy

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#9Tom Lane
tgl@sss.pgh.pa.us
In reply to: David G. Johnston (#7)
Re: Make PG's "NOT NULL"s and attnotnull ("is_nullable") conform to SQL-2011

"David G. Johnston" <david.g.johnston@gmail.com> writes:

This is a bit hard to reason about given that our implementation of
inheritance is non-standard.

Yeah, that's a fairly key point. We've solved those problems with
respect to inherited CHECK constraints, and it seems like what we
ought to do with NOT NULL is make it work the same as CHECK, rather
than invent some new concepts.

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers