<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.postgresql.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Intgr</id>
	<title>PostgreSQL wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.postgresql.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Intgr"/>
	<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/wiki/Special:Contributions/Intgr"/>
	<updated>2026-06-10T02:27:40Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.39.17</generator>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=MVCC_violations&amp;diff=23675</id>
		<title>MVCC violations</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=MVCC_violations&amp;diff=23675"/>
		<updated>2014-11-03T16:56:50Z</updated>

		<summary type="html">&lt;p&gt;Intgr: Document violations using STABLE PL/pgSQL functions; fix table layouts&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In general, PostgreSQL aims to be strict with ACID transaction semantics. But there are some documented cases that, for performance or usability reasons, violate the MVCC protocol, and thus the atomicity, consistency or isolation properties of ACID transactions. Such instances are sometimes referred to as &amp;quot;MVCC violations&amp;quot;. This page aims to illustrate when such situations occur.&lt;br /&gt;
&lt;br /&gt;
In general, MVCC violations are detectable using:&lt;br /&gt;
* REPEATABLE READ isolation level -- usually the easiest way to reliably reveal violations.&lt;br /&gt;
* With the default READ COMMITTED level, violations are visible only rarely when winning a tight race condition, or when a 3rd session happens to synchronize the backends in a certain way.&lt;br /&gt;
* Within STABLE PL/pgSQL functions, even when using the READ COMMITTED level, due to snapshot allocation optimizations with STABLE functions.&lt;br /&gt;
&lt;br /&gt;
== TRUNCATE TABLE ==&lt;br /&gt;
&lt;br /&gt;
Using TRUNCATE is a common technique for quickly replacing the contents of a table with new contents from an external source. Due to performance tradeoffs, the table can temporarily appear empty to concurrent transactions.&lt;br /&gt;
&lt;br /&gt;
To avoid this problem, use the &amp;lt;code&amp;gt;DELETE FROM&amp;lt;/code&amp;gt; statement, which has a higher performance and I/O cost.&lt;br /&gt;
&lt;br /&gt;
=== With REPEATABLE READ isolation level ===&lt;br /&gt;
&lt;br /&gt;
This issue is the easiest do demonstrate in the REPEATABLE READ isolation level. Any reading transaction should see either &amp;quot;old data&amp;quot; or &amp;quot;new data&amp;quot; in the table, never an empty table.&lt;br /&gt;
&lt;br /&gt;
Test case:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!colspan=2|Preparation&lt;br /&gt;
|-&lt;br /&gt;
|colspan=2|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
CREATE TABLE a AS SELECT &#039;old data&#039;::text;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! Reading session&lt;br /&gt;
! Writing session&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
BEGIN ISOLATION LEVEL REPEATABLE READ;&lt;br /&gt;
SELECT txid_current(); -- force snapshot allocation&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;BEGIN;&lt;br /&gt;
TRUNCATE TABLE a;&lt;br /&gt;
INSERT INTO a VALUES (&#039;new data&#039;);&lt;br /&gt;
COMMIT;&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;SELECT * FROM a;&lt;br /&gt;
 text &lt;br /&gt;
------&lt;br /&gt;
(0 rows)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== With READ COMMITTED (default) isolation ===&lt;br /&gt;
&lt;br /&gt;
This issue is still present in the default READ COMMITTED isolation level, but more difficult to trigger reliably, because a fresh snapshot is allocated for each new query.&lt;br /&gt;
&lt;br /&gt;
Thanks to Andrew Gierth for pointing out this scenario and Andres Freund for coming up with this test case.&lt;br /&gt;
&lt;br /&gt;
Test case:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!colspan=3|Preparation&lt;br /&gt;
|-&lt;br /&gt;
|colspan=3|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
CREATE TABLE sync(text text);&lt;br /&gt;
CREATE TABLE a AS SELECT &#039;old data&#039;::text;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! Synchronizing session&lt;br /&gt;
! Reading session&lt;br /&gt;
! Writing session&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
PREPARE prep AS&lt;br /&gt;
  SELECT * FROM sync UNION ALL SELECT * FROM a;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
BEGIN;&lt;br /&gt;
LOCK TABLE sync;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
EXECUTE prep;&lt;br /&gt;
-- blocks behind session #1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
BEGIN;&lt;br /&gt;
TRUNCATE TABLE a;&lt;br /&gt;
INSERT INTO a VALUES (&#039;new data&#039;);&lt;br /&gt;
COMMIT;&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;ROLLBACK;&amp;lt;/source&amp;gt;&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
-- session unblocks after #1 rollback&lt;br /&gt;
 text &lt;br /&gt;
------&lt;br /&gt;
(0 rows)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== STABLE functions ===&lt;br /&gt;
&lt;br /&gt;
MVCC violations are also easily visible to STABLE PL/pgSQL functions due to the way snapshots are allocated. In earlier versions (9.1 and earlier. Not sure about 9.2???), this also affected SQL language functions. [http://www.postgresql.org/docs/current/static/xfunc-volatility.html Documentation for function snapshot allocation]. Thanks to Marko Tiikkaja for the test case.&lt;br /&gt;
&lt;br /&gt;
Test case:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!colspan=2|Preparation&lt;br /&gt;
|-&lt;br /&gt;
|colspan=2|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
CREATE TABLE a AS SELECT &#039;old data&#039;::text;&lt;br /&gt;
CREATE FUNCTION get_a()&lt;br /&gt;
  RETURNS SETOF text LANGUAGE plpgsql STABLE&lt;br /&gt;
  AS &#039;BEGIN RETURN QUERY SELECT text FROM a; END&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! Writing session&lt;br /&gt;
! Reading session&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
BEGIN;&lt;br /&gt;
TRUNCATE TABLE a;&lt;br /&gt;
INSERT INTO a VALUES (&#039;new data&#039;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SELECT * FROM get_a();&lt;br /&gt;
-- blocks behind session #1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;COMMIT;&amp;lt;/source&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
-- session unblocks after #1 commits&lt;br /&gt;
 get_a&lt;br /&gt;
-------&lt;br /&gt;
(0 rows)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== COPY FREEZE ==&lt;br /&gt;
&lt;br /&gt;
The FREEZE option of the COPY command was introduced in PostgreSQL version 9.3 to avoid expensive vacuum maintenance later on the restored table. In this case, the reading session should see an empty table, since its snapshot started before any rows were inserted (copied).&lt;br /&gt;
&lt;br /&gt;
To avoid this problem, simply don&#039;t use the FREEZE option.&lt;br /&gt;
&lt;br /&gt;
Test case:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!colspan=2|Preparation&lt;br /&gt;
|-&lt;br /&gt;
|colspan=2|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
CREATE TABLE a (text text);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! Reading session&lt;br /&gt;
! Writing session&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;BEGIN ISOLATION LEVEL REPEATABLE READ;&lt;br /&gt;
SELECT txid_current(); -- force snapshot allocation&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
BEGIN;&lt;br /&gt;
TRUNCATE TABLE a;&lt;br /&gt;
COPY a FROM STDIN WITH (FREEZE);&lt;br /&gt;
phantom row&lt;br /&gt;
\.&lt;br /&gt;
COMMIT;&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SELECT * FROM a;&lt;br /&gt;
    text     &lt;br /&gt;
-------------&lt;br /&gt;
 phantom row&lt;br /&gt;
(1 row)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== UPDATE &amp;amp; SELECT FOR UPDATE ==&lt;br /&gt;
&lt;br /&gt;
In the READ COMMITTED isolation level, any command that acquires row locks, when faced with concurrently modified rows, is able to &amp;quot;reach into the future&amp;quot; and see the latest committed row version outside of its own snapshot. Arguably it doesn&#039;t violate ACID properties because READ COMMITTED is allowed to see concurrently committed rows. But it goes against usual PostgreSQL MVCC behavior where a single statement cannot see any anomalies even in READ COMMITTED.&lt;br /&gt;
&lt;br /&gt;
To avoid this, simply use a higher isolation level. Unlike previous examples, this one cannot happen in REPEATABLE READ and higher levels, instead it throws the error &amp;quot;could not serialize access due to concurrent update&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
User-visible symptoms include:&lt;br /&gt;
* Result rows violating ordering specified by ORDER BY clause because the ordering is applied in the original snapshot &#039;&#039;before&#039;&#039; acquiring row locks.&lt;br /&gt;
* Result rows that appear to violate causality (and possibly FOREIGN KEY constraints?)&lt;br /&gt;
* WHERE clause expressions evaulated twice for the same row -- once for the old copy and again for the new copy.&lt;br /&gt;
* Result containing fewer rows because the new locked version no longer matches the WHERE clause. (Note: the inverse is not true: rows whose old version didn&#039;t match will never appear in the result set, even if their new version does).&lt;br /&gt;
&lt;br /&gt;
Test case:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!colspan=2|Preparation&lt;br /&gt;
|-&lt;br /&gt;
|colspan=2|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
CREATE TABLE a AS SELECT &#039;a&#039;::text UNION ALL SELECT &#039;b&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! Writing session&lt;br /&gt;
! Reading session&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
BEGIN;&lt;br /&gt;
UPDATE a SET text=&#039;zzz&#039; WHERE text=&#039;a&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SELECT * FROM a ORDER BY text FOR UPDATE;&lt;br /&gt;
-- blocks behind session #1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
COMMIT;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
-- session unblocks after #1 commits&lt;br /&gt;
 text &lt;br /&gt;
------&lt;br /&gt;
 zzz    -- notice rows are out of order&lt;br /&gt;
 b&lt;br /&gt;
(2 rows)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== ALTER TABLE rewrite ==&lt;br /&gt;
&lt;br /&gt;
When querying a table that has been rewritten by ALTER TABLE in another session, the table may appear temporarily empty to concurrent transactions. Again, this is easier to reproduce using the REPEATABLE READ isolation level. Thanks to Marko Tiikkaja for the test case.&lt;br /&gt;
&lt;br /&gt;
Test case:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!colspan=2|Preparation&lt;br /&gt;
|-&lt;br /&gt;
|colspan=2|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
CREATE TABLE a AS SELECT &#039;data&#039;::text;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! Writing session&lt;br /&gt;
! Reading session&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
BEGIN;&lt;br /&gt;
ALTER TABLE a&lt;br /&gt;
    ADD COLUMN b int DEFAULT 0;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
BEGIN ISOLATION LEVEL REPEATABLE READ;&lt;br /&gt;
SELECT * FROM a;&lt;br /&gt;
-- blocks behind session #1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;COMMIT;&amp;lt;/source&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
-- session unblocks after #1 commits&lt;br /&gt;
 text | b &lt;br /&gt;
------+---&lt;br /&gt;
(0 rows)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Historic issues ==&lt;br /&gt;
&lt;br /&gt;
* In PostgreSQL 8.2 and earlier, the CLUSTER command could cause DELETEd/UPDATEd rows to disappear for older snapshots.&lt;/div&gt;</summary>
		<author><name>Intgr</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=MVCC_violations&amp;diff=23673</id>
		<title>MVCC violations</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=MVCC_violations&amp;diff=23673"/>
		<updated>2014-11-03T16:03:09Z</updated>

		<summary type="html">&lt;p&gt;Intgr: ALTER TABLE rewrite&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In general, PostgreSQL aims to be strict with ACID transaction semantics. But there are some documented cases that, for performance or usability reasons, violate the MVCC protocol, and thus the atomicity, consistency or isolation properties of ACID transactions. Such instances are sometimes referred to as &amp;quot;MVCC violations&amp;quot;. This page aims to illustrate when such situations occur.&lt;br /&gt;
&lt;br /&gt;
In general, such scenarios are easy to demonstrate reliably with the REPEATABLE READ isolation level, but occur rarely and unpredictably in the default READ COMMITTED level.&lt;br /&gt;
&lt;br /&gt;
== TRUNCATE TABLE ==&lt;br /&gt;
&lt;br /&gt;
Using TRUNCATE is a common technique for quickly replacing the contents of a table with new contents from an external source. Due to performance tradeoffs, the table can temporarily appear empty to concurrent transactions.&lt;br /&gt;
&lt;br /&gt;
To avoid this problem, use the &amp;lt;code&amp;gt;DELETE FROM&amp;lt;/code&amp;gt; statement, which has a higher performance and I/O cost.&lt;br /&gt;
&lt;br /&gt;
=== With REPEATABLE READ isolation level ===&lt;br /&gt;
&lt;br /&gt;
This issue is the easiest do demonstrate in the REPEATABLE READ isolation level. Any reading transaction should see either &amp;quot;old data&amp;quot; or &amp;quot;new data&amp;quot; in the table, never an empty table.&lt;br /&gt;
&lt;br /&gt;
Test case:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!colspan=3|Preparation&lt;br /&gt;
|-&lt;br /&gt;
|colspan=3|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
CREATE TABLE a AS SELECT &#039;old data&#039;::text;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! Reading session&lt;br /&gt;
! Writing session&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
BEGIN ISOLATION LEVEL REPEATABLE READ;&lt;br /&gt;
SELECT txid_current(); -- force snapshot allocation&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;BEGIN;&lt;br /&gt;
TRUNCATE TABLE a;&lt;br /&gt;
INSERT INTO a VALUES (&#039;new data&#039;);&lt;br /&gt;
COMMIT;&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;SELECT * FROM a;&lt;br /&gt;
 text &lt;br /&gt;
------&lt;br /&gt;
(0 rows)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== With READ COMMITTED (default) isolation ===&lt;br /&gt;
&lt;br /&gt;
This issue is still present in the default READ COMMITTED isolation level, but more difficult to trigger reliably, because a fresh snapshot is allocated for each new query.&lt;br /&gt;
&lt;br /&gt;
Thanks to Andrew Gierth for pointing out this scenario and Andres Freund for coming up with this test case.&lt;br /&gt;
&lt;br /&gt;
Test case:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!colspan=3|Preparation&lt;br /&gt;
|-&lt;br /&gt;
|colspan=3|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
CREATE TABLE sync(text text);&lt;br /&gt;
CREATE TABLE a AS SELECT &#039;old data&#039;::text;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! Synchronizing session&lt;br /&gt;
! Reading session&lt;br /&gt;
! Writing session&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
PREPARE prep AS&lt;br /&gt;
  SELECT * FROM sync UNION ALL SELECT * FROM a;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
BEGIN;&lt;br /&gt;
LOCK TABLE sync;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
EXECUTE prep;&lt;br /&gt;
-- blocks behind session #1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
BEGIN;&lt;br /&gt;
TRUNCATE TABLE a;&lt;br /&gt;
INSERT INTO a VALUES (&#039;new data&#039;);&lt;br /&gt;
COMMIT;&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;ROLLBACK;&amp;lt;/source&amp;gt;&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
-- session unblocks after #1 rollback&lt;br /&gt;
 text &lt;br /&gt;
------&lt;br /&gt;
(0 rows)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== COPY FREEZE ==&lt;br /&gt;
&lt;br /&gt;
The FREEZE option of the COPY command was introduced in PostgreSQL version 9.3 to avoid expensive vacuum maintenance later on the restored table. In this case, the reading session should see an empty table, since its snapshot started before any rows were inserted (copied).&lt;br /&gt;
&lt;br /&gt;
To avoid this problem, simply don&#039;t use the FREEZE option.&lt;br /&gt;
&lt;br /&gt;
Test case:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!colspan=3|Preparation&lt;br /&gt;
|-&lt;br /&gt;
|colspan=3|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
CREATE TABLE a (text text);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! Reading session&lt;br /&gt;
! Writing session&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;BEGIN ISOLATION LEVEL REPEATABLE READ;&lt;br /&gt;
SELECT txid_current(); -- force snapshot allocation&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
BEGIN;&lt;br /&gt;
TRUNCATE TABLE a;&lt;br /&gt;
COPY a FROM STDIN WITH (FREEZE);&lt;br /&gt;
phantom row&lt;br /&gt;
\.&lt;br /&gt;
COMMIT;&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SELECT * FROM a;&lt;br /&gt;
    text     &lt;br /&gt;
-------------&lt;br /&gt;
 phantom row&lt;br /&gt;
(1 row)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== UPDATE &amp;amp; SELECT FOR UPDATE ==&lt;br /&gt;
&lt;br /&gt;
In the READ COMMITTED isolation level, any command that acquires row locks, when faced with concurrently modified rows, is able to &amp;quot;reach into the future&amp;quot; and see the latest committed row version outside of its own snapshot. Arguably it doesn&#039;t violate ACID properties because READ COMMITTED is allowed to see concurrently committed rows. But it goes against usual PostgreSQL MVCC behavior where a single statement cannot see any anomalies even in READ COMMITTED.&lt;br /&gt;
&lt;br /&gt;
To avoid this, simply use a higher isolation level. Unlike previous examples, this one cannot happen in REPEATABLE READ and higher levels, instead it throws the error &amp;quot;could not serialize access due to concurrent update&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
User-visible symptoms include:&lt;br /&gt;
* Result rows violating ordering specified by ORDER BY clause because the ordering is applied in the original snapshot &#039;&#039;before&#039;&#039; acquiring row locks.&lt;br /&gt;
* Result rows that appear to violate causality (and possibly FOREIGN KEY constraints?)&lt;br /&gt;
* WHERE clause expressions evaulated twice for the same row -- once for the old copy and again for the new copy.&lt;br /&gt;
* Result containing fewer rows because the new locked version no longer matches the WHERE clause. (Note: the inverse is not true: rows whose old version didn&#039;t match will never appear in the result set, even if their new version does).&lt;br /&gt;
&lt;br /&gt;
Test case:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!colspan=3|Preparation&lt;br /&gt;
|-&lt;br /&gt;
|colspan=3|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
CREATE TABLE a AS SELECT &#039;a&#039;::text UNION ALL SELECT &#039;b&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! Writing session&lt;br /&gt;
! Reading session&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
BEGIN;&lt;br /&gt;
UPDATE a SET text=&#039;zzz&#039; WHERE text=&#039;a&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SELECT * FROM a ORDER BY text FOR UPDATE;&lt;br /&gt;
-- blocks behind session #1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
COMMIT;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
-- session unblocks after #1 commits&lt;br /&gt;
 text &lt;br /&gt;
------&lt;br /&gt;
 zzz    -- notice rows are out of order&lt;br /&gt;
 b&lt;br /&gt;
(2 rows)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== ALTER TABLE rewrite ==&lt;br /&gt;
&lt;br /&gt;
Querying a table that has been rewritten by ALTER TABLE in another session, the table may appear temporarily empty to concurrent transactions. Again, this is easier to reproduce using the REPEATABLE READ isolation level. Thanks to Marko Tiikkaja for the test case.&lt;br /&gt;
&lt;br /&gt;
Test case:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!colspan=3|Preparation&lt;br /&gt;
|-&lt;br /&gt;
|colspan=3|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
CREATE TABLE a AS SELECT &#039;data&#039;::text;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! Writing session&lt;br /&gt;
! Reading session&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
BEGIN;&lt;br /&gt;
ALTER TABLE a&lt;br /&gt;
    ADD COLUMN b int DEFAULT 0;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
BEGIN ISOLATION LEVEL REPEATABLE READ;&lt;br /&gt;
SELECT * FROM a;&lt;br /&gt;
-- blocks behind session #1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;COMMIT;&amp;lt;/source&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
-- session unblocks after #1 commits&lt;br /&gt;
 text | b &lt;br /&gt;
------+---&lt;br /&gt;
(0 rows)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Historic issues ==&lt;br /&gt;
&lt;br /&gt;
* In PostgreSQL 8.2 and earlier, the CLUSTER command could cause DELETEd/UPDATEd rows to disappear for older snapshots.&lt;/div&gt;</summary>
		<author><name>Intgr</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=MVCC_violations&amp;diff=22942</id>
		<title>MVCC violations</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=MVCC_violations&amp;diff=22942"/>
		<updated>2014-08-04T09:03:01Z</updated>

		<summary type="html">&lt;p&gt;Intgr: /* UPDATE &amp;amp; SELECT FOR UPDATE */ clarification&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In general, PostgreSQL aims to be strict with ACID transaction semantics. But there are some documented cases that, for performance or usability reasons, violate the MVCC protocol, and thus the atomicity, consistency or isolation properties of ACID transactions. Such instances are sometimes referred to as &amp;quot;MVCC violations&amp;quot;. This page aims to illustrate when such situations occur.&lt;br /&gt;
&lt;br /&gt;
In general, such scenarios are easy to demonstrate reliably with the REPEATABLE READ isolation level, but occur rarely and unpredictably in the default READ COMMITTED level.&lt;br /&gt;
&lt;br /&gt;
== TRUNCATE TABLE ==&lt;br /&gt;
&lt;br /&gt;
Using TRUNCATE is a common technique for quickly replacing the contents of a table with new contents from an external source. Due to performance tradeoffs, the table can temporarily appear empty to concurrent transactions.&lt;br /&gt;
&lt;br /&gt;
To avoid this problem, use the &amp;lt;code&amp;gt;DELETE FROM&amp;lt;/code&amp;gt; statement, which has a higher performance and I/O cost.&lt;br /&gt;
&lt;br /&gt;
=== With REPEATABLE READ isolation level ===&lt;br /&gt;
&lt;br /&gt;
This issue is the easiest do demonstrate in the REPEATABLE READ isolation level. Any reading transaction should see either &amp;quot;old data&amp;quot; or &amp;quot;new data&amp;quot; in the table, never an empty table.&lt;br /&gt;
&lt;br /&gt;
Test case:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!colspan=3|Preparation&lt;br /&gt;
|-&lt;br /&gt;
|colspan=3|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
CREATE TABLE a AS SELECT &#039;old data&#039;::text;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! Reading session&lt;br /&gt;
! Writing session&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
BEGIN ISOLATION LEVEL REPEATABLE READ;&lt;br /&gt;
SELECT txid_current(); -- force snapshot allocation&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;BEGIN;&lt;br /&gt;
TRUNCATE TABLE a;&lt;br /&gt;
INSERT INTO a VALUES (&#039;new data&#039;);&lt;br /&gt;
COMMIT;&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;SELECT * FROM a;&lt;br /&gt;
 text &lt;br /&gt;
------&lt;br /&gt;
(0 rows)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== With READ COMMITTED (default) isolation ===&lt;br /&gt;
&lt;br /&gt;
This issue is still present in the default READ COMMITTED isolation level, but more difficult to trigger reliably, because a fresh snapshot is allocated for each new query.&lt;br /&gt;
&lt;br /&gt;
Thanks to Andrew Gierth for pointing out this scenario and Andres Freund for coming up with this test case.&lt;br /&gt;
&lt;br /&gt;
Test case:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!colspan=3|Preparation&lt;br /&gt;
|-&lt;br /&gt;
|colspan=3|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
CREATE TABLE sync(text text);&lt;br /&gt;
CREATE TABLE a AS SELECT &#039;old data&#039;::text;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! Synchronizing session&lt;br /&gt;
! Reading session&lt;br /&gt;
! Writing session&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
PREPARE prep AS&lt;br /&gt;
  SELECT * FROM sync UNION ALL SELECT * FROM a;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
BEGIN;&lt;br /&gt;
LOCK TABLE sync;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
EXECUTE prep;&lt;br /&gt;
-- blocks behind session #1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
BEGIN;&lt;br /&gt;
TRUNCATE TABLE a;&lt;br /&gt;
INSERT INTO a VALUES (&#039;new data&#039;);&lt;br /&gt;
COMMIT;&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;ROLLBACK;&amp;lt;/source&amp;gt;&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
-- session unblocks after #1 rollback&lt;br /&gt;
 text &lt;br /&gt;
------&lt;br /&gt;
(0 rows)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== COPY FREEZE ==&lt;br /&gt;
&lt;br /&gt;
The FREEZE option of the COPY command was introduced in PostgreSQL version 9.3 to avoid expensive vacuum maintenance later on the restored table. In this case, the reading session should see an empty table, since its snapshot started before any rows were inserted (copied).&lt;br /&gt;
&lt;br /&gt;
To avoid this problem, simply don&#039;t use the FREEZE option.&lt;br /&gt;
&lt;br /&gt;
Test case:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!colspan=3|Preparation&lt;br /&gt;
|-&lt;br /&gt;
|colspan=3|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
CREATE TABLE a (text text);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! Reading session&lt;br /&gt;
! Writing session&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;BEGIN ISOLATION LEVEL REPEATABLE READ;&lt;br /&gt;
SELECT txid_current(); -- force snapshot allocation&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
BEGIN;&lt;br /&gt;
TRUNCATE TABLE a;&lt;br /&gt;
COPY a FROM STDIN WITH (FREEZE);&lt;br /&gt;
phantom row&lt;br /&gt;
\.&lt;br /&gt;
COMMIT;&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SELECT * FROM a;&lt;br /&gt;
    text     &lt;br /&gt;
-------------&lt;br /&gt;
 phantom row&lt;br /&gt;
(1 row)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== UPDATE &amp;amp; SELECT FOR UPDATE ==&lt;br /&gt;
&lt;br /&gt;
In the READ COMMITTED isolation level, any command that acquires row locks, when faced with concurrently modified rows, is able to &amp;quot;reach into the future&amp;quot; and see the latest committed row version outside of its own snapshot. Arguably it doesn&#039;t violate ACID properties because READ COMMITTED is allowed to see concurrently committed rows. But it goes against usual PostgreSQL MVCC behavior where a single statement cannot see any anomalies even in READ COMMITTED.&lt;br /&gt;
&lt;br /&gt;
To avoid this, simply use a higher isolation level. Unlike previous examples, this one cannot happen in REPEATABLE READ and higher levels, instead it throws the error &amp;quot;could not serialize access due to concurrent update&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
User-visible symptoms include:&lt;br /&gt;
* Result rows violating ordering specified by ORDER BY clause because the ordering is applied in the original snapshot &#039;&#039;before&#039;&#039; acquiring row locks.&lt;br /&gt;
* Result rows that appear to violate causality (and possibly FOREIGN KEY constraints?)&lt;br /&gt;
* WHERE clause expressions evaulated twice for the same row -- once for the old copy and again for the new copy.&lt;br /&gt;
* Result containing fewer rows because the new locked version no longer matches the WHERE clause. (Note: the inverse is not true: rows whose old version didn&#039;t match will never appear in the result set, even if their new version does).&lt;br /&gt;
&lt;br /&gt;
Test case:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!colspan=3|Preparation&lt;br /&gt;
|-&lt;br /&gt;
|colspan=3|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
CREATE TABLE a AS SELECT &#039;a&#039;::text UNION ALL SELECT &#039;b&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! Writing session&lt;br /&gt;
! Reading session&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
BEGIN;&lt;br /&gt;
UPDATE a SET text=&#039;zzz&#039; WHERE text=&#039;a&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SELECT * FROM a ORDER BY text FOR UPDATE;&lt;br /&gt;
-- blocks behind session #1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
COMMIT;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
-- session unblocks after #1 commits&lt;br /&gt;
 text &lt;br /&gt;
------&lt;br /&gt;
 zzz    -- notice rows are out of order&lt;br /&gt;
 b&lt;br /&gt;
(2 rows)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Historic issues ==&lt;br /&gt;
&lt;br /&gt;
* In PostgreSQL 8.2 and earlier, the CLUSTER command could cause DELETEd/UPDATEd rows to disappear for older snapshots.&lt;/div&gt;</summary>
		<author><name>Intgr</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=MVCC_violations&amp;diff=22941</id>
		<title>MVCC violations</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=MVCC_violations&amp;diff=22941"/>
		<updated>2014-08-04T08:42:36Z</updated>

		<summary type="html">&lt;p&gt;Intgr: UPDATE &amp;amp; SELECT FOR UPDATE&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In general, PostgreSQL aims to be strict with ACID transaction semantics. But there are some documented cases that, for performance or usability reasons, violate the MVCC protocol, and thus the atomicity, consistency or isolation properties of ACID transactions. Such instances are sometimes referred to as &amp;quot;MVCC violations&amp;quot;. This page aims to illustrate when such situations occur.&lt;br /&gt;
&lt;br /&gt;
In general, such scenarios are easy to demonstrate reliably with the REPEATABLE READ isolation level, but occur rarely and unpredictably in the default READ COMMITTED level.&lt;br /&gt;
&lt;br /&gt;
== TRUNCATE TABLE ==&lt;br /&gt;
&lt;br /&gt;
Using TRUNCATE is a common technique for quickly replacing the contents of a table with new contents from an external source. Due to performance tradeoffs, the table can temporarily appear empty to concurrent transactions.&lt;br /&gt;
&lt;br /&gt;
To avoid this problem, use the &amp;lt;code&amp;gt;DELETE FROM&amp;lt;/code&amp;gt; statement, which has a higher performance and I/O cost.&lt;br /&gt;
&lt;br /&gt;
=== With REPEATABLE READ isolation level ===&lt;br /&gt;
&lt;br /&gt;
This issue is the easiest do demonstrate in the REPEATABLE READ isolation level. Any reading transaction should see either &amp;quot;old data&amp;quot; or &amp;quot;new data&amp;quot; in the table, never an empty table.&lt;br /&gt;
&lt;br /&gt;
Test case:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!colspan=3|Preparation&lt;br /&gt;
|-&lt;br /&gt;
|colspan=3|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
CREATE TABLE a AS SELECT &#039;old data&#039;::text;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! Reading session&lt;br /&gt;
! Writing session&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
BEGIN ISOLATION LEVEL REPEATABLE READ;&lt;br /&gt;
SELECT txid_current(); -- force snapshot allocation&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;BEGIN;&lt;br /&gt;
TRUNCATE TABLE a;&lt;br /&gt;
INSERT INTO a VALUES (&#039;new data&#039;);&lt;br /&gt;
COMMIT;&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;SELECT * FROM a;&lt;br /&gt;
 text &lt;br /&gt;
------&lt;br /&gt;
(0 rows)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== With READ COMMITTED (default) isolation ===&lt;br /&gt;
&lt;br /&gt;
This issue is still present in the default READ COMMITTED isolation level, but more difficult to trigger reliably, because a fresh snapshot is allocated for each new query.&lt;br /&gt;
&lt;br /&gt;
Thanks to Andrew Gierth for pointing out this scenario and Andres Freund for coming up with this test case.&lt;br /&gt;
&lt;br /&gt;
Test case:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!colspan=3|Preparation&lt;br /&gt;
|-&lt;br /&gt;
|colspan=3|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
CREATE TABLE sync(text text);&lt;br /&gt;
CREATE TABLE a AS SELECT &#039;old data&#039;::text;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! Synchronizing session&lt;br /&gt;
! Reading session&lt;br /&gt;
! Writing session&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
PREPARE prep AS&lt;br /&gt;
  SELECT * FROM sync UNION ALL SELECT * FROM a;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
BEGIN;&lt;br /&gt;
LOCK TABLE sync;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
EXECUTE prep;&lt;br /&gt;
-- blocks behind session #1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
BEGIN;&lt;br /&gt;
TRUNCATE TABLE a;&lt;br /&gt;
INSERT INTO a VALUES (&#039;new data&#039;);&lt;br /&gt;
COMMIT;&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;ROLLBACK;&amp;lt;/source&amp;gt;&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
-- session unblocks after #1 rollback&lt;br /&gt;
 text &lt;br /&gt;
------&lt;br /&gt;
(0 rows)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== COPY FREEZE ==&lt;br /&gt;
&lt;br /&gt;
The FREEZE option of the COPY command was introduced in PostgreSQL version 9.3 to avoid expensive vacuum maintenance later on the restored table. In this case, the reading session should see an empty table, since its snapshot started before any rows were inserted (copied).&lt;br /&gt;
&lt;br /&gt;
To avoid this problem, simply don&#039;t use the FREEZE option.&lt;br /&gt;
&lt;br /&gt;
Test case:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!colspan=3|Preparation&lt;br /&gt;
|-&lt;br /&gt;
|colspan=3|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
CREATE TABLE a (text text);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! Reading session&lt;br /&gt;
! Writing session&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;BEGIN ISOLATION LEVEL REPEATABLE READ;&lt;br /&gt;
SELECT txid_current(); -- force snapshot allocation&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
BEGIN;&lt;br /&gt;
TRUNCATE TABLE a;&lt;br /&gt;
COPY a FROM STDIN WITH (FREEZE);&lt;br /&gt;
phantom row&lt;br /&gt;
\.&lt;br /&gt;
COMMIT;&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SELECT * FROM a;&lt;br /&gt;
    text     &lt;br /&gt;
-------------&lt;br /&gt;
 phantom row&lt;br /&gt;
(1 row)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== UPDATE &amp;amp; SELECT FOR UPDATE ==&lt;br /&gt;
&lt;br /&gt;
In the READ COMMITTED isolation level, any command that acquires row locks, when faced with concurrently modified rows, is able to &amp;quot;reach into the future&amp;quot; and see the latest committed row version outside of its own snapshot. Arguably it doesn&#039;t violate ACID properties because READ COMMITTED is allowed to see concurrently committed rows. But it goes against usual PostgreSQL MVCC behavior where a single statement cannot see any anomalies even in READ COMMITTED.&lt;br /&gt;
&lt;br /&gt;
To avoid this, simply use a higher isolation level. Unlike previous examples, this one cannot happen in REPEATABLE READ and higher levels, instead it throws the error &amp;quot;could not serialize access due to concurrent update&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
User-visible symptoms include:&lt;br /&gt;
* Result rows violating ordering specified by ORDER BY clause because the ordering is applied in the original snapshot &#039;&#039;before&#039;&#039; acquiring row locks.&lt;br /&gt;
* Result rows that appear to violate causality (and possibly FOREIGN KEY constraints?)&lt;br /&gt;
* WHERE clause expressions evaulated twice for the same row -- once for the old copy and again for the new copy.&lt;br /&gt;
* Result containing fewer rows because the new locked version no longer matches the WHERE clause.&lt;br /&gt;
&lt;br /&gt;
Test case:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!colspan=3|Preparation&lt;br /&gt;
|-&lt;br /&gt;
|colspan=3|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
CREATE TABLE a AS SELECT &#039;a&#039;::text UNION ALL SELECT &#039;b&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! Writing session&lt;br /&gt;
! Reading session&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
BEGIN;&lt;br /&gt;
UPDATE a SET text=&#039;zzz&#039; WHERE text=&#039;a&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SELECT * FROM a ORDER BY text FOR UPDATE;&lt;br /&gt;
-- blocks behind session #1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
COMMIT;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
-- session unblocks after #1 commits&lt;br /&gt;
 text &lt;br /&gt;
------&lt;br /&gt;
 zzz    -- notice rows are out of order&lt;br /&gt;
 b&lt;br /&gt;
(2 rows)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Historic issues ==&lt;br /&gt;
&lt;br /&gt;
* In PostgreSQL 8.2 and earlier, the CLUSTER command could cause DELETEd/UPDATEd rows to disappear for older snapshots.&lt;/div&gt;</summary>
		<author><name>Intgr</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=MVCC_violations&amp;diff=22933</id>
		<title>MVCC violations</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=MVCC_violations&amp;diff=22933"/>
		<updated>2014-08-01T14:38:02Z</updated>

		<summary type="html">&lt;p&gt;Intgr: CLUSTER in PostgreSQL 8.2 and earlier&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In general, PostgreSQL aims to be strict with ACID transaction semantics. But there are some documented cases that, for performance reasons, violate the MVCC protocol, and thus the atomicity, consistency or isolation properties of ACID transactions. Such instances are sometimes referred to as &amp;quot;MVCC violations&amp;quot;. This page aims to illustrate when such situations occur.&lt;br /&gt;
&lt;br /&gt;
In general, such scenarios are easy to demonstrate reliably with the REPEATABLE READ isolation level, but occur rarely and unpredictably in the default READ COMMITTED level.&lt;br /&gt;
&lt;br /&gt;
== TRUNCATE TABLE ==&lt;br /&gt;
&lt;br /&gt;
Using TRUNCATE is a common technique for quickly replacing the contents of a table with new contents from an external source. Due to performance tradeoffs, the table can temporarily appear empty to concurrent transactions.&lt;br /&gt;
&lt;br /&gt;
To avoid this problem, use the &amp;lt;code&amp;gt;DELETE FROM&amp;lt;/code&amp;gt; statement, which has a higher performance and I/O cost.&lt;br /&gt;
&lt;br /&gt;
=== With REPEATABLE READ isolation level ===&lt;br /&gt;
&lt;br /&gt;
This issue is the easiest do demonstrate in the REPEATABLE READ isolation level. Any reading transaction should see either &amp;quot;old data&amp;quot; or &amp;quot;new data&amp;quot; in the table, never an empty table.&lt;br /&gt;
&lt;br /&gt;
Test case:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!colspan=3|Preparation&lt;br /&gt;
|-&lt;br /&gt;
|colspan=3|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
CREATE TABLE a AS SELECT &#039;old data&#039;::text;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! Reading session&lt;br /&gt;
! Writing session&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;BEGIN ISOLATION LEVEL REPEATABLE READ;&lt;br /&gt;
SELECT txid_current(); -- force snapshot allocation&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;BEGIN;&lt;br /&gt;
TRUNCATE TABLE a;&lt;br /&gt;
INSERT INTO a VALUES (&#039;new data&#039;);&lt;br /&gt;
COMMIT;&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;SELECT * FROM a;&lt;br /&gt;
 text &lt;br /&gt;
------&lt;br /&gt;
(0 rows)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== With READ COMMITTED (default) isolation ===&lt;br /&gt;
&lt;br /&gt;
This issue is still present in the default READ COMMITTED isolation level, but more difficult to trigger reliably, because a fresh snapshot is allocated for each new query.&lt;br /&gt;
&lt;br /&gt;
Thanks to Andrew Gierth for pointing out this scenario and Andres Freund for coming up with this test case.&lt;br /&gt;
&lt;br /&gt;
Test case:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!colspan=3|Preparation&lt;br /&gt;
|-&lt;br /&gt;
|colspan=3|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
CREATE TABLE sync(text text);&lt;br /&gt;
CREATE TABLE a AS SELECT &#039;old data&#039;::text;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! Synchronizing session&lt;br /&gt;
! Reading session&lt;br /&gt;
! Writing session&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
PREPARE prep AS&lt;br /&gt;
  SELECT * FROM sync UNION ALL SELECT * FROM a;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
BEGIN;&lt;br /&gt;
LOCK TABLE sync;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
EXECUTE prep;&lt;br /&gt;
-- blocks behind session #1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
BEGIN;&lt;br /&gt;
TRUNCATE TABLE a;&lt;br /&gt;
INSERT INTO a VALUES (&#039;new data&#039;);&lt;br /&gt;
COMMIT;&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;ROLLBACK;&amp;lt;/source&amp;gt;&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
-- session unblocks after #1 rollback&lt;br /&gt;
 text &lt;br /&gt;
------&lt;br /&gt;
(0 rows)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== COPY FREEZE ==&lt;br /&gt;
&lt;br /&gt;
The FREEZE option of the COPY command was introduced in PostgreSQL version 9.3 to avoid expensive vacuum maintenance later on the restored table. In this case, the reading session should see an empty table, since its snapshot started before any rows were inserted (copied).&lt;br /&gt;
&lt;br /&gt;
To avoid this problem, simply don&#039;t use the FREEZE option.&lt;br /&gt;
&lt;br /&gt;
Test case:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!colspan=3|Preparation&lt;br /&gt;
|-&lt;br /&gt;
|colspan=3|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
CREATE TABLE a (text text);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! Reading session&lt;br /&gt;
! Writing session&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;BEGIN ISOLATION LEVEL REPEATABLE READ;&lt;br /&gt;
SELECT txid_current(); -- force snapshot allocation&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
BEGIN;&lt;br /&gt;
TRUNCATE TABLE a;&lt;br /&gt;
COPY a FROM STDIN WITH (FREEZE);&lt;br /&gt;
phantom row&lt;br /&gt;
\.&lt;br /&gt;
COMMIT;&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SELECT * FROM a;&lt;br /&gt;
    text     &lt;br /&gt;
-------------&lt;br /&gt;
 phantom row&lt;br /&gt;
(1 row)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Historic issues ==&lt;br /&gt;
&lt;br /&gt;
* In PostgreSQL 8.2 and earlier, the CLUSTER command could cause DELETEd/UPDATEd rows to disappear for older snapshots.&lt;/div&gt;</summary>
		<author><name>Intgr</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=MVCC_violations&amp;diff=22932</id>
		<title>MVCC violations</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=MVCC_violations&amp;diff=22932"/>
		<updated>2014-08-01T14:24:24Z</updated>

		<summary type="html">&lt;p&gt;Intgr: Add COPY FREEZE test case&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In general, PostgreSQL aims to be strict with ACID transaction semantics. But there are some documented cases that, for performance reasons, violate the MVCC protocol, and thus the atomicity, consistency or isolation properties of ACID transactions. Such instances are sometimes referred to as &amp;quot;MVCC violations&amp;quot;. This page aims to illustrate when such situations occur.&lt;br /&gt;
&lt;br /&gt;
In general, such scenarios are easy to demonstrate reliably with the REPEATABLE READ isolation level, but occur rarely and unpredictably in the default READ COMMITTED level.&lt;br /&gt;
&lt;br /&gt;
== TRUNCATE TABLE ==&lt;br /&gt;
&lt;br /&gt;
Using TRUNCATE is a common technique for quickly replacing the contents of a table with new contents from an external source. Due to performance tradeoffs, the table can temporarily appear empty to concurrent transactions.&lt;br /&gt;
&lt;br /&gt;
To avoid this problem, use the &amp;lt;code&amp;gt;DELETE FROM&amp;lt;/code&amp;gt; statement, which has a higher performance and I/O cost.&lt;br /&gt;
&lt;br /&gt;
=== With REPEATABLE READ isolation level ===&lt;br /&gt;
&lt;br /&gt;
This issue is the easiest do demonstrate in the REPEATABLE READ isolation level. Any reading transaction should see either &amp;quot;old data&amp;quot; or &amp;quot;new data&amp;quot; in the table, never an empty table.&lt;br /&gt;
&lt;br /&gt;
Test case:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!colspan=3|Preparation&lt;br /&gt;
|-&lt;br /&gt;
|colspan=3|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
CREATE TABLE a AS SELECT &#039;old data&#039;::text;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! Reading session&lt;br /&gt;
! Writing session&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;BEGIN ISOLATION LEVEL REPEATABLE READ;&lt;br /&gt;
SELECT txid_current(); -- force snapshot allocation&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;BEGIN;&lt;br /&gt;
TRUNCATE TABLE a;&lt;br /&gt;
INSERT INTO a VALUES (&#039;new data&#039;);&lt;br /&gt;
COMMIT;&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;SELECT * FROM a;&lt;br /&gt;
 text &lt;br /&gt;
------&lt;br /&gt;
(0 rows)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== With READ COMMITTED (default) isolation ===&lt;br /&gt;
&lt;br /&gt;
This issue is still present in the default READ COMMITTED isolation level, but more difficult to trigger reliably, because a fresh snapshot is allocated for each new query.&lt;br /&gt;
&lt;br /&gt;
Thanks to Andrew Gierth for pointing out this scenario and Andres Freund for coming up with this test case.&lt;br /&gt;
&lt;br /&gt;
Test case:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!colspan=3|Preparation&lt;br /&gt;
|-&lt;br /&gt;
|colspan=3|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
CREATE TABLE sync(text text);&lt;br /&gt;
CREATE TABLE a AS SELECT &#039;old data&#039;::text;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! Synchronizing session&lt;br /&gt;
! Reading session&lt;br /&gt;
! Writing session&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
PREPARE prep AS&lt;br /&gt;
  SELECT * FROM sync UNION ALL SELECT * FROM a;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
BEGIN;&lt;br /&gt;
LOCK TABLE sync;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
EXECUTE prep;&lt;br /&gt;
-- blocks behind session #1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
BEGIN;&lt;br /&gt;
TRUNCATE TABLE a;&lt;br /&gt;
INSERT INTO a VALUES (&#039;new data&#039;);&lt;br /&gt;
COMMIT;&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;ROLLBACK;&amp;lt;/source&amp;gt;&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
-- session unblocks after #1 rollback&lt;br /&gt;
 text &lt;br /&gt;
------&lt;br /&gt;
(0 rows)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== COPY FREEZE ==&lt;br /&gt;
&lt;br /&gt;
The FREEZE option of the COPY command was introduced in PostgreSQL version 9.3 to avoid expensive vacuum maintenance later on the restored table. In this case, the reading session should see an empty table, since its snapshot started before any rows were inserted (copied).&lt;br /&gt;
&lt;br /&gt;
To avoid this problem, simply don&#039;t use the FREEZE option.&lt;br /&gt;
&lt;br /&gt;
Test case:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!colspan=3|Preparation&lt;br /&gt;
|-&lt;br /&gt;
|colspan=3|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
CREATE TABLE a (text text);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! Reading session&lt;br /&gt;
! Writing session&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;BEGIN ISOLATION LEVEL REPEATABLE READ;&lt;br /&gt;
SELECT txid_current(); -- force snapshot allocation&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
BEGIN;&lt;br /&gt;
TRUNCATE TABLE a;&lt;br /&gt;
COPY a FROM STDIN WITH (FREEZE);&lt;br /&gt;
phantom row&lt;br /&gt;
\.&lt;br /&gt;
COMMIT;&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SELECT * FROM a;&lt;br /&gt;
    text     &lt;br /&gt;
-------------&lt;br /&gt;
 phantom row&lt;br /&gt;
(1 row)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Intgr</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=MVCC_violations&amp;diff=22931</id>
		<title>MVCC violations</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=MVCC_violations&amp;diff=22931"/>
		<updated>2014-08-01T14:09:16Z</updated>

		<summary type="html">&lt;p&gt;Intgr: Test cases&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In general, PostgreSQL aims to be strict with ACID transaction semantics. But there are some documented cases that, for performance reasons, violate the MVCC protocol, and thus the atomicity, consistency or isolation properties of ACID transactions. Such instances are sometimes referred to as &amp;quot;MVCC violations&amp;quot;. This page aims to illustrate when such situations occur.&lt;br /&gt;
&lt;br /&gt;
In general, such scenarios are easy to demonstrate reliably with the REPEATABLE READ isolation level, but occur rarely and unpredictably in the default READ COMMITTED level.&lt;br /&gt;
&lt;br /&gt;
== TRUNCATE TABLE ==&lt;br /&gt;
&lt;br /&gt;
Using TRUNCATE is a common technique for quickly replacing the contents of a table with new content. Due to performance tradeoffs, the table can temporarily appear empty to concurrent transactions.&lt;br /&gt;
&lt;br /&gt;
To avoid this problem, use the &amp;lt;code&amp;gt;DELETE FROM&amp;lt;/code&amp;gt; statement, which has a higher performance and I/O cost.&lt;br /&gt;
&lt;br /&gt;
=== With REPEATABLE READ isolation level ===&lt;br /&gt;
&lt;br /&gt;
This issue is the easiest do demonstrate in the REPEATABLE READ isolation level. Any reading transaction should see either &amp;quot;old data&amp;quot; or &amp;quot;new data&amp;quot; in the table, never an empty table.&lt;br /&gt;
&lt;br /&gt;
Test case:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!colspan=3|Preparation&lt;br /&gt;
|-&lt;br /&gt;
|colspan=3|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
CREATE TABLE a AS SELECT &#039;old data&#039;::text;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! Reading session&lt;br /&gt;
! Writing session&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;BEGIN ISOLATION LEVEL REPEATABLE READ;&lt;br /&gt;
SELECT txid_current(); -- force snapshot allocation&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;BEGIN;&lt;br /&gt;
TRUNCATE TABLE a;&lt;br /&gt;
INSERT INTO a VALUES (&#039;new data&#039;);&lt;br /&gt;
COMMIT;&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;SELECT * FROM a;&lt;br /&gt;
 text &lt;br /&gt;
------&lt;br /&gt;
(0 rows)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== With READ COMMITTED (default) isolation ===&lt;br /&gt;
&lt;br /&gt;
This issue is still present in the default READ COMMITTED isolation level, but more difficult to trigger reliably, because a fresh snapshot is allocated for each new query.&lt;br /&gt;
&lt;br /&gt;
Thanks to Andrew Gierth for pointing out this scenario and Andres Freund for coming up with this test case.&lt;br /&gt;
&lt;br /&gt;
Test case:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!colspan=3|Preparation&lt;br /&gt;
|-&lt;br /&gt;
|colspan=3|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
CREATE TABLE sync(text text);&lt;br /&gt;
CREATE TABLE a AS SELECT &#039;old data&#039;::text;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! Synchronizing session&lt;br /&gt;
! Reading session&lt;br /&gt;
! Writing session&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
PREPARE prep AS&lt;br /&gt;
  SELECT * FROM sync UNION ALL SELECT * FROM a;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
BEGIN;&lt;br /&gt;
LOCK TABLE sync;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
EXECUTE prep;&lt;br /&gt;
-- blocks behind session #1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
BEGIN;&lt;br /&gt;
TRUNCATE TABLE a;&lt;br /&gt;
INSERT INTO a VALUES (&#039;new data&#039;);&lt;br /&gt;
COMMIT;&amp;lt;/source&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;ROLLBACK;&amp;lt;/source&amp;gt;&lt;br /&gt;
| &amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
-- session unblocks after #1 rollback&lt;br /&gt;
 text &lt;br /&gt;
------&lt;br /&gt;
(0 rows)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Intgr</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=MVCC_violations&amp;diff=22929</id>
		<title>MVCC violations</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=MVCC_violations&amp;diff=22929"/>
		<updated>2014-08-01T13:35:32Z</updated>

		<summary type="html">&lt;p&gt;Intgr: Created page with &amp;quot;In general, PostgreSQL aims to be strict with ACID transaction semantics. But there are some documented cases that, for performance reasons, violate the MVCC protocol, and thu...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In general, PostgreSQL aims to be strict with ACID transaction semantics. But there are some documented cases that, for performance reasons, violate the MVCC protocol, and thus the atomicity, consistency or isolation properties of ACID transactions. Such instances are sometimes referred to as &amp;quot;MVCC violations&amp;quot;. This page aims to illustrate when such situations occur.&lt;br /&gt;
&lt;br /&gt;
==TRUNCATE TABLE==&lt;br /&gt;
&lt;br /&gt;
Using TRUNCATE is a common technique for quickly replacing the contents of a table with new content. Due to performance tradeoffs, the table can temporarily appear empty to concurrent transactions.&lt;br /&gt;
&lt;br /&gt;
=== In REPEATABLE READ isolation level ===&lt;br /&gt;
&lt;br /&gt;
This issue is the easiest do demonstrate in the REPEATABLE READ isolation level:&lt;br /&gt;
&lt;br /&gt;
[Work in progress]&lt;/div&gt;</summary>
		<author><name>Intgr</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=What%27s_new_in_PostgreSQL_9.4&amp;diff=22426</id>
		<title>What&#039;s new in PostgreSQL 9.4</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=What%27s_new_in_PostgreSQL_9.4&amp;diff=22426"/>
		<updated>2014-05-22T17:24:14Z</updated>

		<summary type="html">&lt;p&gt;Intgr: correct plural&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page contains an overview of PostgreSQL Version 9.4&#039;s features, including descriptions, testing and usage information, and links to blog posts containing further information. See also [[PostgreSQL 9.4 Open Items]].&lt;br /&gt;
&lt;br /&gt;
=Major new features=&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Replication improvements==&lt;br /&gt;
&lt;br /&gt;
===Replication slots &amp;lt;!-- Andres Freund and Robert Haas --&amp;gt;===&lt;br /&gt;
&lt;br /&gt;
TODO: Blog posts, redundancy of wal_keep_segments et al.&lt;br /&gt;
&lt;br /&gt;
Replication slots allow standbys to provide information to the primary or upstream cascading standby as to the point they&#039;ve reached in the write-ahead log.  This information is available to the primary even when the standby is offline or disconnected.  This eliminates the need for wal_keep_segments, which required the admin to estimate how many extra WAL files would be needed to be kept around in order to ensure supply to the standby in case of excessive replication lag.&lt;br /&gt;
&lt;br /&gt;
Here is an example:&lt;br /&gt;
&lt;br /&gt;
On the primary server, set max_replication_slots to allow the standby to register to a slot:&lt;br /&gt;
&lt;br /&gt;
  max_replication_slots = 1&lt;br /&gt;
&lt;br /&gt;
The wal_level will also need to be set to at least &amp;quot;archive&amp;quot;, but as this example will be using a hot standby, we&#039;ll set it to &amp;quot;hot_standby&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
  wal_level = hot_standby&lt;br /&gt;
&lt;br /&gt;
Restart the primary for these settings to take effect, then connect to the primary and create a replication slot:&lt;br /&gt;
&lt;br /&gt;
  SELECT * FROM pg_create_physical_replication_slot(&#039;standby_replication_slot&#039;);&lt;br /&gt;
&lt;br /&gt;
A standby can then use this replication slot by specifying it as the primary_slotname parameter in its recovery.conf:&lt;br /&gt;
&lt;br /&gt;
  primary_slotname = &#039;standby_replication_slot&#039;&lt;br /&gt;
&lt;br /&gt;
On the primary, you can see this being used:&lt;br /&gt;
&lt;br /&gt;
  postgres=# SELECT * FROM pg_replication_slots;&lt;br /&gt;
         slot_name       | plugin | slot_type | datoid | database | active | xmin | catalog_xmin | restart_lsn &lt;br /&gt;
  -----------------------+--------+-----------+--------+----------+--------+------+--------------+-------------&lt;br /&gt;
   standby_physical_slot |        | physical  |        |          | t      |      |              | 0/3000420&lt;br /&gt;
  (1 row)&lt;br /&gt;
&lt;br /&gt;
Now the primary will keep hold of WAL for as along as it needs to, which is until all standbys have reported that they have progressed beyond that point.  Note, however, that if a standby goes offline, and the replication slow isn&#039;t dropped, WAL will build up on the primary.  So if a standby needs to be decommissioned, it&#039;s slot should then be dropped like so:&lt;br /&gt;
&lt;br /&gt;
  # SELECT pg_drop_replication_slot(&#039;standby_replication_slot&#039;);&lt;br /&gt;
   pg_drop_replication_slot &lt;br /&gt;
  --------------------------&lt;br /&gt;
   &lt;br /&gt;
  (1 row)&lt;br /&gt;
&lt;br /&gt;
Otherwise, ensure there is enough disk capacity available to keep WAL on the primary until the standby returns.&lt;br /&gt;
&lt;br /&gt;
In future logical replication will also take advantage of replication slots.&lt;br /&gt;
&lt;br /&gt;
==Logical decoding &amp;lt;!-- Andres Freund, Robert Haas, Álvaro Herrera, Abhijit Menon-Sen, Peter Geoghegan, Kevin Grittner, Robert Haas, Heikki Linnakangas, Fujii Masao, Abhijit Menon-Sen, Michael Paquier, Simon Riggs, Craig Ringer, and Steve Singer --&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
TODO: Blog posts, explanation of what it&#039;s the groundwork for&lt;br /&gt;
&lt;br /&gt;
==Performance improvements==&lt;br /&gt;
&lt;br /&gt;
===GIN indexes now faster and smaller &amp;lt;!-- Alexander Korotkov, Heikki Linnakangas --&amp;gt;===&lt;br /&gt;
&lt;br /&gt;
TODO: Blog posts, benchmark results&lt;br /&gt;
&lt;br /&gt;
===pg_prewarm===&lt;br /&gt;
&lt;br /&gt;
When a database instance is restarted, its shared buffers are empty again, which means all queries will initially have to read data in direct from disk.  pg_prewarm can load relation data back into the buffers to &amp;quot;warm&amp;quot; the buffers back up again.  This will mean that queries, that would otherwise have to load parts of a table in bit by bit, can have the data available in shared buffers ready for them.&lt;br /&gt;
&lt;br /&gt;
TODO: Example&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Other new features=&lt;br /&gt;
&lt;br /&gt;
==ALTER SYSTEM==&lt;br /&gt;
&lt;br /&gt;
Normally, cluster-wide settings need to be edited in the postgresql.conf, but now changes can be made via the ALTER SYSTEM command.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
  postgres=# ALTER SYSTEM SET log_min_duration_statement = &#039;5s&#039;;&lt;br /&gt;
&lt;br /&gt;
This doesn&#039;t actually change postgresql.conf.  Instead it writes the setting to a file called postgresql.auto.conf.  This file &#039;&#039;&#039;*always*&#039;&#039;&#039; gets read last, so it will always override any settings in postgresql.conf.  Setting it to DEFAULT removes the line from postgresql.auto.conf:&lt;br /&gt;
&lt;br /&gt;
  postgres=# ALTER SYSTEM SET log_min_duration_statement = DEFAULT;&lt;br /&gt;
&lt;br /&gt;
An advantage of making changes this way is that the settings are more likely to be correct as they are validated before they are added:&lt;br /&gt;
&lt;br /&gt;
  postgres=# ALTER SYSTEM SET wal_level = &#039;like the legend of the phoenix&#039;;&lt;br /&gt;
  ERROR:  invalid value for parameter &amp;quot;wal_level&amp;quot;: &amp;quot;like the legend of the phoenix&amp;quot;&lt;br /&gt;
  HINT:  Available values: minimal, archive, hot_standby, logical.&lt;br /&gt;
&lt;br /&gt;
If this had been set in postgresql.conf instead, and someone attempted to restart the cluster, it would fail.  Naturally postgresql.auto.conf should never be edited manually.&lt;br /&gt;
&lt;br /&gt;
==REFRESH MATERIALIZED VIEW CONCURRENTLY==&lt;br /&gt;
&lt;br /&gt;
Prior to PostgreSQL 9.4, refreshing a materialized view meant locking the entire table, and therefore preventing anything querying it, and if a refresh took a long time to acquire the exclusive lock (while it waits for queries using it to finish), it in turn is holding up subsequent queries.  This can now been mitigated with the CONCURRENTLY keyword:&lt;br /&gt;
&lt;br /&gt;
  postgres=# REFRESH MATERIALIZED VIEW CONCURRENTLY mv_data;&lt;br /&gt;
&lt;br /&gt;
A unique index will need to exist on the materialized view though.  Instead of locking the materialized view up, it instead creates a temporary updated version of it, compares the two versions, then applies INSERTs and DELETEs against the materialized view to apply the difference.  This means queries can still use the materialized view while it&#039;s being updated.&lt;br /&gt;
&lt;br /&gt;
Unlike its non-concurrent form, tuples aren&#039;t frozen, and it needs VACUUMing due to the aforementioned DELETEs that will leave dead tuples behind.&lt;br /&gt;
&lt;br /&gt;
==WITH ORDINALITY==&lt;br /&gt;
&lt;br /&gt;
Set-returning functions are most frequently used in the FROM clause of a query, and now if it&#039;s suffixed with WITH ORDINALITY, a column containing an ordered sequence of numbers is added.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&lt;br /&gt;
  postgres=# SELECT * FROM json_object_keys(&#039;{&amp;quot;mobile&amp;quot;: 4234234232, &amp;quot;email&amp;quot;: &amp;quot;x@me.com&amp;quot;, &amp;quot;address&amp;quot;: &amp;quot;1 Street Lane&amp;quot;}&#039;::json) WITH ORDINALITY;&lt;br /&gt;
   json_object_keys | ordinality &lt;br /&gt;
  ------------------+------------&lt;br /&gt;
   mobile           |          1&lt;br /&gt;
   email            |          2&lt;br /&gt;
   address          |          3&lt;br /&gt;
  (3 rows)&lt;br /&gt;
&lt;br /&gt;
==Ordered-set aggregates==&lt;br /&gt;
&lt;br /&gt;
There is now support for ordered-set aggregates which provide order-sensitive information on columns.  One example is the mode average:&lt;br /&gt;
&lt;br /&gt;
  postgres=# SELECT mode() WITHIN GROUP (ORDER BY eye_colour) FROM population;&lt;br /&gt;
   mode  &lt;br /&gt;
  -------&lt;br /&gt;
   brown&lt;br /&gt;
  (1 row)&lt;br /&gt;
&lt;br /&gt;
Or get the value of a column the specified percentage in, such as 20%&lt;br /&gt;
&lt;br /&gt;
  postgres=# SELECT percentile_disc(0.2) WITHIN GROUP (ORDER BY age) FROM population;&lt;br /&gt;
   percentile_disc &lt;br /&gt;
  -----------------&lt;br /&gt;
                31&lt;br /&gt;
  (1 row)&lt;br /&gt;
&lt;br /&gt;
=Backwards compatibility=&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:PostgreSQL_9.4]]&lt;br /&gt;
[[Category:What&#039;s_new_in_this_release]]&lt;/div&gt;</summary>
		<author><name>Intgr</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=Index_Maintenance&amp;diff=22048</id>
		<title>Index Maintenance</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=Index_Maintenance&amp;diff=22048"/>
		<updated>2014-04-02T12:23:31Z</updated>

		<summary type="html">&lt;p&gt;Intgr: Change &amp;quot;unique&amp;quot; column to be per-index not per-relation. The current &amp;quot;unique&amp;quot; column tells you whether the table has any unique indexes at all, which is not very useful in this query&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;One day, you will probably need to cope with [http://www.postgresql.org/docs/current/static/routine-reindex.html routine reindexing] on your database, particularly if you don&#039;t use VACUUM aggressively enough.  A particularly handy command in this area is [http://www.postgresql.org/docs/8.3/static/sql-cluster.html CLUSTER], which can help with other types of cleanup.&lt;br /&gt;
&lt;br /&gt;
Avoid using [[VACUUM FULL]] in versions 8.4 and earlier.&lt;br /&gt;
&lt;br /&gt;
== Index summary ==&lt;br /&gt;
&lt;br /&gt;
Here&#039;s a sample query to pull the number of rows, indexes, and some info about those indexes for each table.  (Only works on 8.3; ditch the pg_size_pretty if you’re on an earlier version)&lt;br /&gt;
&lt;br /&gt;
{{SnippetInfo|Index summary|lang=SQL|version=&amp;gt;=8.1|category=Performance}}&lt;br /&gt;
&amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SELECT&lt;br /&gt;
    pg_class.relname,&lt;br /&gt;
    pg_size_pretty(pg_class.reltuples::bigint) AS rows_in_bytes,&lt;br /&gt;
    pg_class.reltuples AS num_rows,&lt;br /&gt;
    count(indexname) AS number_of_indexes,&lt;br /&gt;
    CASE WHEN x.is_unique = 1 THEN &#039;Y&#039;&lt;br /&gt;
       ELSE &#039;N&#039;&lt;br /&gt;
    END AS UNIQUE,&lt;br /&gt;
    SUM(case WHEN number_of_columns = 1 THEN 1&lt;br /&gt;
              ELSE 0&lt;br /&gt;
            END) AS single_column,&lt;br /&gt;
    SUM(case WHEN number_of_columns IS NULL THEN 0&lt;br /&gt;
             WHEN number_of_columns = 1 THEN 0&lt;br /&gt;
             ELSE 1&lt;br /&gt;
           END) AS multi_column&lt;br /&gt;
FROM pg_namespace &lt;br /&gt;
LEFT OUTER JOIN pg_class ON pg_namespace.oid = pg_class.relnamespace&lt;br /&gt;
LEFT OUTER JOIN&lt;br /&gt;
       (SELECT indrelid,&lt;br /&gt;
           max(CAST(indisunique AS integer)) AS is_unique&lt;br /&gt;
       FROM pg_index&lt;br /&gt;
       GROUP BY indrelid) x&lt;br /&gt;
       ON pg_class.oid = x.indrelid&lt;br /&gt;
LEFT OUTER JOIN&lt;br /&gt;
    ( SELECT c.relname AS ctablename, ipg.relname AS indexname, x.indnatts AS number_of_columns FROM pg_index x&lt;br /&gt;
           JOIN pg_class c ON c.oid = x.indrelid&lt;br /&gt;
           JOIN pg_class ipg ON ipg.oid = x.indexrelid  )&lt;br /&gt;
    AS foo&lt;br /&gt;
    ON pg_class.relname = foo.ctablename&lt;br /&gt;
WHERE &lt;br /&gt;
     pg_namespace.nspname=&#039;public&#039;&lt;br /&gt;
AND  pg_class.relkind = &#039;r&#039;&lt;br /&gt;
GROUP BY pg_class.relname, pg_class.reltuples, x.is_unique&lt;br /&gt;
ORDER BY 2;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Index size/usage statistics ==&lt;br /&gt;
&lt;br /&gt;
Table &amp;amp; index sizes along which indexes are being scanned and how many tuples are fetched.  See [[Disk Usage]] for another view that includes both table and index sizes.&lt;br /&gt;
&lt;br /&gt;
{{SnippetInfo|Index statistics|lang=SQL|version=&amp;gt;=8.1|category=Performance}}&lt;br /&gt;
&amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SELECT&lt;br /&gt;
    t.tablename,&lt;br /&gt;
    indexname,&lt;br /&gt;
    c.reltuples AS num_rows,&lt;br /&gt;
    pg_size_pretty(pg_relation_size(quote_ident(t.tablename)::text)) AS table_size,&lt;br /&gt;
    pg_size_pretty(pg_relation_size(quote_ident(indexrelname)::text)) AS index_size,&lt;br /&gt;
    CASE WHEN indisunique THEN &#039;Y&#039;&lt;br /&gt;
       ELSE &#039;N&#039;&lt;br /&gt;
    END AS unique,&lt;br /&gt;
    idx_scan AS number_of_scans,&lt;br /&gt;
    idx_tup_read AS tuples_read,&lt;br /&gt;
    idx_tup_fetch AS tuples_fetched&lt;br /&gt;
FROM pg_tables t&lt;br /&gt;
LEFT OUTER JOIN pg_class c ON t.tablename=c.relname&lt;br /&gt;
LEFT OUTER JOIN&lt;br /&gt;
    ( SELECT c.relname as ctablename, ipg.relname as indexname, x.indnatts as number_of_columns, idx_scan, idx_tup_read, idx_tup_fetch, indexrelname, indisunique FROM pg_index x&lt;br /&gt;
           JOIN pg_class c ON c.oid = x.indrelid&lt;br /&gt;
           JOIN pg_class ipg ON ipg.oid = x.indexrelid&lt;br /&gt;
           JOIN pg_stat_all_indexes psai ON x.indexrelid = psai.indexrelid )&lt;br /&gt;
    as foo&lt;br /&gt;
    ON t.tablename = foo.ctablename&lt;br /&gt;
WHERE t.schemaname=&#039;public&#039;&lt;br /&gt;
order by 1,2;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Duplicate indexes ==&lt;br /&gt;
Finds multiple indexes that have the same set of columns, same opclass, expression and predicate -- which make them equivalent. &#039;&#039;&#039;Usually&#039;&#039;&#039; it&#039;s safe to drop one of them, but I give no guarantees. :)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SELECT pg_size_pretty(sum(pg_relation_size(idx))::bigint) as size,&lt;br /&gt;
       (array_agg(idx))[1] as idx1, (array_agg(idx))[2] as idx2,&lt;br /&gt;
       (array_agg(idx))[3] as idx3, (array_agg(idx))[4] as idx4&lt;br /&gt;
FROM (&lt;br /&gt;
    SELECT indexrelid::regclass as idx, (indrelid::text ||E&#039;\n&#039;|| indclass::text ||E&#039;\n&#039;|| indkey::text ||E&#039;\n&#039;||&lt;br /&gt;
                                         coalesce(indexprs::text,&#039;&#039;)||E&#039;\n&#039; || coalesce(indpred::text,&#039;&#039;)) as key&lt;br /&gt;
    FROM pg_index) sub&lt;br /&gt;
GROUP BY key HAVING count(*)&amp;gt;1&lt;br /&gt;
ORDER BY sum(pg_relation_size(idx)) DESC;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Index Bloat ==&lt;br /&gt;
&lt;br /&gt;
One of the common needs for a REINDEX is when indexes become bloated due to either sparse deletions or use of VACUUM FULL.  An estimator for the amount of bloat in a table has been included in the [http://bucardo.org/wiki/Check_postgres check_postgres] script, which you can call directly or incorporate into a larger monitoring system.  Scripts based on this code and/or its concepts from other sources include:&lt;br /&gt;
* [http://pgsql.tapoueh.org/site/html/news/20080131.bloat.html bloat view] (Dimitri Fontaine)&lt;br /&gt;
* [http://www.pgcon.org/2009/schedule/events/153.en.html Visualizing Postgres] - index_byte_sizes view (Michael Glaesemann, myYearbook)&lt;br /&gt;
* [http://labs.omniti.com/trac/pgtreats/browser/trunk/tools OmniTI Tasty Treats for PostgreSQL] - shell and Perl pg_bloat_report scripts&lt;br /&gt;
&lt;br /&gt;
== Unused Indexes ==&lt;br /&gt;
&lt;br /&gt;
Since indexes add significant overhead to any table change operation, they should be removed if they are not being used for either queries or constraint enforcement (such as making sure a value is unique).  How to find such indexes:&lt;br /&gt;
&lt;br /&gt;
* [http://www.xzilla.net/blog/2008/Jul/Index-pruning-techniques.html Index pruning techniques]&lt;br /&gt;
* [http://hype-free.blogspot.com/2008/09/finding-unused-indexes-in-postgresql.html Finding unused indexes]&lt;br /&gt;
* [http://it.toolbox.com/blogs/database-soup/finding-useless-indexes-28796 Finding useless indexes]&lt;br /&gt;
* [http://jmorano.moretrix.com/2014/02/postgresql-monitor-unused-indexes/ &#039;Monitor unused indexes&#039; by Johnny Morano]&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&lt;br /&gt;
* Index statistics queries from [http://www.baconandtech.com/2009/06/06/book-review-part-i-refactoring-sql-applications-with-bonus-queries/ &amp;quot;Refactoring SQL Applications&amp;quot; review]&lt;br /&gt;
&lt;br /&gt;
[[Category:Administration]][[Category:Performance]]&lt;/div&gt;</summary>
		<author><name>Intgr</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=Performance_Optimization&amp;diff=21829</id>
		<title>Performance Optimization</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=Performance_Optimization&amp;diff=21829"/>
		<updated>2014-02-12T10:15:49Z</updated>

		<summary type="html">&lt;p&gt;Intgr: This article is obsolete; talks about Postgres 8.2 and manual VACUUMing. Most other articles cover shared_buffers and effective_cache_size anyway&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== General Setup and Optimization ==&lt;br /&gt;
* [[Tuning Your PostgreSQL Server]] by Greg Smith, Robert Treat, and Christopher Browne&lt;br /&gt;
* [http://www.revsys.com/writings/postgresql-performance.html Performance Tuning PostgreSQL] by Frank Wiles&lt;br /&gt;
* [http://www.pgcon.org/2008/schedule/events/104.en.html GUCs: A Three Hour Tour] by Josh Berkus.  Also useful here is his [http://pgfoundry.org/docman/view.php/1000106/84/calcfactors.sxc tuning OpenOffice spreadsheet], which suggests tuning values for 5 different types of workloads. &lt;br /&gt;
* [http://linuxfinances.info/info/quickstart.html QuickStart Guide to Tuning  PostgreSQL] by Christopher Browne&lt;br /&gt;
* [http://www.varlena.com/GeneralBits/Tidbits/annotated_conf_e.html Annotated postgresql.conf] by Josh Berkus and Shridhar Daithankar (older V7.4 targeted version of material covered in the GUC tour referenced above)&lt;br /&gt;
* [http://www.varlena.com/GeneralBits/Tidbits/perf.html Performance Tuning] by Josh Berkus and Shridhar Daithankar&lt;br /&gt;
* [http://www.zope.org/Members/pupq/pg_in_aggregates Replacing Slow Loops in PostgreSQL] by Joel Burton&lt;br /&gt;
* [http://momjian.us/main/writings/pgsql/hw_performance/ PostgreSQL Hardware Performance Tuning] by Bruce Momjian&lt;br /&gt;
* [http://www.targeted.org/articles/databases/fragmentation.html The effects of data fragmentation in a mixed load database] by Dmitry Dvoinikov&lt;br /&gt;
* [http://www.2ndquadrant.com/static/2quad/media/pdfs/talks/Postgres_Performance_Update83.pdf PostgreSQL Performance Features in 8.3] by Simon Riggs&lt;br /&gt;
* [http://www.2ndquadrant.com/static/2quad/media/pdfs/talks/Postgres_Performance_Update84.pdf PostgreSQL Performance Features in 8.4] by Simon Riggs&lt;br /&gt;
&lt;br /&gt;
Performance courses are available from a number of companies. Check [http://www.postgresql.org/about/eventarchive events and trainings] for further details.&lt;br /&gt;
&lt;br /&gt;
==Critical maintenance for performance==&lt;br /&gt;
*[[Introduction to VACUUM, ANALYZE, EXPLAIN, and COUNT]] by Jim Nasby.&lt;br /&gt;
*[[VACUUM FULL]] and why you should avoid it&lt;br /&gt;
*[[Planner Statistics]]&lt;br /&gt;
*[[Using EXPLAIN]]&lt;br /&gt;
*[[Logging Difficult Queries]]&lt;br /&gt;
*[[Logging Checkpoints]]&lt;br /&gt;
*[http://www.westnet.com/~gsmith/content/postgresql/chkp-bgw-83.htm Checkpoints and the Background Writer:  PostgreSQL 8.3 Improvements and Migration] by Greg Smith&lt;br /&gt;
*[[Bulk Loading and Restores]]&lt;br /&gt;
*[[Performance Analysis Tools]] by Craig Ringer&lt;br /&gt;
&lt;br /&gt;
== Database architecture ==&lt;br /&gt;
* [[Priorities|Limiting and prioritizing user/query/database resource usage]] by Craig Ringer&lt;br /&gt;
* [[Prioritizing databases by separating into multiple clusters]] by Craig Ringer&lt;br /&gt;
* [[Clustering]]&lt;br /&gt;
* [[Shared Storage]]&lt;br /&gt;
&lt;br /&gt;
==Database Hardware Selection and Setup==&lt;br /&gt;
* [[Database Hardware]]&lt;br /&gt;
* [[Reliable Writes]]&lt;br /&gt;
&lt;br /&gt;
==Benchmark Workloads== &lt;br /&gt;
* [[:Category:Benchmarking]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Administration]][[Category:Performance]][[Category:Benchmarking]]&lt;br /&gt;
[[Category:General articles and guides]]&lt;/div&gt;</summary>
		<author><name>Intgr</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=Streaming_Replication&amp;diff=20610</id>
		<title>Streaming Replication</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=Streaming_Replication&amp;diff=20610"/>
		<updated>2013-08-14T12:41:23Z</updated>

		<summary type="html">&lt;p&gt;Intgr: It&amp;#039;s extremely crazy to grant superuser access with &amp;quot;trust&amp;quot; method, and isn&amp;#039;t required in 9.1+ versions&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Streaming Replication&#039;&#039;&#039; (SR) provides the capability to continuously ship and&lt;br /&gt;
apply the [http://www.postgresql.org/docs/current/static/wal.html WAL XLOG] records to some number of standby servers in order to keep them current.&lt;br /&gt;
&lt;br /&gt;
This feature was added to PostgreSQL 9.0.  The discussion below is a developer oriented one that contains some out of date information.  Users of this feature should use the documentation for the feature or a setup tutorial instead:&lt;br /&gt;
&lt;br /&gt;
* [http://www.postgresql.org/docs/current/static/warm-standby.html PostgreSQL Streaming Replication Documentation] - this documentation is for the latest version, but provides links you can use to look up the docs for your version.&lt;br /&gt;
&lt;br /&gt;
* [[Binary Replication Tutorial]] provides an introduction to using this replication feature.&lt;br /&gt;
&lt;br /&gt;
* The related but independent [[Hot Standby]] feature.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Developer and historical details on the project =&lt;br /&gt;
SR was developed for inclusion in PostgreSQL 9.0 by NTT OSS Center. The lead developer is [mailto:masao.fujii@gmail.com Masao Fujii].  [http://www.pgcon.org/2008/schedule/events/76.en.html Synchronous Log Shipping Replication Presentation] introduces the early design of the feature.&lt;br /&gt;
&lt;br /&gt;
= Usage =&lt;br /&gt;
== Users Overview ==&lt;br /&gt;
* &#039;&#039;&#039;Log-shipping&#039;&#039;&#039;&lt;br /&gt;
** XLOG records generated in the primary are periodically shipped to the standby via the network.&lt;br /&gt;
** In the existing warm standby, only records in a filled file are shipped, what&#039;s referred to as file-based log-shipping.  In SR, XLOG records in partially-filled XLOG file are shipped too, implementing record-based log-shipping.  This means the window for data loss in SR is usually smaller than in warm standby, unless the warm standby was also configured for record-based shipping (which is complicated to setup).&lt;br /&gt;
** The content of XLOG files written to the standby are exactly the same as those on the primary. XLOG files shipped can be used for a normal recovery and PITR.&lt;br /&gt;
* &#039;&#039;&#039;Multiple standbys&#039;&#039;&#039;&lt;br /&gt;
** More than one standby can establish a connection to the primary for SR. XLOG records are concurrently shipped to all these standbys. The delay/death of a standby does not harm log-shipping to other standbys.&lt;br /&gt;
** The maximum number of standbys can be specified as a GUC variable.&lt;br /&gt;
* &#039;&#039;&#039;Continuous recovery&#039;&#039;&#039;&lt;br /&gt;
** The standby continuously replays XLOG records shipped without using pg_standby.&lt;br /&gt;
** XLOG records shipped are replayed as soon as possible without waiting until XLOG file has been filled. The combination of [[Hot Standby]] and SR would make the latest data inserted into the primary visible in the standby almost immediately.&lt;br /&gt;
** The standby periodically removes old XLOG files which are no longer needed for recovery, to prevent excessive disk usage.&lt;br /&gt;
* &#039;&#039;&#039;Setup&#039;&#039;&#039;&lt;br /&gt;
** The start of log-shipping does not interfere with any query processing on the primary.&lt;br /&gt;
** The standby can be started in various conditions.&lt;br /&gt;
*** If there are XLOG files in archive directory and restore_command is supplied, at first those files are replayed. Then the standby requests XLOG records following the last applied one to the primary. This prevents XLOG files already present in the standby from being shipped again. Similarly, XLOG files in pg_xlog are also replayed before starting log-shipping.&lt;br /&gt;
*** If there is no XLOG files on the standby, the standby requests XLOG records following the starting XLOG location of recovery (the redo starting location).&lt;br /&gt;
* &#039;&#039;&#039;Connection settings and authentication&#039;&#039;&#039;&lt;br /&gt;
** A user can configure the same settings as a normal connection to a connection for SR (e.g., keepalive, pg_hba.conf).&lt;br /&gt;
* &#039;&#039;&#039;Activation&#039;&#039;&#039;&lt;br /&gt;
** The standby can keep waiting for activation as long as a user likes. This prevents the standby from being automatically brought up by failure of recovery or network outage.&lt;br /&gt;
* &#039;&#039;&#039;Progress report&#039;&#039;&#039;&lt;br /&gt;
** The primary and standby report the progress of log-shipping in PS display.&lt;br /&gt;
* &#039;&#039;&#039;Graceful shutdown&#039;&#039;&#039;&lt;br /&gt;
** When smart/fast shutdown is requested, the primary waits to exit until XLOG records have been sent to the standby, up to the shutdown checkpoint record.&lt;br /&gt;
&lt;br /&gt;
== Restrictions ==&lt;br /&gt;
* &#039;&#039;&#039;Synchronous log-shipping&#039;&#039;&#039;&lt;br /&gt;
** By default, SR supports operates in asynchronous manner, so the commit command might return a &amp;quot;success&amp;quot; to a client before the corresponding XLOG records are shipped to the standby. To enable synchronous replication, see [http://www.postgresql.org/docs/current/static/warm-standby.html#SYNCHRONOUS-REPLICATION Synchronous Replication]&lt;br /&gt;
* &#039;&#039;&#039;Replication beyond timeline&#039;&#039;&#039;&lt;br /&gt;
** A user has to get a fresh backup whenever making the old standby catch up.&lt;br /&gt;
* &#039;&#039;&#039;Clustering&#039;&#039;&#039;&lt;br /&gt;
** Postgres doesn&#039;t provide any clustering feature.&lt;br /&gt;
&lt;br /&gt;
== How to Use ==&lt;br /&gt;
* &#039;&#039;&#039;1.&#039;&#039;&#039; Install postgres in the primary and standby server as usual.  This requires only &#039;&#039;configure&#039;&#039;, &#039;&#039;make&#039;&#039; and &#039;&#039;make install&#039;&#039;.&lt;br /&gt;
* &#039;&#039;&#039;2.&#039;&#039;&#039; Create the initial database cluster in the primary server as usual, using &#039;&#039;initdb&#039;&#039;.&lt;br /&gt;
* &#039;&#039;&#039;3.&#039;&#039;&#039; Set up connections and authentication so that the standby server can successfully connect to the &#039;&#039;replication&#039;&#039; pseudo-database on the primary.&lt;br /&gt;
 $ $EDITOR postgresql.conf&lt;br /&gt;
 &lt;br /&gt;
 listen_addresses = &#039;192.168.0.10&#039;&lt;br /&gt;
 &lt;br /&gt;
 $ $EDITOR pg_hba.conf&lt;br /&gt;
 &lt;br /&gt;
 # The standby server must connect with a user that has replication privileges.&lt;br /&gt;
 host  replication  replication  192.168.0.20/22  trust&lt;br /&gt;
* &#039;&#039;&#039;4.&#039;&#039;&#039; Set up the streaming replication related parameters on the primary server.&lt;br /&gt;
 $ $EDITOR postgresql.conf&lt;br /&gt;
 &lt;br /&gt;
 # To enable read-only queries on a standby server, wal_level must be set to&lt;br /&gt;
 # &amp;quot;hot_standby&amp;quot;. But you can choose &amp;quot;archive&amp;quot; if you never connect to the&lt;br /&gt;
 # server in standby mode.&lt;br /&gt;
 wal_level = hot_standby&lt;br /&gt;
 &lt;br /&gt;
 # Set the maximum number of concurrent connections from the standby servers.&lt;br /&gt;
 max_wal_senders = 5&lt;br /&gt;
 &lt;br /&gt;
 # To prevent the primary server from removing the WAL segments required for&lt;br /&gt;
 # the standby server before shipping them, set the minimum number of segments&lt;br /&gt;
 # retained in the pg_xlog directory. At least wal_keep_segments should be&lt;br /&gt;
 # larger than the number of segments generated between the beginning of&lt;br /&gt;
 # online-backup and the startup of streaming replication. If you enable WAL&lt;br /&gt;
 # archiving to an archive directory accessible from the standby, this may&lt;br /&gt;
 # not be necessary.&lt;br /&gt;
 wal_keep_segments = 32&lt;br /&gt;
 &lt;br /&gt;
 # Enable WAL archiving on the primary to an archive directory accessible from&lt;br /&gt;
 # the standby. If wal_keep_segments is a high enough number to retain the WAL&lt;br /&gt;
 # segments required for the standby server, this is not necessary.&lt;br /&gt;
 archive_mode    = on&lt;br /&gt;
 archive_command = &#039;cp %p /path_to/archive/%f&#039;&lt;br /&gt;
* &#039;&#039;&#039;5.&#039;&#039;&#039; Start postgres on the primary server.&lt;br /&gt;
* &#039;&#039;&#039;6.&#039;&#039;&#039; Make a base backup by copying the primary server&#039;s data directory to the standby server.&lt;br /&gt;
 $ psql -c &amp;quot;SELECT pg_start_backup(&#039;label&#039;, true)&amp;quot;&lt;br /&gt;
 $ rsync -ac ${PGDATA}/ standby:/srv/pgsql/standby/ --exclude postmaster.pid&lt;br /&gt;
 $ psql -c &amp;quot;SELECT pg_stop_backup()&amp;quot;&lt;br /&gt;
* &#039;&#039;&#039;7.&#039;&#039;&#039; Set up replication-related parameters, connections and authentication in the standby server like the primary, so that the standby might work as a primary after failover.&lt;br /&gt;
* &#039;&#039;&#039;8.&#039;&#039;&#039; Enable read-only queries on the standby server. But if wal_level is &#039;&#039;archive&#039;&#039; on the primary, leave hot_standby unchanged (i.e., off).&lt;br /&gt;
 $ $EDITOR postgresql.conf&lt;br /&gt;
 &lt;br /&gt;
 hot_standby = on&lt;br /&gt;
* &#039;&#039;&#039;9.&#039;&#039;&#039; Create a recovery command file in the standby server; the following parameters are required for streaming replication.&lt;br /&gt;
 $ $EDITOR recovery.conf&lt;br /&gt;
 # Note that recovery.conf must be in $PGDATA directory.&lt;br /&gt;
 &lt;br /&gt;
 # Specifies whether to start the server as a standby. In streaming replication,&lt;br /&gt;
 # this parameter must to be set to on.&lt;br /&gt;
 standby_mode          = &#039;on&#039;&lt;br /&gt;
 &lt;br /&gt;
 # Specifies a connection string which is used for the standby server to connect&lt;br /&gt;
 # with the primary.&lt;br /&gt;
 primary_conninfo      = &#039;host=192.168.0.10 port=5432 user=postgres&#039;&lt;br /&gt;
 &lt;br /&gt;
 # Specifies a trigger file whose presence should cause streaming replication to&lt;br /&gt;
 # end (i.e., failover).&lt;br /&gt;
 trigger_file = &#039;/path_to/trigger&#039;&lt;br /&gt;
 &lt;br /&gt;
 # Specifies a command to load archive segments from the WAL archive. If&lt;br /&gt;
 # wal_keep_segments is a high enough number to retain the WAL segments&lt;br /&gt;
 # required for the standby server, this may not be necessary. But&lt;br /&gt;
 # a large workload can cause segments to be recycled before the standby&lt;br /&gt;
 # is fully synchronized, requiring you to start again from a new base backup.&lt;br /&gt;
 restore_command = &#039;cp /path_to/archive/%f &amp;quot;%p&amp;quot;&#039;&lt;br /&gt;
* &#039;&#039;&#039;10.&#039;&#039;&#039; Start postgres in the standby server. It will start streaming replication.&lt;br /&gt;
* &#039;&#039;&#039;11.&#039;&#039;&#039; You can calculate the replication lag by comparing the current WAL write location on the primary with the last WAL location received/replayed by the standby. They can be retrieved using &#039;&#039;pg_current_xlog_location&#039;&#039; on the primary and the &#039;&#039;pg_last_xlog_receive_location&#039;&#039;/&#039;&#039;pg_last_xlog_replay_location&#039;&#039; on the standby, respectively.&lt;br /&gt;
 $ psql -c &amp;quot;SELECT pg_current_xlog_location()&amp;quot; -h192.168.0.10 (primary host)&lt;br /&gt;
  pg_current_xlog_location &lt;br /&gt;
 --------------------------&lt;br /&gt;
  0/2000000&lt;br /&gt;
 (1 row)&lt;br /&gt;
 &lt;br /&gt;
 $ psql -c &amp;quot;select pg_last_xlog_receive_location()&amp;quot; -h192.168.0.20 (standby host)&lt;br /&gt;
  pg_last_xlog_receive_location &lt;br /&gt;
 -------------------------------&lt;br /&gt;
  0/2000000&lt;br /&gt;
 (1 row)&lt;br /&gt;
 &lt;br /&gt;
 $ psql -c &amp;quot;select pg_last_xlog_replay_location()&amp;quot; -h192.168.0.20 (standby host)&lt;br /&gt;
  pg_last_xlog_replay_location &lt;br /&gt;
 ------------------------------&lt;br /&gt;
  0/2000000&lt;br /&gt;
 (1 row)&lt;br /&gt;
* &#039;&#039;&#039;12.&#039;&#039;&#039; You can also check the progress of streaming replication by using &#039;&#039;ps&#039;&#039; command.&lt;br /&gt;
 # The displayed LSNs indicate the byte position that the standby server has&lt;br /&gt;
 # written up to in the xlogs.&lt;br /&gt;
 [primary] $ ps -ef | grep sender&lt;br /&gt;
 postgres  6879  6831  0 10:31 ?        00:00:00 postgres: wal sender process postgres 127.0.0.1(44663) streaming 0/2000000&lt;br /&gt;
 &lt;br /&gt;
 [standby] $ ps -ef | grep receiver&lt;br /&gt;
 postgres  6878  6872  1 10:31 ?        00:00:01 postgres: wal receiver process   streaming 0/2000000&lt;br /&gt;
* How to do failover&lt;br /&gt;
** Create the trigger file in the standby after the primary fails.&lt;br /&gt;
* How to stop the primary or the standby server&lt;br /&gt;
** Shut down it as usual (&#039;&#039;pg_ctl stop&#039;&#039;).&lt;br /&gt;
* How to restart streaming replication after failover&lt;br /&gt;
** Repeat the operations from &#039;&#039;&#039;6th&#039;&#039;&#039;; making a fresh backup, some configurations and starting the original primary as the standby. The primary server doesn&#039;t need to be stopped during these operations.&lt;br /&gt;
* How to restart streaming replication after the standby fails&lt;br /&gt;
** Restart postgres in the standby server after eliminating the cause of failure.&lt;br /&gt;
* How to disconnect the standby from the primary&lt;br /&gt;
** Create the trigger file in the standby while the primary is running. Then the standby would be brought up.&lt;br /&gt;
* How to re-synchronize the stand-alone standby after isolation&lt;br /&gt;
** Shut down the standby as usual. And repeat the operations from &#039;&#039;&#039;6th&#039;&#039;&#039;.&lt;br /&gt;
* If you have more than one slave, promoting one will break the other(s). Update their recovery.conf settings to point to the new master, set recovery_target_timeline to &#039;latest&#039;, scp/rsync the pg_xlog directory, and restart the slave.&lt;br /&gt;
&lt;br /&gt;
= Todo =&lt;br /&gt;
== v9.0 ==&lt;br /&gt;
&lt;br /&gt;
Moved to [[PostgreSQL_9.0_Open_Items]]&lt;br /&gt;
&lt;br /&gt;
=== Committed ===&lt;br /&gt;
* [http://archives.postgresql.org/pgsql-hackers/2010-01/msg01455.php Retrying from archive and some refactoring around Read/FetchRecord().] - [http://archives.postgresql.org/pgsql-committers/2010-01/msg00395.php commit]&lt;br /&gt;
* [http://archives.postgresql.org/pgsql-hackers/2010-01/msg02601.php SR wrongly treats the WAL-boundary.] - [http://archives.postgresql.org/pgsql-committers/2010-01/msg00396.php commit]&lt;br /&gt;
* [http://archives.postgresql.org/pgsql-hackers/2010-01/msg01715.php Adjust SR for some later changes about wal-skipping.] - [http://archives.postgresql.org/pgsql-committers/2010-01/msg00399.php commit]&lt;br /&gt;
* [http://archives.postgresql.org/pgsql-hackers/2010-02/msg00024.php VACUUM FULL unexpectedly writes an XLOG UNLOGGED record.] - [http://archives.postgresql.org/pgsql-committers/2010-02/msg00038.php commit]&lt;br /&gt;
* [http://archives.postgresql.org/pgsql-hackers/2010-01/msg01754.php Add a message type header.] - [http://archives.postgresql.org/pgsql-committers/2010-02/msg00037.php commit]&lt;br /&gt;
* [http://archives.postgresql.org/pgsql-hackers/2010-01/msg01536.php Documentation: Add a new &amp;quot;Replication&amp;quot; chapter.] - [http://archives.postgresql.org/pgsql-committers/2010-02/msg00115.php commit]&lt;br /&gt;
* [http://archives.postgresql.org/pgsql-hackers/2010-02/msg00350.php Failed assertion during recovery of partial WAL file.] - [http://archives.postgresql.org/pgsql-committers/2010-02/msg00124.php commit]&lt;br /&gt;
* [http://archives.postgresql.org/pgsql-hackers/2010-02/msg00712.php A PANIC error might occur in the standby because of a partially-filled archived WAL file.] - [http://archives.postgresql.org/pgsql-committers/2010-02/msg00137.php commit]&lt;br /&gt;
* [http://archives.postgresql.org/pgsql-hackers/2010-02/msg00330.php Improve the standby messages.] - [http://archives.postgresql.org/pgsql-committers/2010-02/msg00140.php commit]&lt;br /&gt;
* [http://archives.postgresql.org/pgsql-hackers/2010-01/msg01672.php pq_getbyte_if_available() is not working because the win32 socket emulation layer simply wasn&#039;t designed to deal with non-blocking sockets.] - [http://archives.postgresql.org/pgsql-committers/2010-02/msg00198.php commit]&lt;br /&gt;
* [http://archives.postgresql.org/pgsql-hackers/2010-02/msg01488.php Walsender might emit unfit messages.] - [http://archives.postgresql.org/pgsql-committers/2010-02/msg00239.php commit]&lt;br /&gt;
* [http://archives.postgresql.org/pgsql-hackers/2010-02/msg01236.php Streaming replication on win32, still broken.] - [http://archives.postgresql.org/pgsql-committers/2010-02/msg00270.php commit]&lt;br /&gt;
* [http://archives.postgresql.org/pgsql-hackers/2010-02/msg00992.php Create new section for recovery.conf.] - [http://archives.postgresql.org/pgsql-committers/2010-02/msg00295.php commit]&lt;br /&gt;
* [http://archives.postgresql.org/pgsql-hackers/2010-02/msg01824.php Assertion failure in walreceiver.] - [http://archives.postgresql.org/pgsql-committers/2010-02/msg00356.php commit]&lt;br /&gt;
* [http://archives.postgresql.org/pgsql-hackers/2010-01/msg01717.php Forbid a startup of walsender during recovery, and emit a suitable message? Or allow walsender to be started also during recovery?] - [http://archives.postgresql.org/message-id/20100316090955.9A5107541D0@cvs.postgresql.org commit]&lt;br /&gt;
* [http://archives.postgresql.org/pgsql-hackers/2010-02/msg01003.php How do we clean down the archive without using pg_standby?] - [http://archives.postgresql.org/message-id/20100318091718.BC14D7541D0@cvs.postgresql.org commit]&lt;br /&gt;
* [http://archives.postgresql.org/pgsql-hackers/2010-02/msg01510.php File-based log shipping without pg_standby doesn&#039;t replay the WAL files in pg_xlog.] - [http://archives.postgresql.org/pgsql-committers/2010-03/msg00356.php commit]&lt;br /&gt;
&lt;br /&gt;
== v9.1 ==&lt;br /&gt;
=== Synchronization capability ===&lt;br /&gt;
* Introduce the replication mode which can control how long transaction commit waits for replication before the commit command returns a &amp;quot;success&amp;quot; to a client. The valid modes are &#039;&#039;async&#039;&#039;, &#039;&#039;recv&#039;&#039; and &#039;&#039;fsync&#039;&#039;.&lt;br /&gt;
** &#039;&#039;async&#039;&#039; doesn&#039;t make transaction commit wait for replication, i.e., asynchronous replication.&lt;br /&gt;
** &#039;&#039;recv&#039;&#039; or &#039;&#039;fsync&#039;&#039; makes transaction commit wait for XLOG to be received or fsynced by the standby, respectively.&lt;br /&gt;
** (&#039;&#039;apply&#039;&#039; makes transaction commit wait for XLOG to be replayed by the standby. This mode will be supported in v9.2 or later)&lt;br /&gt;
** The replication mode is specified in recovery.conf of the standby as well as other parameters for replication.&lt;br /&gt;
*** The startup process reads the replication mode from recovery.conf and shares it to walreceiver via new shared-memory variable.&lt;br /&gt;
*** Walreceiver also shares it to walsender by using the replication handshake message (existing protocol needs to be extended).&lt;br /&gt;
** Based on the replication mode, walreceiver sends the reply meaning that replication is done up to the specified location to the primary.&lt;br /&gt;
*** In async, walreceiver doesn&#039;t need to send any reply other than end-of-replication message.&lt;br /&gt;
*** In recv or fsync, walreceiver sends the reply just after receiving or flushing XLOG, respectively.&lt;br /&gt;
*** New message type for the reply needs to be defined. The reply is sent as CopyData message.&lt;br /&gt;
** Walreceiver writes all the outstanding XLOG to disk before shutting down.&lt;br /&gt;
** Walsender receives the reply from the standby, updates the location of the last record replicated, and announces completion of replication.&lt;br /&gt;
*** New shared-memory variable to keep that location is required.&lt;br /&gt;
** When processing the commit command, backend waits for XLOG to be replicated to only the standbys which are in the recv or fsync replication mode.&lt;br /&gt;
*** Also smart shutdown waits for XLOG of shutdown checkpoint to be replicated.&lt;br /&gt;
* Required optimization&lt;br /&gt;
** Walsender should send outstanding XLOG without waiting wal_sender_delay.&lt;br /&gt;
*** When processing the commit command, backend signals walsender to send outstanding XLOG immediately.&lt;br /&gt;
** Backend should exit the wait loop as soon as the reply arrives at the primary.&lt;br /&gt;
*** When receiving the reply, walsender signals backends to get up from the sleep and determine whether to exit the wait loop by checking the location of the last XLOG replicated.&lt;br /&gt;
*** Only backends waiting for XLOG to be replicated up to the location contained in the reply are sent the signal.&lt;br /&gt;
** Walsender waits for the signal from backends and the reply from the standby at the same time, by using select/poll.&lt;br /&gt;
** Walsender reads XLOG from not only disk but also shared memory (wal buffers).&lt;br /&gt;
** Walreceiver should flush XLOG file only when XLOG file is switched or the related page is flushed.&lt;br /&gt;
*** When startup process or bgwriter flushes the buffer page, it checks whether the related XLOG has already been flushed via shared memory (location of the last XLOG flushed).&lt;br /&gt;
*** It flushes the buffer page, if XLOG file has already been flushed.&lt;br /&gt;
*** It signals walreceiver to flush XLOG file immediately and waits for the flush to complete, if XLOG file has not been flushed yet.&lt;br /&gt;
** While the standby is catching up with the primary, those servers should ignore the replication mode and perform asynchronous replication.&lt;br /&gt;
*** After those servers have almost gotten into synchronization, they perform replication based on the specified replication mode.&lt;br /&gt;
*** New replication states like &#039;catching-up&#039;, &#039;sync&#039;, etc need to be defined, and the state machine for them is required on both servers.&lt;br /&gt;
*** Current replication state can be monitored on both servers via SQL.&lt;br /&gt;
* Required timeout&lt;br /&gt;
** Add new parameter replication_timeout which is the maximum time to wait until XLOG is replicated to the standby. (does this match http://www.postgresql.org/docs/current/interactive/runtime-config-replication.html ?)&lt;br /&gt;
** Add new parameter (replication_timeout_action) to specify the reaction to replication_timeout.&lt;br /&gt;
&lt;br /&gt;
== Future release ==&lt;br /&gt;
* &#039;&#039;&#039;Synchronization capability&#039;&#039;&#039;&lt;br /&gt;
** Introduce the synchronization mode which can control how long transaction commit waits for replication before the commit command returns a &amp;quot;success&amp;quot; to a client. The valid modes are &#039;&#039;async&#039;&#039;, &#039;&#039;recv&#039;&#039;, &#039;&#039;fsync&#039;&#039; and &#039;&#039;apply&#039;&#039;.&lt;br /&gt;
*** &#039;&#039;async&#039;&#039; doesn&#039;t make transaction commit wait for replication, i.e., asynchronous replication.&lt;br /&gt;
*** &#039;&#039;recv&#039;&#039;, &#039;&#039;fsync&#039;&#039; and &#039;&#039;apply&#039;&#039; makes transaction commit wait for XLOG records to be received, fsynced and applied on the standby, respectively.&lt;br /&gt;
** Change walsender to be able to read XLOG from not only the disk but also shared memory.&lt;br /&gt;
** Add new parameter replication_timeout which is the maximum time to wait until XLOG records are replicated to the standby. (does this match http://www.postgresql.org/docs/current/interactive/runtime-config-replication.html ?)&lt;br /&gt;
** Add new parameter (replication_timeout_action) to specify the reaction to replication_timeout.&lt;br /&gt;
* &#039;&#039;&#039;Monitoring&#039;&#039;&#039;&lt;br /&gt;
** Provide the capability to check the progress and gap of streaming replication via one query. A collaboration of HS and SR is necessary to provide that capability on the standby side.&lt;br /&gt;
** Provide the capability to check if the specified repliation is in progress via a query. Also more detailed status information might be necessary, e.g, the standby is catching up now, has already gotten into sync, and so on.&lt;br /&gt;
** Change the stats collector to collect the statistics information about replication, e.g., average delay of replication time.&lt;br /&gt;
** Develop the tool to calculate the latest XLOG position from XLOG files. This is necessary to check the gap of replication after the server fails.&lt;br /&gt;
** Also develop the tool to extract the user-readable contents from XLOG files. This is necessary to see the contents of the gap, and manually restore them.&lt;br /&gt;
* &#039;&#039;&#039;Easy to Use&#039;&#039;&#039;&lt;br /&gt;
** Introduce the parameters like:&lt;br /&gt;
*** replication_halt_timeout - replication will halt if no data has been sent for this much time.&lt;br /&gt;
*** replication_halt_segments - replication will halt if number of WAL files in pg_xlog exceeds this threshold.&lt;br /&gt;
*** These parameters allow us to avoid disk overflow.&lt;br /&gt;
** Add new feature which transfers also base backup via the direct connection between the primary and the standby.&lt;br /&gt;
** Add new hooks like walsender_hook and walreceiver_hook to cooperate with the add-on program for compression like pglesslog.&lt;br /&gt;
** Provide a graceful termination of replication via a query on the primary. On the standby, a trigger file mechanism already provides that capability.&lt;br /&gt;
** Support replication beyond timeline. The timeline history files need to be shipped from the primary to the standby.&lt;br /&gt;
* &#039;&#039;&#039;Robustness&#039;&#039;&#039;&lt;br /&gt;
** Support keepalive in libpq. This is useful for a client and the standby to detect a failure of the primary immediately.&lt;br /&gt;
* &#039;&#039;&#039;Miscellaneous&#039;&#039;&#039;&lt;br /&gt;
** Standalone walreceiver tool, which connects to the primary, continuously receives and writes XLOG records, independently from postgres server.&lt;br /&gt;
** Cascade streaming replication. Allow walsender to send XLOG to another standby during recovery.&lt;br /&gt;
** WAL archiving during recovery.&lt;br /&gt;
&lt;br /&gt;
[[Category:Replication]]&lt;/div&gt;</summary>
		<author><name>Intgr</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=Extension_build_troubleshooting&amp;diff=19979</id>
		<title>Extension build troubleshooting</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=Extension_build_troubleshooting&amp;diff=19979"/>
		<updated>2013-05-28T19:39:25Z</updated>

		<summary type="html">&lt;p&gt;Intgr: /* Troubleshooting */ replace hostname with foobar&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Usually all that&#039;s necessary to build an extension is the following commands:&lt;br /&gt;
&lt;br /&gt;
 make&lt;br /&gt;
 make install&lt;br /&gt;
 make installcheck&lt;br /&gt;
&lt;br /&gt;
Followed by a SQL command to create the extension in a database (replace &amp;lt;tt&amp;gt;foobar&amp;lt;/tt&amp;gt; with the name of the extension):&lt;br /&gt;
&lt;br /&gt;
 CREATE EXTENSION foobar;&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
If you encounter an error such as:&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;Makefile&amp;quot;, line 8: Need an operator&lt;br /&gt;
&lt;br /&gt;
You need to use GNU make, which may well be installed on your system as gmake:&lt;br /&gt;
&lt;br /&gt;
 gmake&lt;br /&gt;
 gmake install&lt;br /&gt;
 gmake installcheck&lt;br /&gt;
&lt;br /&gt;
If you encounter an error such as:&lt;br /&gt;
&lt;br /&gt;
 make: pg_config: Command not found&lt;br /&gt;
&lt;br /&gt;
Be sure that you have pg_config installed and in your path. If you used a package management system such as RPM to install PostgreSQL, be sure that the -devel package is also installed. If necessary tell the build process where to find it:&lt;br /&gt;
&lt;br /&gt;
 env PG_CONFIG=/path/to/pg_config make &amp;amp;&amp;amp; make installcheck &amp;amp;&amp;amp; make install&lt;br /&gt;
&lt;br /&gt;
If you encounter an error such as:&lt;br /&gt;
&lt;br /&gt;
 ERROR:  must be owner of database regression&lt;br /&gt;
&lt;br /&gt;
You need to run the test suite using a super user, such as the default &amp;quot;postgres&amp;quot; super user:&lt;br /&gt;
&lt;br /&gt;
 make installcheck PGUSER=postgres&lt;br /&gt;
&lt;br /&gt;
Once the extension is installed, you can add it to a database. If you&#039;re running PostgreSQL 9.1.0 or greater, it&#039;s a simple as connecting to a database as a super user and running (replace &amp;lt;tt&amp;gt;foobar&amp;lt;/tt&amp;gt; with the name of the extension):&lt;br /&gt;
&lt;br /&gt;
 CREATE EXTENSION foobar;&lt;br /&gt;
&lt;br /&gt;
If you&#039;ve upgraded your cluster to PostgreSQL 9.1 and already had the extension installed, you can upgrade it to a properly packaged extension with:&lt;br /&gt;
&lt;br /&gt;
 CREATE EXTENSION foobar FROM unpackaged;&lt;br /&gt;
&lt;br /&gt;
For versions of PostgreSQL less than 9.1.0, you&#039;ll need to run the installation script (replace &amp;lt;tt&amp;gt;foobar&amp;lt;/tt&amp;gt; with the name of the extension):&lt;br /&gt;
&lt;br /&gt;
 psql -d mydb -f /path/to/pgsql/share/contrib/foobar.sql&lt;br /&gt;
&lt;br /&gt;
If you want to install the extension and all of its supporting objects into a specific schema, use the PGOPTIONS environment variable to specify the schema, like so:&lt;br /&gt;
&lt;br /&gt;
 PGOPTIONS=--search_path=extensions psql -d mydb -f foobar.sql&lt;br /&gt;
&lt;br /&gt;
== Credits ==&lt;br /&gt;
&lt;br /&gt;
This troubleshooting guide was originally written by &#039;&#039;&#039;David E. Wheeler&#039;&#039;&#039;. Copied from his [http://pgxn.org/dist/hostname/ hostname extension] README.&lt;/div&gt;</summary>
		<author><name>Intgr</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=Extension_build_troubleshooting&amp;diff=19978</id>
		<title>Extension build troubleshooting</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=Extension_build_troubleshooting&amp;diff=19978"/>
		<updated>2013-05-28T19:37:37Z</updated>

		<summary type="html">&lt;p&gt;Intgr: clarify&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Usually all that&#039;s necessary to build an extension is the following commands:&lt;br /&gt;
&lt;br /&gt;
 make&lt;br /&gt;
 make install&lt;br /&gt;
 make installcheck&lt;br /&gt;
&lt;br /&gt;
Followed by a SQL command to create the extension in a database (replace &amp;lt;tt&amp;gt;foobar&amp;lt;/tt&amp;gt; with the name of the extension):&lt;br /&gt;
&lt;br /&gt;
 CREATE EXTENSION foobar;&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
If you encounter an error such as:&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;Makefile&amp;quot;, line 8: Need an operator&lt;br /&gt;
&lt;br /&gt;
You need to use GNU make, which may well be installed on your system as gmake:&lt;br /&gt;
&lt;br /&gt;
 gmake&lt;br /&gt;
 gmake install&lt;br /&gt;
 gmake installcheck&lt;br /&gt;
&lt;br /&gt;
If you encounter an error such as:&lt;br /&gt;
&lt;br /&gt;
 make: pg_config: Command not found&lt;br /&gt;
&lt;br /&gt;
Be sure that you have pg_config installed and in your path. If you used a package management system such as RPM to install PostgreSQL, be sure that the -devel package is also installed. If necessary tell the build process where to find it:&lt;br /&gt;
&lt;br /&gt;
 env PG_CONFIG=/path/to/pg_config make &amp;amp;&amp;amp; make installcheck &amp;amp;&amp;amp; make install&lt;br /&gt;
&lt;br /&gt;
If you encounter an error such as:&lt;br /&gt;
&lt;br /&gt;
 ERROR:  must be owner of database regression&lt;br /&gt;
&lt;br /&gt;
You need to run the test suite using a super user, such as the default &amp;quot;postgres&amp;quot; super user:&lt;br /&gt;
&lt;br /&gt;
 make installcheck PGUSER=postgres&lt;br /&gt;
&lt;br /&gt;
Once the extension is installed, you can add it to a database. If you&#039;re running PostgreSQL 9.1.0 or greater, it&#039;s a simple as connecting to a database as a super user and running (replace &amp;lt;tt&amp;gt;foobar&amp;lt;/tt&amp;gt; with the name of the extension):&lt;br /&gt;
&lt;br /&gt;
 CREATE EXTENSION foobar;&lt;br /&gt;
&lt;br /&gt;
If you&#039;ve upgraded your cluster to PostgreSQL 9.1 and already had hostname installed, you can upgrade it to a properly packaged extension with:&lt;br /&gt;
&lt;br /&gt;
 CREATE EXTENSION hostname FROM unpackaged;&lt;br /&gt;
&lt;br /&gt;
For versions of PostgreSQL less than 9.1.0, you&#039;ll need to run the installation script (replace &amp;lt;tt&amp;gt;foobar&amp;lt;/tt&amp;gt; with the name of the extension):&lt;br /&gt;
&lt;br /&gt;
 psql -d mydb -f /path/to/pgsql/share/contrib/foobar.sql&lt;br /&gt;
&lt;br /&gt;
If you want to install the extension and all of its supporting objects into a specific schema, use the PGOPTIONS environment variable to specify the schema, like so:&lt;br /&gt;
&lt;br /&gt;
 PGOPTIONS=--search_path=extensions psql -d mydb -f foobar.sql&lt;br /&gt;
&lt;br /&gt;
== Credits ==&lt;br /&gt;
&lt;br /&gt;
This troubleshooting guide was originally written by &#039;&#039;&#039;David E. Wheeler&#039;&#039;&#039;. Copied from his [http://pgxn.org/dist/hostname/ hostname extension] README.&lt;/div&gt;</summary>
		<author><name>Intgr</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=Extension_build_troubleshooting&amp;diff=19977</id>
		<title>Extension build troubleshooting</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=Extension_build_troubleshooting&amp;diff=19977"/>
		<updated>2013-05-28T19:33:13Z</updated>

		<summary type="html">&lt;p&gt;Intgr: Created page with &amp;quot;Usually all that&amp;#039;s necessary to build an extension is the following commands:   make  make install  make installcheck  Followed by a SQL DDL command to create the extension in a …&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Usually all that&#039;s necessary to build an extension is the following commands:&lt;br /&gt;
&lt;br /&gt;
 make&lt;br /&gt;
 make install&lt;br /&gt;
 make installcheck&lt;br /&gt;
&lt;br /&gt;
Followed by a SQL DDL command to create the extension in a database:&lt;br /&gt;
&lt;br /&gt;
 CREATE EXTENSION foobar;&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
If you encounter an error such as:&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;Makefile&amp;quot;, line 8: Need an operator&lt;br /&gt;
&lt;br /&gt;
You need to use GNU make, which may well be installed on your system as gmake:&lt;br /&gt;
&lt;br /&gt;
 gmake&lt;br /&gt;
 gmake install&lt;br /&gt;
 gmake installcheck&lt;br /&gt;
&lt;br /&gt;
If you encounter an error such as:&lt;br /&gt;
&lt;br /&gt;
 make: pg_config: Command not found&lt;br /&gt;
&lt;br /&gt;
Be sure that you have pg_config installed and in your path. If you used a package management system such as RPM to install PostgreSQL, be sure that the -devel package is also installed. If necessary tell the build process where to find it:&lt;br /&gt;
&lt;br /&gt;
 env PG_CONFIG=/path/to/pg_config make &amp;amp;&amp;amp; make installcheck &amp;amp;&amp;amp; make install&lt;br /&gt;
&lt;br /&gt;
If you encounter an error such as:&lt;br /&gt;
&lt;br /&gt;
 ERROR:  must be owner of database regression&lt;br /&gt;
&lt;br /&gt;
You need to run the test suite using a super user, such as the default &amp;quot;postgres&amp;quot; super user:&lt;br /&gt;
&lt;br /&gt;
 make installcheck PGUSER=postgres&lt;br /&gt;
&lt;br /&gt;
Once the extension is installed, you can add it to a database. If you&#039;re running PostgreSQL 9.1.0 or greater, it&#039;s a simple as connecting to a database as a super user and running (replace &amp;lt;tt&amp;gt;foobar&amp;lt;/tt&amp;gt; with name of the extension):&lt;br /&gt;
&lt;br /&gt;
 CREATE EXTENSION foobar;&lt;br /&gt;
&lt;br /&gt;
If you&#039;ve upgraded your cluster to PostgreSQL 9.1 and already had hostname installed, you can upgrade it to a properly packaged extension with:&lt;br /&gt;
&lt;br /&gt;
 CREATE EXTENSION hostname FROM unpackaged;&lt;br /&gt;
&lt;br /&gt;
For versions of PostgreSQL less than 9.1.0, you&#039;ll need to run the installation script (replace &amp;lt;tt&amp;gt;foobar&amp;lt;/tt&amp;gt; with name of the extension):&lt;br /&gt;
&lt;br /&gt;
 psql -d mydb -f /path/to/pgsql/share/contrib/foobar.sql&lt;br /&gt;
&lt;br /&gt;
If you want to install the extension and all of its supporting objects into a specific schema, use the PGOPTIONS environment variable to specify the schema, like so:&lt;br /&gt;
&lt;br /&gt;
 PGOPTIONS=--search_path=extensions psql -d mydb -f foobar.sql&lt;br /&gt;
&lt;br /&gt;
== Credits ==&lt;br /&gt;
&lt;br /&gt;
This troubleshooting guide was originally written by &#039;&#039;&#039;David E. Wheeler&#039;&#039;&#039;. Copied from his [http://pgxn.org/dist/hostname/ hostname extension] README.&lt;/div&gt;</summary>
		<author><name>Intgr</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=Query_column_with_range_types&amp;diff=19326</id>
		<title>Query column with range types</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=Query_column_with_range_types&amp;diff=19326"/>
		<updated>2013-04-04T20:00:22Z</updated>

		<summary type="html">&lt;p&gt;Intgr: /* Code */ more blank lines&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Rationale ==&lt;br /&gt;
&lt;br /&gt;
The main use case for range types is to store ranges in PostgreSQL tables, and then find rows whose range includes a certain literal. These can already be indexed using GIN and GiST index types.&lt;br /&gt;
&amp;lt;!-- create table rng as select numrange(i, i+100) rng from generate_series(1,1000000) i; create index on rng using gist(rng); --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 db=# EXPLAIN ANALYZE SELECT * FROM rng WHERE rng @&amp;gt; 10.0;&lt;br /&gt;
 Bitmap Heap Scan on rng  (cost=48.40..2709.45 rows=1000 width=32) (actual time=0.103..0.103 rows=10 loops=1)&lt;br /&gt;
   Recheck Cond: (rng @&amp;gt; 10.0)&lt;br /&gt;
   -&amp;gt;  Bitmap Index Scan on rng_rng_idx  (cost=0.00..48.15 rows=1000 width=0) (actual time=0.096..0.096 rows=10 loops=1)&lt;br /&gt;
         Index Cond: (rng @&amp;gt; 10.0)&lt;br /&gt;
 Total runtime: 0.136 ms&lt;br /&gt;
&lt;br /&gt;
However, you cannot index inverse queries - if you want to find single values in a certain range:&lt;br /&gt;
&amp;lt;!-- create table num as select generate_series(1,1000000)::numeric i; create index on num(i); vacuum num; --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 db=# EXPLAIN ANALYZE SELECT * FROM num WHERE i &amp;lt;@ &#039;[0, 10)&#039;;&lt;br /&gt;
 Seq Scan on num  (cost=0.00..16925.00 rows=1000 width=6) (actual time=0.014..188.761 rows=9 loops=1)&lt;br /&gt;
   Filter: (i &amp;lt;@ &#039;[0,10]&#039;::numrange)&lt;br /&gt;
   Rows Removed by Filter: 999991&lt;br /&gt;
 Total runtime: 188.820 ms&lt;br /&gt;
&lt;br /&gt;
== Example ==&lt;br /&gt;
&lt;br /&gt;
Of course the above query is equivalent to the indexable query &amp;lt;tt&amp;gt;WHERE num &amp;gt;= 0 AND num &amp;lt; 10&amp;lt;/tt&amp;gt;. But what if you want to use range types? Well, you can create a custom operator with a function that automatically gets inlined:&lt;br /&gt;
&lt;br /&gt;
 db=# EXPLAIN ANALYZE SELECT * FROM num WHERE i &amp;lt;@ &#039;[0, 10)&#039;;&lt;br /&gt;
 Index Only Scan using num_i_idx on num  (cost=0.00..4.56 rows=10 width=6) (actual time=0.014..0.016 rows=9 loops=1)&lt;br /&gt;
   Index Cond: ((i &amp;gt;= 0::numeric) AND (i &amp;lt; 10::numeric))&lt;br /&gt;
   Heap Fetches: 0&lt;br /&gt;
 Total runtime: 0.039 ms&lt;br /&gt;
&lt;br /&gt;
Infinite terms get optimized out:&lt;br /&gt;
&lt;br /&gt;
 db=# EXPLAIN ANALYZE SELECT * FROM num WHERE i &amp;lt;@ &#039;[,10]&#039;;&lt;br /&gt;
 Index Only Scan using num_i_idx on num  (cost=0.00..4.53 rows=10 width=6) (actual time=0.007..0.009 rows=10 loops=1)&lt;br /&gt;
   Index Cond: (i &amp;lt;= 10::numeric)&lt;br /&gt;
   Heap Fetches: 0&lt;br /&gt;
 Total runtime: 0.032 ms&lt;br /&gt;
&lt;br /&gt;
=== Beware! ===&lt;br /&gt;
&lt;br /&gt;
These custom operators are deliberately defined to be non-commative. If you create these operators, do not write range queries in the form &amp;lt;tt&amp;gt;10.0 &amp;lt;@ range_col&amp;lt;/tt&amp;gt; because it will blow up:&lt;br /&gt;
&lt;br /&gt;
 db=# EXPLAIN ANALYZE SELECT * FROM rng WHERE 10.0 &amp;lt;@ rng;&lt;br /&gt;
 Seq Scan on rng  (cost=0.00..46358.16 rows=444424 width=32) (actual time=0.013..240.054 rows=10 loops=1)&lt;br /&gt;
   Filter: ((lower_inf(rng) OR CASE WHEN lower_inc(rng) THEN (10.0 &amp;gt;= lower(rng)) ELSE (10.0 &amp;gt; lower(rng)) END)&lt;br /&gt;
        AND (upper_inf(rng) OR CASE WHEN upper_inc(rng) THEN (10.0 &amp;lt;= upper(rng)) ELSE (10.0 &amp;lt; upper(rng)) END))&lt;br /&gt;
   Rows Removed by Filter: 999990&lt;br /&gt;
 Total runtime: 240.125 ms&lt;br /&gt;
&lt;br /&gt;
== Code ==&lt;br /&gt;
&lt;br /&gt;
You can adapt this code to any range type you need, just by changing the types of the function and the operator.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
-- int4range (integer)&lt;br /&gt;
CREATE OR REPLACE FUNCTION range_contains(el integer, rng int4range) RETURNS bool IMMUTABLE LANGUAGE sql AS $$&lt;br /&gt;
SELECT (lower_inf(rng) OR (CASE WHEN lower_inc(rng) THEN el &amp;gt;= lower(rng) ELSE el &amp;gt; lower(rng) END))&lt;br /&gt;
   AND (upper_inf(rng) OR (CASE WHEN upper_inc(rng) THEN el &amp;lt;= upper(rng) ELSE el &amp;lt; upper(rng) END))&lt;br /&gt;
$$;&lt;br /&gt;
CREATE OPERATOR &amp;lt;@ (procedure=range_contains, leftarg=integer, rightarg=int4range);&lt;br /&gt;
&lt;br /&gt;
-- int8range (bigint)&lt;br /&gt;
CREATE OR REPLACE FUNCTION range_contains(el bigint, rng int8range) RETURNS bool IMMUTABLE LANGUAGE sql AS $$&lt;br /&gt;
SELECT (lower_inf(rng) OR (CASE WHEN lower_inc(rng) THEN el &amp;gt;= lower(rng) ELSE el &amp;gt; lower(rng) END))&lt;br /&gt;
   AND (upper_inf(rng) OR (CASE WHEN upper_inc(rng) THEN el &amp;lt;= upper(rng) ELSE el &amp;lt; upper(rng) END))&lt;br /&gt;
$$;&lt;br /&gt;
CREATE OPERATOR &amp;lt;@ (procedure=range_contains, leftarg=bigint, rightarg=int8range);&lt;br /&gt;
&lt;br /&gt;
-- numrange (numeric)&lt;br /&gt;
CREATE OR REPLACE FUNCTION range_contains(el numeric, rng numrange) RETURNS bool IMMUTABLE LANGUAGE sql AS $$&lt;br /&gt;
SELECT (lower_inf(rng) OR (CASE WHEN lower_inc(rng) THEN el &amp;gt;= lower(rng) ELSE el &amp;gt; lower(rng) END))&lt;br /&gt;
   AND (upper_inf(rng) OR (CASE WHEN upper_inc(rng) THEN el &amp;lt;= upper(rng) ELSE el &amp;lt; upper(rng) END))&lt;br /&gt;
$$;&lt;br /&gt;
CREATE OPERATOR &amp;lt;@ (procedure=range_contains, leftarg=numeric, rightarg=numrange);&lt;br /&gt;
&lt;br /&gt;
-- tsrange (timestamp without time zone)&lt;br /&gt;
CREATE OR REPLACE FUNCTION range_contains(el timestamp, rng tsrange) RETURNS bool IMMUTABLE LANGUAGE sql AS $$&lt;br /&gt;
SELECT (lower_inf(rng) OR (CASE WHEN lower_inc(rng) THEN el &amp;gt;= lower(rng) ELSE el &amp;gt; lower(rng) END))&lt;br /&gt;
   AND (upper_inf(rng) OR (CASE WHEN upper_inc(rng) THEN el &amp;lt;= upper(rng) ELSE el &amp;lt; upper(rng) END))&lt;br /&gt;
$$;&lt;br /&gt;
CREATE OPERATOR &amp;lt;@ (procedure=range_contains, leftarg=timestamp, rightarg=tsrange);&lt;br /&gt;
&lt;br /&gt;
-- tstzrange (timestamp with time zone)&lt;br /&gt;
CREATE OR REPLACE FUNCTION range_contains(el timestamptz, rng tstzrange) RETURNS bool IMMUTABLE LANGUAGE sql AS $$&lt;br /&gt;
SELECT (lower_inf(rng) OR (CASE WHEN lower_inc(rng) THEN el &amp;gt;= lower(rng) ELSE el &amp;gt; lower(rng) END))&lt;br /&gt;
   AND (upper_inf(rng) OR (CASE WHEN upper_inc(rng) THEN el &amp;lt;= upper(rng) ELSE el &amp;lt; upper(rng) END))&lt;br /&gt;
$$;&lt;br /&gt;
CREATE OPERATOR &amp;lt;@ (procedure=range_contains, leftarg=timestamptz, rightarg=tstzrange);&lt;br /&gt;
&lt;br /&gt;
-- daterange (date)&lt;br /&gt;
CREATE OR REPLACE FUNCTION range_contains(el date, rng daterange) RETURNS bool IMMUTABLE LANGUAGE sql AS $$&lt;br /&gt;
SELECT (lower_inf(rng) OR (CASE WHEN lower_inc(rng) THEN el &amp;gt;= lower(rng) ELSE el &amp;gt; lower(rng) END))&lt;br /&gt;
   AND (upper_inf(rng) OR (CASE WHEN upper_inc(rng) THEN el &amp;lt;= upper(rng) ELSE el &amp;lt; upper(rng) END))&lt;br /&gt;
$$;&lt;br /&gt;
CREATE OPERATOR &amp;lt;@ (procedure=range_contains, leftarg=date, rightarg=daterange);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Idea from Andres Freund, implemented by Marti Raudsepp.&lt;/div&gt;</summary>
		<author><name>Intgr</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=Query_column_with_range_types&amp;diff=19325</id>
		<title>Query column with range types</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=Query_column_with_range_types&amp;diff=19325"/>
		<updated>2013-04-04T19:59:28Z</updated>

		<summary type="html">&lt;p&gt;Intgr: credits&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Rationale ==&lt;br /&gt;
&lt;br /&gt;
The main use case for range types is to store ranges in PostgreSQL tables, and then find rows whose range includes a certain literal. These can already be indexed using GIN and GiST index types.&lt;br /&gt;
&amp;lt;!-- create table rng as select numrange(i, i+100) rng from generate_series(1,1000000) i; create index on rng using gist(rng); --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 db=# EXPLAIN ANALYZE SELECT * FROM rng WHERE rng @&amp;gt; 10.0;&lt;br /&gt;
 Bitmap Heap Scan on rng  (cost=48.40..2709.45 rows=1000 width=32) (actual time=0.103..0.103 rows=10 loops=1)&lt;br /&gt;
   Recheck Cond: (rng @&amp;gt; 10.0)&lt;br /&gt;
   -&amp;gt;  Bitmap Index Scan on rng_rng_idx  (cost=0.00..48.15 rows=1000 width=0) (actual time=0.096..0.096 rows=10 loops=1)&lt;br /&gt;
         Index Cond: (rng @&amp;gt; 10.0)&lt;br /&gt;
 Total runtime: 0.136 ms&lt;br /&gt;
&lt;br /&gt;
However, you cannot index inverse queries - if you want to find single values in a certain range:&lt;br /&gt;
&amp;lt;!-- create table num as select generate_series(1,1000000)::numeric i; create index on num(i); vacuum num; --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 db=# EXPLAIN ANALYZE SELECT * FROM num WHERE i &amp;lt;@ &#039;[0, 10)&#039;;&lt;br /&gt;
 Seq Scan on num  (cost=0.00..16925.00 rows=1000 width=6) (actual time=0.014..188.761 rows=9 loops=1)&lt;br /&gt;
   Filter: (i &amp;lt;@ &#039;[0,10]&#039;::numrange)&lt;br /&gt;
   Rows Removed by Filter: 999991&lt;br /&gt;
 Total runtime: 188.820 ms&lt;br /&gt;
&lt;br /&gt;
== Example ==&lt;br /&gt;
&lt;br /&gt;
Of course the above query is equivalent to the indexable query &amp;lt;tt&amp;gt;WHERE num &amp;gt;= 0 AND num &amp;lt; 10&amp;lt;/tt&amp;gt;. But what if you want to use range types? Well, you can create a custom operator with a function that automatically gets inlined:&lt;br /&gt;
&lt;br /&gt;
 db=# EXPLAIN ANALYZE SELECT * FROM num WHERE i &amp;lt;@ &#039;[0, 10)&#039;;&lt;br /&gt;
 Index Only Scan using num_i_idx on num  (cost=0.00..4.56 rows=10 width=6) (actual time=0.014..0.016 rows=9 loops=1)&lt;br /&gt;
   Index Cond: ((i &amp;gt;= 0::numeric) AND (i &amp;lt; 10::numeric))&lt;br /&gt;
   Heap Fetches: 0&lt;br /&gt;
 Total runtime: 0.039 ms&lt;br /&gt;
&lt;br /&gt;
Infinite terms get optimized out:&lt;br /&gt;
&lt;br /&gt;
 db=# EXPLAIN ANALYZE SELECT * FROM num WHERE i &amp;lt;@ &#039;[,10]&#039;;&lt;br /&gt;
 Index Only Scan using num_i_idx on num  (cost=0.00..4.53 rows=10 width=6) (actual time=0.007..0.009 rows=10 loops=1)&lt;br /&gt;
   Index Cond: (i &amp;lt;= 10::numeric)&lt;br /&gt;
   Heap Fetches: 0&lt;br /&gt;
 Total runtime: 0.032 ms&lt;br /&gt;
&lt;br /&gt;
=== Beware! ===&lt;br /&gt;
&lt;br /&gt;
These custom operators are deliberately defined to be non-commative. If you create these operators, do not write range queries in the form &amp;lt;tt&amp;gt;10.0 &amp;lt;@ range_col&amp;lt;/tt&amp;gt; because it will blow up:&lt;br /&gt;
&lt;br /&gt;
 db=# EXPLAIN ANALYZE SELECT * FROM rng WHERE 10.0 &amp;lt;@ rng;&lt;br /&gt;
 Seq Scan on rng  (cost=0.00..46358.16 rows=444424 width=32) (actual time=0.013..240.054 rows=10 loops=1)&lt;br /&gt;
   Filter: ((lower_inf(rng) OR CASE WHEN lower_inc(rng) THEN (10.0 &amp;gt;= lower(rng)) ELSE (10.0 &amp;gt; lower(rng)) END)&lt;br /&gt;
        AND (upper_inf(rng) OR CASE WHEN upper_inc(rng) THEN (10.0 &amp;lt;= upper(rng)) ELSE (10.0 &amp;lt; upper(rng)) END))&lt;br /&gt;
   Rows Removed by Filter: 999990&lt;br /&gt;
 Total runtime: 240.125 ms&lt;br /&gt;
&lt;br /&gt;
== Code ==&lt;br /&gt;
&lt;br /&gt;
You can adapt this code to any range type you need, just by changing the types of the function and the operator.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
-- int4range (integer)&lt;br /&gt;
CREATE OR REPLACE FUNCTION range_contains(el integer, rng int4range) RETURNS bool IMMUTABLE LANGUAGE sql AS $$&lt;br /&gt;
SELECT (lower_inf(rng) OR (CASE WHEN lower_inc(rng) THEN el &amp;gt;= lower(rng) ELSE el &amp;gt; lower(rng) END))&lt;br /&gt;
   AND (upper_inf(rng) OR (CASE WHEN upper_inc(rng) THEN el &amp;lt;= upper(rng) ELSE el &amp;lt; upper(rng) END))&lt;br /&gt;
$$;&lt;br /&gt;
CREATE OPERATOR &amp;lt;@ (procedure=range_contains, leftarg=integer, rightarg=int4range);&lt;br /&gt;
&lt;br /&gt;
-- int8range (bigint)&lt;br /&gt;
CREATE OR REPLACE FUNCTION range_contains(el bigint, rng int8range) RETURNS bool IMMUTABLE LANGUAGE sql AS $$&lt;br /&gt;
SELECT (lower_inf(rng) OR (CASE WHEN lower_inc(rng) THEN el &amp;gt;= lower(rng) ELSE el &amp;gt; lower(rng) END))&lt;br /&gt;
   AND (upper_inf(rng) OR (CASE WHEN upper_inc(rng) THEN el &amp;lt;= upper(rng) ELSE el &amp;lt; upper(rng) END))&lt;br /&gt;
$$;&lt;br /&gt;
CREATE OPERATOR &amp;lt;@ (procedure=range_contains, leftarg=bigint, rightarg=int8range);&lt;br /&gt;
&lt;br /&gt;
-- numrange (numeric)&lt;br /&gt;
CREATE OR REPLACE FUNCTION range_contains(el numeric, rng numrange) RETURNS bool IMMUTABLE LANGUAGE sql AS $$&lt;br /&gt;
SELECT (lower_inf(rng) OR (CASE WHEN lower_inc(rng) THEN el &amp;gt;= lower(rng) ELSE el &amp;gt; lower(rng) END))&lt;br /&gt;
   AND (upper_inf(rng) OR (CASE WHEN upper_inc(rng) THEN el &amp;lt;= upper(rng) ELSE el &amp;lt; upper(rng) END))&lt;br /&gt;
$$;&lt;br /&gt;
CREATE OPERATOR &amp;lt;@ (procedure=range_contains, leftarg=numeric, rightarg=numrange);&lt;br /&gt;
&lt;br /&gt;
-- tsrange (timestamp without time zone)&lt;br /&gt;
CREATE OR REPLACE FUNCTION range_contains(el timestamp, rng tsrange) RETURNS bool IMMUTABLE LANGUAGE sql AS $$&lt;br /&gt;
SELECT (lower_inf(rng) OR (CASE WHEN lower_inc(rng) THEN el &amp;gt;= lower(rng) ELSE el &amp;gt; lower(rng) END))&lt;br /&gt;
   AND (upper_inf(rng) OR (CASE WHEN upper_inc(rng) THEN el &amp;lt;= upper(rng) ELSE el &amp;lt; upper(rng) END))&lt;br /&gt;
$$;&lt;br /&gt;
CREATE OPERATOR &amp;lt;@ (procedure=range_contains, leftarg=timestamp, rightarg=tsrange);&lt;br /&gt;
&lt;br /&gt;
-- tstzrange (timestamp with time zone)&lt;br /&gt;
CREATE OR REPLACE FUNCTION range_contains(el timestamptz, rng tstzrange) RETURNS bool IMMUTABLE LANGUAGE sql AS $$&lt;br /&gt;
SELECT (lower_inf(rng) OR (CASE WHEN lower_inc(rng) THEN el &amp;gt;= lower(rng) ELSE el &amp;gt; lower(rng) END))&lt;br /&gt;
   AND (upper_inf(rng) OR (CASE WHEN upper_inc(rng) THEN el &amp;lt;= upper(rng) ELSE el &amp;lt; upper(rng) END))&lt;br /&gt;
$$;&lt;br /&gt;
CREATE OPERATOR &amp;lt;@ (procedure=range_contains, leftarg=timestamptz, rightarg=tstzrange);&lt;br /&gt;
&lt;br /&gt;
-- daterange (date)&lt;br /&gt;
CREATE OR REPLACE FUNCTION range_contains(el date, rng daterange) RETURNS bool IMMUTABLE LANGUAGE sql AS $$&lt;br /&gt;
SELECT (lower_inf(rng) OR (CASE WHEN lower_inc(rng) THEN el &amp;gt;= lower(rng) ELSE el &amp;gt; lower(rng) END))&lt;br /&gt;
   AND (upper_inf(rng) OR (CASE WHEN upper_inc(rng) THEN el &amp;lt;= upper(rng) ELSE el &amp;lt; upper(rng) END))&lt;br /&gt;
$$;&lt;br /&gt;
CREATE OPERATOR &amp;lt;@ (procedure=range_contains, leftarg=date, rightarg=daterange);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Idea from Andres Freund, implemented by Marti Raudsepp.&lt;/div&gt;</summary>
		<author><name>Intgr</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=Query_column_with_range_types&amp;diff=19323</id>
		<title>Query column with range types</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=Query_column_with_range_types&amp;diff=19323"/>
		<updated>2013-04-03T21:34:51Z</updated>

		<summary type="html">&lt;p&gt;Intgr: /* Beware! */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Rationale ==&lt;br /&gt;
&lt;br /&gt;
The main use case for range types is to store ranges in PostgreSQL tables, and then find rows whose range includes a certain literal. These can already be indexed using GIN and GiST index types.&lt;br /&gt;
&amp;lt;!-- create table rng as select numrange(i, i+100) rng from generate_series(1,1000000) i; create index on rng using gist(rng); --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 db=# EXPLAIN ANALYZE SELECT * FROM rng WHERE rng @&amp;gt; 10.0;&lt;br /&gt;
 Bitmap Heap Scan on rng  (cost=48.40..2709.45 rows=1000 width=32) (actual time=0.103..0.103 rows=10 loops=1)&lt;br /&gt;
   Recheck Cond: (rng @&amp;gt; 10.0)&lt;br /&gt;
   -&amp;gt;  Bitmap Index Scan on rng_rng_idx  (cost=0.00..48.15 rows=1000 width=0) (actual time=0.096..0.096 rows=10 loops=1)&lt;br /&gt;
         Index Cond: (rng @&amp;gt; 10.0)&lt;br /&gt;
 Total runtime: 0.136 ms&lt;br /&gt;
&lt;br /&gt;
However, you cannot index inverse queries - if you want to find single values in a certain range:&lt;br /&gt;
&amp;lt;!-- create table num as select generate_series(1,1000000)::numeric i; create index on num(i); vacuum num; --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 db=# EXPLAIN ANALYZE SELECT * FROM num WHERE i &amp;lt;@ &#039;[0, 10)&#039;;&lt;br /&gt;
 Seq Scan on num  (cost=0.00..16925.00 rows=1000 width=6) (actual time=0.014..188.761 rows=9 loops=1)&lt;br /&gt;
   Filter: (i &amp;lt;@ &#039;[0,10]&#039;::numrange)&lt;br /&gt;
   Rows Removed by Filter: 999991&lt;br /&gt;
 Total runtime: 188.820 ms&lt;br /&gt;
&lt;br /&gt;
== Example ==&lt;br /&gt;
&lt;br /&gt;
Of course the above query is equivalent to the indexable query &amp;lt;tt&amp;gt;WHERE num &amp;gt;= 0 AND num &amp;lt; 10&amp;lt;/tt&amp;gt;. But what if you want to use range types? Well, you can create a custom operator with a function that automatically gets inlined:&lt;br /&gt;
&lt;br /&gt;
 db=# EXPLAIN ANALYZE SELECT * FROM num WHERE i &amp;lt;@ &#039;[0, 10)&#039;;&lt;br /&gt;
 Index Only Scan using num_i_idx on num  (cost=0.00..4.56 rows=10 width=6) (actual time=0.014..0.016 rows=9 loops=1)&lt;br /&gt;
   Index Cond: ((i &amp;gt;= 0::numeric) AND (i &amp;lt; 10::numeric))&lt;br /&gt;
   Heap Fetches: 0&lt;br /&gt;
 Total runtime: 0.039 ms&lt;br /&gt;
&lt;br /&gt;
Infinite terms get optimized out:&lt;br /&gt;
&lt;br /&gt;
 db=# EXPLAIN ANALYZE SELECT * FROM num WHERE i &amp;lt;@ &#039;[,10]&#039;;&lt;br /&gt;
 Index Only Scan using num_i_idx on num  (cost=0.00..4.53 rows=10 width=6) (actual time=0.007..0.009 rows=10 loops=1)&lt;br /&gt;
   Index Cond: (i &amp;lt;= 10::numeric)&lt;br /&gt;
   Heap Fetches: 0&lt;br /&gt;
 Total runtime: 0.032 ms&lt;br /&gt;
&lt;br /&gt;
=== Beware! ===&lt;br /&gt;
&lt;br /&gt;
These custom operators are deliberately defined to be non-commative. If you create these operators, do not write range queries in the form &amp;lt;tt&amp;gt;10.0 &amp;lt;@ range_col&amp;lt;/tt&amp;gt; because it will blow up:&lt;br /&gt;
&lt;br /&gt;
 db=# EXPLAIN ANALYZE SELECT * FROM rng WHERE 10.0 &amp;lt;@ rng;&lt;br /&gt;
 Seq Scan on rng  (cost=0.00..46358.16 rows=444424 width=32) (actual time=0.013..240.054 rows=10 loops=1)&lt;br /&gt;
   Filter: ((lower_inf(rng) OR CASE WHEN lower_inc(rng) THEN (10.0 &amp;gt;= lower(rng)) ELSE (10.0 &amp;gt; lower(rng)) END)&lt;br /&gt;
        AND (upper_inf(rng) OR CASE WHEN upper_inc(rng) THEN (10.0 &amp;lt;= upper(rng)) ELSE (10.0 &amp;lt; upper(rng)) END))&lt;br /&gt;
   Rows Removed by Filter: 999990&lt;br /&gt;
 Total runtime: 240.125 ms&lt;br /&gt;
&lt;br /&gt;
== Code ==&lt;br /&gt;
&lt;br /&gt;
You can adapt this code to any range type you need, just by changing the types of the function and the operator.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
-- int4range (integer)&lt;br /&gt;
CREATE OR REPLACE FUNCTION range_contains(el integer, rng int4range) RETURNS bool IMMUTABLE LANGUAGE sql AS $$&lt;br /&gt;
SELECT (lower_inf(rng) OR (CASE WHEN lower_inc(rng) THEN el &amp;gt;= lower(rng) ELSE el &amp;gt; lower(rng) END))&lt;br /&gt;
   AND (upper_inf(rng) OR (CASE WHEN upper_inc(rng) THEN el &amp;lt;= upper(rng) ELSE el &amp;lt; upper(rng) END))&lt;br /&gt;
$$;&lt;br /&gt;
CREATE OPERATOR &amp;lt;@ (procedure=range_contains, leftarg=integer, rightarg=int4range);&lt;br /&gt;
&lt;br /&gt;
-- int8range (bigint)&lt;br /&gt;
CREATE OR REPLACE FUNCTION range_contains(el bigint, rng int8range) RETURNS bool IMMUTABLE LANGUAGE sql AS $$&lt;br /&gt;
SELECT (lower_inf(rng) OR (CASE WHEN lower_inc(rng) THEN el &amp;gt;= lower(rng) ELSE el &amp;gt; lower(rng) END))&lt;br /&gt;
   AND (upper_inf(rng) OR (CASE WHEN upper_inc(rng) THEN el &amp;lt;= upper(rng) ELSE el &amp;lt; upper(rng) END))&lt;br /&gt;
$$;&lt;br /&gt;
CREATE OPERATOR &amp;lt;@ (procedure=range_contains, leftarg=bigint, rightarg=int8range);&lt;br /&gt;
&lt;br /&gt;
-- numrange (numeric)&lt;br /&gt;
CREATE OR REPLACE FUNCTION range_contains(el numeric, rng numrange) RETURNS bool IMMUTABLE LANGUAGE sql AS $$&lt;br /&gt;
SELECT (lower_inf(rng) OR (CASE WHEN lower_inc(rng) THEN el &amp;gt;= lower(rng) ELSE el &amp;gt; lower(rng) END))&lt;br /&gt;
   AND (upper_inf(rng) OR (CASE WHEN upper_inc(rng) THEN el &amp;lt;= upper(rng) ELSE el &amp;lt; upper(rng) END))&lt;br /&gt;
$$;&lt;br /&gt;
CREATE OPERATOR &amp;lt;@ (procedure=range_contains, leftarg=numeric, rightarg=numrange);&lt;br /&gt;
&lt;br /&gt;
-- tsrange (timestamp without time zone)&lt;br /&gt;
CREATE OR REPLACE FUNCTION range_contains(el timestamp, rng tsrange) RETURNS bool IMMUTABLE LANGUAGE sql AS $$&lt;br /&gt;
SELECT (lower_inf(rng) OR (CASE WHEN lower_inc(rng) THEN el &amp;gt;= lower(rng) ELSE el &amp;gt; lower(rng) END))&lt;br /&gt;
   AND (upper_inf(rng) OR (CASE WHEN upper_inc(rng) THEN el &amp;lt;= upper(rng) ELSE el &amp;lt; upper(rng) END))&lt;br /&gt;
$$;&lt;br /&gt;
CREATE OPERATOR &amp;lt;@ (procedure=range_contains, leftarg=timestamp, rightarg=tsrange);&lt;br /&gt;
&lt;br /&gt;
-- tstzrange (timestamp with time zone)&lt;br /&gt;
CREATE OR REPLACE FUNCTION range_contains(el timestamptz, rng tstzrange) RETURNS bool IMMUTABLE LANGUAGE sql AS $$&lt;br /&gt;
SELECT (lower_inf(rng) OR (CASE WHEN lower_inc(rng) THEN el &amp;gt;= lower(rng) ELSE el &amp;gt; lower(rng) END))&lt;br /&gt;
   AND (upper_inf(rng) OR (CASE WHEN upper_inc(rng) THEN el &amp;lt;= upper(rng) ELSE el &amp;lt; upper(rng) END))&lt;br /&gt;
$$;&lt;br /&gt;
CREATE OPERATOR &amp;lt;@ (procedure=range_contains, leftarg=timestamptz, rightarg=tstzrange);&lt;br /&gt;
&lt;br /&gt;
-- daterange (date)&lt;br /&gt;
CREATE OR REPLACE FUNCTION range_contains(el date, rng daterange) RETURNS bool IMMUTABLE LANGUAGE sql AS $$&lt;br /&gt;
SELECT (lower_inf(rng) OR (CASE WHEN lower_inc(rng) THEN el &amp;gt;= lower(rng) ELSE el &amp;gt; lower(rng) END))&lt;br /&gt;
   AND (upper_inf(rng) OR (CASE WHEN upper_inc(rng) THEN el &amp;lt;= upper(rng) ELSE el &amp;lt; upper(rng) END))&lt;br /&gt;
$$;&lt;br /&gt;
CREATE OPERATOR &amp;lt;@ (procedure=range_contains, leftarg=date, rightarg=daterange);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Intgr</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=Query_column_with_range_types&amp;diff=19322</id>
		<title>Query column with range types</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=Query_column_with_range_types&amp;diff=19322"/>
		<updated>2013-04-03T21:26:47Z</updated>

		<summary type="html">&lt;p&gt;Intgr: Created page with &amp;quot;== Rationale ==  The main use case for range types is to store ranges in PostgreSQL tables, and then find rows whose range includes a certain literal. These can already be indexe…&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Rationale ==&lt;br /&gt;
&lt;br /&gt;
The main use case for range types is to store ranges in PostgreSQL tables, and then find rows whose range includes a certain literal. These can already be indexed using GIN and GiST index types.&lt;br /&gt;
&amp;lt;!-- create table rng as select numrange(i, i+100) rng from generate_series(1,1000000) i; create index on rng using gist(rng); --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 db=# EXPLAIN ANALYZE SELECT * FROM rng WHERE rng @&amp;gt; 10.0;&lt;br /&gt;
 Bitmap Heap Scan on rng  (cost=48.40..2709.45 rows=1000 width=32) (actual time=0.103..0.103 rows=10 loops=1)&lt;br /&gt;
   Recheck Cond: (rng @&amp;gt; 10.0)&lt;br /&gt;
   -&amp;gt;  Bitmap Index Scan on rng_rng_idx  (cost=0.00..48.15 rows=1000 width=0) (actual time=0.096..0.096 rows=10 loops=1)&lt;br /&gt;
         Index Cond: (rng @&amp;gt; 10.0)&lt;br /&gt;
 Total runtime: 0.136 ms&lt;br /&gt;
&lt;br /&gt;
However, you cannot index inverse queries - if you want to find single values in a certain range:&lt;br /&gt;
&amp;lt;!-- create table num as select generate_series(1,1000000)::numeric i; create index on num(i); vacuum num; --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 db=# EXPLAIN ANALYZE SELECT * FROM num WHERE i &amp;lt;@ &#039;[0, 10)&#039;;&lt;br /&gt;
 Seq Scan on num  (cost=0.00..16925.00 rows=1000 width=6) (actual time=0.014..188.761 rows=9 loops=1)&lt;br /&gt;
   Filter: (i &amp;lt;@ &#039;[0,10]&#039;::numrange)&lt;br /&gt;
   Rows Removed by Filter: 999991&lt;br /&gt;
 Total runtime: 188.820 ms&lt;br /&gt;
&lt;br /&gt;
== Example ==&lt;br /&gt;
&lt;br /&gt;
Of course the above query is equivalent to the indexable query &amp;lt;tt&amp;gt;WHERE num &amp;gt;= 0 AND num &amp;lt; 10&amp;lt;/tt&amp;gt;. But what if you want to use range types? Well, you can create a custom operator with a function that automatically gets inlined:&lt;br /&gt;
&lt;br /&gt;
 db=# EXPLAIN ANALYZE SELECT * FROM num WHERE i &amp;lt;@ &#039;[0, 10)&#039;;&lt;br /&gt;
 Index Only Scan using num_i_idx on num  (cost=0.00..4.56 rows=10 width=6) (actual time=0.014..0.016 rows=9 loops=1)&lt;br /&gt;
   Index Cond: ((i &amp;gt;= 0::numeric) AND (i &amp;lt; 10::numeric))&lt;br /&gt;
   Heap Fetches: 0&lt;br /&gt;
 Total runtime: 0.039 ms&lt;br /&gt;
&lt;br /&gt;
Infinite terms get optimized out:&lt;br /&gt;
&lt;br /&gt;
 db=# EXPLAIN ANALYZE SELECT * FROM num WHERE i &amp;lt;@ &#039;[,10]&#039;;&lt;br /&gt;
 Index Only Scan using num_i_idx on num  (cost=0.00..4.53 rows=10 width=6) (actual time=0.007..0.009 rows=10 loops=1)&lt;br /&gt;
   Index Cond: (i &amp;lt;= 10::numeric)&lt;br /&gt;
   Heap Fetches: 0&lt;br /&gt;
 Total runtime: 0.032 ms&lt;br /&gt;
&lt;br /&gt;
=== Beware! ===&lt;br /&gt;
&lt;br /&gt;
These custom operators are deliberately defined to be non-commative. Do not write range queries in the form &amp;lt;tt&amp;gt;10.0 &amp;lt;@ range_col&amp;lt;/tt&amp;gt; because it will blow up:&lt;br /&gt;
&lt;br /&gt;
 db=# EXPLAIN ANALYZE SELECT * FROM rng WHERE 10.0 &amp;lt;@ rng;&lt;br /&gt;
 Seq Scan on rng  (cost=0.00..46358.16 rows=444424 width=32) (actual time=0.013..240.054 rows=10 loops=1)&lt;br /&gt;
   Filter: ((lower_inf(rng) OR CASE WHEN lower_inc(rng) THEN (10.0 &amp;gt;= lower(rng)) ELSE (10.0 &amp;gt; lower(rng)) END) AND (upper_inf(rng) OR CASE WHEN upper_inc(rng) THEN (10.0 &amp;lt;= upper(rng)) ELSE (10.0 &amp;lt; upper(rng)) END))&lt;br /&gt;
   Rows Removed by Filter: 999990&lt;br /&gt;
 Total runtime: 240.125 ms&lt;br /&gt;
&lt;br /&gt;
== Code ==&lt;br /&gt;
&lt;br /&gt;
You can adapt this code to any range type you need, just by changing the types of the function and the operator.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
-- int4range (integer)&lt;br /&gt;
CREATE OR REPLACE FUNCTION range_contains(el integer, rng int4range) RETURNS bool IMMUTABLE LANGUAGE sql AS $$&lt;br /&gt;
SELECT (lower_inf(rng) OR (CASE WHEN lower_inc(rng) THEN el &amp;gt;= lower(rng) ELSE el &amp;gt; lower(rng) END))&lt;br /&gt;
   AND (upper_inf(rng) OR (CASE WHEN upper_inc(rng) THEN el &amp;lt;= upper(rng) ELSE el &amp;lt; upper(rng) END))&lt;br /&gt;
$$;&lt;br /&gt;
CREATE OPERATOR &amp;lt;@ (procedure=range_contains, leftarg=integer, rightarg=int4range);&lt;br /&gt;
&lt;br /&gt;
-- int8range (bigint)&lt;br /&gt;
CREATE OR REPLACE FUNCTION range_contains(el bigint, rng int8range) RETURNS bool IMMUTABLE LANGUAGE sql AS $$&lt;br /&gt;
SELECT (lower_inf(rng) OR (CASE WHEN lower_inc(rng) THEN el &amp;gt;= lower(rng) ELSE el &amp;gt; lower(rng) END))&lt;br /&gt;
   AND (upper_inf(rng) OR (CASE WHEN upper_inc(rng) THEN el &amp;lt;= upper(rng) ELSE el &amp;lt; upper(rng) END))&lt;br /&gt;
$$;&lt;br /&gt;
CREATE OPERATOR &amp;lt;@ (procedure=range_contains, leftarg=bigint, rightarg=int8range);&lt;br /&gt;
&lt;br /&gt;
-- numrange (numeric)&lt;br /&gt;
CREATE OR REPLACE FUNCTION range_contains(el numeric, rng numrange) RETURNS bool IMMUTABLE LANGUAGE sql AS $$&lt;br /&gt;
SELECT (lower_inf(rng) OR (CASE WHEN lower_inc(rng) THEN el &amp;gt;= lower(rng) ELSE el &amp;gt; lower(rng) END))&lt;br /&gt;
   AND (upper_inf(rng) OR (CASE WHEN upper_inc(rng) THEN el &amp;lt;= upper(rng) ELSE el &amp;lt; upper(rng) END))&lt;br /&gt;
$$;&lt;br /&gt;
CREATE OPERATOR &amp;lt;@ (procedure=range_contains, leftarg=numeric, rightarg=numrange);&lt;br /&gt;
&lt;br /&gt;
-- tsrange (timestamp without time zone)&lt;br /&gt;
CREATE OR REPLACE FUNCTION range_contains(el timestamp, rng tsrange) RETURNS bool IMMUTABLE LANGUAGE sql AS $$&lt;br /&gt;
SELECT (lower_inf(rng) OR (CASE WHEN lower_inc(rng) THEN el &amp;gt;= lower(rng) ELSE el &amp;gt; lower(rng) END))&lt;br /&gt;
   AND (upper_inf(rng) OR (CASE WHEN upper_inc(rng) THEN el &amp;lt;= upper(rng) ELSE el &amp;lt; upper(rng) END))&lt;br /&gt;
$$;&lt;br /&gt;
CREATE OPERATOR &amp;lt;@ (procedure=range_contains, leftarg=timestamp, rightarg=tsrange);&lt;br /&gt;
&lt;br /&gt;
-- tstzrange (timestamp with time zone)&lt;br /&gt;
CREATE OR REPLACE FUNCTION range_contains(el timestamptz, rng tstzrange) RETURNS bool IMMUTABLE LANGUAGE sql AS $$&lt;br /&gt;
SELECT (lower_inf(rng) OR (CASE WHEN lower_inc(rng) THEN el &amp;gt;= lower(rng) ELSE el &amp;gt; lower(rng) END))&lt;br /&gt;
   AND (upper_inf(rng) OR (CASE WHEN upper_inc(rng) THEN el &amp;lt;= upper(rng) ELSE el &amp;lt; upper(rng) END))&lt;br /&gt;
$$;&lt;br /&gt;
CREATE OPERATOR &amp;lt;@ (procedure=range_contains, leftarg=timestamptz, rightarg=tstzrange);&lt;br /&gt;
&lt;br /&gt;
-- daterange (date)&lt;br /&gt;
CREATE OR REPLACE FUNCTION range_contains(el date, rng daterange) RETURNS bool IMMUTABLE LANGUAGE sql AS $$&lt;br /&gt;
SELECT (lower_inf(rng) OR (CASE WHEN lower_inc(rng) THEN el &amp;gt;= lower(rng) ELSE el &amp;gt; lower(rng) END))&lt;br /&gt;
   AND (upper_inf(rng) OR (CASE WHEN upper_inc(rng) THEN el &amp;lt;= upper(rng) ELSE el &amp;lt; upper(rng) END))&lt;br /&gt;
$$;&lt;br /&gt;
CREATE OPERATOR &amp;lt;@ (procedure=range_contains, leftarg=date, rightarg=daterange);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Intgr</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=Using_pg_upgrade_on_Ubuntu/Debian&amp;diff=18719</id>
		<title>Using pg upgrade on Ubuntu/Debian</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=Using_pg_upgrade_on_Ubuntu/Debian&amp;diff=18719"/>
		<updated>2012-12-20T18:07:27Z</updated>

		<summary type="html">&lt;p&gt;Intgr: Remove -F, since 9.2.2 already uses synchronous_commit=off, which is safer and not much slower&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Instructions for how to convert/upgrade a PostgreSQL database cluster using pg_upgrade on Ubuntu or Debian. For the sake of example, I&#039;m upgrading from version 9.1 to 9.2, but it should work with any version (8.3 and up -- [http://www.postgresql.org/docs/current/static/pgupgrade.html subject to limitations in pg_upgrade]).&lt;br /&gt;
&lt;br /&gt;
Simply replace any version numbers on the example command lines given below.&lt;br /&gt;
&lt;br /&gt;
== WARNING! ==&lt;br /&gt;
&#039;&#039;&#039;These instructions are experimental!&#039;&#039;&#039; This way of upgrading is not yet supported by Ubuntu upstream. Do it at your own risk. Always test in a staging environment before running on production. I have tested this on Ubuntu 12.04.&lt;br /&gt;
&lt;br /&gt;
When in doubt, use the old but slower pg_upgradecluster method.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
First you need to install relevant packages: postgresql-VER and postgresql-server-dev-VER. If you&#039;re using contrib extensions, you also need postgresql-contrib-VER, and possibly other modules like postgresql-plpython-VER...&lt;br /&gt;
&lt;br /&gt;
 sudo apt-get install postgresql-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; \&lt;br /&gt;
                      postgresql-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By default, Ubuntu creates a database cluster named &amp;quot;main&amp;quot; with each installed version. We will use these. Verify that these are configured:&lt;br /&gt;
&lt;br /&gt;
 # sudo pg_lsclusters&lt;br /&gt;
 Version Cluster   Port Status Owner    Data directory                     Log file&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      5432 down   postgres /var/lib/postgresql/9.1/main       /var/log/postgresql/postgresql-9.1-main.log&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      5433 down   postgres /var/lib/postgresql/9.2/main       /var/log/postgresql/postgresql-9.2-main.log&lt;br /&gt;
&lt;br /&gt;
== Upgrading to version 9.2 or later ==&lt;br /&gt;
First you need to stop the relevant database clusters. To stop all clusters, run:&lt;br /&gt;
&lt;br /&gt;
 sudo /etc/init.d/postgresql stop&lt;br /&gt;
&lt;br /&gt;
(If you don&#039;t want to stop all clusters, you can also use pg_ctlcluster to manage them one by one)&lt;br /&gt;
&lt;br /&gt;
Do the upgrade... (For extra performance, you can use the --link option to pg_upgrade; please [http://www.postgresql.org/docs/current/static/pgupgrade.html read pg_upgrade documentation first])&lt;br /&gt;
&lt;br /&gt;
 cd /tmp&lt;br /&gt;
 sudo -H -u postgres /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/bin/pg_upgrade \&lt;br /&gt;
    -b /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -B /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -d /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -D /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -o &#039; -c config_file=/etc/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf&#039; \&lt;br /&gt;
    -O &#039; -c config_file=/etc/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf&#039;&lt;br /&gt;
&lt;br /&gt;
See if it worked...&lt;br /&gt;
&lt;br /&gt;
 sudo pg_ctlcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; start&lt;br /&gt;
 sudo -u postgres psql --cluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 postgres=# select version();&lt;br /&gt;
 PostgreSQL 9.2rc1 on x86_64-unknown-linux-gnu, compiled by gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3, 64-bit&lt;br /&gt;
 postgres=# \l+&lt;br /&gt;
 ... list of databases ...&lt;br /&gt;
&lt;br /&gt;
== Upgrading to version 9.1 ==&lt;br /&gt;
The above instructions don&#039;t work when you upgrade to PostgreSQL 9.1. You have to jump through some hoops.&lt;br /&gt;
&lt;br /&gt;
First, stop all clusters:&lt;br /&gt;
&lt;br /&gt;
 sudo /etc/init.d/postgresql stop&lt;br /&gt;
&lt;br /&gt;
Note that I&#039;m now using version numbers &amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt; and &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 # sudo pg_lsclusters&lt;br /&gt;
 Version Cluster   Port Status Owner    Data directory                     Log file&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      &amp;lt;span style=&amp;quot;color:purple&amp;quot;&amp;gt;5432&amp;lt;/span&amp;gt; down   postgres /var/lib/postgresql/9.0/main       /var/log/postgresql/postgresql-9.0-main.log&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      &amp;lt;span style=&amp;quot;color:darkcyan&amp;quot;&amp;gt;5433&amp;lt;/span&amp;gt; down   postgres /var/lib/postgresql/9.1/main       /var/log/postgresql/postgresql-9.1-main.log&lt;br /&gt;
&lt;br /&gt;
First you have to symlink the configuration files to respective PostgreSQL data directories, where pg_upgrade expects to find them.&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/&lt;br /&gt;
 ln -s /etc/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/&lt;br /&gt;
&lt;br /&gt;
And now you have to run the pg_upgrade script with your respective configured port numbers:&lt;br /&gt;
&lt;br /&gt;
 cd /tmp&lt;br /&gt;
 sudo -H -u postgres /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/bin/pg_upgrade \&lt;br /&gt;
    -b /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -B /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -d /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -D /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -p &amp;lt;span style=&amp;quot;color:purple&amp;quot;&amp;gt;5432&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -P &amp;lt;span style=&amp;quot;color:darkcyan&amp;quot;&amp;gt;5433&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Afterwards, you may delete the unnecessary config file links (but it&#039;s safe to leave them there if you want)&lt;br /&gt;
&lt;br /&gt;
 rm /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf&lt;br /&gt;
 rm /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf&lt;br /&gt;
&lt;br /&gt;
== What next ==&lt;br /&gt;
Don&#039;t forget to merge your configuration changes in postgresql.conf, pg_hba.conf and other files.&lt;br /&gt;
&lt;br /&gt;
If you upgraded from 9.0 or earlier and you&#039;re using contrib modules or other addons, it is recommended to migrate them to proper extensions. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;CREATE EXTENSION hstore SCHEMA public FROM unpackaged;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
==== New cluster database &amp;quot;XXX&amp;quot; is not empty ====&lt;br /&gt;
The new cluster version already contains some data. If you want to get rid of it -- &#039;&#039;&#039;delete all data&#039;&#039;&#039; in the 9.2 version cluster, run:&lt;br /&gt;
&lt;br /&gt;
 pg_dropcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
 pg_createcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Where do I get PostgreSQL 9.2? ====&lt;br /&gt;
On Ubuntu, you can simply install 9.2 from the semi-official &amp;quot;PPA&amp;quot; repository:&lt;br /&gt;
&lt;br /&gt;
 sudo apt-get install python-software-properties&lt;br /&gt;
 sudo apt-add-repository ppa:pitti/postgresql&lt;br /&gt;
 sudo apt-get update&lt;br /&gt;
 sudo apt-get install postgresql-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Warning:&#039;&#039;&#039; Support for the current major version in the PPA may be dropped when a new major version is released. If you want to use this PPA, be prepared to always upgrade to the newest major version soon after it&#039;s released.&lt;/div&gt;</summary>
		<author><name>Intgr</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=Using_pg_upgrade_on_Ubuntu/Debian&amp;diff=18692</id>
		<title>Using pg upgrade on Ubuntu/Debian</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=Using_pg_upgrade_on_Ubuntu/Debian&amp;diff=18692"/>
		<updated>2012-12-10T21:49:49Z</updated>

		<summary type="html">&lt;p&gt;Intgr: Work around bug in pg_upgrade 9.2.2&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Instructions for how to convert/upgrade a PostgreSQL database cluster using pg_upgrade on Ubuntu or Debian. For the sake of example, I&#039;m upgrading from version 9.1 to 9.2, but it should work with any version (8.3 and up -- [http://www.postgresql.org/docs/current/static/pgupgrade.html subject to limitations in pg_upgrade]).&lt;br /&gt;
&lt;br /&gt;
Simply replace any version numbers on the example command lines given below.&lt;br /&gt;
&lt;br /&gt;
== WARNING! ==&lt;br /&gt;
&#039;&#039;&#039;These instructions are experimental!&#039;&#039;&#039; This way of upgrading is not yet supported by Ubuntu upstream. Do it at your own risk. Always test in a staging environment before running on production. I have tested this on Ubuntu 12.04.&lt;br /&gt;
&lt;br /&gt;
When in doubt, use the old but slower pg_upgradecluster method.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
First you need to install relevant packages: postgresql-VER and postgresql-server-dev-VER. If you&#039;re using contrib extensions, you also need postgresql-contrib-VER, and possibly other modules like postgresql-plpython-VER...&lt;br /&gt;
&lt;br /&gt;
 sudo apt-get install postgresql-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; \&lt;br /&gt;
                      postgresql-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By default, Ubuntu creates a database cluster named &amp;quot;main&amp;quot; with each installed version. We will use these. Verify that these are configured:&lt;br /&gt;
&lt;br /&gt;
 # sudo pg_lsclusters&lt;br /&gt;
 Version Cluster   Port Status Owner    Data directory                     Log file&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      5432 down   postgres /var/lib/postgresql/9.1/main       /var/log/postgresql/postgresql-9.1-main.log&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      5433 down   postgres /var/lib/postgresql/9.2/main       /var/log/postgresql/postgresql-9.2-main.log&lt;br /&gt;
&lt;br /&gt;
== Upgrading to version 9.2 or later ==&lt;br /&gt;
First you need to stop the relevant database clusters. To stop all clusters, run:&lt;br /&gt;
&lt;br /&gt;
 sudo /etc/init.d/postgresql stop&lt;br /&gt;
&lt;br /&gt;
(If you don&#039;t want to stop all clusters, you can also use pg_ctlcluster to manage them one by one)&lt;br /&gt;
&lt;br /&gt;
Do the upgrade... (For extra performance, you can use the --link option to pg_upgrade; please [http://www.postgresql.org/docs/current/static/pgupgrade.html read pg_upgrade documentation first])&lt;br /&gt;
&lt;br /&gt;
 cd /tmp&lt;br /&gt;
 sudo -H -u postgres /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/bin/pg_upgrade \&lt;br /&gt;
    -b /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -B /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -d /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -D /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -o &#039; -c config_file=/etc/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf&#039; \&lt;br /&gt;
    -O &#039; -c config_file=/etc/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf -F&#039;&lt;br /&gt;
&lt;br /&gt;
See if it worked...&lt;br /&gt;
&lt;br /&gt;
 sudo pg_ctlcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; start&lt;br /&gt;
 sudo -u postgres psql --cluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 postgres=# select version();&lt;br /&gt;
 PostgreSQL 9.2rc1 on x86_64-unknown-linux-gnu, compiled by gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3, 64-bit&lt;br /&gt;
 postgres=# \l+&lt;br /&gt;
 ... list of databases ...&lt;br /&gt;
&lt;br /&gt;
== Upgrading to version 9.1 ==&lt;br /&gt;
The above instructions don&#039;t work when you upgrade to PostgreSQL 9.1. You have to jump through some hoops.&lt;br /&gt;
&lt;br /&gt;
First, stop all clusters:&lt;br /&gt;
&lt;br /&gt;
 sudo /etc/init.d/postgresql stop&lt;br /&gt;
&lt;br /&gt;
Note that I&#039;m now using version numbers &amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt; and &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 # sudo pg_lsclusters&lt;br /&gt;
 Version Cluster   Port Status Owner    Data directory                     Log file&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      &amp;lt;span style=&amp;quot;color:purple&amp;quot;&amp;gt;5432&amp;lt;/span&amp;gt; down   postgres /var/lib/postgresql/9.0/main       /var/log/postgresql/postgresql-9.0-main.log&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      &amp;lt;span style=&amp;quot;color:darkcyan&amp;quot;&amp;gt;5433&amp;lt;/span&amp;gt; down   postgres /var/lib/postgresql/9.1/main       /var/log/postgresql/postgresql-9.1-main.log&lt;br /&gt;
&lt;br /&gt;
First you have to symlink the configuration files to respective PostgreSQL data directories, where pg_upgrade expects to find them.&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/&lt;br /&gt;
 ln -s /etc/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/&lt;br /&gt;
&lt;br /&gt;
And now you have to run the pg_upgrade script with your respective configured port numbers:&lt;br /&gt;
&lt;br /&gt;
 cd /tmp&lt;br /&gt;
 sudo -H -u postgres /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/bin/pg_upgrade \&lt;br /&gt;
    -b /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -B /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -d /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -D /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -p &amp;lt;span style=&amp;quot;color:purple&amp;quot;&amp;gt;5432&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -P &amp;lt;span style=&amp;quot;color:darkcyan&amp;quot;&amp;gt;5433&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Afterwards, you may delete the unnecessary config file links (but it&#039;s safe to leave them there if you want)&lt;br /&gt;
&lt;br /&gt;
 rm /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf&lt;br /&gt;
 rm /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf&lt;br /&gt;
&lt;br /&gt;
== What next ==&lt;br /&gt;
Don&#039;t forget to merge your configuration changes in postgresql.conf, pg_hba.conf and other files.&lt;br /&gt;
&lt;br /&gt;
If you upgraded from 9.0 or earlier and you&#039;re using contrib modules or other addons, it is recommended to migrate them to proper extensions. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;CREATE EXTENSION hstore SCHEMA public FROM unpackaged;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
==== New cluster database &amp;quot;XXX&amp;quot; is not empty ====&lt;br /&gt;
The new cluster version already contains some data. If you want to get rid of it -- &#039;&#039;&#039;delete all data&#039;&#039;&#039; in the 9.2 version cluster, run:&lt;br /&gt;
&lt;br /&gt;
 pg_dropcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
 pg_createcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Where do I get PostgreSQL 9.2? ====&lt;br /&gt;
On Ubuntu, you can simply install 9.2 from the semi-official &amp;quot;PPA&amp;quot; repository:&lt;br /&gt;
&lt;br /&gt;
 sudo apt-get install python-software-properties&lt;br /&gt;
 sudo apt-add-repository ppa:pitti/postgresql&lt;br /&gt;
 sudo apt-get update&lt;br /&gt;
 sudo apt-get install postgresql-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Warning:&#039;&#039;&#039; Support for the current major version in the PPA may be dropped when a new major version is released. If you want to use this PPA, be prepared to always upgrade to the newest major version soon after it&#039;s released.&lt;/div&gt;</summary>
		<author><name>Intgr</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=Index-only_scans&amp;diff=18606</id>
		<title>Index-only scans</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=Index-only_scans&amp;diff=18606"/>
		<updated>2012-11-16T13:39:01Z</updated>

		<summary type="html">&lt;p&gt;Intgr: Be clearer that this is PostgreSQL-specific. AFAIK some other databases do store visibility info in their indexes&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Index-only scans are a major performance feature added to Postgres 9.2. They allow certain types of queries to be satisfied just by retrieving data from indexes, and not from tables. This can result in a significant reduction in the amount of I/O necessary to satisfy queries.&lt;br /&gt;
&lt;br /&gt;
During a regular index scan, indexes are traversed, like any other tree structure, by comparing a constant against Datums that are stored in the index. Btree-indexed types must satisfy the trichotomy property; that is, the type must follow the reflexive, symmetric and transitive law. Those laws accord with our intuitive understanding of how a type ought to behave anyway, but the fact that an index&#039;s physical structure reflects the relative values of Datums actually mandates that these rules be followed by types. Indexes contain what are technically redundant copies of the column data that is indexed.&lt;br /&gt;
&lt;br /&gt;
PostgreSQL indexes do not contain visibility information. That is, it is not possible to ascertain if any given tuple is visible to the current transaction, which is why it has taken so long for index-only scans to be implemented. Writing an implementation with a cheap but reliable visibility look-aside proved challenging.&lt;br /&gt;
&lt;br /&gt;
The implementation of the feature disproportionately involved making an existing on-disk structure called the visibility map crash-safe. It was necessary for the structure to reliably (and inexpensively) indicate visibility of index tuples - to do any less would imply the possibility of index-only scans producing incorrect results, which of course would be absolutely unacceptable.&lt;br /&gt;
&lt;br /&gt;
The fact that indexes only contain data that is actually indexed, and not other unindexed columns, naturally precludes using an index-only scan when the other columns are queried (by appearing in a query select list, for example).&lt;br /&gt;
&lt;br /&gt;
=== Example queries where index-only scans could be used in principle ===&lt;br /&gt;
&lt;br /&gt;
Assuming that there is some (non-expression) index on a column (typically a primary key):&lt;br /&gt;
&lt;br /&gt;
  select count(*) from categories;&lt;br /&gt;
&lt;br /&gt;
Assuming that there is a composite index on (1st_indexed_col, 2nd_indexed_col):&lt;br /&gt;
&lt;br /&gt;
  select 1st_indexed_col, 2nd_indexed_col from categories;&lt;br /&gt;
&lt;br /&gt;
Postgres 9.2 added the capability of allowing indexed_col op ANY(ARRAY[...]) conditions to be used in plain index scans and index-only scans. Previously, such conditions could only be used in bitmap index scans. For this reason, it is possible to see an index-only scan for these ScalarArrayOpExpr queries:&lt;br /&gt;
&lt;br /&gt;
  select indexed_col from categories where indexed_col in (4, 5, 6);&lt;br /&gt;
&lt;br /&gt;
=== Index-only scans and index-access methods ===&lt;br /&gt;
&lt;br /&gt;
Index-only scans are not actually limited to scans on btree indexes. SP-GiST operator classes may optionally support index-only scans (naturally, this is only sensible when the index isn&#039;t lossy).&lt;br /&gt;
&lt;br /&gt;
  postgres=# select amname, amcanreturn from pg_am where amcanreturn != 0;&lt;br /&gt;
   amname | amcanreturn&lt;br /&gt;
  --------+--------------&lt;br /&gt;
   btree  | btcanreturn&lt;br /&gt;
   spgist | spgcanreturn&lt;br /&gt;
  (2 rows)&lt;br /&gt;
&lt;br /&gt;
Support for additional index AMs may follow in a future release of PostgreSQL.&lt;br /&gt;
&lt;br /&gt;
=== The Visibility Map (and other relation forks) ===&lt;br /&gt;
&lt;br /&gt;
The Visibility Map is a simple data structure associated with every heap relation (table). It is a &amp;quot;relation fork&amp;quot;; an on-disk ancillary file associated with a particular relation (table or index). Note that index relations (that is, indexes) do not have a visibility map associated with them. The visibility map is concerned with tracking which tuples are visible to all transactions at a high level. Tuples from one transaction may or may not be visible to any given other transaction, depending on whether or not their originating transaction actually committed (yet, or ever, if the transaction aborted), and when that occurred relative to our transaction&#039;s current snapshot. Note that the exact&lt;br /&gt;
behaviour depends on our transaction isolation level. Note also that it is quite possible for one transaction to see one physical tuple/set of values for one logical tuple, while another transaction sees other, distinct values for that same logical tuple, because, in effect, each of the two transaction has a differing idea of what constitutes &amp;quot;now&amp;quot;. This is the core idea of MVCC. When there is absolute consensus that all physical tuples in a heap page are visible, the page&#039;s corresponding bit may be set.&lt;br /&gt;
&lt;br /&gt;
Another relation fork that you may be familiar with is the freespace map. In contrast to the visibility map, there is a FSM for both heap and index relations (with the sole exception of hash index relations, which have none).&lt;br /&gt;
&lt;br /&gt;
The purpose of the freespace map is to quickly locate a page with enough free space to hold a tuple to be stored, or to determine if no such page exists and the relation has to be extended.&lt;br /&gt;
&lt;br /&gt;
In PostgreSQL 8.4, the current freespace map implementation was added. It made the freespace map an on-disk relation fork. The previous implementation required administrators to guestimate the number of relations, and the required freespace map size for each, so that the freespace map existed only in a fixed allocation of shared memory. This tended to result in wasted space due to undersizing, as the core system&#039;s storage manager needlessly extended relations.&lt;br /&gt;
&lt;br /&gt;
  [peter@peterlaptop 12935]$ ls -l -h -a&lt;br /&gt;
  -rw-------. 1 peter peter 8.0K Sep 28 00:00 12910&lt;br /&gt;
  -rw-------. 1 peter peter  24K Sep 28 00:00 12910_fsm&lt;br /&gt;
  -rw-------. 1 peter peter 8.0K Sep 28 00:00 12910_vm&lt;br /&gt;
  ***SNIP***&lt;br /&gt;
&lt;br /&gt;
The FSM is structured as a binary tree [http://www.postgresql.org/docs/9.2/static/storage-fsm.html]. There is one leaf node per heap page, with non-leaf nodes stores the maximum amount of free space for any of its children. So, unlike EXPLAIN output&#039;s node costs, the values are not cumulative.&lt;br /&gt;
&lt;br /&gt;
The visibility map is a simpler structure. There is one bit for each page in the heap relation that the visibility map corresponds to.&lt;br /&gt;
&lt;br /&gt;
The primary practical reason for having and maintaining the visibility map is to optimise VACUUM. A set bit indicates that all tuples on the corresponding heap page are known to be visible to all transactions, and therefore that vacuuming the page is unnecessary. Like the new freespace map implementation, the visibility map was added in Postgres 8.4.&lt;br /&gt;
&lt;br /&gt;
The visibility map is conservative in that a set bit (1) indicates that all tuples are visible on the page, but an unset bit (0) indicates that that condition may or may not be true [http://www.postgresql.org/docs/9.2/static/storage-vm.html].&lt;br /&gt;
&lt;br /&gt;
=== Crash safety, recovery and the visibility map ===&lt;br /&gt;
&lt;br /&gt;
This involves WAL-logging setting a bit within the visibility map during VACUUM, and taking various special measures during recovery.&lt;br /&gt;
&lt;br /&gt;
The Postgres write-ahead log is widely used to ensure crash-safety, but it is also intergral to the built-in Hot Standby/Streaming replication feature.&lt;br /&gt;
&lt;br /&gt;
Recovery treats marking a page all-visible as a recovery conflict for snapshots that could still fail to see XIDs on that page.  PostgreSQL may in the future try to soften this, so that the implementation simply forces index scans to do heap fetches in cases where this may be an issue, rather than throwing a hard conflict.&lt;br /&gt;
&lt;br /&gt;
=== Covering indexes ===&lt;br /&gt;
&lt;br /&gt;
Covering indexes are indexes creating for the express purpose of being used in index-only scans. They typically &amp;quot;cover&amp;quot; more columns than would otherwise make sense for an index, typically columns that are known to be part of particular expensive, frequently executed query&#039;s selectlist. PostgreSQL supports using just the first few columns of the index in a regular index scan if that is in the query&#039;s predicate, so covering indexes need not be completely useless for regular index scans.&lt;br /&gt;
&lt;br /&gt;
=== Interaction with HOT ===&lt;br /&gt;
&lt;br /&gt;
HOT (Heap-only tuples) is a major performance feature that was added in Postgres 8.3. This allowed UPDATES to rows (which, owing to Postgres&#039;s MVCC architecture, are implemented with a deletion and insertion of physical tuples) to only have to create a new physical heap tuple when inserting, and not a new index tuple, if and only if the update did not affect indexed columns.&lt;br /&gt;
&lt;br /&gt;
With HOT, it became possible for an index scan to traverse a so-called HOT chain; it could get from the physical index tuple (which would probably have been created by an original INSERT, and related to an earlier version of the logical tuple), to the corresponding physical heap tuple. The heap tuple would itself contain a pointer to the next version of the tuple (that is, the tuple ctid), which might, in turn, have a pointer of its own. The index scan eventually arrives at tuple that is current according to the query&#039;s snapshot.&lt;br /&gt;
&lt;br /&gt;
HOT also enables opportunistic mini-vacuums, where the HOT chain is &amp;quot;pruned&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
All told, this performance optimisation has been found to be very valuable, particularly for OLTP workloads. It is quite natural that tuples that are frequently updated are generally not indexed. However, when considering creating a covering index, the need to maximise the number of HOT updates should be carefully weighed.&lt;br /&gt;
&lt;br /&gt;
You can monitor the total proportion of HOT updates for each relation using this query.&lt;br /&gt;
&lt;br /&gt;
  postgres=# select n_tup_upd, n_tup_hot_upd from pg_stat_user_tables;&lt;br /&gt;
&lt;br /&gt;
=== What types of queries may be satisfied by an index-only scan? ===&lt;br /&gt;
&lt;br /&gt;
Aside from the obvious restriction that queries cannot reference columns that are not indexed by a single index in order to use an index-only scan, the need to visit the heap where all tuples are not known to be visible is relatively expensive. The planner weighs this factor heavily when considering an index-only scan, and in general the need to ensure that the bulk of the table&#039;s tuples have their visibility map bits set is likely to restrict index-only scans&#039; usefulness to queries against infrequently updated tables.&lt;br /&gt;
&lt;br /&gt;
It is not necessary for all bits to be set; index-only scans may &amp;quot;visit the heap&amp;quot; if that is necessary. Index-only scans are something of a misnomer, in fact - index mostly scans might be a more appropriate appellation. An explain analyze involving an index-only scan will indicate how frequently that occurred in practice.&lt;br /&gt;
&lt;br /&gt;
  postgres=# explain analyze select count(*) from categories;&lt;br /&gt;
                                                                  QUERY PLAN&lt;br /&gt;
  ------------------------------------------------------------------------------------------------------------------------------------------&lt;br /&gt;
   Aggregate  (cost=12.53..12.54 rows=1 width=0) (actual time=0.046..0.046 rows=1 loops=1)&lt;br /&gt;
     -&amp;gt;  Index Only Scan using categories_pkey on categories  (cost=0.00..12.49 rows=16 width=0) (actual time=0.018..0.038 rows=16 loops=1)&lt;br /&gt;
           Heap Fetches: 16&lt;br /&gt;
   Total runtime: 0.108 ms&lt;br /&gt;
  (4 rows)&lt;br /&gt;
&lt;br /&gt;
As the number of heap &amp;quot;visits&amp;quot; goes up, the planner will eventually conclude that an index-only scan isn&#039;t desirable, as it isn&#039;t the cheapest possible plan according to its cost model. The value of index-only scans lies wholly in their potential to allow us to elide heap access (if only partially) and minimise I/O.&lt;br /&gt;
&lt;br /&gt;
=== Is &amp;quot;count(*)&amp;quot; much faster now? ===&lt;br /&gt;
&lt;br /&gt;
A traditional complaint made of PostgreSQL, generally when comparing it unfavourably with MySQL (at least when using the MyIsam storage engine, which doesn&#039;t use MVCC) has been &amp;quot;count(*) is slow&amp;quot;. Index-only scans *can* be used to satisfy these queries without there being any predicate to limit the number of rows returned, and without forcing an index to be used by specifying that the tuples should be ordered by an indexed column. However, in practice that isn&#039;t particularly likely.&lt;br /&gt;
&lt;br /&gt;
It is important to realise that the planner is concerned with minimising the total cost of the query. With databases, the cost of I/O typically dominates. For that reason, &amp;quot;count(*) without any predicate&amp;quot; queries will only use an index-only scan if the index is significantly smaller than its table. This typically only happens when the table&#039;s row width is much wider than some indexes&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Why isn&#039;t my query using an index-only scan? ===&lt;br /&gt;
&lt;br /&gt;
VACUUM does not have any particular tendency to behave more aggressively to facilitate using index-only scans more frequently. While VACUUM can be set to behave more aggressively in various ways, it&#039;s far from clear that to do so specifically to make index-only scans occur more frequently represents a sensible course of action.&lt;br /&gt;
&lt;br /&gt;
The planner doesn&#039;t directly examine the entire visibility map of a relation when considering an index-only scan (however, the executor does maintain a running tally, which is visible in explain analyze output). However, the planner does naturally weigh the proportion of pages which are known visible to all.&lt;br /&gt;
&lt;br /&gt;
In Postgres 9.2, statistics are gathered about the proportion of pages that are known all-visible. The pg_class.relallvisible column indicates how many pages are visible (the proportion can be obtained by calculating it as a proportion of pg_class.relpages). These statistics are updated during VACUUM and ANALYZE.&lt;br /&gt;
&lt;br /&gt;
Note that it is possible to examine the number of index scans (including index-only scans and bitmap index scans) by examining&lt;br /&gt;
pg_stat_user_indexes.idx_scan. If your covering index isn&#039;t being used, you&#039;re essentially paying for the overhead of maintaining it during writes with no benefit in return. Drop the index!&lt;br /&gt;
&lt;br /&gt;
=== Summary ===&lt;br /&gt;
&lt;br /&gt;
It is possible for index-only scans to greatly decrease the amount of I/O required to execute some queries. For certain queries, particularly queries that are characteristic of data warehousing (i.e. relatively large amounts of static, infrequently-updated data where reports on historic data is frequently required), they can considerably improve performance. Such queries have been observed to execute anything from twice to twenty times as fast with index-only scans. However, one should bear in mind that:&lt;br /&gt;
&lt;br /&gt;
* Index-only scans are opportunistic, in that they take advantage of a pre-existing state of affairs where it happens to be possible to elide heap access. However, the server doesn&#039;t make any particular effort to facilitate index-only scans, and it is difficult to recommend a course of action to make index-only scans occur more frequently, except to define covering indexes in response to a measured need (For example, when pg_stat_statements indicates that a disproportionate amount of I/O is being used to execute a query against fairly static data, with a smallish subset of table columns retrieved).&lt;br /&gt;
&lt;br /&gt;
* When creating a covering index, the likely effect on HOT updates should be weighed heavily. Are there many HOT updates on the table to begin with? This is a general point of concern, because creating an index may prevent HOT updates from occurring, and because the number of HOT updates is a reasonably good proxy for just how static a table is, and therefore how likely it is that most heap pages are known to be all-visible.&lt;br /&gt;
&lt;br /&gt;
* Index-only scans are only used when the planner surmises that that will reduce the total amount of I/O required, according to its imperfect cost-based modelling. This all heavily depends on visibility of tuples, if an index would be used anyway (i.e. how selective a predicate is, etc), and if there is actually an index available that could be used by an index-only scan in principle.&lt;br /&gt;
&lt;br /&gt;
[[Category:Indexes]]&lt;/div&gt;</summary>
		<author><name>Intgr</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=Using_pg_upgrade_on_Ubuntu/Debian&amp;diff=18491</id>
		<title>Using pg upgrade on Ubuntu/Debian</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=Using_pg_upgrade_on_Ubuntu/Debian&amp;diff=18491"/>
		<updated>2012-10-29T11:19:16Z</updated>

		<summary type="html">&lt;p&gt;Intgr: Supported in 8.3 and up, subject to documented limitations&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Instructions for how to convert/upgrade a PostgreSQL database cluster using pg_upgrade on Ubuntu or Debian. For the sake of example, I&#039;m upgrading from version 9.1 to 9.2, but it should work with any version (8.3 and up -- [http://www.postgresql.org/docs/current/static/pgupgrade.html subject to limitations in pg_upgrade]).&lt;br /&gt;
&lt;br /&gt;
Simply replace any version numbers on the example command lines given below.&lt;br /&gt;
&lt;br /&gt;
== WARNING! ==&lt;br /&gt;
&#039;&#039;&#039;These instructions are experimental!&#039;&#039;&#039; This way of upgrading is not yet supported by Ubuntu upstream. Do it at your own risk. Always test in a staging environment before running on production. I have tested this on Ubuntu 12.04.&lt;br /&gt;
&lt;br /&gt;
When in doubt, use the old but slower pg_upgradecluster method.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
First you need to install relevant packages: postgresql-VER and postgresql-server-dev-VER. If you&#039;re using contrib extensions, you also need postgresql-contrib-VER, and possibly other modules like postgresql-plpython-VER...&lt;br /&gt;
&lt;br /&gt;
 sudo apt-get install postgresql-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; \&lt;br /&gt;
                      postgresql-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By default, Ubuntu creates a database cluster named &amp;quot;main&amp;quot; with each installed version. We will use these. Verify that these are configured:&lt;br /&gt;
&lt;br /&gt;
 # sudo pg_lsclusters&lt;br /&gt;
 Version Cluster   Port Status Owner    Data directory                     Log file&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      5432 down   postgres /var/lib/postgresql/9.1/main       /var/log/postgresql/postgresql-9.1-main.log&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      5433 down   postgres /var/lib/postgresql/9.2/main       /var/log/postgresql/postgresql-9.2-main.log&lt;br /&gt;
&lt;br /&gt;
== Upgrading to version 9.2 or later ==&lt;br /&gt;
First you need to stop the relevant database clusters. To stop all clusters, run:&lt;br /&gt;
&lt;br /&gt;
 sudo /etc/init.d/postgresql stop&lt;br /&gt;
&lt;br /&gt;
(If you don&#039;t want to stop all clusters, you can also use pg_ctlcluster to manage them one by one)&lt;br /&gt;
&lt;br /&gt;
Do the upgrade... (For extra performance, you can use the --link option to pg_upgrade; please [http://www.postgresql.org/docs/current/static/pgupgrade.html read pg_upgrade documentation first])&lt;br /&gt;
&lt;br /&gt;
 cd /tmp&lt;br /&gt;
 sudo -H -u postgres /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/bin/pg_upgrade \&lt;br /&gt;
    -b /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -B /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -d /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -D /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -o &#039;-c config_file=/etc/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf&#039; \&lt;br /&gt;
    -O &#039;-c config_file=/etc/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf -F&#039;&lt;br /&gt;
&lt;br /&gt;
See if it worked...&lt;br /&gt;
&lt;br /&gt;
 sudo pg_ctlcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; start&lt;br /&gt;
 sudo -u postgres psql --cluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 postgres=# select version();&lt;br /&gt;
 PostgreSQL 9.2rc1 on x86_64-unknown-linux-gnu, compiled by gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3, 64-bit&lt;br /&gt;
 postgres=# \l+&lt;br /&gt;
 ... list of databases ...&lt;br /&gt;
&lt;br /&gt;
== Upgrading to version 9.1 ==&lt;br /&gt;
The above instructions don&#039;t work when you upgrade to PostgreSQL 9.1. You have to jump through some hoops.&lt;br /&gt;
&lt;br /&gt;
First, stop all clusters:&lt;br /&gt;
&lt;br /&gt;
 sudo /etc/init.d/postgresql stop&lt;br /&gt;
&lt;br /&gt;
Note that I&#039;m now using version numbers &amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt; and &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 # sudo pg_lsclusters&lt;br /&gt;
 Version Cluster   Port Status Owner    Data directory                     Log file&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      &amp;lt;span style=&amp;quot;color:purple&amp;quot;&amp;gt;5432&amp;lt;/span&amp;gt; down   postgres /var/lib/postgresql/9.0/main       /var/log/postgresql/postgresql-9.0-main.log&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      &amp;lt;span style=&amp;quot;color:darkcyan&amp;quot;&amp;gt;5433&amp;lt;/span&amp;gt; down   postgres /var/lib/postgresql/9.1/main       /var/log/postgresql/postgresql-9.1-main.log&lt;br /&gt;
&lt;br /&gt;
First you have to symlink the configuration files to respective PostgreSQL data directories, where pg_upgrade expects to find them.&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/&lt;br /&gt;
 ln -s /etc/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/&lt;br /&gt;
&lt;br /&gt;
And now you have to run the pg_upgrade script with your respective configured port numbers:&lt;br /&gt;
&lt;br /&gt;
 cd /tmp&lt;br /&gt;
 sudo -H -u postgres /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/bin/pg_upgrade \&lt;br /&gt;
    -b /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -B /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -d /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -D /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -p &amp;lt;span style=&amp;quot;color:purple&amp;quot;&amp;gt;5432&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -P &amp;lt;span style=&amp;quot;color:darkcyan&amp;quot;&amp;gt;5433&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Afterwards, you may delete the unnecessary config file links (but it&#039;s safe to leave them there if you want)&lt;br /&gt;
&lt;br /&gt;
 rm /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf&lt;br /&gt;
 rm /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf&lt;br /&gt;
&lt;br /&gt;
== What next ==&lt;br /&gt;
Don&#039;t forget to merge your configuration changes in postgresql.conf, pg_hba.conf and other files.&lt;br /&gt;
&lt;br /&gt;
If you upgraded from 9.0 or earlier and you&#039;re using contrib modules or other addons, it is recommended to migrate them to proper extensions. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;CREATE EXTENSION hstore SCHEMA public FROM unpackaged;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
==== New cluster database &amp;quot;XXX&amp;quot; is not empty ====&lt;br /&gt;
The new cluster version already contains some data. If you want to get rid of it -- &#039;&#039;&#039;delete all data&#039;&#039;&#039; in the 9.2 version cluster, run:&lt;br /&gt;
&lt;br /&gt;
 pg_dropcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
 pg_createcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Where do I get PostgreSQL 9.2? ====&lt;br /&gt;
On Ubuntu, you can simply install 9.2 from the semi-official &amp;quot;PPA&amp;quot; repository:&lt;br /&gt;
&lt;br /&gt;
 sudo apt-get install python-software-properties&lt;br /&gt;
 sudo apt-add-repository ppa:pitti/postgresql&lt;br /&gt;
 sudo apt-get update&lt;br /&gt;
 sudo apt-get install postgresql-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Warning:&#039;&#039;&#039; Support for the current major version in the PPA may be dropped when a new major version is released. If you want to use this PPA, be prepared to always upgrade to the newest major version soon after it&#039;s released.&lt;/div&gt;</summary>
		<author><name>Intgr</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=Using_pg_upgrade_on_Ubuntu/Debian&amp;diff=18490</id>
		<title>Using pg upgrade on Ubuntu/Debian</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=Using_pg_upgrade_on_Ubuntu/Debian&amp;diff=18490"/>
		<updated>2012-10-29T11:07:25Z</updated>

		<summary type="html">&lt;p&gt;Intgr: /* New cluster database &amp;quot;XXX&amp;quot; is not empty */ clarify&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Instructions for how to convert/upgrade a PostgreSQL database cluster using pg_upgrade on Ubuntu or Debian. For the sake of example, I&#039;m upgrading from version 9.1 to 9.2, but it should work with any version. Replace any version numbers on the command lines.&lt;br /&gt;
&lt;br /&gt;
== WARNING! ==&lt;br /&gt;
&#039;&#039;&#039;These instructions are experimental!&#039;&#039;&#039; This way of upgrading is not yet supported by Ubuntu upstream. Do it at your own risk. Always test in a staging environment before running on production. I have tested this on Ubuntu 12.04.&lt;br /&gt;
&lt;br /&gt;
When in doubt, use the old but slower pg_upgradecluster method.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
First you need to install relevant packages: postgresql-VER and postgresql-server-dev-VER. If you&#039;re using contrib extensions, you also need postgresql-contrib-VER, and possibly other modules like postgresql-plpython-VER...&lt;br /&gt;
&lt;br /&gt;
 sudo apt-get install postgresql-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; \&lt;br /&gt;
                      postgresql-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By default, Ubuntu creates a database cluster named &amp;quot;main&amp;quot; with each installed version. We will use these. Verify that these are configured:&lt;br /&gt;
&lt;br /&gt;
 # sudo pg_lsclusters&lt;br /&gt;
 Version Cluster   Port Status Owner    Data directory                     Log file&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      5432 down   postgres /var/lib/postgresql/9.1/main       /var/log/postgresql/postgresql-9.1-main.log&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      5433 down   postgres /var/lib/postgresql/9.2/main       /var/log/postgresql/postgresql-9.2-main.log&lt;br /&gt;
&lt;br /&gt;
== Upgrading to version 9.2 or later ==&lt;br /&gt;
First you need to stop the relevant database clusters. To stop all clusters, run:&lt;br /&gt;
&lt;br /&gt;
 sudo /etc/init.d/postgresql stop&lt;br /&gt;
&lt;br /&gt;
(If you don&#039;t want to stop all clusters, you can also use pg_ctlcluster to manage them one by one)&lt;br /&gt;
&lt;br /&gt;
Do the upgrade... (For extra performance, you can use the --link option to pg_upgrade; please [http://www.postgresql.org/docs/current/static/pgupgrade.html read pg_upgrade documentation first])&lt;br /&gt;
&lt;br /&gt;
 cd /tmp&lt;br /&gt;
 sudo -H -u postgres /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/bin/pg_upgrade \&lt;br /&gt;
    -b /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -B /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -d /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -D /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -o &#039;-c config_file=/etc/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf&#039; \&lt;br /&gt;
    -O &#039;-c config_file=/etc/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf -F&#039;&lt;br /&gt;
&lt;br /&gt;
See if it worked...&lt;br /&gt;
&lt;br /&gt;
 sudo pg_ctlcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; start&lt;br /&gt;
 sudo -u postgres psql --cluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 postgres=# select version();&lt;br /&gt;
 PostgreSQL 9.2rc1 on x86_64-unknown-linux-gnu, compiled by gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3, 64-bit&lt;br /&gt;
 postgres=# \l+&lt;br /&gt;
 ... list of databases ...&lt;br /&gt;
&lt;br /&gt;
== Upgrading to version 9.1 ==&lt;br /&gt;
The above instructions don&#039;t work when you upgrade to PostgreSQL 9.1. You have to jump through some hoops.&lt;br /&gt;
&lt;br /&gt;
First, stop all clusters:&lt;br /&gt;
&lt;br /&gt;
 sudo /etc/init.d/postgresql stop&lt;br /&gt;
&lt;br /&gt;
Note that I&#039;m now using version numbers &amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt; and &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 # sudo pg_lsclusters&lt;br /&gt;
 Version Cluster   Port Status Owner    Data directory                     Log file&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      &amp;lt;span style=&amp;quot;color:purple&amp;quot;&amp;gt;5432&amp;lt;/span&amp;gt; down   postgres /var/lib/postgresql/9.0/main       /var/log/postgresql/postgresql-9.0-main.log&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      &amp;lt;span style=&amp;quot;color:darkcyan&amp;quot;&amp;gt;5433&amp;lt;/span&amp;gt; down   postgres /var/lib/postgresql/9.1/main       /var/log/postgresql/postgresql-9.1-main.log&lt;br /&gt;
&lt;br /&gt;
First you have to symlink the configuration files to respective PostgreSQL data directories, where pg_upgrade expects to find them.&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/&lt;br /&gt;
 ln -s /etc/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/&lt;br /&gt;
&lt;br /&gt;
And now you have to run the pg_upgrade script with your respective configured port numbers:&lt;br /&gt;
&lt;br /&gt;
 cd /tmp&lt;br /&gt;
 sudo -H -u postgres /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/bin/pg_upgrade \&lt;br /&gt;
    -b /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -B /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -d /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -D /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -p &amp;lt;span style=&amp;quot;color:purple&amp;quot;&amp;gt;5432&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -P &amp;lt;span style=&amp;quot;color:darkcyan&amp;quot;&amp;gt;5433&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Afterwards, you may delete the unnecessary config file links (but it&#039;s safe to leave them there if you want)&lt;br /&gt;
&lt;br /&gt;
 rm /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf&lt;br /&gt;
 rm /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf&lt;br /&gt;
&lt;br /&gt;
== What next ==&lt;br /&gt;
Don&#039;t forget to merge your configuration changes in postgresql.conf, pg_hba.conf and other files.&lt;br /&gt;
&lt;br /&gt;
If you upgraded from 9.0 or earlier and you&#039;re using contrib modules or other addons, it is recommended to migrate them to proper extensions. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;CREATE EXTENSION hstore SCHEMA public FROM unpackaged;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
==== New cluster database &amp;quot;XXX&amp;quot; is not empty ====&lt;br /&gt;
The new cluster version already contains some data. If you want to get rid of it -- &#039;&#039;&#039;delete all data&#039;&#039;&#039; in the 9.2 version cluster, run:&lt;br /&gt;
&lt;br /&gt;
 pg_dropcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
 pg_createcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Where do I get PostgreSQL 9.2? ====&lt;br /&gt;
On Ubuntu, you can simply install 9.2 from the semi-official &amp;quot;PPA&amp;quot; repository:&lt;br /&gt;
&lt;br /&gt;
 sudo apt-get install python-software-properties&lt;br /&gt;
 sudo apt-add-repository ppa:pitti/postgresql&lt;br /&gt;
 sudo apt-get update&lt;br /&gt;
 sudo apt-get install postgresql-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Warning:&#039;&#039;&#039; Support for the current major version in the PPA may be dropped when a new major version is released. If you want to use this PPA, be prepared to always upgrade to the newest major version soon after it&#039;s released.&lt;/div&gt;</summary>
		<author><name>Intgr</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=Using_pg_upgrade_on_Ubuntu/Debian&amp;diff=18489</id>
		<title>Using pg upgrade on Ubuntu/Debian</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=Using_pg_upgrade_on_Ubuntu/Debian&amp;diff=18489"/>
		<updated>2012-10-29T11:06:40Z</updated>

		<summary type="html">&lt;p&gt;Intgr: /* Upgrading to version 9.1 */ explain&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Instructions for how to convert/upgrade a PostgreSQL database cluster using pg_upgrade on Ubuntu or Debian. For the sake of example, I&#039;m upgrading from version 9.1 to 9.2, but it should work with any version. Replace any version numbers on the command lines.&lt;br /&gt;
&lt;br /&gt;
== WARNING! ==&lt;br /&gt;
&#039;&#039;&#039;These instructions are experimental!&#039;&#039;&#039; This way of upgrading is not yet supported by Ubuntu upstream. Do it at your own risk. Always test in a staging environment before running on production. I have tested this on Ubuntu 12.04.&lt;br /&gt;
&lt;br /&gt;
When in doubt, use the old but slower pg_upgradecluster method.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
First you need to install relevant packages: postgresql-VER and postgresql-server-dev-VER. If you&#039;re using contrib extensions, you also need postgresql-contrib-VER, and possibly other modules like postgresql-plpython-VER...&lt;br /&gt;
&lt;br /&gt;
 sudo apt-get install postgresql-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; \&lt;br /&gt;
                      postgresql-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By default, Ubuntu creates a database cluster named &amp;quot;main&amp;quot; with each installed version. We will use these. Verify that these are configured:&lt;br /&gt;
&lt;br /&gt;
 # sudo pg_lsclusters&lt;br /&gt;
 Version Cluster   Port Status Owner    Data directory                     Log file&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      5432 down   postgres /var/lib/postgresql/9.1/main       /var/log/postgresql/postgresql-9.1-main.log&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      5433 down   postgres /var/lib/postgresql/9.2/main       /var/log/postgresql/postgresql-9.2-main.log&lt;br /&gt;
&lt;br /&gt;
== Upgrading to version 9.2 or later ==&lt;br /&gt;
First you need to stop the relevant database clusters. To stop all clusters, run:&lt;br /&gt;
&lt;br /&gt;
 sudo /etc/init.d/postgresql stop&lt;br /&gt;
&lt;br /&gt;
(If you don&#039;t want to stop all clusters, you can also use pg_ctlcluster to manage them one by one)&lt;br /&gt;
&lt;br /&gt;
Do the upgrade... (For extra performance, you can use the --link option to pg_upgrade; please [http://www.postgresql.org/docs/current/static/pgupgrade.html read pg_upgrade documentation first])&lt;br /&gt;
&lt;br /&gt;
 cd /tmp&lt;br /&gt;
 sudo -H -u postgres /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/bin/pg_upgrade \&lt;br /&gt;
    -b /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -B /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -d /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -D /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -o &#039;-c config_file=/etc/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf&#039; \&lt;br /&gt;
    -O &#039;-c config_file=/etc/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf -F&#039;&lt;br /&gt;
&lt;br /&gt;
See if it worked...&lt;br /&gt;
&lt;br /&gt;
 sudo pg_ctlcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; start&lt;br /&gt;
 sudo -u postgres psql --cluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 postgres=# select version();&lt;br /&gt;
 PostgreSQL 9.2rc1 on x86_64-unknown-linux-gnu, compiled by gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3, 64-bit&lt;br /&gt;
 postgres=# \l+&lt;br /&gt;
 ... list of databases ...&lt;br /&gt;
&lt;br /&gt;
== Upgrading to version 9.1 ==&lt;br /&gt;
The above instructions don&#039;t work when you upgrade to PostgreSQL 9.1. You have to jump through some hoops.&lt;br /&gt;
&lt;br /&gt;
First, stop all clusters:&lt;br /&gt;
&lt;br /&gt;
 sudo /etc/init.d/postgresql stop&lt;br /&gt;
&lt;br /&gt;
Note that I&#039;m now using version numbers &amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt; and &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 # sudo pg_lsclusters&lt;br /&gt;
 Version Cluster   Port Status Owner    Data directory                     Log file&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      &amp;lt;span style=&amp;quot;color:purple&amp;quot;&amp;gt;5432&amp;lt;/span&amp;gt; down   postgres /var/lib/postgresql/9.0/main       /var/log/postgresql/postgresql-9.0-main.log&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      &amp;lt;span style=&amp;quot;color:darkcyan&amp;quot;&amp;gt;5433&amp;lt;/span&amp;gt; down   postgres /var/lib/postgresql/9.1/main       /var/log/postgresql/postgresql-9.1-main.log&lt;br /&gt;
&lt;br /&gt;
First you have to symlink the configuration files to respective PostgreSQL data directories, where pg_upgrade expects to find them.&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/&lt;br /&gt;
 ln -s /etc/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/&lt;br /&gt;
&lt;br /&gt;
And now you have to run the pg_upgrade script with your respective configured port numbers:&lt;br /&gt;
&lt;br /&gt;
 cd /tmp&lt;br /&gt;
 sudo -H -u postgres /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/bin/pg_upgrade \&lt;br /&gt;
    -b /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -B /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -d /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -D /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -p &amp;lt;span style=&amp;quot;color:purple&amp;quot;&amp;gt;5432&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -P &amp;lt;span style=&amp;quot;color:darkcyan&amp;quot;&amp;gt;5433&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Afterwards, you may delete the unnecessary config file links (but it&#039;s safe to leave them there if you want)&lt;br /&gt;
&lt;br /&gt;
 rm /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf&lt;br /&gt;
 rm /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf&lt;br /&gt;
&lt;br /&gt;
== What next ==&lt;br /&gt;
Don&#039;t forget to merge your configuration changes in postgresql.conf, pg_hba.conf and other files.&lt;br /&gt;
&lt;br /&gt;
If you upgraded from 9.0 or earlier and you&#039;re using contrib modules or other addons, it is recommended to migrate them to proper extensions. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;CREATE EXTENSION hstore SCHEMA public FROM unpackaged;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
==== New cluster database &amp;quot;XXX&amp;quot; is not empty ====&lt;br /&gt;
The new cluster version already contains some data. For example, if you want to &#039;&#039;&#039;delete all data&#039;&#039;&#039; in the 9.2 version cluster, run:&lt;br /&gt;
&lt;br /&gt;
 pg_dropcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
 pg_createcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Where do I get PostgreSQL 9.2? ====&lt;br /&gt;
On Ubuntu, you can simply install 9.2 from the semi-official &amp;quot;PPA&amp;quot; repository:&lt;br /&gt;
&lt;br /&gt;
 sudo apt-get install python-software-properties&lt;br /&gt;
 sudo apt-add-repository ppa:pitti/postgresql&lt;br /&gt;
 sudo apt-get update&lt;br /&gt;
 sudo apt-get install postgresql-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Warning:&#039;&#039;&#039; Support for the current major version in the PPA may be dropped when a new major version is released. If you want to use this PPA, be prepared to always upgrade to the newest major version soon after it&#039;s released.&lt;/div&gt;</summary>
		<author><name>Intgr</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=Using_pg_upgrade_on_Ubuntu/Debian&amp;diff=18488</id>
		<title>Using pg upgrade on Ubuntu/Debian</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=Using_pg_upgrade_on_Ubuntu/Debian&amp;diff=18488"/>
		<updated>2012-10-29T11:05:44Z</updated>

		<summary type="html">&lt;p&gt;Intgr: /* Upgrading to version 9.1 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Instructions for how to convert/upgrade a PostgreSQL database cluster using pg_upgrade on Ubuntu or Debian. For the sake of example, I&#039;m upgrading from version 9.1 to 9.2, but it should work with any version. Replace any version numbers on the command lines.&lt;br /&gt;
&lt;br /&gt;
== WARNING! ==&lt;br /&gt;
&#039;&#039;&#039;These instructions are experimental!&#039;&#039;&#039; This way of upgrading is not yet supported by Ubuntu upstream. Do it at your own risk. Always test in a staging environment before running on production. I have tested this on Ubuntu 12.04.&lt;br /&gt;
&lt;br /&gt;
When in doubt, use the old but slower pg_upgradecluster method.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
First you need to install relevant packages: postgresql-VER and postgresql-server-dev-VER. If you&#039;re using contrib extensions, you also need postgresql-contrib-VER, and possibly other modules like postgresql-plpython-VER...&lt;br /&gt;
&lt;br /&gt;
 sudo apt-get install postgresql-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; \&lt;br /&gt;
                      postgresql-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By default, Ubuntu creates a database cluster named &amp;quot;main&amp;quot; with each installed version. We will use these. Verify that these are configured:&lt;br /&gt;
&lt;br /&gt;
 # sudo pg_lsclusters&lt;br /&gt;
 Version Cluster   Port Status Owner    Data directory                     Log file&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      5432 down   postgres /var/lib/postgresql/9.1/main       /var/log/postgresql/postgresql-9.1-main.log&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      5433 down   postgres /var/lib/postgresql/9.2/main       /var/log/postgresql/postgresql-9.2-main.log&lt;br /&gt;
&lt;br /&gt;
== Upgrading to version 9.2 or later ==&lt;br /&gt;
First you need to stop the relevant database clusters. To stop all clusters, run:&lt;br /&gt;
&lt;br /&gt;
 sudo /etc/init.d/postgresql stop&lt;br /&gt;
&lt;br /&gt;
(If you don&#039;t want to stop all clusters, you can also use pg_ctlcluster to manage them one by one)&lt;br /&gt;
&lt;br /&gt;
Do the upgrade... (For extra performance, you can use the --link option to pg_upgrade; please [http://www.postgresql.org/docs/current/static/pgupgrade.html read pg_upgrade documentation first])&lt;br /&gt;
&lt;br /&gt;
 cd /tmp&lt;br /&gt;
 sudo -H -u postgres /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/bin/pg_upgrade \&lt;br /&gt;
    -b /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -B /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -d /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -D /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -o &#039;-c config_file=/etc/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf&#039; \&lt;br /&gt;
    -O &#039;-c config_file=/etc/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf -F&#039;&lt;br /&gt;
&lt;br /&gt;
See if it worked...&lt;br /&gt;
&lt;br /&gt;
 sudo pg_ctlcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; start&lt;br /&gt;
 sudo -u postgres psql --cluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 postgres=# select version();&lt;br /&gt;
 PostgreSQL 9.2rc1 on x86_64-unknown-linux-gnu, compiled by gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3, 64-bit&lt;br /&gt;
 postgres=# \l+&lt;br /&gt;
 ... list of databases ...&lt;br /&gt;
&lt;br /&gt;
== Upgrading to version 9.1 ==&lt;br /&gt;
The above instructions don&#039;t work when you upgrade to PostgreSQL 9.1. You have to jump through some hoops.&lt;br /&gt;
&lt;br /&gt;
First, stop all clusters:&lt;br /&gt;
&lt;br /&gt;
 sudo /etc/init.d/postgresql stop&lt;br /&gt;
&lt;br /&gt;
Note that I&#039;m now using version numbers &amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt; and &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 # sudo pg_lsclusters&lt;br /&gt;
 Version Cluster   Port Status Owner    Data directory                     Log file&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      &amp;lt;span style=&amp;quot;color:purple&amp;quot;&amp;gt;5432&amp;lt;/span&amp;gt; down   postgres /var/lib/postgresql/9.0/main       /var/log/postgresql/postgresql-9.0-main.log&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      &amp;lt;span style=&amp;quot;color:darkcyan&amp;quot;&amp;gt;5433&amp;lt;/span&amp;gt; down   postgres /var/lib/postgresql/9.1/main       /var/log/postgresql/postgresql-9.1-main.log&lt;br /&gt;
&lt;br /&gt;
First you have to symlink the configuration files to respective PostgreSQL data directories.&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/&lt;br /&gt;
 ln -s /etc/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/&lt;br /&gt;
&lt;br /&gt;
And now you have to run the pg_upgrade script with your respective configured port numbers:&lt;br /&gt;
&lt;br /&gt;
 cd /tmp&lt;br /&gt;
 sudo -H -u postgres /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/bin/pg_upgrade \&lt;br /&gt;
    -b /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -B /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -d /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -D /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -p &amp;lt;span style=&amp;quot;color:purple&amp;quot;&amp;gt;5432&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -P &amp;lt;span style=&amp;quot;color:darkcyan&amp;quot;&amp;gt;5433&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Afterwards, you may delete the unnecessary config file links (but it&#039;s safe to leave them there if you want)&lt;br /&gt;
&lt;br /&gt;
 rm /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf&lt;br /&gt;
 rm /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf&lt;br /&gt;
&lt;br /&gt;
== What next ==&lt;br /&gt;
Don&#039;t forget to merge your configuration changes in postgresql.conf, pg_hba.conf and other files.&lt;br /&gt;
&lt;br /&gt;
If you upgraded from 9.0 or earlier and you&#039;re using contrib modules or other addons, it is recommended to migrate them to proper extensions. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;CREATE EXTENSION hstore SCHEMA public FROM unpackaged;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
==== New cluster database &amp;quot;XXX&amp;quot; is not empty ====&lt;br /&gt;
The new cluster version already contains some data. For example, if you want to &#039;&#039;&#039;delete all data&#039;&#039;&#039; in the 9.2 version cluster, run:&lt;br /&gt;
&lt;br /&gt;
 pg_dropcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
 pg_createcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Where do I get PostgreSQL 9.2? ====&lt;br /&gt;
On Ubuntu, you can simply install 9.2 from the semi-official &amp;quot;PPA&amp;quot; repository:&lt;br /&gt;
&lt;br /&gt;
 sudo apt-get install python-software-properties&lt;br /&gt;
 sudo apt-add-repository ppa:pitti/postgresql&lt;br /&gt;
 sudo apt-get update&lt;br /&gt;
 sudo apt-get install postgresql-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Warning:&#039;&#039;&#039; Support for the current major version in the PPA may be dropped when a new major version is released. If you want to use this PPA, be prepared to always upgrade to the newest major version soon after it&#039;s released.&lt;/div&gt;</summary>
		<author><name>Intgr</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=Using_pg_upgrade_on_Ubuntu/Debian&amp;diff=18487</id>
		<title>Using pg upgrade on Ubuntu/Debian</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=Using_pg_upgrade_on_Ubuntu/Debian&amp;diff=18487"/>
		<updated>2012-10-29T11:04:18Z</updated>

		<summary type="html">&lt;p&gt;Intgr: fix 9.2 &amp;quot;prerelease&amp;quot; warning&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Instructions for how to convert/upgrade a PostgreSQL database cluster using pg_upgrade on Ubuntu or Debian. For the sake of example, I&#039;m upgrading from version 9.1 to 9.2, but it should work with any version. Replace any version numbers on the command lines.&lt;br /&gt;
&lt;br /&gt;
== WARNING! ==&lt;br /&gt;
&#039;&#039;&#039;These instructions are experimental!&#039;&#039;&#039; This way of upgrading is not yet supported by Ubuntu upstream. Do it at your own risk. Always test in a staging environment before running on production. I have tested this on Ubuntu 12.04.&lt;br /&gt;
&lt;br /&gt;
When in doubt, use the old but slower pg_upgradecluster method.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
First you need to install relevant packages: postgresql-VER and postgresql-server-dev-VER. If you&#039;re using contrib extensions, you also need postgresql-contrib-VER, and possibly other modules like postgresql-plpython-VER...&lt;br /&gt;
&lt;br /&gt;
 sudo apt-get install postgresql-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; \&lt;br /&gt;
                      postgresql-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By default, Ubuntu creates a database cluster named &amp;quot;main&amp;quot; with each installed version. We will use these. Verify that these are configured:&lt;br /&gt;
&lt;br /&gt;
 # sudo pg_lsclusters&lt;br /&gt;
 Version Cluster   Port Status Owner    Data directory                     Log file&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      5432 down   postgres /var/lib/postgresql/9.1/main       /var/log/postgresql/postgresql-9.1-main.log&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      5433 down   postgres /var/lib/postgresql/9.2/main       /var/log/postgresql/postgresql-9.2-main.log&lt;br /&gt;
&lt;br /&gt;
== Upgrading to version 9.2 or later ==&lt;br /&gt;
First you need to stop the relevant database clusters. To stop all clusters, run:&lt;br /&gt;
&lt;br /&gt;
 sudo /etc/init.d/postgresql stop&lt;br /&gt;
&lt;br /&gt;
(If you don&#039;t want to stop all clusters, you can also use pg_ctlcluster to manage them one by one)&lt;br /&gt;
&lt;br /&gt;
Do the upgrade... (For extra performance, you can use the --link option to pg_upgrade; please [http://www.postgresql.org/docs/current/static/pgupgrade.html read pg_upgrade documentation first])&lt;br /&gt;
&lt;br /&gt;
 cd /tmp&lt;br /&gt;
 sudo -H -u postgres /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/bin/pg_upgrade \&lt;br /&gt;
    -b /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -B /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -d /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -D /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -o &#039;-c config_file=/etc/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf&#039; \&lt;br /&gt;
    -O &#039;-c config_file=/etc/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf -F&#039;&lt;br /&gt;
&lt;br /&gt;
See if it worked...&lt;br /&gt;
&lt;br /&gt;
 sudo pg_ctlcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; start&lt;br /&gt;
 sudo -u postgres psql --cluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 postgres=# select version();&lt;br /&gt;
 PostgreSQL 9.2rc1 on x86_64-unknown-linux-gnu, compiled by gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3, 64-bit&lt;br /&gt;
 postgres=# \l+&lt;br /&gt;
 ... list of databases ...&lt;br /&gt;
&lt;br /&gt;
== Upgrading to version 9.1 ==&lt;br /&gt;
The above instructions don&#039;t work when you upgrade to PostgreSQL 9.1. You have to jump through some hoops.&lt;br /&gt;
&lt;br /&gt;
Note that I&#039;m now using version numbers &amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt; and &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 # sudo pg_lsclusters&lt;br /&gt;
 Version Cluster   Port Status Owner    Data directory                     Log file&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      &amp;lt;span style=&amp;quot;color:purple&amp;quot;&amp;gt;5432&amp;lt;/span&amp;gt; down   postgres /var/lib/postgresql/9.0/main       /var/log/postgresql/postgresql-9.0-main.log&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      &amp;lt;span style=&amp;quot;color:darkcyan&amp;quot;&amp;gt;5433&amp;lt;/span&amp;gt; down   postgres /var/lib/postgresql/9.1/main       /var/log/postgresql/postgresql-9.1-main.log&lt;br /&gt;
&lt;br /&gt;
First you have to symlink the configuration files to respective PostgreSQL data directories.&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/&lt;br /&gt;
 ln -s /etc/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/&lt;br /&gt;
&lt;br /&gt;
And now you have to run the pg_upgrade script with your respective configured port numbers:&lt;br /&gt;
&lt;br /&gt;
 cd /tmp&lt;br /&gt;
 sudo -H -u postgres /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/bin/pg_upgrade \&lt;br /&gt;
    -b /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -B /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -d /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -D /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -p &amp;lt;span style=&amp;quot;color:purple&amp;quot;&amp;gt;5432&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -P &amp;lt;span style=&amp;quot;color:darkcyan&amp;quot;&amp;gt;5433&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Afterwards, you may delete the unnecessary config file links (but it&#039;s safe to leave them there if you want)&lt;br /&gt;
&lt;br /&gt;
 rm /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf&lt;br /&gt;
 rm /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf&lt;br /&gt;
&lt;br /&gt;
== What next ==&lt;br /&gt;
Don&#039;t forget to merge your configuration changes in postgresql.conf, pg_hba.conf and other files.&lt;br /&gt;
&lt;br /&gt;
If you upgraded from 9.0 or earlier and you&#039;re using contrib modules or other addons, it is recommended to migrate them to proper extensions. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;CREATE EXTENSION hstore SCHEMA public FROM unpackaged;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
==== New cluster database &amp;quot;XXX&amp;quot; is not empty ====&lt;br /&gt;
The new cluster version already contains some data. For example, if you want to &#039;&#039;&#039;delete all data&#039;&#039;&#039; in the 9.2 version cluster, run:&lt;br /&gt;
&lt;br /&gt;
 pg_dropcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
 pg_createcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Where do I get PostgreSQL 9.2? ====&lt;br /&gt;
On Ubuntu, you can simply install 9.2 from the semi-official &amp;quot;PPA&amp;quot; repository:&lt;br /&gt;
&lt;br /&gt;
 sudo apt-get install python-software-properties&lt;br /&gt;
 sudo apt-add-repository ppa:pitti/postgresql&lt;br /&gt;
 sudo apt-get update&lt;br /&gt;
 sudo apt-get install postgresql-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Warning:&#039;&#039;&#039; Support for the current major version in the PPA may be dropped when a new major version is released. If you want to use this PPA, be prepared to always upgrade to the newest major version soon after it&#039;s released.&lt;/div&gt;</summary>
		<author><name>Intgr</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=Using_pg_upgrade_on_Ubuntu/Debian&amp;diff=18486</id>
		<title>Using pg upgrade on Ubuntu/Debian</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=Using_pg_upgrade_on_Ubuntu/Debian&amp;diff=18486"/>
		<updated>2012-10-29T11:02:09Z</updated>

		<summary type="html">&lt;p&gt;Intgr: /* Prerequisites */ remove port number coloring from 9.2 example&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Instructions for how to convert/upgrade a PostgreSQL database cluster using pg_upgrade on Ubuntu or Debian. For the sake of example, I&#039;m upgrading from version 9.1 to 9.2, but it should work with any version. Replace any version numbers on the command lines.&lt;br /&gt;
&lt;br /&gt;
== WARNING! ==&lt;br /&gt;
&#039;&#039;&#039;These instructions are experimental!&#039;&#039;&#039;&lt;br /&gt;
* This way of upgrading is not yet supported by Ubuntu upstream. Do it at your own risk. I have tested this on Ubuntu 12.04.&lt;br /&gt;
* PostgreSQL 9.2 is still a testing release (currently at RC 1). Do not run it in production!&lt;br /&gt;
&lt;br /&gt;
When in doubt, use the old but slower pg_upgradecluster method.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
First you need to install relevant packages: postgresql-VER and postgresql-server-dev-VER. If you&#039;re using contrib extensions, you also need postgresql-contrib-VER, and possibly other modules like postgresql-plpython-VER...&lt;br /&gt;
&lt;br /&gt;
 sudo apt-get install postgresql-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; \&lt;br /&gt;
                      postgresql-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By default, Ubuntu creates a database cluster named &amp;quot;main&amp;quot; with each installed version. We will use these. Verify that these are configured:&lt;br /&gt;
&lt;br /&gt;
 # sudo pg_lsclusters&lt;br /&gt;
 Version Cluster   Port Status Owner    Data directory                     Log file&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      5432 down   postgres /var/lib/postgresql/9.1/main       /var/log/postgresql/postgresql-9.1-main.log&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      5433 down   postgres /var/lib/postgresql/9.2/main       /var/log/postgresql/postgresql-9.2-main.log&lt;br /&gt;
&lt;br /&gt;
== Upgrading to version 9.2 or later ==&lt;br /&gt;
First you need to stop the relevant database clusters. To stop all clusters, run:&lt;br /&gt;
&lt;br /&gt;
 sudo /etc/init.d/postgresql stop&lt;br /&gt;
&lt;br /&gt;
(If you don&#039;t want to stop all clusters, you can also use pg_ctlcluster to manage them one by one)&lt;br /&gt;
&lt;br /&gt;
Do the upgrade... (For extra performance, you can use the --link option to pg_upgrade; please [http://www.postgresql.org/docs/current/static/pgupgrade.html read pg_upgrade documentation first])&lt;br /&gt;
&lt;br /&gt;
 cd /tmp&lt;br /&gt;
 sudo -H -u postgres /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/bin/pg_upgrade \&lt;br /&gt;
    -b /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -B /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -d /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -D /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -o &#039;-c config_file=/etc/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf&#039; \&lt;br /&gt;
    -O &#039;-c config_file=/etc/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf -F&#039;&lt;br /&gt;
&lt;br /&gt;
See if it worked...&lt;br /&gt;
&lt;br /&gt;
 sudo pg_ctlcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; start&lt;br /&gt;
 sudo -u postgres psql --cluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 postgres=# select version();&lt;br /&gt;
 PostgreSQL 9.2rc1 on x86_64-unknown-linux-gnu, compiled by gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3, 64-bit&lt;br /&gt;
 postgres=# \l+&lt;br /&gt;
 ... list of databases ...&lt;br /&gt;
&lt;br /&gt;
== Upgrading to version 9.1 ==&lt;br /&gt;
The above instructions don&#039;t work when you upgrade to PostgreSQL 9.1. You have to jump through some hoops.&lt;br /&gt;
&lt;br /&gt;
Note that I&#039;m now using version numbers &amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt; and &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 # sudo pg_lsclusters&lt;br /&gt;
 Version Cluster   Port Status Owner    Data directory                     Log file&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      &amp;lt;span style=&amp;quot;color:purple&amp;quot;&amp;gt;5432&amp;lt;/span&amp;gt; down   postgres /var/lib/postgresql/9.0/main       /var/log/postgresql/postgresql-9.0-main.log&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      &amp;lt;span style=&amp;quot;color:darkcyan&amp;quot;&amp;gt;5433&amp;lt;/span&amp;gt; down   postgres /var/lib/postgresql/9.1/main       /var/log/postgresql/postgresql-9.1-main.log&lt;br /&gt;
&lt;br /&gt;
First you have to symlink the configuration files to respective PostgreSQL data directories.&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/&lt;br /&gt;
 ln -s /etc/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/&lt;br /&gt;
&lt;br /&gt;
And now you have to run the pg_upgrade script with your respective configured port numbers:&lt;br /&gt;
&lt;br /&gt;
 cd /tmp&lt;br /&gt;
 sudo -H -u postgres /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/bin/pg_upgrade \&lt;br /&gt;
    -b /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -B /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -d /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -D /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -p &amp;lt;span style=&amp;quot;color:purple&amp;quot;&amp;gt;5432&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -P &amp;lt;span style=&amp;quot;color:darkcyan&amp;quot;&amp;gt;5433&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Afterwards, you may delete the unnecessary config file links (but it&#039;s safe to leave them there if you want)&lt;br /&gt;
&lt;br /&gt;
 rm /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf&lt;br /&gt;
 rm /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf&lt;br /&gt;
&lt;br /&gt;
== What next ==&lt;br /&gt;
Don&#039;t forget to merge your configuration changes in postgresql.conf, pg_hba.conf and other files.&lt;br /&gt;
&lt;br /&gt;
If you upgraded from 9.0 or earlier and you&#039;re using contrib modules or other addons, it is recommended to migrate them to proper extensions. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;CREATE EXTENSION hstore SCHEMA public FROM unpackaged;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
==== New cluster database &amp;quot;XXX&amp;quot; is not empty ====&lt;br /&gt;
The new cluster version already contains some data. For example, if you want to &#039;&#039;&#039;delete all data&#039;&#039;&#039; in the 9.2 version cluster, run:&lt;br /&gt;
&lt;br /&gt;
 pg_dropcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
 pg_createcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Where do I get PostgreSQL 9.2? ====&lt;br /&gt;
On Ubuntu, you can simply install 9.2 from the semi-official &amp;quot;PPA&amp;quot; repository:&lt;br /&gt;
&lt;br /&gt;
 sudo apt-get install python-software-properties&lt;br /&gt;
 sudo apt-add-repository ppa:pitti/postgresql&lt;br /&gt;
 sudo apt-get update&lt;br /&gt;
 sudo apt-get install postgresql-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Warning:&#039;&#039;&#039; Support for the current major version in the PPA may be dropped when a new major version is released. If you want to use this PPA, be prepared to always upgrade to the newest major version soon after it&#039;s released.&lt;/div&gt;</summary>
		<author><name>Intgr</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=Using_pg_upgrade_on_Ubuntu/Debian&amp;diff=18485</id>
		<title>Using pg upgrade on Ubuntu/Debian</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=Using_pg_upgrade_on_Ubuntu/Debian&amp;diff=18485"/>
		<updated>2012-10-29T11:00:18Z</updated>

		<summary type="html">&lt;p&gt;Intgr: /* Upgrading to version 9.1 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Instructions for how to convert/upgrade a PostgreSQL database cluster using pg_upgrade on Ubuntu or Debian. For the sake of example, I&#039;m upgrading from version 9.1 to 9.2, but it should work with any version. Replace any version numbers on the command lines.&lt;br /&gt;
&lt;br /&gt;
== WARNING! ==&lt;br /&gt;
&#039;&#039;&#039;These instructions are experimental!&#039;&#039;&#039;&lt;br /&gt;
* This way of upgrading is not yet supported by Ubuntu upstream. Do it at your own risk. I have tested this on Ubuntu 12.04.&lt;br /&gt;
* PostgreSQL 9.2 is still a testing release (currently at RC 1). Do not run it in production!&lt;br /&gt;
&lt;br /&gt;
When in doubt, use the old but slower pg_upgradecluster method.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
First you need to install relevant packages: postgresql-VER and postgresql-server-dev-VER. If you&#039;re using contrib extensions, you also need postgresql-contrib-VER, and possibly other modules like postgresql-plpython-VER...&lt;br /&gt;
&lt;br /&gt;
 sudo apt-get install postgresql-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; \&lt;br /&gt;
                      postgresql-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By default, Ubuntu creates a database cluster named &amp;quot;main&amp;quot; with each installed version. We will use these. Verify that these are configured:&lt;br /&gt;
&lt;br /&gt;
 # sudo pg_lsclusters&lt;br /&gt;
 Version Cluster   Port Status Owner    Data directory                     Log file&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      &amp;lt;span style=&amp;quot;color:purple&amp;quot;&amp;gt;5432&amp;lt;/span&amp;gt; down   postgres /var/lib/postgresql/9.1/main       /var/log/postgresql/postgresql-9.1-main.log&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      &amp;lt;span style=&amp;quot;color:darkcyan&amp;quot;&amp;gt;5433&amp;lt;/span&amp;gt; down   postgres /var/lib/postgresql/9.2/main       /var/log/postgresql/postgresql-9.2-main.log&lt;br /&gt;
&lt;br /&gt;
== Upgrading to version 9.2 or later ==&lt;br /&gt;
First you need to stop the relevant database clusters. To stop all clusters, run:&lt;br /&gt;
&lt;br /&gt;
 sudo /etc/init.d/postgresql stop&lt;br /&gt;
&lt;br /&gt;
(If you don&#039;t want to stop all clusters, you can also use pg_ctlcluster to manage them one by one)&lt;br /&gt;
&lt;br /&gt;
Do the upgrade... (For extra performance, you can use the --link option to pg_upgrade; please [http://www.postgresql.org/docs/current/static/pgupgrade.html read pg_upgrade documentation first])&lt;br /&gt;
&lt;br /&gt;
 cd /tmp&lt;br /&gt;
 sudo -H -u postgres /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/bin/pg_upgrade \&lt;br /&gt;
    -b /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -B /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -d /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -D /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -o &#039;-c config_file=/etc/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf&#039; \&lt;br /&gt;
    -O &#039;-c config_file=/etc/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf -F&#039;&lt;br /&gt;
&lt;br /&gt;
See if it worked...&lt;br /&gt;
&lt;br /&gt;
 sudo pg_ctlcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; start&lt;br /&gt;
 sudo -u postgres psql --cluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 postgres=# select version();&lt;br /&gt;
 PostgreSQL 9.2rc1 on x86_64-unknown-linux-gnu, compiled by gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3, 64-bit&lt;br /&gt;
 postgres=# \l+&lt;br /&gt;
 ... list of databases ...&lt;br /&gt;
&lt;br /&gt;
== Upgrading to version 9.1 ==&lt;br /&gt;
The above instructions don&#039;t work when you upgrade to PostgreSQL 9.1. You have to jump through some hoops.&lt;br /&gt;
&lt;br /&gt;
Note that I&#039;m now using version numbers &amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt; and &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 # sudo pg_lsclusters&lt;br /&gt;
 Version Cluster   Port Status Owner    Data directory                     Log file&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      &amp;lt;span style=&amp;quot;color:purple&amp;quot;&amp;gt;5432&amp;lt;/span&amp;gt; down   postgres /var/lib/postgresql/9.0/main       /var/log/postgresql/postgresql-9.0-main.log&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      &amp;lt;span style=&amp;quot;color:darkcyan&amp;quot;&amp;gt;5433&amp;lt;/span&amp;gt; down   postgres /var/lib/postgresql/9.1/main       /var/log/postgresql/postgresql-9.1-main.log&lt;br /&gt;
&lt;br /&gt;
First you have to symlink the configuration files to respective PostgreSQL data directories.&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/&lt;br /&gt;
 ln -s /etc/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/&lt;br /&gt;
&lt;br /&gt;
And now you have to run the pg_upgrade script with your respective configured port numbers:&lt;br /&gt;
&lt;br /&gt;
 cd /tmp&lt;br /&gt;
 sudo -H -u postgres /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/bin/pg_upgrade \&lt;br /&gt;
    -b /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -B /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -d /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -D /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -p &amp;lt;span style=&amp;quot;color:purple&amp;quot;&amp;gt;5432&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -P &amp;lt;span style=&amp;quot;color:darkcyan&amp;quot;&amp;gt;5433&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Afterwards, you may delete the unnecessary config file links (but it&#039;s safe to leave them there if you want)&lt;br /&gt;
&lt;br /&gt;
 rm /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf&lt;br /&gt;
 rm /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf&lt;br /&gt;
&lt;br /&gt;
== What next ==&lt;br /&gt;
Don&#039;t forget to merge your configuration changes in postgresql.conf, pg_hba.conf and other files.&lt;br /&gt;
&lt;br /&gt;
If you upgraded from 9.0 or earlier and you&#039;re using contrib modules or other addons, it is recommended to migrate them to proper extensions. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;CREATE EXTENSION hstore SCHEMA public FROM unpackaged;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
==== New cluster database &amp;quot;XXX&amp;quot; is not empty ====&lt;br /&gt;
The new cluster version already contains some data. For example, if you want to &#039;&#039;&#039;delete all data&#039;&#039;&#039; in the 9.2 version cluster, run:&lt;br /&gt;
&lt;br /&gt;
 pg_dropcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
 pg_createcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Where do I get PostgreSQL 9.2? ====&lt;br /&gt;
On Ubuntu, you can simply install 9.2 from the semi-official &amp;quot;PPA&amp;quot; repository:&lt;br /&gt;
&lt;br /&gt;
 sudo apt-get install python-software-properties&lt;br /&gt;
 sudo apt-add-repository ppa:pitti/postgresql&lt;br /&gt;
 sudo apt-get update&lt;br /&gt;
 sudo apt-get install postgresql-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Warning:&#039;&#039;&#039; Support for the current major version in the PPA may be dropped when a new major version is released. If you want to use this PPA, be prepared to always upgrade to the newest major version soon after it&#039;s released.&lt;/div&gt;</summary>
		<author><name>Intgr</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=Using_pg_upgrade_on_Ubuntu/Debian&amp;diff=18484</id>
		<title>Using pg upgrade on Ubuntu/Debian</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=Using_pg_upgrade_on_Ubuntu/Debian&amp;diff=18484"/>
		<updated>2012-10-29T10:59:20Z</updated>

		<summary type="html">&lt;p&gt;Intgr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Instructions for how to convert/upgrade a PostgreSQL database cluster using pg_upgrade on Ubuntu or Debian. For the sake of example, I&#039;m upgrading from version 9.1 to 9.2, but it should work with any version. Replace any version numbers on the command lines.&lt;br /&gt;
&lt;br /&gt;
== WARNING! ==&lt;br /&gt;
&#039;&#039;&#039;These instructions are experimental!&#039;&#039;&#039;&lt;br /&gt;
* This way of upgrading is not yet supported by Ubuntu upstream. Do it at your own risk. I have tested this on Ubuntu 12.04.&lt;br /&gt;
* PostgreSQL 9.2 is still a testing release (currently at RC 1). Do not run it in production!&lt;br /&gt;
&lt;br /&gt;
When in doubt, use the old but slower pg_upgradecluster method.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
First you need to install relevant packages: postgresql-VER and postgresql-server-dev-VER. If you&#039;re using contrib extensions, you also need postgresql-contrib-VER, and possibly other modules like postgresql-plpython-VER...&lt;br /&gt;
&lt;br /&gt;
 sudo apt-get install postgresql-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; \&lt;br /&gt;
                      postgresql-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By default, Ubuntu creates a database cluster named &amp;quot;main&amp;quot; with each installed version. We will use these. Verify that these are configured:&lt;br /&gt;
&lt;br /&gt;
 # sudo pg_lsclusters&lt;br /&gt;
 Version Cluster   Port Status Owner    Data directory                     Log file&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      &amp;lt;span style=&amp;quot;color:purple&amp;quot;&amp;gt;5432&amp;lt;/span&amp;gt; down   postgres /var/lib/postgresql/9.1/main       /var/log/postgresql/postgresql-9.1-main.log&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      &amp;lt;span style=&amp;quot;color:darkcyan&amp;quot;&amp;gt;5433&amp;lt;/span&amp;gt; down   postgres /var/lib/postgresql/9.2/main       /var/log/postgresql/postgresql-9.2-main.log&lt;br /&gt;
&lt;br /&gt;
== Upgrading to version 9.2 or later ==&lt;br /&gt;
First you need to stop the relevant database clusters. To stop all clusters, run:&lt;br /&gt;
&lt;br /&gt;
 sudo /etc/init.d/postgresql stop&lt;br /&gt;
&lt;br /&gt;
(If you don&#039;t want to stop all clusters, you can also use pg_ctlcluster to manage them one by one)&lt;br /&gt;
&lt;br /&gt;
Do the upgrade... (For extra performance, you can use the --link option to pg_upgrade; please [http://www.postgresql.org/docs/current/static/pgupgrade.html read pg_upgrade documentation first])&lt;br /&gt;
&lt;br /&gt;
 cd /tmp&lt;br /&gt;
 sudo -H -u postgres /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/bin/pg_upgrade \&lt;br /&gt;
    -b /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -B /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -d /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -D /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -o &#039;-c config_file=/etc/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf&#039; \&lt;br /&gt;
    -O &#039;-c config_file=/etc/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf -F&#039;&lt;br /&gt;
&lt;br /&gt;
See if it worked...&lt;br /&gt;
&lt;br /&gt;
 sudo pg_ctlcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; start&lt;br /&gt;
 sudo -u postgres psql --cluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 postgres=# select version();&lt;br /&gt;
 PostgreSQL 9.2rc1 on x86_64-unknown-linux-gnu, compiled by gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3, 64-bit&lt;br /&gt;
 postgres=# \l+&lt;br /&gt;
 ... list of databases ...&lt;br /&gt;
&lt;br /&gt;
== Upgrading to version 9.1 ==&lt;br /&gt;
The above instructions don&#039;t work when you upgrade to PostgreSQL 9.1. You have to jump through some hoops.&lt;br /&gt;
&lt;br /&gt;
Note that I&#039;m now using version numbers &amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt; and span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
First you have to symlink the configuration files to respective PostgreSQL data directories.&lt;br /&gt;
&lt;br /&gt;
 ln -s /etc/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/&lt;br /&gt;
 ln -s /etc/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/&lt;br /&gt;
&lt;br /&gt;
And now you have to run the pg_upgrade script with your respective configured port numbers:&lt;br /&gt;
&lt;br /&gt;
 # sudo pg_lsclusters&lt;br /&gt;
 Version Cluster   Port Status Owner    Data directory                     Log file&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      &amp;lt;span style=&amp;quot;color:purple&amp;quot;&amp;gt;5432&amp;lt;/span&amp;gt; down   postgres /var/lib/postgresql/9.1/main       /var/log/postgresql/postgresql-9.0-main.log&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      &amp;lt;span style=&amp;quot;color:darkcyan&amp;quot;&amp;gt;5433&amp;lt;/span&amp;gt; down   postgres /var/lib/postgresql/9.2/main       /var/log/postgresql/postgresql-9.1-main.log&lt;br /&gt;
&lt;br /&gt;
 cd /tmp&lt;br /&gt;
 sudo -H -u postgres /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/bin/pg_upgrade \&lt;br /&gt;
    -b /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -B /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -d /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -D /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -p &amp;lt;span style=&amp;quot;color:purple&amp;quot;&amp;gt;5432&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -P &amp;lt;span style=&amp;quot;color:darkcyan&amp;quot;&amp;gt;5433&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Afterwards, you may delete the unnecessary config file links (but it&#039;s safe to leave them there if you want)&lt;br /&gt;
&lt;br /&gt;
 rm /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf&lt;br /&gt;
 rm /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.0&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf&lt;br /&gt;
&lt;br /&gt;
== What next ==&lt;br /&gt;
Don&#039;t forget to merge your configuration changes in postgresql.conf, pg_hba.conf and other files.&lt;br /&gt;
&lt;br /&gt;
If you upgraded from 9.0 or earlier and you&#039;re using contrib modules or other addons, it is recommended to migrate them to proper extensions. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;CREATE EXTENSION hstore SCHEMA public FROM unpackaged;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
==== New cluster database &amp;quot;XXX&amp;quot; is not empty ====&lt;br /&gt;
The new cluster version already contains some data. For example, if you want to &#039;&#039;&#039;delete all data&#039;&#039;&#039; in the 9.2 version cluster, run:&lt;br /&gt;
&lt;br /&gt;
 pg_dropcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
 pg_createcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Where do I get PostgreSQL 9.2? ====&lt;br /&gt;
On Ubuntu, you can simply install 9.2 from the semi-official &amp;quot;PPA&amp;quot; repository:&lt;br /&gt;
&lt;br /&gt;
 sudo apt-get install python-software-properties&lt;br /&gt;
 sudo apt-add-repository ppa:pitti/postgresql&lt;br /&gt;
 sudo apt-get update&lt;br /&gt;
 sudo apt-get install postgresql-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Warning:&#039;&#039;&#039; Support for the current major version in the PPA may be dropped when a new major version is released. If you want to use this PPA, be prepared to always upgrade to the newest major version soon after it&#039;s released.&lt;/div&gt;</summary>
		<author><name>Intgr</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=Using_pg_upgrade_on_Ubuntu/Debian&amp;diff=18483</id>
		<title>Using pg upgrade on Ubuntu/Debian</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=Using_pg_upgrade_on_Ubuntu/Debian&amp;diff=18483"/>
		<updated>2012-10-29T10:47:26Z</updated>

		<summary type="html">&lt;p&gt;Intgr: /* Upgrading */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Instructions for how to convert/upgrade a PostgreSQL database cluster using pg_upgrade on Ubuntu or Debian. For the sake of example, I&#039;m upgrading from version 9.1 to 9.2, but it should work with any version. Replace any version numbers on the command lines.&lt;br /&gt;
&lt;br /&gt;
== WARNING! ==&lt;br /&gt;
&#039;&#039;&#039;These instructions are experimental!&#039;&#039;&#039;&lt;br /&gt;
* This way of upgrading is not yet supported by Ubuntu upstream. Do it at your own risk. I have tested this on Ubuntu 12.04.&lt;br /&gt;
* PostgreSQL 9.2 is still a testing release (currently at RC 1). Do not run it in production!&lt;br /&gt;
&lt;br /&gt;
When in doubt, use the old but slower pg_upgradecluster method.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
First you need to install relevant packages: postgresql-VER and postgresql-server-dev-VER. If you&#039;re using contrib extensions, you also need postgresql-contrib-VER, and possibly other modules like postgresql-plpython-VER...&lt;br /&gt;
&lt;br /&gt;
 sudo apt-get install postgresql-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; \&lt;br /&gt;
                      postgresql-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By default, Ubuntu creates a database cluster named &amp;quot;main&amp;quot; with each installed version. We will use these. Verify that these are configured:&lt;br /&gt;
&lt;br /&gt;
 # sudo pg_lsclusters&lt;br /&gt;
 Version Cluster   Port Status Owner    Data directory                     Log file&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      5432 down   postgres /var/lib/postgresql/9.1/main       /var/log/postgresql/postgresql-9.1-main.log&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      5433 down   postgres /var/lib/postgresql/9.2/main       /var/log/postgresql/postgresql-9.2-main.log&lt;br /&gt;
&lt;br /&gt;
== Upgrading to version 9.2 or later ==&lt;br /&gt;
First you need to stop the relevant database clusters. To stop all clusters, run:&lt;br /&gt;
&lt;br /&gt;
 sudo /etc/init.d/postgresql stop&lt;br /&gt;
&lt;br /&gt;
(If you don&#039;t want to stop all clusters, you can also use pg_ctlcluster to manage them one by one)&lt;br /&gt;
&lt;br /&gt;
Do the upgrade... (For extra performance, you can use the --link option to pg_upgrade; please [http://www.postgresql.org/docs/current/static/pgupgrade.html read pg_upgrade documentation first])&lt;br /&gt;
&lt;br /&gt;
 cd /tmp&lt;br /&gt;
 sudo -H -u postgres /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/bin/pg_upgrade \&lt;br /&gt;
    -b /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -B /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -d /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -D /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -o &#039;-c config_file=/etc/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf&#039; \&lt;br /&gt;
    -O &#039;-c config_file=/etc/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf -F&#039;&lt;br /&gt;
&lt;br /&gt;
See if it worked...&lt;br /&gt;
&lt;br /&gt;
 sudo pg_ctlcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; start&lt;br /&gt;
 sudo -u postgres psql --cluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 postgres=# select version();&lt;br /&gt;
 PostgreSQL 9.2rc1 on x86_64-unknown-linux-gnu, compiled by gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3, 64-bit&lt;br /&gt;
 postgres=# \l+&lt;br /&gt;
 ... list of databases ...&lt;br /&gt;
&lt;br /&gt;
== What next ==&lt;br /&gt;
Don&#039;t forget to merge your configuration changes in postgresql.conf, pg_hba.conf and other files.&lt;br /&gt;
&lt;br /&gt;
If you upgraded from 9.0 or earlier and you&#039;re using contrib modules or other addons, it is recommended to migrate them to proper extensions. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;CREATE EXTENSION hstore SCHEMA public FROM unpackaged;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
==== New cluster database &amp;quot;XXX&amp;quot; is not empty ====&lt;br /&gt;
The new cluster version already contains some data. For example, if you want to &#039;&#039;&#039;delete all data&#039;&#039;&#039; in the 9.2 version cluster, run:&lt;br /&gt;
&lt;br /&gt;
 pg_dropcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
 pg_createcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Where do I get PostgreSQL 9.2? ====&lt;br /&gt;
On Ubuntu, you can simply install 9.2 from the semi-official &amp;quot;PPA&amp;quot; repository:&lt;br /&gt;
&lt;br /&gt;
 sudo apt-get install python-software-properties&lt;br /&gt;
 sudo apt-add-repository ppa:pitti/postgresql&lt;br /&gt;
 sudo apt-get update&lt;br /&gt;
 sudo apt-get install postgresql-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Warning:&#039;&#039;&#039; Support for the current major version in the PPA may be dropped when a new major version is released. If you want to use this PPA, be prepared to always upgrade to the newest major version soon after it&#039;s released.&lt;/div&gt;</summary>
		<author><name>Intgr</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=Using_pg_upgrade_on_Ubuntu/Debian&amp;diff=18466</id>
		<title>Using pg upgrade on Ubuntu/Debian</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=Using_pg_upgrade_on_Ubuntu/Debian&amp;diff=18466"/>
		<updated>2012-10-26T12:31:15Z</updated>

		<summary type="html">&lt;p&gt;Intgr: /* Where do I get PostgreSQL 9.2? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Instructions for how to convert/upgrade a PostgreSQL database cluster using pg_upgrade on Ubuntu or Debian. For the sake of example, I&#039;m upgrading from version 9.1 to 9.2, but it should work with any version. Replace any version numbers on the command lines.&lt;br /&gt;
&lt;br /&gt;
== WARNING! ==&lt;br /&gt;
&#039;&#039;&#039;These instructions are experimental!&#039;&#039;&#039;&lt;br /&gt;
* This way of upgrading is not yet supported by Ubuntu upstream. Do it at your own risk. I have tested this on Ubuntu 12.04.&lt;br /&gt;
* PostgreSQL 9.2 is still a testing release (currently at RC 1). Do not run it in production!&lt;br /&gt;
&lt;br /&gt;
When in doubt, use the old but slower pg_upgradecluster method.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
First you need to install relevant packages: postgresql-VER and postgresql-server-dev-VER. If you&#039;re using contrib extensions, you also need postgresql-contrib-VER, and possibly other modules like postgresql-plpython-VER...&lt;br /&gt;
&lt;br /&gt;
 sudo apt-get install postgresql-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; \&lt;br /&gt;
                      postgresql-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By default, Ubuntu creates a database cluster named &amp;quot;main&amp;quot; with each installed version. We will use these. Verify that these are configured:&lt;br /&gt;
&lt;br /&gt;
 # sudo pg_lsclusters&lt;br /&gt;
 Version Cluster   Port Status Owner    Data directory                     Log file&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      5432 down   postgres /var/lib/postgresql/9.1/main       /var/log/postgresql/postgresql-9.1-main.log&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      5433 down   postgres /var/lib/postgresql/9.2/main       /var/log/postgresql/postgresql-9.2-main.log&lt;br /&gt;
&lt;br /&gt;
== Upgrading ==&lt;br /&gt;
First you need to stop the relevant database clusters. To stop all clusters, run:&lt;br /&gt;
&lt;br /&gt;
 sudo /etc/init.d/postgresql stop&lt;br /&gt;
&lt;br /&gt;
(If you don&#039;t want to stop all clusters, you can also use pg_ctlcluster to manage them one by one)&lt;br /&gt;
&lt;br /&gt;
Do the upgrade... (For extra performance, you can use the --link option to pg_upgrade; please [http://www.postgresql.org/docs/current/static/pgupgrade.html read pg_upgrade documentation first])&lt;br /&gt;
&lt;br /&gt;
 cd /tmp&lt;br /&gt;
 sudo -H -u postgres /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/bin/pg_upgrade \&lt;br /&gt;
    -b /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -B /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -d /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -D /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -o &#039;-c config_file=/etc/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf&#039; \&lt;br /&gt;
    -O &#039;-c config_file=/etc/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf -F&#039;&lt;br /&gt;
&lt;br /&gt;
See if it worked...&lt;br /&gt;
&lt;br /&gt;
 sudo pg_ctlcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; start&lt;br /&gt;
 sudo -u postgres psql --cluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 postgres=# select version();&lt;br /&gt;
 PostgreSQL 9.2rc1 on x86_64-unknown-linux-gnu, compiled by gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3, 64-bit&lt;br /&gt;
 postgres=# \l+&lt;br /&gt;
 ... list of databases ...&lt;br /&gt;
&lt;br /&gt;
== What next ==&lt;br /&gt;
Don&#039;t forget to merge your configuration changes in postgresql.conf, pg_hba.conf and other files.&lt;br /&gt;
&lt;br /&gt;
If you upgraded from 9.0 or earlier and you&#039;re using contrib modules or other addons, it is recommended to migrate them to proper extensions. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;CREATE EXTENSION hstore SCHEMA public FROM unpackaged;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
==== New cluster database &amp;quot;XXX&amp;quot; is not empty ====&lt;br /&gt;
The new cluster version already contains some data. For example, if you want to &#039;&#039;&#039;delete all data&#039;&#039;&#039; in the 9.2 version cluster, run:&lt;br /&gt;
&lt;br /&gt;
 pg_dropcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
 pg_createcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Where do I get PostgreSQL 9.2? ====&lt;br /&gt;
On Ubuntu, you can simply install 9.2 from the semi-official &amp;quot;PPA&amp;quot; repository:&lt;br /&gt;
&lt;br /&gt;
 sudo apt-get install python-software-properties&lt;br /&gt;
 sudo apt-add-repository ppa:pitti/postgresql&lt;br /&gt;
 sudo apt-get update&lt;br /&gt;
 sudo apt-get install postgresql-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Warning:&#039;&#039;&#039; Support for the current major version in the PPA may be dropped when a new major version is released. If you want to use this PPA, be prepared to always upgrade to the newest major version soon after it&#039;s released.&lt;/div&gt;</summary>
		<author><name>Intgr</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=Using_pg_upgrade_on_Ubuntu/Debian&amp;diff=18456</id>
		<title>Using pg upgrade on Ubuntu/Debian</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=Using_pg_upgrade_on_Ubuntu/Debian&amp;diff=18456"/>
		<updated>2012-10-26T09:30:21Z</updated>

		<summary type="html">&lt;p&gt;Intgr: /* Where do I get PostgreSQL 9.2? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Instructions for how to convert/upgrade a PostgreSQL database cluster using pg_upgrade on Ubuntu or Debian. For the sake of example, I&#039;m upgrading from version 9.1 to 9.2, but it should work with any version. Replace any version numbers on the command lines.&lt;br /&gt;
&lt;br /&gt;
== WARNING! ==&lt;br /&gt;
&#039;&#039;&#039;These instructions are experimental!&#039;&#039;&#039;&lt;br /&gt;
* This way of upgrading is not yet supported by Ubuntu upstream. Do it at your own risk. I have tested this on Ubuntu 12.04.&lt;br /&gt;
* PostgreSQL 9.2 is still a testing release (currently at RC 1). Do not run it in production!&lt;br /&gt;
&lt;br /&gt;
When in doubt, use the old but slower pg_upgradecluster method.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
First you need to install relevant packages: postgresql-VER and postgresql-server-dev-VER. If you&#039;re using contrib extensions, you also need postgresql-contrib-VER, and possibly other modules like postgresql-plpython-VER...&lt;br /&gt;
&lt;br /&gt;
 sudo apt-get install postgresql-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; \&lt;br /&gt;
                      postgresql-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By default, Ubuntu creates a database cluster named &amp;quot;main&amp;quot; with each installed version. We will use these. Verify that these are configured:&lt;br /&gt;
&lt;br /&gt;
 # sudo pg_lsclusters&lt;br /&gt;
 Version Cluster   Port Status Owner    Data directory                     Log file&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      5432 down   postgres /var/lib/postgresql/9.1/main       /var/log/postgresql/postgresql-9.1-main.log&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      5433 down   postgres /var/lib/postgresql/9.2/main       /var/log/postgresql/postgresql-9.2-main.log&lt;br /&gt;
&lt;br /&gt;
== Upgrading ==&lt;br /&gt;
First you need to stop the relevant database clusters. To stop all clusters, run:&lt;br /&gt;
&lt;br /&gt;
 sudo /etc/init.d/postgresql stop&lt;br /&gt;
&lt;br /&gt;
(If you don&#039;t want to stop all clusters, you can also use pg_ctlcluster to manage them one by one)&lt;br /&gt;
&lt;br /&gt;
Do the upgrade... (For extra performance, you can use the --link option to pg_upgrade; please [http://www.postgresql.org/docs/current/static/pgupgrade.html read pg_upgrade documentation first])&lt;br /&gt;
&lt;br /&gt;
 cd /tmp&lt;br /&gt;
 sudo -H -u postgres /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/bin/pg_upgrade \&lt;br /&gt;
    -b /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -B /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -d /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -D /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -o &#039;-c config_file=/etc/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf&#039; \&lt;br /&gt;
    -O &#039;-c config_file=/etc/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf -F&#039;&lt;br /&gt;
&lt;br /&gt;
See if it worked...&lt;br /&gt;
&lt;br /&gt;
 sudo pg_ctlcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; start&lt;br /&gt;
 sudo -u postgres psql --cluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 postgres=# select version();&lt;br /&gt;
 PostgreSQL 9.2rc1 on x86_64-unknown-linux-gnu, compiled by gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3, 64-bit&lt;br /&gt;
 postgres=# \l+&lt;br /&gt;
 ... list of databases ...&lt;br /&gt;
&lt;br /&gt;
== What next ==&lt;br /&gt;
Don&#039;t forget to merge your configuration changes in postgresql.conf, pg_hba.conf and other files.&lt;br /&gt;
&lt;br /&gt;
If you upgraded from 9.0 or earlier and you&#039;re using contrib modules or other addons, it is recommended to migrate them to proper extensions. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;CREATE EXTENSION hstore SCHEMA public FROM unpackaged;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
==== New cluster database &amp;quot;XXX&amp;quot; is not empty ====&lt;br /&gt;
The new cluster version already contains some data. For example, if you want to &#039;&#039;&#039;delete all data&#039;&#039;&#039; in the 9.2 version cluster, run:&lt;br /&gt;
&lt;br /&gt;
 pg_dropcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
 pg_createcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Where do I get PostgreSQL 9.2? ====&lt;br /&gt;
On Ubuntu, you can simply install 9.2 from the semi-official &amp;quot;PPA&amp;quot; repository:&lt;br /&gt;
&lt;br /&gt;
 sudo apt-get install python-software-properties&lt;br /&gt;
 sudo apt-add-repository ppa:pitti/postgresql&lt;br /&gt;
 sudo apt-get update&lt;br /&gt;
 sudo apt-get install postgresql-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Warning:&#039;&#039;&#039; Support for the current major version in the PPA may be dropped earlier when a new major version is released. Be prepared to upgrade to the next major version when the older is no longer supported.&lt;/div&gt;</summary>
		<author><name>Intgr</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=Repmgr_cleanup_trigger&amp;diff=18339</id>
		<title>Repmgr cleanup trigger</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=Repmgr_cleanup_trigger&amp;diff=18339"/>
		<updated>2012-10-09T13:25:39Z</updated>

		<summary type="html">&lt;p&gt;Intgr: clarify&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{SnippetInfo|repmgr cleanup trigger|lang=PL/pgSQL|version=9.0+|category=Administrative|depends=repmgr}}&lt;br /&gt;
The &#039;&#039;&#039;repmgr&#039;&#039;&#039; replication system requires you to run daemons on each slave to populate the repl_monitor table with mostly useless state data. In addition, it requires you to run a separate &amp;quot;cluster cleanup&amp;quot; cron job on the master to delete this useless data (hey, the same daemon couldn&#039;t possibly do that, could it?)&lt;br /&gt;
&lt;br /&gt;
To simplify deployment/maintenance, that cron job can be replaced with the following trigger. (Only tested on repmgr 1.2.0)&lt;br /&gt;
&lt;br /&gt;
== Cleanup trigger ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SET search_path=repmgr_CLUSTERNAME; -- change CLUSTERNAME to your repmgr cluster name&lt;br /&gt;
&lt;br /&gt;
CREATE OR REPLACE FUNCTION repl_cleanup_proc() RETURNS trigger LANGUAGE plpgsql&lt;br /&gt;
SET search_path=repmgr_CLUSTERNAME&lt;br /&gt;
AS $$&lt;br /&gt;
DECLARE&lt;br /&gt;
  cleanup_age interval = &#039;1 day&#039;; -- how many records to keep&lt;br /&gt;
  cleanup_batch interval = &#039;1 hour&#039;; -- how many records to delete in one shot&lt;br /&gt;
BEGIN&lt;br /&gt;
  IF EXISTS(SELECT * FROM repl_monitor WHERE last_monitor_time &amp;lt; (now() - cleanup_age - cleanup_batch)) THEN&lt;br /&gt;
    DELETE FROM repl_monitor WHERE last_monitor_time &amp;lt; (now() - cleanup_age);&lt;br /&gt;
  END IF;&lt;br /&gt;
  RETURN new;&lt;br /&gt;
END;&lt;br /&gt;
$$;&lt;br /&gt;
&lt;br /&gt;
CREATE TRIGGER repl_cleanup_trigger AFTER INSERT ON repl_monitor FOR EACH STATEMENT EXECUTE PROCEDURE repl_cleanup_proc();&lt;br /&gt;
&lt;br /&gt;
-- Test the trigger (does not insert any data, but triggers deletion if necessary)&lt;br /&gt;
INSERT INTO repl_monitor (primary_node) SELECT null WHERE false;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Replication]]&lt;/div&gt;</summary>
		<author><name>Intgr</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=Repmgr_cleanup_trigger&amp;diff=18328</id>
		<title>Repmgr cleanup trigger</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=Repmgr_cleanup_trigger&amp;diff=18328"/>
		<updated>2012-10-02T09:28:36Z</updated>

		<summary type="html">&lt;p&gt;Intgr: +test&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{SnippetInfo|repmgr cleanup trigger|lang=PL/pgSQL|version=9.0+|category=Administrative|depends=repmgr}}&lt;br /&gt;
The &#039;&#039;&#039;repmgr&#039;&#039;&#039; replication system requires you to run daemons on each slave to populate the repl_monitor table with mostly useless state data. In addition, it requires you to run a separate &amp;quot;cluster cleanup&amp;quot; cron job on the master to delete this useless data (hey, the same daemon couldn&#039;t possibly do that, could it?)&lt;br /&gt;
&lt;br /&gt;
To simplify deployment/maintenance, that cron job can be replaced with the following trigger. (Only tested on repmgr 1.2.0)&lt;br /&gt;
&lt;br /&gt;
== Cleanup trigger ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SET search_path=repmgr_CLUSTERNAME; -- change CLUSTERNAME to your repmgr cluster name&lt;br /&gt;
&lt;br /&gt;
CREATE OR REPLACE FUNCTION repl_cleanup_proc() RETURNS trigger LANGUAGE plpgsql&lt;br /&gt;
SET search_path=repmgr_CLUSTERNAME&lt;br /&gt;
AS $$&lt;br /&gt;
DECLARE&lt;br /&gt;
  cleanup_age interval = &#039;1 day&#039;; -- how many records to keep&lt;br /&gt;
  cleanup_batch interval = &#039;1 hour&#039;; -- how many records to delete in one shot&lt;br /&gt;
BEGIN&lt;br /&gt;
  IF EXISTS(SELECT * FROM repl_monitor WHERE last_monitor_time &amp;lt; (now() - cleanup_age - cleanup_batch)) THEN&lt;br /&gt;
    DELETE FROM repl_monitor WHERE last_monitor_time &amp;lt; (now() - cleanup_age);&lt;br /&gt;
  END IF;&lt;br /&gt;
  RETURN new;&lt;br /&gt;
END;&lt;br /&gt;
$$;&lt;br /&gt;
&lt;br /&gt;
CREATE TRIGGER repl_cleanup_trigger AFTER INSERT ON repl_monitor FOR EACH STATEMENT EXECUTE PROCEDURE repl_cleanup_proc();&lt;br /&gt;
&lt;br /&gt;
-- Test the trigger (does not insert any data)&lt;br /&gt;
INSERT INTO repl_monitor (primary_node) SELECT null WHERE false;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Replication]]&lt;/div&gt;</summary>
		<author><name>Intgr</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=Repmgr&amp;diff=18327</id>
		<title>Repmgr</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=Repmgr&amp;diff=18327"/>
		<updated>2012-10-02T09:04:43Z</updated>

		<summary type="html">&lt;p&gt;Intgr: Created page with &amp;quot;&amp;#039;&amp;#039;&amp;#039;repmgr&amp;#039;&amp;#039;&amp;#039; is a set of open source tools that helps DBAs and System administrators manage a cluster of PostgreSQL databases.  See: [http://www.repmgr.org/ www.repmgr.org]  [[Ca…&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;repmgr&#039;&#039;&#039; is a set of open source tools that helps DBAs and System administrators manage a cluster of PostgreSQL databases.&lt;br /&gt;
&lt;br /&gt;
See: [http://www.repmgr.org/ www.repmgr.org]&lt;br /&gt;
&lt;br /&gt;
[[Category:Replication]]&lt;/div&gt;</summary>
		<author><name>Intgr</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=Repmgr_cleanup_trigger&amp;diff=18325</id>
		<title>Repmgr cleanup trigger</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=Repmgr_cleanup_trigger&amp;diff=18325"/>
		<updated>2012-10-02T08:14:25Z</updated>

		<summary type="html">&lt;p&gt;Intgr: Created page with &amp;quot;{{SnippetInfo|repmgr cleanup trigger|lang=PL/pgSQL|version=9.0+|category=Administrative}} The &amp;#039;&amp;#039;&amp;#039;repmgr&amp;#039;&amp;#039;&amp;#039; replication system requires you to run daemons on each slave to populat…&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{SnippetInfo|repmgr cleanup trigger|lang=PL/pgSQL|version=9.0+|category=Administrative}}&lt;br /&gt;
The &#039;&#039;&#039;repmgr&#039;&#039;&#039; replication system requires you to run daemons on each slave to populate the repl_monitor table with mostly useless state data. In addition, it requires you to run a &amp;quot;cluster cleanup&amp;quot; cron job on the master to delete this useless data (hey, the same daemon couldn&#039;t possibly do that, could it?)&lt;br /&gt;
&lt;br /&gt;
To simplify deployment/maintenance, that cron job can be replaced with the following trigger.&lt;br /&gt;
&lt;br /&gt;
== Cleanup trigger ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SET search_path=repmgr_CLUSTERNAME; -- change CLUSTERNAME to your repmgr cluster name&lt;br /&gt;
&lt;br /&gt;
CREATE OR REPLACE FUNCTION repl_cleanup_proc() RETURNS trigger LANGUAGE plpgsql&lt;br /&gt;
SET search_path=repmgr_CLUSTERNAME&lt;br /&gt;
AS $$&lt;br /&gt;
DECLARE&lt;br /&gt;
  cleanup_age interval = &#039;1 day&#039;; -- how many records to keep&lt;br /&gt;
  cleanup_batch interval = &#039;1 hour&#039;; -- how many records to delete in one shot&lt;br /&gt;
BEGIN&lt;br /&gt;
  IF EXISTS(SELECT * FROM repl_monitor WHERE last_monitor_time &amp;lt; (now() - cleanup_age - cleanup_batch)) THEN&lt;br /&gt;
    DELETE FROM repl_monitor WHERE last_monitor_time &amp;lt; (now() - cleanup_age);&lt;br /&gt;
  END IF;&lt;br /&gt;
  RETURN new;&lt;br /&gt;
END;&lt;br /&gt;
$$;&lt;br /&gt;
&lt;br /&gt;
CREATE TRIGGER repl_cleanup_trigger AFTER INSERT ON repl_monitor FOR EACH STATEMENT EXECUTE PROCEDURE repl_cleanup_proc();&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Intgr</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=What%27s_new_in_PostgreSQL_9.2&amp;diff=18297</id>
		<title>What&#039;s new in PostgreSQL 9.2</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=What%27s_new_in_PostgreSQL_9.2&amp;diff=18297"/>
		<updated>2012-09-25T15:14:33Z</updated>

		<summary type="html">&lt;p&gt;Intgr: /* Have EXTRACT of a non-timezone-aware value measure the epoch from local midnight, not UTC midnight  */ missing space&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Languages}}&lt;br /&gt;
&lt;br /&gt;
This document showcases many of the latest developments in PostgreSQL 9.2, compared to the last major release &amp;amp;ndash; PostgreSQL 9.1. There are many improvements in this release, so this wiki page covers many of the more important changes in detail. The full list of changes is itemised in &#039;&#039;Release Notes&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Major new features=&lt;br /&gt;
&lt;br /&gt;
==Index-only scans &amp;lt;!-- Robert Haas, Ibrar Ahmed, Heikki Linnakangas, Tom Lane --&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
In PostgreSQL, indexes have no &amp;quot;visibility&amp;quot; information. It means that when you access a record by its index, PostgreSQL has to visit the real tuple in the table to be sure it is visible to you: the tuple the index points to may simply be an old version of the record you are looking for.&lt;br /&gt;
&lt;br /&gt;
It can be a very big performance problem: the index is mostly ordered, so accessing its records is quite efficient, while the records may be scattered all over the place (that&#039;s a reason why PostgreSQL has a cluster command, but that&#039;s another story). In 9.2, PostgreSQL will use an &amp;quot;Index Only Scan&amp;quot; when possible, and not access the record itself if it doesn&#039;t need to.&lt;br /&gt;
&lt;br /&gt;
There is still no visibility information in the index. So in order to do this, PostgreSQL uses the visibility map ([http://www.postgresql.org/docs/devel/static/storage-vm.html visibility map]) , which tells it whether the whole content of a (usually) 8K page is visible to all transactions or not. When the index record points to a tuple contained in an «all visible» page, PostgreSQL won&#039;t have to access the tuple, it will be able to build it directly from the index. Of course, all the columns requested by the query must be in the index.&lt;br /&gt;
&lt;br /&gt;
The visibility map is maintained by VACUUM (it sets the visible bit), and by the backends doing SQL work (they unset the visible bit).&lt;br /&gt;
&lt;br /&gt;
If the data has been read only since the last VACUUM then the data is All Visible and the index only scan feature can improve performance.&lt;br /&gt;
&lt;br /&gt;
Here is an example.&lt;br /&gt;
&lt;br /&gt;
  CREATE TABLE demo_ios (col1 float, col2 float, col3 text);&lt;br /&gt;
&lt;br /&gt;
In this table, we&#039;ll put random data, in order to have &amp;quot;scattered&amp;quot; data. We&#039;ll put 100 million records, to have a big recordset, and have it not fit in memory (that&#039;s a 4GB-ram machine). This is an ideal case, made for this demo. The gains won&#039;t be that big in real life.&lt;br /&gt;
&lt;br /&gt;
  INSERT INTO demo_ios SELECT generate_series(1,100000000),random(), &#039;mynotsolongstring&#039;;&lt;br /&gt;
  &lt;br /&gt;
  SELECT pg_size_pretty(pg_total_relation_size(&#039;demo_ios&#039;));&lt;br /&gt;
   pg_size_pretty &lt;br /&gt;
  ----------------&lt;br /&gt;
   6512 MB&lt;br /&gt;
&lt;br /&gt;
Let&#039;s pretend that the query is this:&lt;br /&gt;
&lt;br /&gt;
  SELECT col1,col2 FROM demo_ios where col2 BETWEEN 0.01 AND 0.02&lt;br /&gt;
&lt;br /&gt;
In order to use an index only scan on this query, we need an index on col2,col1 (col2 first, as it is used in the WHERE clause).&lt;br /&gt;
&lt;br /&gt;
  CREATE index idx_demo_ios on demo_ios(col2,col1);&lt;br /&gt;
&lt;br /&gt;
We vacuum the table, so that the visibility map to be up-to-date:&lt;br /&gt;
&lt;br /&gt;
  VACUUM demo_ios;&lt;br /&gt;
&lt;br /&gt;
All the timing you&#039;ll see below are done on a cold OS and PostgreSQL cache (that&#039;s where the gains are, as the purpose on Index Only Scans is to reduce I/O).&lt;br /&gt;
&lt;br /&gt;
Let&#039;s first try without Index Only Scans:&lt;br /&gt;
&lt;br /&gt;
  SET enable_indexonlyscan to off;&lt;br /&gt;
  &lt;br /&gt;
  EXPLAIN (analyze,buffers) select col1,col2 FROM demo_ios where col2 between 0.01 and 0.02;&lt;br /&gt;
                                                                 QUERY PLAN                                                               &lt;br /&gt;
  ----------------------------------------------------------------------------------------------------------------------------------------&lt;br /&gt;
   Bitmap Heap Scan on demo_ios  (cost=25643.01..916484.44 rows=993633 width=16) (actual time=763.391..362963.899 rows=1000392 loops=1)&lt;br /&gt;
     Recheck Cond: ((col2 &amp;gt;= 0.01::double precision) AND (col2 &amp;lt;= 0.02::double precision))&lt;br /&gt;
     Rows Removed by Index Recheck: 68098621&lt;br /&gt;
     Buffers: shared hit=2 read=587779&lt;br /&gt;
     -&amp;gt;  Bitmap Index Scan on idx_demo_ios  (cost=0.00..25394.60 rows=993633 width=0) (actual time=759.011..759.011 rows=1000392 loops=1)&lt;br /&gt;
           Index Cond: ((col2 &amp;gt;= 0.01::double precision) AND (col2 &amp;lt;= 0.02::double precision))&lt;br /&gt;
           Buffers: shared hit=2 read=3835&lt;br /&gt;
   Total runtime: 364390.127 ms&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
With Index Only Scans:&lt;br /&gt;
&lt;br /&gt;
  explain (analyze,buffers) select col1,col2 from demo_ios where col2 between 0.01 and 0.02;&lt;br /&gt;
                                                                    QUERY PLAN                                                                   &lt;br /&gt;
  -----------------------------------------------------------------------------------------------------------------------------------------------&lt;br /&gt;
   Index Only Scan using idx_demo_ios on demo_ios  (cost=0.00..35330.93 rows=993633 width=16) (actual time=58.100..3250.589 rows=1000392 loops=1)&lt;br /&gt;
     Index Cond: ((col2 &amp;gt;= 0.01::double precision) AND (col2 &amp;lt;= 0.02::double precision))&lt;br /&gt;
     Heap Fetches: 0&lt;br /&gt;
     Buffers: shared hit=923073 read=3848&lt;br /&gt;
   Total runtime: 4297.405 ms&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
As nothing is free, there are a few things to keep in mind:&lt;br /&gt;
&lt;br /&gt;
* Adding indexes for index only scans obviously adds indexes to your table. So updates will be slower.&lt;br /&gt;
* You will index columns that weren&#039;t indexed before. So there will be less opportunities for HOT updates.&lt;br /&gt;
* Gains will probably be smaller in real life situations, especially when data is changed between VACUUMs&lt;br /&gt;
&lt;br /&gt;
This required making visibility map changes crash-safe, so visibility map bit changes are now WAL-logged.&lt;br /&gt;
&lt;br /&gt;
==Replication improvements &amp;lt;!-- Fujii Masao, Simon Riggs, Magnus Hagander, Jun Ishizuka --&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
Streaming Replication becomes more polished with this release. &lt;br /&gt;
&lt;br /&gt;
One of the main remaining gripes about streaming replication is that all the slaves have to be connected to the same and unique master, consuming its resources. Moreover, in case of a failover, it could be complicated to reconnect all the remaining slaves to the newly promoted master, if one is not using a tool like repmgr. &lt;br /&gt;
&lt;br /&gt;
With 9.2, a  standby can also send replication changes, allowing cascading replication.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s build this. We start with an already working 9.2 database.&lt;br /&gt;
&lt;br /&gt;
We set it up for replication:&lt;br /&gt;
&lt;br /&gt;
postgresql.conf:&lt;br /&gt;
  wal_level=hot_standby #(could be archive too)&lt;br /&gt;
  max_wal_senders=5&lt;br /&gt;
  hot_standby=on&lt;br /&gt;
&lt;br /&gt;
You&#039;ll probably also want to activate archiving in production, it won&#039;t be done here.&lt;br /&gt;
&lt;br /&gt;
pg_hba.conf (do not use trust in production):&lt;br /&gt;
  host   replication replication_user          0.0.0.0/0                      md5&lt;br /&gt;
 &lt;br /&gt;
Create the user:&lt;br /&gt;
  create user replication_user replication password &#039;secret&#039;;&lt;br /&gt;
&lt;br /&gt;
Clone the cluster:&lt;br /&gt;
&lt;br /&gt;
  pg_basebackup -h localhost -U replication_user -D data2&lt;br /&gt;
  Password:&lt;br /&gt;
&lt;br /&gt;
We have a brand new cluster in the data2 directory. We&#039;ll change the port so that it can start (postgresql.conf), as both clusters are running on the same machine:&lt;br /&gt;
  port=5433&lt;br /&gt;
&lt;br /&gt;
We add a recovery.conf to tell it how to stream from the master database:&lt;br /&gt;
  standby_mode = on&lt;br /&gt;
  primary_conninfo = &#039;host=localhost port=5432 user=replication_user password=secret&#039; &lt;br /&gt;
&lt;br /&gt;
  pg_ctl -D data2 start&lt;br /&gt;
  server starting&lt;br /&gt;
  LOG:  database system was interrupted; last known up at 2012-07-03 17:58:09 CEST&lt;br /&gt;
  LOG:  creating missing WAL directory &amp;quot;pg_xlog/archive_status&amp;quot;&lt;br /&gt;
  LOG:  entering standby mode&lt;br /&gt;
  LOG:  streaming replication successfully connected to primary&lt;br /&gt;
  LOG:  redo starts at 0/9D000020&lt;br /&gt;
  LOG:  consistent recovery state reached at 0/9D0000B8&lt;br /&gt;
  LOG:  database system is ready to accept read only connections&lt;br /&gt;
&lt;br /&gt;
Now, let&#039;s add a second slave, which will use this slave:&lt;br /&gt;
&lt;br /&gt;
  pg_basebackup -h localhost -U replication_user -D data3 -p 5433&lt;br /&gt;
  Password: &lt;br /&gt;
&lt;br /&gt;
We edit data3&#039;s postgresql.conf to change the port:&lt;br /&gt;
  port=5434&lt;br /&gt;
&lt;br /&gt;
We modify the recovery.conf to stream from the slave:&lt;br /&gt;
  standby_mode = on&lt;br /&gt;
  primary_conninfo = &#039;host=localhost port=5433 user=replication_user password=secret&#039;             # e.g. &#039;host=localhost port=5432&#039;&lt;br /&gt;
&lt;br /&gt;
We start the third cluster:&lt;br /&gt;
  pg_ctl -D data3 start&lt;br /&gt;
  server starting&lt;br /&gt;
  LOG:  database system was interrupted while in recovery at log time 2012-07-03 17:58:09 CEST&lt;br /&gt;
  HINT:  If this has occurred more than once some data might be corrupted and you might need to choose an earlier recovery target.&lt;br /&gt;
  LOG:  creating missing WAL directory &amp;quot;pg_xlog/archive_status&amp;quot;&lt;br /&gt;
  LOG:  entering standby mode&lt;br /&gt;
  LOG:  streaming replication successfully connected to primary&lt;br /&gt;
  LOG:  redo starts at 0/9D000020&lt;br /&gt;
  LOG:  consistent recovery state reached at 0/9E000000&lt;br /&gt;
  LOG:  database system is ready to accept read only connections&lt;br /&gt;
&lt;br /&gt;
Now, everything modified on the master cluster get streamed to the first slave, and from there to the second slave. This second replication has to be monitored from the first slave (the master knows nothing about it).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
As you may have noticed from the example, pg_basebackup now works from slaves.&lt;br /&gt;
&lt;br /&gt;
There is another use case that wasn&#039;t covered: what if a user didn&#039;t care for having a full fledged slave, and only wanted to stream the WAL files to another location, to benefit from the reduced data loss without the burden of maintaining a slave ?&lt;br /&gt;
&lt;br /&gt;
pg_receivexlog is provided just for this purpose: it pretends to be a PostgreSQL slave, but only stores the log files as they are streamed, in a directory:&lt;br /&gt;
  pg_receivexlog -D /tmp/new_logs -h localhost -U replication_user&lt;br /&gt;
&lt;br /&gt;
will connect to the master (or a slave), and start creating files: &lt;br /&gt;
  ls /tmp/new_logs/&lt;br /&gt;
  00000001000000000000009E.partial&lt;br /&gt;
&lt;br /&gt;
Files are of the segment size, so they can be used for a normal recovery of the database. It&#039;s the same as an archive command, but with a much smaller granularity.&lt;br /&gt;
&lt;br /&gt;
Remember to rename the last segment to remove the .partial suffix before using it with a PITR restore or any other operation.&lt;br /&gt;
&lt;br /&gt;
The synchronous_commit parameter has a new value: remote_write. It can be used when there is a synchronous slave (synchronous_standby_names is set), meaning that the master doesn&#039;t have to wait for the slave to have written the data to disk, only for the slave to have acknowledged the data. With this set, data is protected from a crash on the master, but could still be lost if the slave crashed at the same time (i.e. before having written the in flight data to disk). As this is a quite remote possibility, and the performance improvement will be large, some people will be interested in this compromise.&lt;br /&gt;
&lt;br /&gt;
==JSON datatype==&lt;br /&gt;
&lt;br /&gt;
The JSON datatype is meant for storing JSON-structured data. It will validate that the input JSON string is correct JSON:&lt;br /&gt;
&lt;br /&gt;
  =# SELECT &#039;{&amp;quot;username&amp;quot;:&amp;quot;john&amp;quot;,&amp;quot;posts&amp;quot;:121,&amp;quot;emailaddress&amp;quot;:&amp;quot;john@nowhere.com&amp;quot;}&#039;::json;&lt;br /&gt;
                                 json                                &lt;br /&gt;
  -------------------------------------------------------------------&lt;br /&gt;
   {&amp;quot;username&amp;quot;:&amp;quot;john&amp;quot;,&amp;quot;posts&amp;quot;:121,&amp;quot;emailaddress&amp;quot;:&amp;quot;john@nowhere.com&amp;quot;}&lt;br /&gt;
  (1 row)&lt;br /&gt;
  &lt;br /&gt;
  =# SELECT &#039;{&amp;quot;username&amp;quot;,&amp;quot;posts&amp;quot;:121,&amp;quot;emailaddress&amp;quot;:&amp;quot;john@nowhere.com&amp;quot;}&#039;::json;&lt;br /&gt;
  ERROR:  invalid input syntax for type json at character 8&lt;br /&gt;
  DETAIL:  Expected &amp;quot;:&amp;quot;, but found &amp;quot;,&amp;quot;.&lt;br /&gt;
  CONTEXT:  JSON data, line 1: {&amp;quot;username&amp;quot;,...&lt;br /&gt;
  STATEMENT:  SELECT &#039;{&amp;quot;username&amp;quot;,&amp;quot;posts&amp;quot;:121,&amp;quot;emailaddress&amp;quot;:&amp;quot;john@nowhere.com&amp;quot;}&#039;::json;&lt;br /&gt;
  ERROR:  invalid input syntax for type json&lt;br /&gt;
  LINE 1: SELECT &#039;{&amp;quot;username&amp;quot;,&amp;quot;posts&amp;quot;:121,&amp;quot;emailaddress&amp;quot;:&amp;quot;john@nowhere...&lt;br /&gt;
                 ^&lt;br /&gt;
  DETAIL:  Expected &amp;quot;:&amp;quot;, but found &amp;quot;,&amp;quot;.&lt;br /&gt;
  CONTEXT:  JSON data, line 1: {&amp;quot;username&amp;quot;,...&lt;br /&gt;
&lt;br /&gt;
You can also convert a row type to JSON:&lt;br /&gt;
&lt;br /&gt;
  =#SELECT * FROM demo ;&lt;br /&gt;
   username | posts |    emailaddress     &lt;br /&gt;
  ----------+-------+---------------------&lt;br /&gt;
   john     |   121 | john@nowhere.com&lt;br /&gt;
   mickael  |   215 | mickael@nowhere.com&lt;br /&gt;
  (2 rows)&lt;br /&gt;
  &lt;br /&gt;
  =# SELECT row_to_json(demo) FROM demo;&lt;br /&gt;
                                 row_to_json                               &lt;br /&gt;
  -------------------------------------------------------------------------&lt;br /&gt;
   {&amp;quot;username&amp;quot;:&amp;quot;john&amp;quot;,&amp;quot;posts&amp;quot;:121,&amp;quot;emailaddress&amp;quot;:&amp;quot;john@nowhere.com&amp;quot;}&lt;br /&gt;
   {&amp;quot;username&amp;quot;:&amp;quot;mickael&amp;quot;,&amp;quot;posts&amp;quot;:215,&amp;quot;emailaddress&amp;quot;:&amp;quot;mickael@nowhere.com&amp;quot;}&lt;br /&gt;
  (2 rows)&lt;br /&gt;
&lt;br /&gt;
Or an array type:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  =# select array_to_json(array_agg(demo)) from demo;&lt;br /&gt;
                                                                  array_to_json                                                                &lt;br /&gt;
  ---------------------------------------------------------------------------------------------------------------------------------------------&lt;br /&gt;
   [{&amp;quot;username&amp;quot;:&amp;quot;john&amp;quot;,&amp;quot;posts&amp;quot;:121,&amp;quot;emailaddress&amp;quot;:&amp;quot;john@nowhere.com&amp;quot;},{&amp;quot;username&amp;quot;:&amp;quot;mickael&amp;quot;,&amp;quot;posts&amp;quot;:215,&amp;quot;emailaddress&amp;quot;:&amp;quot;mickael@nowhere.com&amp;quot;}]&lt;br /&gt;
  (1 row)&lt;br /&gt;
&lt;br /&gt;
== Range Types ==&lt;br /&gt;
&lt;br /&gt;
Range types are used to store a range of data of a given type. There are a few pre-defined types. They are integer (int4range), bigint (int8range), numeric (numrange), timestamp without timezone (tsrange), timestamp with timezone (tstzrange), and date (daterange).&lt;br /&gt;
&lt;br /&gt;
Ranges can be made of continuous (numeric, timestamp...) or discrete (integer, date...) data types. They can be open (the bound isn&#039;t part of the range) or closed (the bound is part of the range). A bound can also be infinite.&lt;br /&gt;
&lt;br /&gt;
Without these datatypes, most people solve the range problems by using two columns in a table. These range types are much more powerful, as you can use many operators on them.&lt;br /&gt;
&lt;br /&gt;
Here is the intersection between then 1000(open)-2000(closed) and 1000(closed)-1200(closed) numeric range:&lt;br /&gt;
&lt;br /&gt;
  SELECT &#039;(1000,2000]&#039;::numrange * &#039;[1000,1200]&#039;::numrange;&lt;br /&gt;
    ?column?   &lt;br /&gt;
  -------------&lt;br /&gt;
   (1000,1200]&lt;br /&gt;
  (1 row)&lt;br /&gt;
&lt;br /&gt;
So you can query on things like: «give me all ranges that intersect this»:&lt;br /&gt;
&lt;br /&gt;
  =# SELECT * from test_range ;&lt;br /&gt;
                         period                        &lt;br /&gt;
  -----------------------------------------------------&lt;br /&gt;
   [&amp;quot;2012-01-01 00:00:00+01&amp;quot;,&amp;quot;2012-01-02 12:00:00+01&amp;quot;]&lt;br /&gt;
   [&amp;quot;2012-01-01 00:00:00+01&amp;quot;,&amp;quot;2012-03-01 00:00:00+01&amp;quot;]&lt;br /&gt;
   [&amp;quot;2008-01-01 00:00:00+01&amp;quot;,&amp;quot;2015-01-01 00:00:00+01&amp;quot;]&lt;br /&gt;
  (3 rows)&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  =# SELECT * FROM test_range WHERE period &amp;amp;&amp;amp; &#039;[2012-01-03 00:00:00,2012-01-03 12:00:00]&#039;; &lt;br /&gt;
                         period                        &lt;br /&gt;
  -----------------------------------------------------&lt;br /&gt;
   [&amp;quot;2012-01-01 00:00:00+01&amp;quot;,&amp;quot;2012-03-01 00:00:00+01&amp;quot;]&lt;br /&gt;
   [&amp;quot;2008-01-01 00:00:00+01&amp;quot;,&amp;quot;2015-01-01 00:00:00+01&amp;quot;]&lt;br /&gt;
  (2 rows)&lt;br /&gt;
&lt;br /&gt;
This query could use an index defined like this:&lt;br /&gt;
&lt;br /&gt;
  =# CREATE INDEX idx_test_range on test_range USING gist (period);&lt;br /&gt;
&lt;br /&gt;
You can also use these range data types to define exclusion constraints:&lt;br /&gt;
&lt;br /&gt;
  CREATE EXTENSION btree_gist ;&lt;br /&gt;
  CREATE TABLE reservation (room_id int, period tstzrange);&lt;br /&gt;
  ALTER TABLE reservation ADD  EXCLUDE USING GIST (room_id WITH =, period WITH &amp;amp;&amp;amp;);&lt;br /&gt;
&lt;br /&gt;
This means that now it is forbidden to have two records in this table where room_id is equal and period overlaps. The extension btree_gist is required to create a GiST index on room_id (it&#039;s an integer, it is usually indexed with a btree index).&lt;br /&gt;
&lt;br /&gt;
  =# INSERT INTO reservation VALUES (1,&#039;(2012-08-23 14:00:00,2012-08-23 15:00:00)&#039;);&lt;br /&gt;
  INSERT 0 1&lt;br /&gt;
  =# INSERT INTO reservation VALUES (2,&#039;(2012-08-23 14:00:00,2012-08-23 15:00:00)&#039;);&lt;br /&gt;
  INSERT 0 1&lt;br /&gt;
  =# INSERT INTO reservation VALUES (1,&#039;(2012-08-23 14:45:00,2012-08-23 15:15:00)&#039;);&lt;br /&gt;
  ERROR:  conflicting key value violates exclusion constraint &amp;quot;reservation_room_id_period_excl&amp;quot;&lt;br /&gt;
  DETAIL:  Key (room_id, period)=(1, (&amp;quot;2012-08-23 14:45:00+02&amp;quot;,&amp;quot;2012-08-23 15:15:00+02&amp;quot;)) &lt;br /&gt;
  conflicts with existing key (room_id, period)=(1, (&amp;quot;2012-08-23 14:00:00+02&amp;quot;,&amp;quot;2012-08-23 15:00:00+02&amp;quot;)).&lt;br /&gt;
  STATEMENT:  INSERT INTO reservation VALUES (1,&#039;(2012-08-23 14:45:00,2012-08-23 15:15:00)&#039;);&lt;br /&gt;
&lt;br /&gt;
One can also declare new range types.&lt;br /&gt;
&lt;br /&gt;
=Performance improvements=&lt;br /&gt;
&lt;br /&gt;
This version has performance improvements on a very large range of domains (non-exaustive):&lt;br /&gt;
&lt;br /&gt;
* The most visible will probably be the Index Only Scans, which has already been introduced in this document.&lt;br /&gt;
&lt;br /&gt;
* The lock contention of several big locks has been significantly reduced, leading to better multi-processor scalability, for machines with over 32 cores mostly. &amp;lt;!-- Robert Haas --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* The performance of in-memory sorts has been improved by up to 25% in some situations, with certain specialized sort functions introduced. &amp;lt;!-- Peter Geoghegan --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* An idle PostgreSQL server now makes less wakeups, leading to lower power consumption&amp;lt;!--Peter Geoghegan--&amp;gt;. This is especially useful on virtualized and embedded environments.&lt;br /&gt;
&lt;br /&gt;
* COPY has been improved, it will generate less WAL volume and fewer locks of a table&#039;s pages. &amp;lt;!-- Heikki Linnakangas --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Statistics are collected on array contents&amp;lt;!-- Alexander Korotkov --&amp;gt;, allowing for better estimations of selectivity on array operations.&lt;br /&gt;
&lt;br /&gt;
* Text-to-anytype concatenation and quote_literal/quote_nullable functions are not volatile any more, enabling better optimization in some cases &amp;lt;!-- Marti Raudsepp --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* The system can now track IO durations &amp;lt;!--Ants Aasma --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This one deserves a little explanation, as it can be a little tricky. Tracking IO durations means asking repeatedly the time to the operating system. Depending on the operating system and the hardware, this can be quite cheap, or extremely costly. The most import factor here is where the system gets its time from. It could be directly retrieved from the processor (TSC), dedicated hardware such as HPET, or an ACPI call. What&#039;s most important is that the cost of getting time can vary from a factor of thousands.&lt;br /&gt;
&lt;br /&gt;
If you are interested in this timing data, it&#039;s better to first check if your system will support it without too much of a performance hit. PostgreSQL provides you with the pg_test_timing tool:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ pg_test_timing &lt;br /&gt;
Testing timing overhead for 3 seconds.&lt;br /&gt;
Per loop time including overhead: 28.02 nsec&lt;br /&gt;
Histogram of timing durations:&lt;br /&gt;
   &amp;lt; usec:      count   percent&lt;br /&gt;
       32:         41  0.00004%&lt;br /&gt;
       16:       1405  0.00131%&lt;br /&gt;
        8:        200  0.00019%&lt;br /&gt;
        4:        388  0.00036%&lt;br /&gt;
        2:    2982558  2.78523%&lt;br /&gt;
        1:  104100166 97.21287%&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here, everything is good: getting time costs around 28 nanoseconds, and has a very small variation. Anything under 100 nanoseconds should be good for production. If you get higher values, you may still find a way to tune your system. You&#039;d better check on the [http://www.postgresql.org/docs/9.2/static/pgtesttiming.html documentation].&lt;br /&gt;
&lt;br /&gt;
Anyway, here is the data you&#039;ll be able to collect if your system is ready for this:&lt;br /&gt;
&lt;br /&gt;
First, you&#039;ll get per-database statistics, which will now give accurate informations about which database is doing most I/O:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
=# SELECT * FROM pg_stat_database WHERE datname = &#039;mydb&#039;;&lt;br /&gt;
-[ RECORD 1 ]--+------------------------------&lt;br /&gt;
datid          | 16384&lt;br /&gt;
datname        | mydb&lt;br /&gt;
numbackends    | 1&lt;br /&gt;
xact_commit    | 270&lt;br /&gt;
xact_rollback  | 2&lt;br /&gt;
blks_read      | 1961&lt;br /&gt;
blks_hit       | 17944&lt;br /&gt;
tup_returned   | 269035&lt;br /&gt;
tup_fetched    | 8850&lt;br /&gt;
tup_inserted   | 16&lt;br /&gt;
tup_updated    | 4&lt;br /&gt;
tup_deleted    | 45&lt;br /&gt;
conflicts      | 0&lt;br /&gt;
temp_files     | 0&lt;br /&gt;
temp_bytes     | 0&lt;br /&gt;
deadlocks      | 0&lt;br /&gt;
blk_read_time  | 583.774&lt;br /&gt;
blk_write_time | 0&lt;br /&gt;
stats_reset    | 2012-07-03 17:18:54.796817+02&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
We see here that mydb has only consumed 583.774 milliseconds of read time.&lt;br /&gt;
&lt;br /&gt;
Explain will benefit from this too:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
=# EXPLAIN (analyze,buffers) SELECT count(*) FROM mots ;&lt;br /&gt;
                                                   QUERY PLAN&lt;br /&gt;
----------------------------------------------------------------------------------------------------------------&lt;br /&gt;
 Aggregate  (cost=1669.95..1669.96 rows=1 width=0) (actual time=21.943..21.943 rows=1 loops=1)&lt;br /&gt;
   Buffers: shared read=493&lt;br /&gt;
   I/O Timings: read=2.578&lt;br /&gt;
   -&amp;gt;  Seq Scan on mots  (cost=0.00..1434.56 rows=94156 width=0) (actual time=0.059..12.933 rows=94156 loops=1)&lt;br /&gt;
         Buffers: shared read=493&lt;br /&gt;
         I/O Timings: read=2.578&lt;br /&gt;
 Total runtime: 22.059 ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
We now have a separate information about the time taken to retrieve data from the operating system. Obviously, here, the data was in the operating system&#039;s cache (2 milliseconds to read 493 blocks).&lt;br /&gt;
&lt;br /&gt;
And last, if you have enabled pg_stat_statements:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
select * from pg_stat_statements where query ~ &#039;words&#039;;&lt;br /&gt;
-[ RECORD 1 ]-------+---------------------------&lt;br /&gt;
userid              | 10&lt;br /&gt;
dbid                | 16384&lt;br /&gt;
query               | select count(*) from words;&lt;br /&gt;
calls               | 2&lt;br /&gt;
total_time          | 78.332&lt;br /&gt;
rows                | 2&lt;br /&gt;
shared_blks_hit     | 0&lt;br /&gt;
shared_blks_read    | 986&lt;br /&gt;
shared_blks_dirtied | 0&lt;br /&gt;
shared_blks_written | 0&lt;br /&gt;
local_blks_hit      | 0&lt;br /&gt;
local_blks_read     | 0&lt;br /&gt;
local_blks_dirtied  | 0&lt;br /&gt;
local_blks_written  | 0&lt;br /&gt;
temp_blks_read      | 0&lt;br /&gt;
temp_blks_written   | 0&lt;br /&gt;
blk_read_time       | 58.427&lt;br /&gt;
blk_write_time      | 0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* As for every version, the optimizer has received its share of improvements &amp;lt;!-- Tom Lane--&amp;gt;&lt;br /&gt;
** Prepared statements used to be optimized once, without any knowledge of the parameters&#039; values. With 9.2, the planner will use specific plans regarding to the parameters sent (the query will be planned at execution), except if the query is executed several times and the planner decides that the generic plan is not too much more expensive than the specific plans.&lt;br /&gt;
** A new feature has been added: parameterized paths. Simply put, it means that a sub-part of a query plan can use parameters it has got from a parent node. It fixes several bad plans that could occur, especially when the optimizer couldn&#039;t reorder joins to put nested loops where it would have been efficient.&lt;br /&gt;
&lt;br /&gt;
This example is straight from the developpers mailing lists &amp;lt;!-- Andres Freund --&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE a (&lt;br /&gt;
    a_id serial PRIMARY KEY NOT NULL,&lt;br /&gt;
    b_id integer&lt;br /&gt;
);&lt;br /&gt;
CREATE INDEX a__b_id ON a USING btree (b_id);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
CREATE TABLE b (&lt;br /&gt;
    b_id serial NOT NULL,&lt;br /&gt;
    c_id integer&lt;br /&gt;
);&lt;br /&gt;
CREATE INDEX b__c_id ON b USING btree (c_id);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
CREATE TABLE c (&lt;br /&gt;
    c_id serial PRIMARY KEY NOT NULL,&lt;br /&gt;
    value integer UNIQUE&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
INSERT INTO b (b_id, c_id)&lt;br /&gt;
    SELECT g.i, g.i FROM generate_series(1, 50000) g(i);&lt;br /&gt;
&lt;br /&gt;
INSERT INTO a(b_id)&lt;br /&gt;
    SELECT g.i FROM generate_series(1, 50000) g(i);&lt;br /&gt;
&lt;br /&gt;
INSERT INTO c(c_id,value)&lt;br /&gt;
    VALUES (1,1);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So we have a referencing b, b referencing c.&lt;br /&gt;
&lt;br /&gt;
Here is an example of a query working badly with PostgreSQL 9.1:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
EXPLAIN ANALYZE SELECT 1&lt;br /&gt;
FROM&lt;br /&gt;
    c&lt;br /&gt;
WHERE&lt;br /&gt;
    EXISTS (&lt;br /&gt;
        SELECT *&lt;br /&gt;
        FROM a&lt;br /&gt;
            JOIN b USING (b_id)&lt;br /&gt;
        WHERE b.c_id = c.c_id)&lt;br /&gt;
    AND c.value = 1;&lt;br /&gt;
                                                      QUERY PLAN&lt;br /&gt;
-----------------------------------------------------------------------------------------------------------------------&lt;br /&gt;
 Nested Loop Semi Join  (cost=1347.00..3702.27 rows=1 width=0) (actual time=13.799..13.802 rows=1 loops=1)&lt;br /&gt;
   Join Filter: (c.c_id = b.c_id)&lt;br /&gt;
   -&amp;gt;  Index Scan using c_value_key on c  (cost=0.00..8.27 rows=1 width=4) (actual time=0.006..0.008 rows=1 loops=1)&lt;br /&gt;
         Index Cond: (value = 1)&lt;br /&gt;
   -&amp;gt;  Hash Join  (cost=1347.00..3069.00 rows=50000 width=4) (actual time=13.788..13.788 rows=1 loops=1)&lt;br /&gt;
         Hash Cond: (a.b_id = b.b_id)&lt;br /&gt;
         -&amp;gt;  Seq Scan on a  (cost=0.00..722.00 rows=50000 width=4) (actual time=0.007..0.007 rows=1 loops=1)&lt;br /&gt;
         -&amp;gt;  Hash  (cost=722.00..722.00 rows=50000 width=8) (actual time=13.760..13.760 rows=50000 loops=1)&lt;br /&gt;
               Buckets: 8192  Batches: 1  Memory Usage: 1954kB&lt;br /&gt;
               -&amp;gt;  Seq Scan on b  (cost=0.00..722.00 rows=50000 width=8) (actual time=0.008..5.702 rows=50000 loops=1)&lt;br /&gt;
 Total runtime: 13.842 ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Not that bad, 13 milliseconds. Still, we are doing sequential scans on a and b, when our common sense tells us that c.value=1 should be used to filter rows more aggressively.&lt;br /&gt;
&lt;br /&gt;
Here&#039;s what 9.2 does with this query:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                                                      QUERY PLAN&lt;br /&gt;
----------------------------------------------------------------------------------------------------------------------------&lt;br /&gt;
 Nested Loop Semi Join  (cost=0.00..16.97 rows=1 width=0) (actual time=0.035..0.037 rows=1 loops=1)&lt;br /&gt;
   -&amp;gt;  Index Scan using c_value_key on c  (cost=0.00..8.27 rows=1 width=4) (actual time=0.007..0.009 rows=1 loops=1)&lt;br /&gt;
         Index Cond: (value = 1)&lt;br /&gt;
   -&amp;gt;  Nested Loop  (cost=0.00..8.69 rows=1 width=4) (actual time=0.025..0.025 rows=1 loops=1)&lt;br /&gt;
         -&amp;gt;  Index Scan using b__c_id on b  (cost=0.00..8.33 rows=1 width=8) (actual time=0.007..0.007 rows=1 loops=1)&lt;br /&gt;
               Index Cond: (c_id = c.c_id)&lt;br /&gt;
         -&amp;gt;  Index Only Scan using a__b_id on a  (cost=0.00..0.35 rows=1 width=4) (actual time=0.014..0.014 rows=1 loops=1)&lt;br /&gt;
               Index Cond: (b_id = b.b_id)&lt;br /&gt;
 Total runtime: 0.089 ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The «parameterized path» is:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   -&amp;gt;  Nested Loop  (cost=0.00..8.69 rows=1 width=4) (actual time=0.025..0.025 rows=1 loops=1)&lt;br /&gt;
         -&amp;gt;  Index Scan using b__c_id on b  (cost=0.00..8.33 rows=1 width=8) (actual time=0.007..0.007 rows=1 loops=1)&lt;br /&gt;
               Index Cond: (c_id = c.c_id)&lt;br /&gt;
         -&amp;gt;  Index Only Scan using a__b_id on a  (cost=0.00..0.35 rows=1 width=4) (actual time=0.014..0.014 rows=1 loops=1)&lt;br /&gt;
               Index Cond: (b_id = b.b_id)&lt;br /&gt;
 Total runtime: 0.089 ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This part of the plan depends on a parent node (c_id=c.c_id). This part of the plan is called each time with a different parameter coming from the parent node.&lt;br /&gt;
&lt;br /&gt;
This plan is of course much faster, as there is no need to fully scan a, and to fully scan AND hash b.&lt;br /&gt;
&lt;br /&gt;
=SP-GiST=&lt;br /&gt;
&lt;br /&gt;
SP-GiST stands for Space Partitionned GiST, GiST being Generalized Search Tree. GiST is an index type, and has been available for quite a while in PostgreSQL. GiST is already very efficient at indexing complex data types, but performance tends to suffer when the source data isn&#039;t uniformly distributed. SP-GiST tries to fix that.&lt;br /&gt;
&lt;br /&gt;
As all indexing methods available in PostgreSQL, SP-GiST is a generic indexing method, meaning its purpose is to index whatever you&#039;ll throw at it, using operators you&#039;ll provide. It means that if you want to create a new datatype, and make it indexable through SP-GiST, you&#039;ll have to follow the documented API.&lt;br /&gt;
&lt;br /&gt;
SP-GiST can be used to implement 3 type of indexes: trie (suffix) indexing, Quadtree (data is divided into quadrants), and k-d tree (k-dimensional tree).&lt;br /&gt;
&lt;br /&gt;
For now, SP-GiST is provided with operator families called &amp;quot;quad_point_ops&amp;quot;, &amp;quot;kd_point_ops&amp;quot; and &amp;quot;text_ops&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
As their names indicate, the first one indexes point types, using a quadtree, the second one indexes point types using a k-d tree, and the third one indexes text, using suffix.&lt;br /&gt;
&lt;br /&gt;
=pg_stat_statements=&lt;br /&gt;
&lt;br /&gt;
This contrib module has received a lot of improvements in this version:&lt;br /&gt;
&lt;br /&gt;
* Queries are normalized: queries that are identical except for their constant values will be considered the same, as long as their post-parse analysis query tree (that is, the internal representation of the query before rule expansion) are the same. This also implies that differences that are not semantically essential to the query, such as variations in whitespace or alias names, or the use of one particular syntax over another equivalent one will not differentiate queries.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
=#SELECT * FROM words WHERE word= &#039;foo&#039;;&lt;br /&gt;
 word &lt;br /&gt;
------&lt;br /&gt;
(0 ligne)&lt;br /&gt;
&lt;br /&gt;
=# SELECT * FROM words WHERE word= &#039;bar&#039;;&lt;br /&gt;
 word &lt;br /&gt;
------&lt;br /&gt;
 bar&lt;br /&gt;
&lt;br /&gt;
=#select * from pg_stat_statements where query like &#039;%words where%&#039;;&lt;br /&gt;
-[ RECORD 1 ]-------+-----------------------------------&lt;br /&gt;
userid              | 10&lt;br /&gt;
dbid                | 16384&lt;br /&gt;
query               | SELECT * FROM words WHERE word= ?;&lt;br /&gt;
calls               | 2&lt;br /&gt;
total_time          | 142.314&lt;br /&gt;
rows                | 1&lt;br /&gt;
shared_blks_hit     | 3&lt;br /&gt;
shared_blks_read    | 5&lt;br /&gt;
shared_blks_dirtied | 0&lt;br /&gt;
shared_blks_written | 0&lt;br /&gt;
local_blks_hit      | 0&lt;br /&gt;
local_blks_read     | 0&lt;br /&gt;
local_blks_dirtied  | 0&lt;br /&gt;
local_blks_written  | 0&lt;br /&gt;
temp_blks_read      | 0&lt;br /&gt;
temp_blks_written   | 0&lt;br /&gt;
blk_read_time       | 142.165&lt;br /&gt;
blk_write_time      | 0&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The two queries are shown as one in pg_stat_statements.&lt;br /&gt;
&lt;br /&gt;
* For prepared statements, the execution part (execute statement) is charged on the prepare statement. That makes it is easier to interpret, and avoids the double-counting there was with PostgreSQL 9.1.&lt;br /&gt;
&lt;br /&gt;
* pg_stat_statements displays timing in milliseconds, to be consistent with other system views.&lt;br /&gt;
&lt;br /&gt;
= Explain improvements=&lt;br /&gt;
&lt;br /&gt;
* Timing can now be disabled with EXPLAIN (analyze on, timing off), leading to lower overhead on platforms where getting the current time is expensive &amp;lt;!--Tomas Vondra--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  =# EXPLAIN (analyze on,timing off) SELECT * FROM reservation ;&lt;br /&gt;
                                       QUERY PLAN                                       &lt;br /&gt;
  ----------------------------------------------------------------------------------------&lt;br /&gt;
   Seq Scan on reservation  (cost=0.00..22.30 rows=1230 width=36) (actual rows=2 loops=1)&lt;br /&gt;
   Total runtime: 0.045 ms&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Have EXPLAIN ANALYZE report the number of rows rejected by filter steps &amp;lt;!--(Marko Tiikkaja)--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This new feature makes it much easier to know how many rows are removed by a filter (and spot potential places to put indexes):&lt;br /&gt;
&lt;br /&gt;
  =# EXPLAIN ANALYZE SELECT * FROM test WHERE a ~ &#039;tra&#039;;&lt;br /&gt;
                                                    QUERY PLAN                                                   &lt;br /&gt;
  ---------------------------------------------------------------------------------------------------------------&lt;br /&gt;
   Seq Scan on test  (cost=0.00..106876.56 rows=2002 width=11) (actual time=2.914..8538.285 rows=120256 loops=1)&lt;br /&gt;
     Filter: (a ~ &#039;tra&#039;::text)&lt;br /&gt;
     Rows Removed by Filter: 5905600&lt;br /&gt;
   Total runtime: 8549.539 ms&lt;br /&gt;
  (4 rows)&lt;br /&gt;
&lt;br /&gt;
=Backward compatibility=&lt;br /&gt;
&lt;br /&gt;
These changes may incur regressions in your applications.&lt;br /&gt;
&lt;br /&gt;
==Ensure that xpath() escapes special characters in string values &amp;lt;!-- (Florian Pflug)--&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Before 9.2:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT (XPATH(&#039;/*/text()&#039;, &#039;&amp;lt;root&amp;gt;&amp;amp;amp;lt;&amp;lt;/root&amp;gt;&#039;))[1];&lt;br /&gt;
 xpath &lt;br /&gt;
-------&lt;br /&gt;
 &amp;lt;&lt;br /&gt;
&lt;br /&gt;
&#039;&amp;lt;&#039; Isn&#039;t valid XML.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
With 9.2:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT (XPATH(&#039;/*/text()&#039;, &#039;&amp;lt;root&amp;gt;&amp;amp;amp;lt;&amp;lt;/root&amp;gt;&#039;))[1];&lt;br /&gt;
 xpath &lt;br /&gt;
-------&lt;br /&gt;
 &amp;amp;amp;lt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Remove hstore&#039;s =&amp;gt; operator &amp;lt;!-- (Robert Haas)--&amp;gt;==&lt;br /&gt;
Up to 9.1, one could use the =&amp;gt; operator to create a hstore. Hstore is a contrib, used to store key/values pairs in a column.&lt;br /&gt;
&lt;br /&gt;
In 9.1:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
=# SELECT &#039;a&#039;=&amp;gt;&#039;b&#039;;&lt;br /&gt;
 ?column? &lt;br /&gt;
----------&lt;br /&gt;
 &amp;quot;a&amp;quot;=&amp;gt;&amp;quot;b&amp;quot;&lt;br /&gt;
(1 row)&lt;br /&gt;
&lt;br /&gt;
=# SELECT pg_typeof(&#039;a&#039;=&amp;gt;&#039;b&#039;);&lt;br /&gt;
 pg_typeof &lt;br /&gt;
-----------&lt;br /&gt;
 hstore&lt;br /&gt;
(1 row)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With 9.2:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT &#039;a&#039;=&amp;gt;&#039;b&#039;;&lt;br /&gt;
ERROR:  operator does not exist: unknown =&amp;gt; unknown at character 11&lt;br /&gt;
HINT:  No operator matches the given name and argument type(s). You might need to add explicit type casts.&lt;br /&gt;
STATEMENT:  SELECT &#039;a&#039;=&amp;gt;&#039;b&#039;;&lt;br /&gt;
ERROR:  operator does not exist: unknown =&amp;gt; unknown&lt;br /&gt;
LINE 1: SELECT &#039;a&#039;=&amp;gt;&#039;b&#039;;&lt;br /&gt;
                  ^&lt;br /&gt;
HINT:  No operator matches the given name and argument type(s). You might need to add explicit type casts.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It doesn&#039;t mean one cannot use &#039;=&amp;gt;&#039; in hstores, it just isn&#039;t an operator anymore:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
=# select hstore(&#039;a=&amp;gt;b&#039;);&lt;br /&gt;
  hstore  &lt;br /&gt;
----------&lt;br /&gt;
 &amp;quot;a&amp;quot;=&amp;gt;&amp;quot;b&amp;quot;&lt;br /&gt;
(1 row)&lt;br /&gt;
&lt;br /&gt;
=# select hstore(&#039;a&#039;,&#039;b&#039;);&lt;br /&gt;
  hstore  &lt;br /&gt;
----------&lt;br /&gt;
 &amp;quot;a&amp;quot;=&amp;gt;&amp;quot;b&amp;quot;&lt;br /&gt;
(1 row)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
are still two valid ways to input a hstore.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;=&amp;gt;&amp;quot; is removed as an operator as it is a reserved keyword in SQL.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Have pg_relation_size() and friends return NULL if the object does not exist  &amp;lt;!-- (Phil Sorber)--&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
A relation could be dropped by a concurrent session, while one was doing a pg_relation_size on it, leading to a SQL exception. Now, it merely returns NULL for this record.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Remove the spclocation field from pg_tablespace &amp;lt;!-- (Magnus Hagander)--&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
The spclocation field provided the real location of the tablespace. It was filled in during the CREATE or ALTER TABLESPACE command. So it could be wrong: somebody just had to shutdown the cluster, move the tablespace&#039;s directory, re-create the symlink in pg_tblspc, and forget to update the spclocation field. The cluster would still run, as the spclocation wasn&#039;t used.&lt;br /&gt;
&lt;br /&gt;
So this field has been removed. To get the tablespace&#039;s location, use pg_tablespace_location():&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
=# SELECT *, pg_tablespace_location(oid) AS spclocation FROM pg_tablespace;&lt;br /&gt;
  spcname   | spcowner | spcacl | spcoptions |  spclocation   &lt;br /&gt;
------------+----------+--------+------------+----------------&lt;br /&gt;
 pg_default |       10 |        |            | &lt;br /&gt;
 pg_global  |       10 |        |            | &lt;br /&gt;
 tmptblspc  |       10 |        |            | /tmp/tmptblspc&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Have EXTRACT of a non-timezone-aware value measure the epoch from local midnight, not UTC midnight &amp;lt;!-- (Tom Lane) --&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
With PostgreSQL 9.1:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
=# SELECT extract(epoch FROM &#039;2012-07-02 00:00:00&#039;::timestamp);&lt;br /&gt;
 date_part  &lt;br /&gt;
------------&lt;br /&gt;
 1341180000&lt;br /&gt;
(1 row)&lt;br /&gt;
&lt;br /&gt;
=# SELECT extract(epoch FROM &#039;2012-07-02 00:00:00&#039;::timestamptz);&lt;br /&gt;
 date_part  &lt;br /&gt;
------------&lt;br /&gt;
 1341180000&lt;br /&gt;
(1 row)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is no difference in behaviour between a timstamp with or without timezone.&lt;br /&gt;
&lt;br /&gt;
With 9.2:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
=# SELECT extract(epoch FROM &#039;2012-07-02 00:00:00&#039;::timestamp);&lt;br /&gt;
 date_part  &lt;br /&gt;
------------&lt;br /&gt;
 1341187200&lt;br /&gt;
(1 row)&lt;br /&gt;
&lt;br /&gt;
=# SELECT extract(epoch FROM &#039;2012-07-02 00:00:00&#039;::timestamptz);&lt;br /&gt;
 date_part  &lt;br /&gt;
------------&lt;br /&gt;
 1341180000&lt;br /&gt;
(1 row)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When the timestamp has no timezone, the epoch is calculated with the &amp;quot;local midnight&amp;quot;, meaning the 1st january of 1970 at midnight, local-time.&lt;br /&gt;
&lt;br /&gt;
==Fix to_date() and to_timestamp() to wrap incomplete dates toward 2020 &amp;lt;!-- (Bruce Momjian)--&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
The wrapping was not consistent between 2 digit dates and 3 digit dates: 2 digit dates always chose the date closest to 2020, 3 digit dates mapped dates from 100 to 999 on 1100 to 1999, and 000 to 099 on 2000 to 2099.&lt;br /&gt;
&lt;br /&gt;
Now PostgreSQL chooses the date closest to 2020, for 2 and 3 digit dates.&lt;br /&gt;
&lt;br /&gt;
With 9.1:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
=# SELECT to_date(&#039;200-07-02&#039;,&#039;YYY-MM-DD&#039;);&lt;br /&gt;
  to_date   &lt;br /&gt;
------------&lt;br /&gt;
 1200-07-02&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With 9.2:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT to_date(&#039;200-07-02&#039;,&#039;YYY-MM-DD&#039;);&lt;br /&gt;
  to_date   &lt;br /&gt;
------------&lt;br /&gt;
 2200-07-02&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==pg_stat_activity and pg_stat_replication&#039;s definitions have changed &amp;lt;!--Magnus Hagander --&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
The view pg_stat_activity has changed. It&#039;s not backward compatible, but let&#039;s see what this new definition brings us:&lt;br /&gt;
&lt;br /&gt;
* current_query disappears and is replaced by two columns:&lt;br /&gt;
** state: is the session running a query, waiting&lt;br /&gt;
** query: what is the last run (or still running if stat is &amp;quot;active&amp;quot;) query&lt;br /&gt;
* The column procpid is renamed to pid, to be consistent with other system views&lt;br /&gt;
&lt;br /&gt;
The benefit is mostly for tracking «idle in transaction» sessions. Up until now, all we could know was that one of these sessions was idle in transaction, meaning it has started a transaction, maybe done some operations, but still not committed. If that session stayed in this state for a while, there was no way of knowing how it got in this state.&lt;br /&gt;
&lt;br /&gt;
Here is an example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
-[ RECORD 1 ]----+---------------------------------&lt;br /&gt;
datid            | 16384&lt;br /&gt;
datname          | postgres&lt;br /&gt;
pid              | 20804&lt;br /&gt;
usesysid         | 10&lt;br /&gt;
usename          | postgres&lt;br /&gt;
application_name | psql&lt;br /&gt;
client_addr      | &lt;br /&gt;
client_hostname  | &lt;br /&gt;
client_port      | -1&lt;br /&gt;
backend_start    | 2012-07-02 15:02:51.146427+02&lt;br /&gt;
xact_start       | 2012-07-02 15:15:28.386865+02&lt;br /&gt;
query_start      | 2012-07-02 15:15:30.410834+02&lt;br /&gt;
state_change     | 2012-07-02 15:15:30.411287+02&lt;br /&gt;
waiting          | f&lt;br /&gt;
state            | idle in transaction&lt;br /&gt;
query            | DELETE FROM test;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With PostgreSQL 9.1, all we would have would be «idle in transaction».&lt;br /&gt;
&lt;br /&gt;
As this change was backward-incompatible, procpid was also renamed to pid, to be more consistent with other system views.&lt;br /&gt;
The view pg_stat_replication has also changed. The column procpid is renamed to pid, to also be consistent with other system views.&lt;br /&gt;
&lt;br /&gt;
==Change all SQL-level statistics timing values to float8-stored milliseconds &amp;lt;!-- (Tom Lane) --&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
pg_stat_user_functions.total_time, pg_stat_user_functions.self_time, pg_stat_xact_user_functions.total_time, pg_stat_xact_user_functions.self_time, and pg_stat_statements.total_time (contrib) are now in milliseconds, to be consistent with the rest of the timing values.&lt;br /&gt;
&lt;br /&gt;
==postgresql.conf parameters changes &amp;lt;!-- (Heikki Linnakangas, Tom Lane, Peter Eisentraut) --&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
* silent_mode has been removed. Use pg_ctl -l postmaster.log&lt;br /&gt;
* wal_sender_delay has been removed. It is no longer needed&lt;br /&gt;
* custom_variable_classes has been removed. All «classes» are accepted without declaration now&lt;br /&gt;
* ssl_ca_file, ssl_cert_file, ssl_crl_file, ssl_key_file have been added, meaning you can now specify the ssl files&lt;br /&gt;
&lt;br /&gt;
= Other new features =&lt;br /&gt;
&lt;br /&gt;
== DROP INDEX CONCURRENTLY ==&lt;br /&gt;
&lt;br /&gt;
The regular DROP INDEX command takes an exclusive lock on the table. Most of the time, this isn&#039;t a problem, because this lock is short-lived. The problem usually occurs when:&lt;br /&gt;
&lt;br /&gt;
* A long-running transaction is running, and has a (shared) lock on the table&lt;br /&gt;
* A DROP INDEX is run on this table in another session, asking for an exclusive lock (and waiting for it, as it won&#039;t be granted until the long-running transaction ends)&lt;br /&gt;
&lt;br /&gt;
At this point, all other transactions needing to take a shared lock on the table (for a simple SELECT for instance) will have to wait too: their lock acquisition is queued after the DROP INDEX&#039;s one.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
DROP INDEX CONCURRENTLY works around this and won&#039;t lock normal DML statements, just as CREATE INDEX CONCURRENTLY. The limitations are also the same: Since you can only DROP one index with the CONCURRENTLY option, and the CASCADE option is not supported.&lt;br /&gt;
&lt;br /&gt;
== NOT VALID CHECK constraints ==&lt;br /&gt;
&lt;br /&gt;
PostgreSQL 9.1 introduced «NOT VALID» foreign keys. This has been extended to CHECK constraints. Adding a «NOT VALID» constraint on a table means that current data won&#039;t be validated, only new and updated rows.&lt;br /&gt;
&lt;br /&gt;
  =# CREATE TABLE test (a int); &lt;br /&gt;
  CREATE TABLE&lt;br /&gt;
  =# INSERT INTO test SELECT generate_series(1,100);&lt;br /&gt;
  INSERT 0 100&lt;br /&gt;
  =# ALTER TABLE test ADD CHECK (a&amp;gt;100) NOT VALID;&lt;br /&gt;
  ALTER TABLE&lt;br /&gt;
  =# INSERT INTO test VALUES (99);&lt;br /&gt;
  ERROR:  new row for relation &amp;quot;test&amp;quot; violates check constraint &amp;quot;test_a_check&amp;quot;&lt;br /&gt;
  DETAIL:  Failing row contains (99).&lt;br /&gt;
  =# INSERT INTO test VALUES (101);&lt;br /&gt;
  INSERT 0 1&lt;br /&gt;
&lt;br /&gt;
Then, later, we can validate the whole table:&lt;br /&gt;
&lt;br /&gt;
  =# ALTER TABLE test VALIDATE CONSTRAINT test_a_check ;&lt;br /&gt;
  ERROR:  check constraint &amp;quot;test_a_check&amp;quot; is violated by some row&lt;br /&gt;
&lt;br /&gt;
Domains, which are types with added constraints, can also be declared as not valid, and validated later.&lt;br /&gt;
&lt;br /&gt;
Check constraints can also be renamed now:&lt;br /&gt;
&lt;br /&gt;
  =# ALTER TABLE test RENAME CONSTRAINT test_a_check TO validate_a;&lt;br /&gt;
  ALTER TABLE&lt;br /&gt;
&lt;br /&gt;
== NO INHERIT constraints ==&lt;br /&gt;
&lt;br /&gt;
Here is another improvement about constraints: they can be declared as not inheritable, which will be useful in partitioned environments. Let&#039;s take PostgreSQL documentation example, and see how it improves the situation:&lt;br /&gt;
&lt;br /&gt;
  CREATE TABLE measurement (&lt;br /&gt;
      city_id         int not null,&lt;br /&gt;
      logdate         date not null,&lt;br /&gt;
      peaktemp        int,&lt;br /&gt;
      unitsales       int,&lt;br /&gt;
      CHECK (logdate IS NULL) NO INHERIT&lt;br /&gt;
  );&lt;br /&gt;
  &lt;br /&gt;
  CREATE TABLE measurement_y2006m02 (&lt;br /&gt;
      CHECK ( logdate &amp;gt;= DATE &#039;2006-02-01&#039; AND logdate &amp;lt; DATE &#039;2006-03-01&#039; )&lt;br /&gt;
  ) INHERITS (measurement);&lt;br /&gt;
  CREATE TABLE measurement_y2006m03 (&lt;br /&gt;
      CHECK ( logdate &amp;gt;= DATE &#039;2006-03-01&#039; AND logdate &amp;lt; DATE &#039;2006-04-01&#039; )&lt;br /&gt;
  ) INHERITS (measurement);&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  INSERT INTO measurement VALUES (1,&#039;2006-02-20&#039;,1,1);&lt;br /&gt;
  ERROR:  new row for relation &amp;quot;measurement&amp;quot; violates check constraint &amp;quot;measurement_logdate_check&amp;quot;&lt;br /&gt;
  DETAIL:  Failing row contains (1, 2006-02-20, 1, 1).&lt;br /&gt;
  INSERT INTO measurement_y2006m02 VALUES (1,&#039;2006-02-20&#039;,1,1);&lt;br /&gt;
  INSERT 0 1&lt;br /&gt;
&lt;br /&gt;
Until now, every check constraint created on measurement would have been inherited by children tables. So adding a constraint forbidding inserts, or allowing only some of them, on the parent table was impossible.&lt;br /&gt;
&lt;br /&gt;
== Reduce ALTER TABLE rewrites ==&lt;br /&gt;
&lt;br /&gt;
A table won&#039;t get rewritten anymore during an ALTER TABLE when changing the type of a column in the following cases:&lt;br /&gt;
&lt;br /&gt;
* varchar(x) to varchar(y) when y&amp;gt;=x. It works too if going from varchar(x) to varchar or text (no size limitation)&lt;br /&gt;
* numeric(x,z) to numeric(y,z) when y&amp;gt;=x, or to numeric without specifier&lt;br /&gt;
* varbit(x) to varbit(y) when y&amp;gt;=x, or to varbit without specifier&lt;br /&gt;
* timestamp(x) to timestamp(y) when y&amp;gt;=x or timestamp without specifier&lt;br /&gt;
* timestamptz(x) to timestamptz(y) when y&amp;gt;=x or timestamptz without specifier&lt;br /&gt;
* interval(x) to interval(y) when y&amp;gt;=x or interval without specifier&lt;br /&gt;
&lt;br /&gt;
== Security barriers and Leakproof ==&lt;br /&gt;
&lt;br /&gt;
This new feature has to do with views security. First, let&#039;s explain the problem, with a very simplified example:&lt;br /&gt;
&lt;br /&gt;
  =# CREATE TABLE all_data (company_id int, company_data varchar);&lt;br /&gt;
  CREATE TABLE&lt;br /&gt;
  =# INSERT INTO all_data VALUES (1,&#039;secret_data_for_company_1&#039;);&lt;br /&gt;
  INSERT 0 1&lt;br /&gt;
  =# INSERT INTO all_data VALUES (2,&#039;secret_data_for_company_2&#039;);&lt;br /&gt;
  INSERT 0 1&lt;br /&gt;
  =# CREATE VIEW company1_data AS SELECT * FROM all_data WHERE company_id = 1;&lt;br /&gt;
  CREATE VIEW&lt;br /&gt;
&lt;br /&gt;
This is a quite classical way of giving access to only a part of a table to a user: we&#039;ll create a user for company_id 1, grant to him the right to access company1_data, and deny him the right to access all_data.&lt;br /&gt;
&lt;br /&gt;
The plan to this query is the following:&lt;br /&gt;
&lt;br /&gt;
  =# explain SELECT * FROM company1_data ;&lt;br /&gt;
                          QUERY PLAN                        &lt;br /&gt;
  ----------------------------------------------------------&lt;br /&gt;
   Seq Scan on all_data  (cost=0.00..25.38 rows=6 width=36)&lt;br /&gt;
     Filter: (company_id = 1)&lt;br /&gt;
&lt;br /&gt;
Even if there was more data, a sequential scan could still be forced: just &amp;quot;SET enable_indexscan to OFF&amp;quot; and the likes.&lt;br /&gt;
&lt;br /&gt;
So this query reads all the records from all_data, filters them, and returns to the user only the matching rows. There is a way to display scanned records before they are filtered: just create a function with a very low cost, and call it while doing the query:&lt;br /&gt;
&lt;br /&gt;
  CREATE OR REPLACE FUNCTION peek(text) RETURNS boolean LANGUAGE plpgsql AS&lt;br /&gt;
  $$&lt;br /&gt;
  BEGIN&lt;br /&gt;
    RAISE NOTICE &#039;%&#039;,$1;&lt;br /&gt;
    RETURN true;&lt;br /&gt;
  END&lt;br /&gt;
  $$&lt;br /&gt;
  COST 0.1;&lt;br /&gt;
&lt;br /&gt;
This function just has to cost less than the = operator, which costs 1, to be executed first.&lt;br /&gt;
&lt;br /&gt;
The result is this:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  =# SELECT * FROM company1_data WHERE peek(company1_data.company_data);&lt;br /&gt;
  NOTICE:  secret_data_for_company_1&lt;br /&gt;
  NOTICE:  secret_data_for_company_2&lt;br /&gt;
   company_id |       company_data        &lt;br /&gt;
  ------------+---------------------------&lt;br /&gt;
            1 | secret_data_for_company_1&lt;br /&gt;
  (1 row)&lt;br /&gt;
&lt;br /&gt;
We got access to the record from the second company (in the NOTICE messages).&lt;br /&gt;
&lt;br /&gt;
So this is the first new feature: the view can be declared as implementing &amp;quot;security barriers&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  =# CREATE VIEW company1_data WITH (security_barrier) AS SELECT * FROM all_data WHERE company_id = 1;&lt;br /&gt;
  CREATE VIEW&lt;br /&gt;
  =# SELECT * FROM company1_data WHERE peek(company1_data.company_data);&lt;br /&gt;
  NOTICE:  secret_data_for_company_1&lt;br /&gt;
   company_id |       company_data        &lt;br /&gt;
  ------------+---------------------------&lt;br /&gt;
            1 | secret_data_for_company_1&lt;br /&gt;
  (1 row)&lt;br /&gt;
&lt;br /&gt;
The view is not leaking anymore. The problem, of course, is that there is a performance impact: maybe the &amp;quot;peek&amp;quot; function could have made the query faster, by filtering lots of rows early in the plan. The rows are now filtered in two separate plan steps:&lt;br /&gt;
&lt;br /&gt;
  =# explain SELECT * FROM company1_data WHERE peek(company1_data.company_data);&lt;br /&gt;
                               QUERY PLAN                             &lt;br /&gt;
  --------------------------------------------------------------------&lt;br /&gt;
   Subquery Scan on company1_data  (cost=0.00..25.44 rows=2 width=36)&lt;br /&gt;
     Filter: peek((company1_data.company_data)::text)&lt;br /&gt;
     -&amp;gt;  Seq Scan on all_data  (cost=0.00..25.38 rows=6 width=36)&lt;br /&gt;
           Filter: (company_id = 1)&lt;br /&gt;
&lt;br /&gt;
This leads to the complementary feature: some function may be declared as &amp;quot;LEAKPROOF&amp;quot;, meaning that they won&#039;t leak the data they are passed into error or notice messages.&lt;br /&gt;
&lt;br /&gt;
Declaring our peek function as LEAKPROOF is a very bad idea, but let&#039;s do it just to demonstrate how it&#039;s used:&lt;br /&gt;
&lt;br /&gt;
  CREATE OR REPLACE FUNCTION peek(text) RETURNS boolean LEAKPROOF LANGUAGE plpgsql AS&lt;br /&gt;
  $$&lt;br /&gt;
  BEGIN&lt;br /&gt;
    RAISE NOTICE &#039;%&#039;,$1;&lt;br /&gt;
    RETURN true;&lt;br /&gt;
  END&lt;br /&gt;
  $$&lt;br /&gt;
  COST 0.1;&lt;br /&gt;
&lt;br /&gt;
A LEAKPROOF function is executed «normally»:&lt;br /&gt;
&lt;br /&gt;
  =# SELECT * FROM company1_data WHERE peek(company1_data.company_data);&lt;br /&gt;
  NOTICE:  secret_data_for_company_1&lt;br /&gt;
  NOTICE:  secret_data_for_company_2&lt;br /&gt;
   company_id |       company_data        &lt;br /&gt;
  ------------+---------------------------&lt;br /&gt;
            1 | secret_data_for_company_1&lt;br /&gt;
  (1 row)&lt;br /&gt;
&lt;br /&gt;
Of course, in our case, peek isn&#039;t LEAKPROOF and shouldn&#039;t be declared as such. Only superuser have the permission to declare a LEAKPROOF function.&lt;br /&gt;
&lt;br /&gt;
== New options for pg_dump ==&lt;br /&gt;
&lt;br /&gt;
Until now, one could ask pg_dump to dump a table&#039;s data, or a table&#039;s meta-data (DDL statements for creating the table&#039;s structure, indexes, constraints). Some meta-data is better restored before the data (the table&#039;s structure, check constraints), some is better after the data (indexes, unique constraints, foreign keys…), for performance reasons mostly.&lt;br /&gt;
&lt;br /&gt;
So there are now a few more options:&lt;br /&gt;
&lt;br /&gt;
* --section=pre-data: dump what&#039;s needed before restoring the data. Of course, this can be combined with a -t for instance, to specify only one table&lt;br /&gt;
* --section=post-data : dump what&#039;s needed after restoring the data.&lt;br /&gt;
* --section=data: dump the data&lt;br /&gt;
* --exclude-table-data: dump everything, except THIS table&#039;s data. It means pg_dump will still dump other tables&#039; data.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:PostgreSQL 9.2]]&lt;/div&gt;</summary>
		<author><name>Intgr</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=What%27s_new_in_PostgreSQL_9.2&amp;diff=18296</id>
		<title>What&#039;s new in PostgreSQL 9.2</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=What%27s_new_in_PostgreSQL_9.2&amp;diff=18296"/>
		<updated>2012-09-25T12:40:42Z</updated>

		<summary type="html">&lt;p&gt;Intgr: /* Security barriers and Leakproof */ unnecessary&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Languages}}&lt;br /&gt;
&lt;br /&gt;
This document showcases many of the latest developments in PostgreSQL 9.2, compared to the last major release &amp;amp;ndash; PostgreSQL 9.1. There are many improvements in this release, so this wiki page covers many of the more important changes in detail. The full list of changes is itemised in &#039;&#039;Release Notes&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Major new features=&lt;br /&gt;
&lt;br /&gt;
==Index-only scans &amp;lt;!-- Robert Haas, Ibrar Ahmed, Heikki Linnakangas, Tom Lane --&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
In PostgreSQL, indexes have no &amp;quot;visibility&amp;quot; information. It means that when you access a record by its index, PostgreSQL has to visit the real tuple in the table to be sure it is visible to you: the tuple the index points to may simply be an old version of the record you are looking for.&lt;br /&gt;
&lt;br /&gt;
It can be a very big performance problem: the index is mostly ordered, so accessing its records is quite efficient, while the records may be scattered all over the place (that&#039;s a reason why PostgreSQL has a cluster command, but that&#039;s another story). In 9.2, PostgreSQL will use an &amp;quot;Index Only Scan&amp;quot; when possible, and not access the record itself if it doesn&#039;t need to.&lt;br /&gt;
&lt;br /&gt;
There is still no visibility information in the index. So in order to do this, PostgreSQL uses the visibility map ([http://www.postgresql.org/docs/devel/static/storage-vm.html visibility map]) , which tells it whether the whole content of a (usually) 8K page is visible to all transactions or not. When the index record points to a tuple contained in an «all visible» page, PostgreSQL won&#039;t have to access the tuple, it will be able to build it directly from the index. Of course, all the columns requested by the query must be in the index.&lt;br /&gt;
&lt;br /&gt;
The visibility map is maintained by VACUUM (it sets the visible bit), and by the backends doing SQL work (they unset the visible bit).&lt;br /&gt;
&lt;br /&gt;
If the data has been read only since the last VACUUM then the data is All Visible and the index only scan feature can improve performance.&lt;br /&gt;
&lt;br /&gt;
Here is an example.&lt;br /&gt;
&lt;br /&gt;
  CREATE TABLE demo_ios (col1 float, col2 float, col3 text);&lt;br /&gt;
&lt;br /&gt;
In this table, we&#039;ll put random data, in order to have &amp;quot;scattered&amp;quot; data. We&#039;ll put 100 million records, to have a big recordset, and have it not fit in memory (that&#039;s a 4GB-ram machine). This is an ideal case, made for this demo. The gains won&#039;t be that big in real life.&lt;br /&gt;
&lt;br /&gt;
  INSERT INTO demo_ios SELECT generate_series(1,100000000),random(), &#039;mynotsolongstring&#039;;&lt;br /&gt;
  &lt;br /&gt;
  SELECT pg_size_pretty(pg_total_relation_size(&#039;demo_ios&#039;));&lt;br /&gt;
   pg_size_pretty &lt;br /&gt;
  ----------------&lt;br /&gt;
   6512 MB&lt;br /&gt;
&lt;br /&gt;
Let&#039;s pretend that the query is this:&lt;br /&gt;
&lt;br /&gt;
  SELECT col1,col2 FROM demo_ios where col2 BETWEEN 0.01 AND 0.02&lt;br /&gt;
&lt;br /&gt;
In order to use an index only scan on this query, we need an index on col2,col1 (col2 first, as it is used in the WHERE clause).&lt;br /&gt;
&lt;br /&gt;
  CREATE index idx_demo_ios on demo_ios(col2,col1);&lt;br /&gt;
&lt;br /&gt;
We vacuum the table, so that the visibility map to be up-to-date:&lt;br /&gt;
&lt;br /&gt;
  VACUUM demo_ios;&lt;br /&gt;
&lt;br /&gt;
All the timing you&#039;ll see below are done on a cold OS and PostgreSQL cache (that&#039;s where the gains are, as the purpose on Index Only Scans is to reduce I/O).&lt;br /&gt;
&lt;br /&gt;
Let&#039;s first try without Index Only Scans:&lt;br /&gt;
&lt;br /&gt;
  SET enable_indexonlyscan to off;&lt;br /&gt;
  &lt;br /&gt;
  EXPLAIN (analyze,buffers) select col1,col2 FROM demo_ios where col2 between 0.01 and 0.02;&lt;br /&gt;
                                                                 QUERY PLAN                                                               &lt;br /&gt;
  ----------------------------------------------------------------------------------------------------------------------------------------&lt;br /&gt;
   Bitmap Heap Scan on demo_ios  (cost=25643.01..916484.44 rows=993633 width=16) (actual time=763.391..362963.899 rows=1000392 loops=1)&lt;br /&gt;
     Recheck Cond: ((col2 &amp;gt;= 0.01::double precision) AND (col2 &amp;lt;= 0.02::double precision))&lt;br /&gt;
     Rows Removed by Index Recheck: 68098621&lt;br /&gt;
     Buffers: shared hit=2 read=587779&lt;br /&gt;
     -&amp;gt;  Bitmap Index Scan on idx_demo_ios  (cost=0.00..25394.60 rows=993633 width=0) (actual time=759.011..759.011 rows=1000392 loops=1)&lt;br /&gt;
           Index Cond: ((col2 &amp;gt;= 0.01::double precision) AND (col2 &amp;lt;= 0.02::double precision))&lt;br /&gt;
           Buffers: shared hit=2 read=3835&lt;br /&gt;
   Total runtime: 364390.127 ms&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
With Index Only Scans:&lt;br /&gt;
&lt;br /&gt;
  explain (analyze,buffers) select col1,col2 from demo_ios where col2 between 0.01 and 0.02;&lt;br /&gt;
                                                                    QUERY PLAN                                                                   &lt;br /&gt;
  -----------------------------------------------------------------------------------------------------------------------------------------------&lt;br /&gt;
   Index Only Scan using idx_demo_ios on demo_ios  (cost=0.00..35330.93 rows=993633 width=16) (actual time=58.100..3250.589 rows=1000392 loops=1)&lt;br /&gt;
     Index Cond: ((col2 &amp;gt;= 0.01::double precision) AND (col2 &amp;lt;= 0.02::double precision))&lt;br /&gt;
     Heap Fetches: 0&lt;br /&gt;
     Buffers: shared hit=923073 read=3848&lt;br /&gt;
   Total runtime: 4297.405 ms&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
As nothing is free, there are a few things to keep in mind:&lt;br /&gt;
&lt;br /&gt;
* Adding indexes for index only scans obviously adds indexes to your table. So updates will be slower.&lt;br /&gt;
* You will index columns that weren&#039;t indexed before. So there will be less opportunities for HOT updates.&lt;br /&gt;
* Gains will probably be smaller in real life situations, especially when data is changed between VACUUMs&lt;br /&gt;
&lt;br /&gt;
This required making visibility map changes crash-safe, so visibility map bit changes are now WAL-logged.&lt;br /&gt;
&lt;br /&gt;
==Replication improvements &amp;lt;!-- Fujii Masao, Simon Riggs, Magnus Hagander, Jun Ishizuka --&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
Streaming Replication becomes more polished with this release. &lt;br /&gt;
&lt;br /&gt;
One of the main remaining gripes about streaming replication is that all the slaves have to be connected to the same and unique master, consuming its resources. Moreover, in case of a failover, it could be complicated to reconnect all the remaining slaves to the newly promoted master, if one is not using a tool like repmgr. &lt;br /&gt;
&lt;br /&gt;
With 9.2, a  standby can also send replication changes, allowing cascading replication.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s build this. We start with an already working 9.2 database.&lt;br /&gt;
&lt;br /&gt;
We set it up for replication:&lt;br /&gt;
&lt;br /&gt;
postgresql.conf:&lt;br /&gt;
  wal_level=hot_standby #(could be archive too)&lt;br /&gt;
  max_wal_senders=5&lt;br /&gt;
  hot_standby=on&lt;br /&gt;
&lt;br /&gt;
You&#039;ll probably also want to activate archiving in production, it won&#039;t be done here.&lt;br /&gt;
&lt;br /&gt;
pg_hba.conf (do not use trust in production):&lt;br /&gt;
  host   replication replication_user          0.0.0.0/0                      md5&lt;br /&gt;
 &lt;br /&gt;
Create the user:&lt;br /&gt;
  create user replication_user replication password &#039;secret&#039;;&lt;br /&gt;
&lt;br /&gt;
Clone the cluster:&lt;br /&gt;
&lt;br /&gt;
  pg_basebackup -h localhost -U replication_user -D data2&lt;br /&gt;
  Password:&lt;br /&gt;
&lt;br /&gt;
We have a brand new cluster in the data2 directory. We&#039;ll change the port so that it can start (postgresql.conf), as both clusters are running on the same machine:&lt;br /&gt;
  port=5433&lt;br /&gt;
&lt;br /&gt;
We add a recovery.conf to tell it how to stream from the master database:&lt;br /&gt;
  standby_mode = on&lt;br /&gt;
  primary_conninfo = &#039;host=localhost port=5432 user=replication_user password=secret&#039; &lt;br /&gt;
&lt;br /&gt;
  pg_ctl -D data2 start&lt;br /&gt;
  server starting&lt;br /&gt;
  LOG:  database system was interrupted; last known up at 2012-07-03 17:58:09 CEST&lt;br /&gt;
  LOG:  creating missing WAL directory &amp;quot;pg_xlog/archive_status&amp;quot;&lt;br /&gt;
  LOG:  entering standby mode&lt;br /&gt;
  LOG:  streaming replication successfully connected to primary&lt;br /&gt;
  LOG:  redo starts at 0/9D000020&lt;br /&gt;
  LOG:  consistent recovery state reached at 0/9D0000B8&lt;br /&gt;
  LOG:  database system is ready to accept read only connections&lt;br /&gt;
&lt;br /&gt;
Now, let&#039;s add a second slave, which will use this slave:&lt;br /&gt;
&lt;br /&gt;
  pg_basebackup -h localhost -U replication_user -D data3 -p 5433&lt;br /&gt;
  Password: &lt;br /&gt;
&lt;br /&gt;
We edit data3&#039;s postgresql.conf to change the port:&lt;br /&gt;
  port=5434&lt;br /&gt;
&lt;br /&gt;
We modify the recovery.conf to stream from the slave:&lt;br /&gt;
  standby_mode = on&lt;br /&gt;
  primary_conninfo = &#039;host=localhost port=5433 user=replication_user password=secret&#039;             # e.g. &#039;host=localhost port=5432&#039;&lt;br /&gt;
&lt;br /&gt;
We start the third cluster:&lt;br /&gt;
  pg_ctl -D data3 start&lt;br /&gt;
  server starting&lt;br /&gt;
  LOG:  database system was interrupted while in recovery at log time 2012-07-03 17:58:09 CEST&lt;br /&gt;
  HINT:  If this has occurred more than once some data might be corrupted and you might need to choose an earlier recovery target.&lt;br /&gt;
  LOG:  creating missing WAL directory &amp;quot;pg_xlog/archive_status&amp;quot;&lt;br /&gt;
  LOG:  entering standby mode&lt;br /&gt;
  LOG:  streaming replication successfully connected to primary&lt;br /&gt;
  LOG:  redo starts at 0/9D000020&lt;br /&gt;
  LOG:  consistent recovery state reached at 0/9E000000&lt;br /&gt;
  LOG:  database system is ready to accept read only connections&lt;br /&gt;
&lt;br /&gt;
Now, everything modified on the master cluster get streamed to the first slave, and from there to the second slave. This second replication has to be monitored from the first slave (the master knows nothing about it).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
As you may have noticed from the example, pg_basebackup now works from slaves.&lt;br /&gt;
&lt;br /&gt;
There is another use case that wasn&#039;t covered: what if a user didn&#039;t care for having a full fledged slave, and only wanted to stream the WAL files to another location, to benefit from the reduced data loss without the burden of maintaining a slave ?&lt;br /&gt;
&lt;br /&gt;
pg_receivexlog is provided just for this purpose: it pretends to be a PostgreSQL slave, but only stores the log files as they are streamed, in a directory:&lt;br /&gt;
  pg_receivexlog -D /tmp/new_logs -h localhost -U replication_user&lt;br /&gt;
&lt;br /&gt;
will connect to the master (or a slave), and start creating files: &lt;br /&gt;
  ls /tmp/new_logs/&lt;br /&gt;
  00000001000000000000009E.partial&lt;br /&gt;
&lt;br /&gt;
Files are of the segment size, so they can be used for a normal recovery of the database. It&#039;s the same as an archive command, but with a much smaller granularity.&lt;br /&gt;
&lt;br /&gt;
Remember to rename the last segment to remove the .partial suffix before using it with a PITR restore or any other operation.&lt;br /&gt;
&lt;br /&gt;
The synchronous_commit parameter has a new value: remote_write. It can be used when there is a synchronous slave (synchronous_standby_names is set), meaning that the master doesn&#039;t have to wait for the slave to have written the data to disk, only for the slave to have acknowledged the data. With this set, data is protected from a crash on the master, but could still be lost if the slave crashed at the same time (i.e. before having written the in flight data to disk). As this is a quite remote possibility, and the performance improvement will be large, some people will be interested in this compromise.&lt;br /&gt;
&lt;br /&gt;
==JSON datatype==&lt;br /&gt;
&lt;br /&gt;
The JSON datatype is meant for storing JSON-structured data. It will validate that the input JSON string is correct JSON:&lt;br /&gt;
&lt;br /&gt;
  =# SELECT &#039;{&amp;quot;username&amp;quot;:&amp;quot;john&amp;quot;,&amp;quot;posts&amp;quot;:121,&amp;quot;emailaddress&amp;quot;:&amp;quot;john@nowhere.com&amp;quot;}&#039;::json;&lt;br /&gt;
                                 json                                &lt;br /&gt;
  -------------------------------------------------------------------&lt;br /&gt;
   {&amp;quot;username&amp;quot;:&amp;quot;john&amp;quot;,&amp;quot;posts&amp;quot;:121,&amp;quot;emailaddress&amp;quot;:&amp;quot;john@nowhere.com&amp;quot;}&lt;br /&gt;
  (1 row)&lt;br /&gt;
  &lt;br /&gt;
  =# SELECT &#039;{&amp;quot;username&amp;quot;,&amp;quot;posts&amp;quot;:121,&amp;quot;emailaddress&amp;quot;:&amp;quot;john@nowhere.com&amp;quot;}&#039;::json;&lt;br /&gt;
  ERROR:  invalid input syntax for type json at character 8&lt;br /&gt;
  DETAIL:  Expected &amp;quot;:&amp;quot;, but found &amp;quot;,&amp;quot;.&lt;br /&gt;
  CONTEXT:  JSON data, line 1: {&amp;quot;username&amp;quot;,...&lt;br /&gt;
  STATEMENT:  SELECT &#039;{&amp;quot;username&amp;quot;,&amp;quot;posts&amp;quot;:121,&amp;quot;emailaddress&amp;quot;:&amp;quot;john@nowhere.com&amp;quot;}&#039;::json;&lt;br /&gt;
  ERROR:  invalid input syntax for type json&lt;br /&gt;
  LINE 1: SELECT &#039;{&amp;quot;username&amp;quot;,&amp;quot;posts&amp;quot;:121,&amp;quot;emailaddress&amp;quot;:&amp;quot;john@nowhere...&lt;br /&gt;
                 ^&lt;br /&gt;
  DETAIL:  Expected &amp;quot;:&amp;quot;, but found &amp;quot;,&amp;quot;.&lt;br /&gt;
  CONTEXT:  JSON data, line 1: {&amp;quot;username&amp;quot;,...&lt;br /&gt;
&lt;br /&gt;
You can also convert a row type to JSON:&lt;br /&gt;
&lt;br /&gt;
  =#SELECT * FROM demo ;&lt;br /&gt;
   username | posts |    emailaddress     &lt;br /&gt;
  ----------+-------+---------------------&lt;br /&gt;
   john     |   121 | john@nowhere.com&lt;br /&gt;
   mickael  |   215 | mickael@nowhere.com&lt;br /&gt;
  (2 rows)&lt;br /&gt;
  &lt;br /&gt;
  =# SELECT row_to_json(demo) FROM demo;&lt;br /&gt;
                                 row_to_json                               &lt;br /&gt;
  -------------------------------------------------------------------------&lt;br /&gt;
   {&amp;quot;username&amp;quot;:&amp;quot;john&amp;quot;,&amp;quot;posts&amp;quot;:121,&amp;quot;emailaddress&amp;quot;:&amp;quot;john@nowhere.com&amp;quot;}&lt;br /&gt;
   {&amp;quot;username&amp;quot;:&amp;quot;mickael&amp;quot;,&amp;quot;posts&amp;quot;:215,&amp;quot;emailaddress&amp;quot;:&amp;quot;mickael@nowhere.com&amp;quot;}&lt;br /&gt;
  (2 rows)&lt;br /&gt;
&lt;br /&gt;
Or an array type:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  =# select array_to_json(array_agg(demo)) from demo;&lt;br /&gt;
                                                                  array_to_json                                                                &lt;br /&gt;
  ---------------------------------------------------------------------------------------------------------------------------------------------&lt;br /&gt;
   [{&amp;quot;username&amp;quot;:&amp;quot;john&amp;quot;,&amp;quot;posts&amp;quot;:121,&amp;quot;emailaddress&amp;quot;:&amp;quot;john@nowhere.com&amp;quot;},{&amp;quot;username&amp;quot;:&amp;quot;mickael&amp;quot;,&amp;quot;posts&amp;quot;:215,&amp;quot;emailaddress&amp;quot;:&amp;quot;mickael@nowhere.com&amp;quot;}]&lt;br /&gt;
  (1 row)&lt;br /&gt;
&lt;br /&gt;
== Range Types ==&lt;br /&gt;
&lt;br /&gt;
Range types are used to store a range of data of a given type. There are a few pre-defined types. They are integer (int4range), bigint (int8range), numeric (numrange), timestamp without timezone (tsrange), timestamp with timezone (tstzrange), and date (daterange).&lt;br /&gt;
&lt;br /&gt;
Ranges can be made of continuous (numeric, timestamp...) or discrete (integer, date...) data types. They can be open (the bound isn&#039;t part of the range) or closed (the bound is part of the range). A bound can also be infinite.&lt;br /&gt;
&lt;br /&gt;
Without these datatypes, most people solve the range problems by using two columns in a table. These range types are much more powerful, as you can use many operators on them.&lt;br /&gt;
&lt;br /&gt;
Here is the intersection between then 1000(open)-2000(closed) and 1000(closed)-1200(closed) numeric range:&lt;br /&gt;
&lt;br /&gt;
  SELECT &#039;(1000,2000]&#039;::numrange * &#039;[1000,1200]&#039;::numrange;&lt;br /&gt;
    ?column?   &lt;br /&gt;
  -------------&lt;br /&gt;
   (1000,1200]&lt;br /&gt;
  (1 row)&lt;br /&gt;
&lt;br /&gt;
So you can query on things like: «give me all ranges that intersect this»:&lt;br /&gt;
&lt;br /&gt;
  =# SELECT * from test_range ;&lt;br /&gt;
                         period                        &lt;br /&gt;
  -----------------------------------------------------&lt;br /&gt;
   [&amp;quot;2012-01-01 00:00:00+01&amp;quot;,&amp;quot;2012-01-02 12:00:00+01&amp;quot;]&lt;br /&gt;
   [&amp;quot;2012-01-01 00:00:00+01&amp;quot;,&amp;quot;2012-03-01 00:00:00+01&amp;quot;]&lt;br /&gt;
   [&amp;quot;2008-01-01 00:00:00+01&amp;quot;,&amp;quot;2015-01-01 00:00:00+01&amp;quot;]&lt;br /&gt;
  (3 rows)&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  =# SELECT * FROM test_range WHERE period &amp;amp;&amp;amp; &#039;[2012-01-03 00:00:00,2012-01-03 12:00:00]&#039;; &lt;br /&gt;
                         period                        &lt;br /&gt;
  -----------------------------------------------------&lt;br /&gt;
   [&amp;quot;2012-01-01 00:00:00+01&amp;quot;,&amp;quot;2012-03-01 00:00:00+01&amp;quot;]&lt;br /&gt;
   [&amp;quot;2008-01-01 00:00:00+01&amp;quot;,&amp;quot;2015-01-01 00:00:00+01&amp;quot;]&lt;br /&gt;
  (2 rows)&lt;br /&gt;
&lt;br /&gt;
This query could use an index defined like this:&lt;br /&gt;
&lt;br /&gt;
  =# CREATE INDEX idx_test_range on test_range USING gist (period);&lt;br /&gt;
&lt;br /&gt;
You can also use these range data types to define exclusion constraints:&lt;br /&gt;
&lt;br /&gt;
  CREATE EXTENSION btree_gist ;&lt;br /&gt;
  CREATE TABLE reservation (room_id int, period tstzrange);&lt;br /&gt;
  ALTER TABLE reservation ADD  EXCLUDE USING GIST (room_id WITH =, period WITH &amp;amp;&amp;amp;);&lt;br /&gt;
&lt;br /&gt;
This means that now it is forbidden to have two records in this table where room_id is equal and period overlaps. The extension btree_gist is required to create a GiST index on room_id (it&#039;s an integer, it is usually indexed with a btree index).&lt;br /&gt;
&lt;br /&gt;
  =# INSERT INTO reservation VALUES (1,&#039;(2012-08-23 14:00:00,2012-08-23 15:00:00)&#039;);&lt;br /&gt;
  INSERT 0 1&lt;br /&gt;
  =# INSERT INTO reservation VALUES (2,&#039;(2012-08-23 14:00:00,2012-08-23 15:00:00)&#039;);&lt;br /&gt;
  INSERT 0 1&lt;br /&gt;
  =# INSERT INTO reservation VALUES (1,&#039;(2012-08-23 14:45:00,2012-08-23 15:15:00)&#039;);&lt;br /&gt;
  ERROR:  conflicting key value violates exclusion constraint &amp;quot;reservation_room_id_period_excl&amp;quot;&lt;br /&gt;
  DETAIL:  Key (room_id, period)=(1, (&amp;quot;2012-08-23 14:45:00+02&amp;quot;,&amp;quot;2012-08-23 15:15:00+02&amp;quot;)) &lt;br /&gt;
  conflicts with existing key (room_id, period)=(1, (&amp;quot;2012-08-23 14:00:00+02&amp;quot;,&amp;quot;2012-08-23 15:00:00+02&amp;quot;)).&lt;br /&gt;
  STATEMENT:  INSERT INTO reservation VALUES (1,&#039;(2012-08-23 14:45:00,2012-08-23 15:15:00)&#039;);&lt;br /&gt;
&lt;br /&gt;
One can also declare new range types.&lt;br /&gt;
&lt;br /&gt;
=Performance improvements=&lt;br /&gt;
&lt;br /&gt;
This version has performance improvements on a very large range of domains (non-exaustive):&lt;br /&gt;
&lt;br /&gt;
* The most visible will probably be the Index Only Scans, which has already been introduced in this document.&lt;br /&gt;
&lt;br /&gt;
* The lock contention of several big locks has been significantly reduced, leading to better multi-processor scalability, for machines with over 32 cores mostly. &amp;lt;!-- Robert Haas --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* The performance of in-memory sorts has been improved by up to 25% in some situations, with certain specialized sort functions introduced. &amp;lt;!-- Peter Geoghegan --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* An idle PostgreSQL server now makes less wakeups, leading to lower power consumption&amp;lt;!--Peter Geoghegan--&amp;gt;. This is especially useful on virtualized and embedded environments.&lt;br /&gt;
&lt;br /&gt;
* COPY has been improved, it will generate less WAL volume and fewer locks of a table&#039;s pages. &amp;lt;!-- Heikki Linnakangas --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Statistics are collected on array contents&amp;lt;!-- Alexander Korotkov --&amp;gt;, allowing for better estimations of selectivity on array operations.&lt;br /&gt;
&lt;br /&gt;
* Text-to-anytype concatenation and quote_literal/quote_nullable functions are not volatile any more, enabling better optimization in some cases &amp;lt;!-- Marti Raudsepp --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* The system can now track IO durations &amp;lt;!--Ants Aasma --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This one deserves a little explanation, as it can be a little tricky. Tracking IO durations means asking repeatedly the time to the operating system. Depending on the operating system and the hardware, this can be quite cheap, or extremely costly. The most import factor here is where the system gets its time from. It could be directly retrieved from the processor (TSC), dedicated hardware such as HPET, or an ACPI call. What&#039;s most important is that the cost of getting time can vary from a factor of thousands.&lt;br /&gt;
&lt;br /&gt;
If you are interested in this timing data, it&#039;s better to first check if your system will support it without too much of a performance hit. PostgreSQL provides you with the pg_test_timing tool:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ pg_test_timing &lt;br /&gt;
Testing timing overhead for 3 seconds.&lt;br /&gt;
Per loop time including overhead: 28.02 nsec&lt;br /&gt;
Histogram of timing durations:&lt;br /&gt;
   &amp;lt; usec:      count   percent&lt;br /&gt;
       32:         41  0.00004%&lt;br /&gt;
       16:       1405  0.00131%&lt;br /&gt;
        8:        200  0.00019%&lt;br /&gt;
        4:        388  0.00036%&lt;br /&gt;
        2:    2982558  2.78523%&lt;br /&gt;
        1:  104100166 97.21287%&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here, everything is good: getting time costs around 28 nanoseconds, and has a very small variation. Anything under 100 nanoseconds should be good for production. If you get higher values, you may still find a way to tune your system. You&#039;d better check on the [http://www.postgresql.org/docs/9.2/static/pgtesttiming.html documentation].&lt;br /&gt;
&lt;br /&gt;
Anyway, here is the data you&#039;ll be able to collect if your system is ready for this:&lt;br /&gt;
&lt;br /&gt;
First, you&#039;ll get per-database statistics, which will now give accurate informations about which database is doing most I/O:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
=# SELECT * FROM pg_stat_database WHERE datname = &#039;mydb&#039;;&lt;br /&gt;
-[ RECORD 1 ]--+------------------------------&lt;br /&gt;
datid          | 16384&lt;br /&gt;
datname        | mydb&lt;br /&gt;
numbackends    | 1&lt;br /&gt;
xact_commit    | 270&lt;br /&gt;
xact_rollback  | 2&lt;br /&gt;
blks_read      | 1961&lt;br /&gt;
blks_hit       | 17944&lt;br /&gt;
tup_returned   | 269035&lt;br /&gt;
tup_fetched    | 8850&lt;br /&gt;
tup_inserted   | 16&lt;br /&gt;
tup_updated    | 4&lt;br /&gt;
tup_deleted    | 45&lt;br /&gt;
conflicts      | 0&lt;br /&gt;
temp_files     | 0&lt;br /&gt;
temp_bytes     | 0&lt;br /&gt;
deadlocks      | 0&lt;br /&gt;
blk_read_time  | 583.774&lt;br /&gt;
blk_write_time | 0&lt;br /&gt;
stats_reset    | 2012-07-03 17:18:54.796817+02&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
We see here that mydb has only consumed 583.774 milliseconds of read time.&lt;br /&gt;
&lt;br /&gt;
Explain will benefit from this too:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
=# EXPLAIN (analyze,buffers) SELECT count(*) FROM mots ;&lt;br /&gt;
                                                   QUERY PLAN&lt;br /&gt;
----------------------------------------------------------------------------------------------------------------&lt;br /&gt;
 Aggregate  (cost=1669.95..1669.96 rows=1 width=0) (actual time=21.943..21.943 rows=1 loops=1)&lt;br /&gt;
   Buffers: shared read=493&lt;br /&gt;
   I/O Timings: read=2.578&lt;br /&gt;
   -&amp;gt;  Seq Scan on mots  (cost=0.00..1434.56 rows=94156 width=0) (actual time=0.059..12.933 rows=94156 loops=1)&lt;br /&gt;
         Buffers: shared read=493&lt;br /&gt;
         I/O Timings: read=2.578&lt;br /&gt;
 Total runtime: 22.059 ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
We now have a separate information about the time taken to retrieve data from the operating system. Obviously, here, the data was in the operating system&#039;s cache (2 milliseconds to read 493 blocks).&lt;br /&gt;
&lt;br /&gt;
And last, if you have enabled pg_stat_statements:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
select * from pg_stat_statements where query ~ &#039;words&#039;;&lt;br /&gt;
-[ RECORD 1 ]-------+---------------------------&lt;br /&gt;
userid              | 10&lt;br /&gt;
dbid                | 16384&lt;br /&gt;
query               | select count(*) from words;&lt;br /&gt;
calls               | 2&lt;br /&gt;
total_time          | 78.332&lt;br /&gt;
rows                | 2&lt;br /&gt;
shared_blks_hit     | 0&lt;br /&gt;
shared_blks_read    | 986&lt;br /&gt;
shared_blks_dirtied | 0&lt;br /&gt;
shared_blks_written | 0&lt;br /&gt;
local_blks_hit      | 0&lt;br /&gt;
local_blks_read     | 0&lt;br /&gt;
local_blks_dirtied  | 0&lt;br /&gt;
local_blks_written  | 0&lt;br /&gt;
temp_blks_read      | 0&lt;br /&gt;
temp_blks_written   | 0&lt;br /&gt;
blk_read_time       | 58.427&lt;br /&gt;
blk_write_time      | 0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* As for every version, the optimizer has received its share of improvements &amp;lt;!-- Tom Lane--&amp;gt;&lt;br /&gt;
** Prepared statements used to be optimized once, without any knowledge of the parameters&#039; values. With 9.2, the planner will use specific plans regarding to the parameters sent (the query will be planned at execution), except if the query is executed several times and the planner decides that the generic plan is not too much more expensive than the specific plans.&lt;br /&gt;
** A new feature has been added: parameterized paths. Simply put, it means that a sub-part of a query plan can use parameters it has got from a parent node. It fixes several bad plans that could occur, especially when the optimizer couldn&#039;t reorder joins to put nested loops where it would have been efficient.&lt;br /&gt;
&lt;br /&gt;
This example is straight from the developpers mailing lists &amp;lt;!-- Andres Freund --&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE a (&lt;br /&gt;
    a_id serial PRIMARY KEY NOT NULL,&lt;br /&gt;
    b_id integer&lt;br /&gt;
);&lt;br /&gt;
CREATE INDEX a__b_id ON a USING btree (b_id);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
CREATE TABLE b (&lt;br /&gt;
    b_id serial NOT NULL,&lt;br /&gt;
    c_id integer&lt;br /&gt;
);&lt;br /&gt;
CREATE INDEX b__c_id ON b USING btree (c_id);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
CREATE TABLE c (&lt;br /&gt;
    c_id serial PRIMARY KEY NOT NULL,&lt;br /&gt;
    value integer UNIQUE&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
INSERT INTO b (b_id, c_id)&lt;br /&gt;
    SELECT g.i, g.i FROM generate_series(1, 50000) g(i);&lt;br /&gt;
&lt;br /&gt;
INSERT INTO a(b_id)&lt;br /&gt;
    SELECT g.i FROM generate_series(1, 50000) g(i);&lt;br /&gt;
&lt;br /&gt;
INSERT INTO c(c_id,value)&lt;br /&gt;
    VALUES (1,1);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So we have a referencing b, b referencing c.&lt;br /&gt;
&lt;br /&gt;
Here is an example of a query working badly with PostgreSQL 9.1:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
EXPLAIN ANALYZE SELECT 1&lt;br /&gt;
FROM&lt;br /&gt;
    c&lt;br /&gt;
WHERE&lt;br /&gt;
    EXISTS (&lt;br /&gt;
        SELECT *&lt;br /&gt;
        FROM a&lt;br /&gt;
            JOIN b USING (b_id)&lt;br /&gt;
        WHERE b.c_id = c.c_id)&lt;br /&gt;
    AND c.value = 1;&lt;br /&gt;
                                                      QUERY PLAN&lt;br /&gt;
-----------------------------------------------------------------------------------------------------------------------&lt;br /&gt;
 Nested Loop Semi Join  (cost=1347.00..3702.27 rows=1 width=0) (actual time=13.799..13.802 rows=1 loops=1)&lt;br /&gt;
   Join Filter: (c.c_id = b.c_id)&lt;br /&gt;
   -&amp;gt;  Index Scan using c_value_key on c  (cost=0.00..8.27 rows=1 width=4) (actual time=0.006..0.008 rows=1 loops=1)&lt;br /&gt;
         Index Cond: (value = 1)&lt;br /&gt;
   -&amp;gt;  Hash Join  (cost=1347.00..3069.00 rows=50000 width=4) (actual time=13.788..13.788 rows=1 loops=1)&lt;br /&gt;
         Hash Cond: (a.b_id = b.b_id)&lt;br /&gt;
         -&amp;gt;  Seq Scan on a  (cost=0.00..722.00 rows=50000 width=4) (actual time=0.007..0.007 rows=1 loops=1)&lt;br /&gt;
         -&amp;gt;  Hash  (cost=722.00..722.00 rows=50000 width=8) (actual time=13.760..13.760 rows=50000 loops=1)&lt;br /&gt;
               Buckets: 8192  Batches: 1  Memory Usage: 1954kB&lt;br /&gt;
               -&amp;gt;  Seq Scan on b  (cost=0.00..722.00 rows=50000 width=8) (actual time=0.008..5.702 rows=50000 loops=1)&lt;br /&gt;
 Total runtime: 13.842 ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Not that bad, 13 milliseconds. Still, we are doing sequential scans on a and b, when our common sense tells us that c.value=1 should be used to filter rows more aggressively.&lt;br /&gt;
&lt;br /&gt;
Here&#039;s what 9.2 does with this query:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                                                      QUERY PLAN&lt;br /&gt;
----------------------------------------------------------------------------------------------------------------------------&lt;br /&gt;
 Nested Loop Semi Join  (cost=0.00..16.97 rows=1 width=0) (actual time=0.035..0.037 rows=1 loops=1)&lt;br /&gt;
   -&amp;gt;  Index Scan using c_value_key on c  (cost=0.00..8.27 rows=1 width=4) (actual time=0.007..0.009 rows=1 loops=1)&lt;br /&gt;
         Index Cond: (value = 1)&lt;br /&gt;
   -&amp;gt;  Nested Loop  (cost=0.00..8.69 rows=1 width=4) (actual time=0.025..0.025 rows=1 loops=1)&lt;br /&gt;
         -&amp;gt;  Index Scan using b__c_id on b  (cost=0.00..8.33 rows=1 width=8) (actual time=0.007..0.007 rows=1 loops=1)&lt;br /&gt;
               Index Cond: (c_id = c.c_id)&lt;br /&gt;
         -&amp;gt;  Index Only Scan using a__b_id on a  (cost=0.00..0.35 rows=1 width=4) (actual time=0.014..0.014 rows=1 loops=1)&lt;br /&gt;
               Index Cond: (b_id = b.b_id)&lt;br /&gt;
 Total runtime: 0.089 ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The «parameterized path» is:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   -&amp;gt;  Nested Loop  (cost=0.00..8.69 rows=1 width=4) (actual time=0.025..0.025 rows=1 loops=1)&lt;br /&gt;
         -&amp;gt;  Index Scan using b__c_id on b  (cost=0.00..8.33 rows=1 width=8) (actual time=0.007..0.007 rows=1 loops=1)&lt;br /&gt;
               Index Cond: (c_id = c.c_id)&lt;br /&gt;
         -&amp;gt;  Index Only Scan using a__b_id on a  (cost=0.00..0.35 rows=1 width=4) (actual time=0.014..0.014 rows=1 loops=1)&lt;br /&gt;
               Index Cond: (b_id = b.b_id)&lt;br /&gt;
 Total runtime: 0.089 ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This part of the plan depends on a parent node (c_id=c.c_id). This part of the plan is called each time with a different parameter coming from the parent node.&lt;br /&gt;
&lt;br /&gt;
This plan is of course much faster, as there is no need to fully scan a, and to fully scan AND hash b.&lt;br /&gt;
&lt;br /&gt;
=SP-GiST=&lt;br /&gt;
&lt;br /&gt;
SP-GiST stands for Space Partitionned GiST, GiST being Generalized Search Tree. GiST is an index type, and has been available for quite a while in PostgreSQL. GiST is already very efficient at indexing complex data types, but performance tends to suffer when the source data isn&#039;t uniformly distributed. SP-GiST tries to fix that.&lt;br /&gt;
&lt;br /&gt;
As all indexing methods available in PostgreSQL, SP-GiST is a generic indexing method, meaning its purpose is to index whatever you&#039;ll throw at it, using operators you&#039;ll provide. It means that if you want to create a new datatype, and make it indexable through SP-GiST, you&#039;ll have to follow the documented API.&lt;br /&gt;
&lt;br /&gt;
SP-GiST can be used to implement 3 type of indexes: trie (suffix) indexing, Quadtree (data is divided into quadrants), and k-d tree (k-dimensional tree).&lt;br /&gt;
&lt;br /&gt;
For now, SP-GiST is provided with operator families called &amp;quot;quad_point_ops&amp;quot;, &amp;quot;kd_point_ops&amp;quot; and &amp;quot;text_ops&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
As their names indicate, the first one indexes point types, using a quadtree, the second one indexes point types using a k-d tree, and the third one indexes text, using suffix.&lt;br /&gt;
&lt;br /&gt;
=pg_stat_statements=&lt;br /&gt;
&lt;br /&gt;
This contrib module has received a lot of improvements in this version:&lt;br /&gt;
&lt;br /&gt;
* Queries are normalized: queries that are identical except for their constant values will be considered the same, as long as their post-parse analysis query tree (that is, the internal representation of the query before rule expansion) are the same. This also implies that differences that are not semantically essential to the query, such as variations in whitespace or alias names, or the use of one particular syntax over another equivalent one will not differentiate queries.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
=#SELECT * FROM words WHERE word= &#039;foo&#039;;&lt;br /&gt;
 word &lt;br /&gt;
------&lt;br /&gt;
(0 ligne)&lt;br /&gt;
&lt;br /&gt;
=# SELECT * FROM words WHERE word= &#039;bar&#039;;&lt;br /&gt;
 word &lt;br /&gt;
------&lt;br /&gt;
 bar&lt;br /&gt;
&lt;br /&gt;
=#select * from pg_stat_statements where query like &#039;%words where%&#039;;&lt;br /&gt;
-[ RECORD 1 ]-------+-----------------------------------&lt;br /&gt;
userid              | 10&lt;br /&gt;
dbid                | 16384&lt;br /&gt;
query               | SELECT * FROM words WHERE word= ?;&lt;br /&gt;
calls               | 2&lt;br /&gt;
total_time          | 142.314&lt;br /&gt;
rows                | 1&lt;br /&gt;
shared_blks_hit     | 3&lt;br /&gt;
shared_blks_read    | 5&lt;br /&gt;
shared_blks_dirtied | 0&lt;br /&gt;
shared_blks_written | 0&lt;br /&gt;
local_blks_hit      | 0&lt;br /&gt;
local_blks_read     | 0&lt;br /&gt;
local_blks_dirtied  | 0&lt;br /&gt;
local_blks_written  | 0&lt;br /&gt;
temp_blks_read      | 0&lt;br /&gt;
temp_blks_written   | 0&lt;br /&gt;
blk_read_time       | 142.165&lt;br /&gt;
blk_write_time      | 0&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The two queries are shown as one in pg_stat_statements.&lt;br /&gt;
&lt;br /&gt;
* For prepared statements, the execution part (execute statement) is charged on the prepare statement. That makes it is easier to interpret, and avoids the double-counting there was with PostgreSQL 9.1.&lt;br /&gt;
&lt;br /&gt;
* pg_stat_statements displays timing in milliseconds, to be consistent with other system views.&lt;br /&gt;
&lt;br /&gt;
= Explain improvements=&lt;br /&gt;
&lt;br /&gt;
* Timing can now be disabled with EXPLAIN (analyze on, timing off), leading to lower overhead on platforms where getting the current time is expensive &amp;lt;!--Tomas Vondra--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  =# EXPLAIN (analyze on,timing off) SELECT * FROM reservation ;&lt;br /&gt;
                                       QUERY PLAN                                       &lt;br /&gt;
  ----------------------------------------------------------------------------------------&lt;br /&gt;
   Seq Scan on reservation  (cost=0.00..22.30 rows=1230 width=36) (actual rows=2 loops=1)&lt;br /&gt;
   Total runtime: 0.045 ms&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Have EXPLAIN ANALYZE report the number of rows rejected by filter steps &amp;lt;!--(Marko Tiikkaja)--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This new feature makes it much easier to know how many rows are removed by a filter (and spot potential places to put indexes):&lt;br /&gt;
&lt;br /&gt;
  =# EXPLAIN ANALYZE SELECT * FROM test WHERE a ~ &#039;tra&#039;;&lt;br /&gt;
                                                    QUERY PLAN                                                   &lt;br /&gt;
  ---------------------------------------------------------------------------------------------------------------&lt;br /&gt;
   Seq Scan on test  (cost=0.00..106876.56 rows=2002 width=11) (actual time=2.914..8538.285 rows=120256 loops=1)&lt;br /&gt;
     Filter: (a ~ &#039;tra&#039;::text)&lt;br /&gt;
     Rows Removed by Filter: 5905600&lt;br /&gt;
   Total runtime: 8549.539 ms&lt;br /&gt;
  (4 rows)&lt;br /&gt;
&lt;br /&gt;
=Backward compatibility=&lt;br /&gt;
&lt;br /&gt;
These changes may incur regressions in your applications.&lt;br /&gt;
&lt;br /&gt;
==Ensure that xpath() escapes special characters in string values &amp;lt;!-- (Florian Pflug)--&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Before 9.2:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT (XPATH(&#039;/*/text()&#039;, &#039;&amp;lt;root&amp;gt;&amp;amp;amp;lt;&amp;lt;/root&amp;gt;&#039;))[1];&lt;br /&gt;
 xpath &lt;br /&gt;
-------&lt;br /&gt;
 &amp;lt;&lt;br /&gt;
&lt;br /&gt;
&#039;&amp;lt;&#039; Isn&#039;t valid XML.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
With 9.2:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT (XPATH(&#039;/*/text()&#039;, &#039;&amp;lt;root&amp;gt;&amp;amp;amp;lt;&amp;lt;/root&amp;gt;&#039;))[1];&lt;br /&gt;
 xpath &lt;br /&gt;
-------&lt;br /&gt;
 &amp;amp;amp;lt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Remove hstore&#039;s =&amp;gt; operator &amp;lt;!-- (Robert Haas)--&amp;gt;==&lt;br /&gt;
Up to 9.1, one could use the =&amp;gt; operator to create a hstore. Hstore is a contrib, used to store key/values pairs in a column.&lt;br /&gt;
&lt;br /&gt;
In 9.1:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
=# SELECT &#039;a&#039;=&amp;gt;&#039;b&#039;;&lt;br /&gt;
 ?column? &lt;br /&gt;
----------&lt;br /&gt;
 &amp;quot;a&amp;quot;=&amp;gt;&amp;quot;b&amp;quot;&lt;br /&gt;
(1 row)&lt;br /&gt;
&lt;br /&gt;
=# SELECT pg_typeof(&#039;a&#039;=&amp;gt;&#039;b&#039;);&lt;br /&gt;
 pg_typeof &lt;br /&gt;
-----------&lt;br /&gt;
 hstore&lt;br /&gt;
(1 row)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With 9.2:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT &#039;a&#039;=&amp;gt;&#039;b&#039;;&lt;br /&gt;
ERROR:  operator does not exist: unknown =&amp;gt; unknown at character 11&lt;br /&gt;
HINT:  No operator matches the given name and argument type(s). You might need to add explicit type casts.&lt;br /&gt;
STATEMENT:  SELECT &#039;a&#039;=&amp;gt;&#039;b&#039;;&lt;br /&gt;
ERROR:  operator does not exist: unknown =&amp;gt; unknown&lt;br /&gt;
LINE 1: SELECT &#039;a&#039;=&amp;gt;&#039;b&#039;;&lt;br /&gt;
                  ^&lt;br /&gt;
HINT:  No operator matches the given name and argument type(s). You might need to add explicit type casts.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It doesn&#039;t mean one cannot use &#039;=&amp;gt;&#039; in hstores, it just isn&#039;t an operator anymore:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
=# select hstore(&#039;a=&amp;gt;b&#039;);&lt;br /&gt;
  hstore  &lt;br /&gt;
----------&lt;br /&gt;
 &amp;quot;a&amp;quot;=&amp;gt;&amp;quot;b&amp;quot;&lt;br /&gt;
(1 row)&lt;br /&gt;
&lt;br /&gt;
=# select hstore(&#039;a&#039;,&#039;b&#039;);&lt;br /&gt;
  hstore  &lt;br /&gt;
----------&lt;br /&gt;
 &amp;quot;a&amp;quot;=&amp;gt;&amp;quot;b&amp;quot;&lt;br /&gt;
(1 row)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
are still two valid ways to input a hstore.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;=&amp;gt;&amp;quot; is removed as an operator as it is a reserved keyword in SQL.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Have pg_relation_size() and friends return NULL if the object does not exist  &amp;lt;!-- (Phil Sorber)--&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
A relation could be dropped by a concurrent session, while one was doing a pg_relation_size on it, leading to a SQL exception. Now, it merely returns NULL for this record.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Remove the spclocation field from pg_tablespace &amp;lt;!-- (Magnus Hagander)--&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
The spclocation field provided the real location of the tablespace. It was filled in during the CREATE or ALTER TABLESPACE command. So it could be wrong: somebody just had to shutdown the cluster, move the tablespace&#039;s directory, re-create the symlink in pg_tblspc, and forget to update the spclocation field. The cluster would still run, as the spclocation wasn&#039;t used.&lt;br /&gt;
&lt;br /&gt;
So this field has been removed. To get the tablespace&#039;s location, use pg_tablespace_location():&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
=# SELECT *, pg_tablespace_location(oid) AS spclocation FROM pg_tablespace;&lt;br /&gt;
  spcname   | spcowner | spcacl | spcoptions |  spclocation   &lt;br /&gt;
------------+----------+--------+------------+----------------&lt;br /&gt;
 pg_default |       10 |        |            | &lt;br /&gt;
 pg_global  |       10 |        |            | &lt;br /&gt;
 tmptblspc  |       10 |        |            | /tmp/tmptblspc&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Have EXTRACT of a non-timezone-aware value measure the epoch from local midnight, not UTC midnight &amp;lt;!-- (Tom Lane) --&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
With PostgreSQL 9.1:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
=#SELECT extract(epoch FROM &#039;2012-07-02 00:00:00&#039;::timestamp);&lt;br /&gt;
 date_part  &lt;br /&gt;
------------&lt;br /&gt;
 1341180000&lt;br /&gt;
(1 row)&lt;br /&gt;
&lt;br /&gt;
=# SELECT extract(epoch FROM &#039;2012-07-02 00:00:00&#039;::timestamptz);&lt;br /&gt;
 date_part  &lt;br /&gt;
------------&lt;br /&gt;
 1341180000&lt;br /&gt;
(1 row)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is no difference in behaviour between a timstamp with or without timezone.&lt;br /&gt;
&lt;br /&gt;
With 9.2:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
=#SELECT extract(epoch FROM &#039;2012-07-02 00:00:00&#039;::timestamp);&lt;br /&gt;
 date_part  &lt;br /&gt;
------------&lt;br /&gt;
 1341187200&lt;br /&gt;
(1 row)&lt;br /&gt;
&lt;br /&gt;
=# SELECT extract(epoch FROM &#039;2012-07-02 00:00:00&#039;::timestamptz);&lt;br /&gt;
 date_part  &lt;br /&gt;
------------&lt;br /&gt;
 1341180000&lt;br /&gt;
(1 row)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When the timestamp has no timezone, the epoch is calculated with the &amp;quot;local midnight&amp;quot;, meaning the 1st january of 1970 at midnight, local-time.&lt;br /&gt;
&lt;br /&gt;
==Fix to_date() and to_timestamp() to wrap incomplete dates toward 2020 &amp;lt;!-- (Bruce Momjian)--&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
The wrapping was not consistent between 2 digit dates and 3 digit dates: 2 digit dates always chose the date closest to 2020, 3 digit dates mapped dates from 100 to 999 on 1100 to 1999, and 000 to 099 on 2000 to 2099.&lt;br /&gt;
&lt;br /&gt;
Now PostgreSQL chooses the date closest to 2020, for 2 and 3 digit dates.&lt;br /&gt;
&lt;br /&gt;
With 9.1:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
=# SELECT to_date(&#039;200-07-02&#039;,&#039;YYY-MM-DD&#039;);&lt;br /&gt;
  to_date   &lt;br /&gt;
------------&lt;br /&gt;
 1200-07-02&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With 9.2:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT to_date(&#039;200-07-02&#039;,&#039;YYY-MM-DD&#039;);&lt;br /&gt;
  to_date   &lt;br /&gt;
------------&lt;br /&gt;
 2200-07-02&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==pg_stat_activity and pg_stat_replication&#039;s definitions have changed &amp;lt;!--Magnus Hagander --&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
The view pg_stat_activity has changed. It&#039;s not backward compatible, but let&#039;s see what this new definition brings us:&lt;br /&gt;
&lt;br /&gt;
* current_query disappears and is replaced by two columns:&lt;br /&gt;
** state: is the session running a query, waiting&lt;br /&gt;
** query: what is the last run (or still running if stat is &amp;quot;active&amp;quot;) query&lt;br /&gt;
* The column procpid is renamed to pid, to be consistent with other system views&lt;br /&gt;
&lt;br /&gt;
The benefit is mostly for tracking «idle in transaction» sessions. Up until now, all we could know was that one of these sessions was idle in transaction, meaning it has started a transaction, maybe done some operations, but still not committed. If that session stayed in this state for a while, there was no way of knowing how it got in this state.&lt;br /&gt;
&lt;br /&gt;
Here is an example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
-[ RECORD 1 ]----+---------------------------------&lt;br /&gt;
datid            | 16384&lt;br /&gt;
datname          | postgres&lt;br /&gt;
pid              | 20804&lt;br /&gt;
usesysid         | 10&lt;br /&gt;
usename          | postgres&lt;br /&gt;
application_name | psql&lt;br /&gt;
client_addr      | &lt;br /&gt;
client_hostname  | &lt;br /&gt;
client_port      | -1&lt;br /&gt;
backend_start    | 2012-07-02 15:02:51.146427+02&lt;br /&gt;
xact_start       | 2012-07-02 15:15:28.386865+02&lt;br /&gt;
query_start      | 2012-07-02 15:15:30.410834+02&lt;br /&gt;
state_change     | 2012-07-02 15:15:30.411287+02&lt;br /&gt;
waiting          | f&lt;br /&gt;
state            | idle in transaction&lt;br /&gt;
query            | DELETE FROM test;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With PostgreSQL 9.1, all we would have would be «idle in transaction».&lt;br /&gt;
&lt;br /&gt;
As this change was backward-incompatible, procpid was also renamed to pid, to be more consistent with other system views.&lt;br /&gt;
The view pg_stat_replication has also changed. The column procpid is renamed to pid, to also be consistent with other system views.&lt;br /&gt;
&lt;br /&gt;
==Change all SQL-level statistics timing values to float8-stored milliseconds &amp;lt;!-- (Tom Lane) --&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
pg_stat_user_functions.total_time, pg_stat_user_functions.self_time, pg_stat_xact_user_functions.total_time, pg_stat_xact_user_functions.self_time, and pg_stat_statements.total_time (contrib) are now in milliseconds, to be consistent with the rest of the timing values.&lt;br /&gt;
&lt;br /&gt;
==postgresql.conf parameters changes &amp;lt;!-- (Heikki Linnakangas, Tom Lane, Peter Eisentraut) --&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
* silent_mode has been removed. Use pg_ctl -l postmaster.log&lt;br /&gt;
* wal_sender_delay has been removed. It is no longer needed&lt;br /&gt;
* custom_variable_classes has been removed. All «classes» are accepted without declaration now&lt;br /&gt;
* ssl_ca_file, ssl_cert_file, ssl_crl_file, ssl_key_file have been added, meaning you can now specify the ssl files&lt;br /&gt;
&lt;br /&gt;
= Other new features =&lt;br /&gt;
&lt;br /&gt;
== DROP INDEX CONCURRENTLY ==&lt;br /&gt;
&lt;br /&gt;
The regular DROP INDEX command takes an exclusive lock on the table. Most of the time, this isn&#039;t a problem, because this lock is short-lived. The problem usually occurs when:&lt;br /&gt;
&lt;br /&gt;
* A long-running transaction is running, and has a (shared) lock on the table&lt;br /&gt;
* A DROP INDEX is run on this table in another session, asking for an exclusive lock (and waiting for it, as it won&#039;t be granted until the long-running transaction ends)&lt;br /&gt;
&lt;br /&gt;
At this point, all other transactions needing to take a shared lock on the table (for a simple SELECT for instance) will have to wait too: their lock acquisition is queued after the DROP INDEX&#039;s one.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
DROP INDEX CONCURRENTLY works around this and won&#039;t lock normal DML statements, just as CREATE INDEX CONCURRENTLY. The limitations are also the same: Since you can only DROP one index with the CONCURRENTLY option, and the CASCADE option is not supported.&lt;br /&gt;
&lt;br /&gt;
== NOT VALID CHECK constraints ==&lt;br /&gt;
&lt;br /&gt;
PostgreSQL 9.1 introduced «NOT VALID» foreign keys. This has been extended to CHECK constraints. Adding a «NOT VALID» constraint on a table means that current data won&#039;t be validated, only new and updated rows.&lt;br /&gt;
&lt;br /&gt;
  =# CREATE TABLE test (a int); &lt;br /&gt;
  CREATE TABLE&lt;br /&gt;
  =# INSERT INTO test SELECT generate_series(1,100);&lt;br /&gt;
  INSERT 0 100&lt;br /&gt;
  =# ALTER TABLE test ADD CHECK (a&amp;gt;100) NOT VALID;&lt;br /&gt;
  ALTER TABLE&lt;br /&gt;
  =# INSERT INTO test VALUES (99);&lt;br /&gt;
  ERROR:  new row for relation &amp;quot;test&amp;quot; violates check constraint &amp;quot;test_a_check&amp;quot;&lt;br /&gt;
  DETAIL:  Failing row contains (99).&lt;br /&gt;
  =# INSERT INTO test VALUES (101);&lt;br /&gt;
  INSERT 0 1&lt;br /&gt;
&lt;br /&gt;
Then, later, we can validate the whole table:&lt;br /&gt;
&lt;br /&gt;
  =# ALTER TABLE test VALIDATE CONSTRAINT test_a_check ;&lt;br /&gt;
  ERROR:  check constraint &amp;quot;test_a_check&amp;quot; is violated by some row&lt;br /&gt;
&lt;br /&gt;
Domains, which are types with added constraints, can also be declared as not valid, and validated later.&lt;br /&gt;
&lt;br /&gt;
Check constraints can also be renamed now:&lt;br /&gt;
&lt;br /&gt;
  =# ALTER TABLE test RENAME CONSTRAINT test_a_check TO validate_a;&lt;br /&gt;
  ALTER TABLE&lt;br /&gt;
&lt;br /&gt;
== NO INHERIT constraints ==&lt;br /&gt;
&lt;br /&gt;
Here is another improvement about constraints: they can be declared as not inheritable, which will be useful in partitioned environments. Let&#039;s take PostgreSQL documentation example, and see how it improves the situation:&lt;br /&gt;
&lt;br /&gt;
  CREATE TABLE measurement (&lt;br /&gt;
      city_id         int not null,&lt;br /&gt;
      logdate         date not null,&lt;br /&gt;
      peaktemp        int,&lt;br /&gt;
      unitsales       int,&lt;br /&gt;
      CHECK (logdate IS NULL) NO INHERIT&lt;br /&gt;
  );&lt;br /&gt;
  &lt;br /&gt;
  CREATE TABLE measurement_y2006m02 (&lt;br /&gt;
      CHECK ( logdate &amp;gt;= DATE &#039;2006-02-01&#039; AND logdate &amp;lt; DATE &#039;2006-03-01&#039; )&lt;br /&gt;
  ) INHERITS (measurement);&lt;br /&gt;
  CREATE TABLE measurement_y2006m03 (&lt;br /&gt;
      CHECK ( logdate &amp;gt;= DATE &#039;2006-03-01&#039; AND logdate &amp;lt; DATE &#039;2006-04-01&#039; )&lt;br /&gt;
  ) INHERITS (measurement);&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  INSERT INTO measurement VALUES (1,&#039;2006-02-20&#039;,1,1);&lt;br /&gt;
  ERROR:  new row for relation &amp;quot;measurement&amp;quot; violates check constraint &amp;quot;measurement_logdate_check&amp;quot;&lt;br /&gt;
  DETAIL:  Failing row contains (1, 2006-02-20, 1, 1).&lt;br /&gt;
  INSERT INTO measurement_y2006m02 VALUES (1,&#039;2006-02-20&#039;,1,1);&lt;br /&gt;
  INSERT 0 1&lt;br /&gt;
&lt;br /&gt;
Until now, every check constraint created on measurement would have been inherited by children tables. So adding a constraint forbidding inserts, or allowing only some of them, on the parent table was impossible.&lt;br /&gt;
&lt;br /&gt;
== Reduce ALTER TABLE rewrites ==&lt;br /&gt;
&lt;br /&gt;
A table won&#039;t get rewritten anymore during an ALTER TABLE when changing the type of a column in the following cases:&lt;br /&gt;
&lt;br /&gt;
* varchar(x) to varchar(y) when y&amp;gt;=x. It works too if going from varchar(x) to varchar or text (no size limitation)&lt;br /&gt;
* numeric(x,z) to numeric(y,z) when y&amp;gt;=x, or to numeric without specifier&lt;br /&gt;
* varbit(x) to varbit(y) when y&amp;gt;=x, or to varbit without specifier&lt;br /&gt;
* timestamp(x) to timestamp(y) when y&amp;gt;=x or timestamp without specifier&lt;br /&gt;
* timestamptz(x) to timestamptz(y) when y&amp;gt;=x or timestamptz without specifier&lt;br /&gt;
* interval(x) to interval(y) when y&amp;gt;=x or interval without specifier&lt;br /&gt;
&lt;br /&gt;
== Security barriers and Leakproof ==&lt;br /&gt;
&lt;br /&gt;
This new feature has to do with views security. First, let&#039;s explain the problem, with a very simplified example:&lt;br /&gt;
&lt;br /&gt;
  =# CREATE TABLE all_data (company_id int, company_data varchar);&lt;br /&gt;
  CREATE TABLE&lt;br /&gt;
  =# INSERT INTO all_data VALUES (1,&#039;secret_data_for_company_1&#039;);&lt;br /&gt;
  INSERT 0 1&lt;br /&gt;
  =# INSERT INTO all_data VALUES (2,&#039;secret_data_for_company_2&#039;);&lt;br /&gt;
  INSERT 0 1&lt;br /&gt;
  =# CREATE VIEW company1_data AS SELECT * FROM all_data WHERE company_id = 1;&lt;br /&gt;
  CREATE VIEW&lt;br /&gt;
&lt;br /&gt;
This is a quite classical way of giving access to only a part of a table to a user: we&#039;ll create a user for company_id 1, grant to him the right to access company1_data, and deny him the right to access all_data.&lt;br /&gt;
&lt;br /&gt;
The plan to this query is the following:&lt;br /&gt;
&lt;br /&gt;
  =# explain SELECT * FROM company1_data ;&lt;br /&gt;
                          QUERY PLAN                        &lt;br /&gt;
  ----------------------------------------------------------&lt;br /&gt;
   Seq Scan on all_data  (cost=0.00..25.38 rows=6 width=36)&lt;br /&gt;
     Filter: (company_id = 1)&lt;br /&gt;
&lt;br /&gt;
Even if there was more data, a sequential scan could still be forced: just &amp;quot;SET enable_indexscan to OFF&amp;quot; and the likes.&lt;br /&gt;
&lt;br /&gt;
So this query reads all the records from all_data, filters them, and returns to the user only the matching rows. There is a way to display scanned records before they are filtered: just create a function with a very low cost, and call it while doing the query:&lt;br /&gt;
&lt;br /&gt;
  CREATE OR REPLACE FUNCTION peek(text) RETURNS boolean LANGUAGE plpgsql AS&lt;br /&gt;
  $$&lt;br /&gt;
  BEGIN&lt;br /&gt;
    RAISE NOTICE &#039;%&#039;,$1;&lt;br /&gt;
    RETURN true;&lt;br /&gt;
  END&lt;br /&gt;
  $$&lt;br /&gt;
  COST 0.1;&lt;br /&gt;
&lt;br /&gt;
This function just has to cost less than the = operator, which costs 1, to be executed first.&lt;br /&gt;
&lt;br /&gt;
The result is this:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  =# SELECT * FROM company1_data WHERE peek(company1_data.company_data);&lt;br /&gt;
  NOTICE:  secret_data_for_company_1&lt;br /&gt;
  NOTICE:  secret_data_for_company_2&lt;br /&gt;
   company_id |       company_data        &lt;br /&gt;
  ------------+---------------------------&lt;br /&gt;
            1 | secret_data_for_company_1&lt;br /&gt;
  (1 row)&lt;br /&gt;
&lt;br /&gt;
We got access to the record from the second company (in the NOTICE messages).&lt;br /&gt;
&lt;br /&gt;
So this is the first new feature: the view can be declared as implementing &amp;quot;security barriers&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  =# CREATE VIEW company1_data WITH (security_barrier) AS SELECT * FROM all_data WHERE company_id = 1;&lt;br /&gt;
  CREATE VIEW&lt;br /&gt;
  =# SELECT * FROM company1_data WHERE peek(company1_data.company_data);&lt;br /&gt;
  NOTICE:  secret_data_for_company_1&lt;br /&gt;
   company_id |       company_data        &lt;br /&gt;
  ------------+---------------------------&lt;br /&gt;
            1 | secret_data_for_company_1&lt;br /&gt;
  (1 row)&lt;br /&gt;
&lt;br /&gt;
The view is not leaking anymore. The problem, of course, is that there is a performance impact: maybe the &amp;quot;peek&amp;quot; function could have made the query faster, by filtering lots of rows early in the plan. The rows are now filtered in two separate plan steps:&lt;br /&gt;
&lt;br /&gt;
  =# explain SELECT * FROM company1_data WHERE peek(company1_data.company_data);&lt;br /&gt;
                               QUERY PLAN                             &lt;br /&gt;
  --------------------------------------------------------------------&lt;br /&gt;
   Subquery Scan on company1_data  (cost=0.00..25.44 rows=2 width=36)&lt;br /&gt;
     Filter: peek((company1_data.company_data)::text)&lt;br /&gt;
     -&amp;gt;  Seq Scan on all_data  (cost=0.00..25.38 rows=6 width=36)&lt;br /&gt;
           Filter: (company_id = 1)&lt;br /&gt;
&lt;br /&gt;
This leads to the complementary feature: some function may be declared as &amp;quot;LEAKPROOF&amp;quot;, meaning that they won&#039;t leak the data they are passed into error or notice messages.&lt;br /&gt;
&lt;br /&gt;
Declaring our peek function as LEAKPROOF is a very bad idea, but let&#039;s do it just to demonstrate how it&#039;s used:&lt;br /&gt;
&lt;br /&gt;
  CREATE OR REPLACE FUNCTION peek(text) RETURNS boolean LEAKPROOF LANGUAGE plpgsql AS&lt;br /&gt;
  $$&lt;br /&gt;
  BEGIN&lt;br /&gt;
    RAISE NOTICE &#039;%&#039;,$1;&lt;br /&gt;
    RETURN true;&lt;br /&gt;
  END&lt;br /&gt;
  $$&lt;br /&gt;
  COST 0.1;&lt;br /&gt;
&lt;br /&gt;
A LEAKPROOF function is executed «normally»:&lt;br /&gt;
&lt;br /&gt;
  =# SELECT * FROM company1_data WHERE peek(company1_data.company_data);&lt;br /&gt;
  NOTICE:  secret_data_for_company_1&lt;br /&gt;
  NOTICE:  secret_data_for_company_2&lt;br /&gt;
   company_id |       company_data        &lt;br /&gt;
  ------------+---------------------------&lt;br /&gt;
            1 | secret_data_for_company_1&lt;br /&gt;
  (1 row)&lt;br /&gt;
&lt;br /&gt;
Of course, in our case, peek isn&#039;t LEAKPROOF and shouldn&#039;t be declared as such. Only superuser have the permission to declare a LEAKPROOF function.&lt;br /&gt;
&lt;br /&gt;
== New options for pg_dump ==&lt;br /&gt;
&lt;br /&gt;
Until now, one could ask pg_dump to dump a table&#039;s data, or a table&#039;s meta-data (DDL statements for creating the table&#039;s structure, indexes, constraints). Some meta-data is better restored before the data (the table&#039;s structure, check constraints), some is better after the data (indexes, unique constraints, foreign keys…), for performance reasons mostly.&lt;br /&gt;
&lt;br /&gt;
So there are now a few more options:&lt;br /&gt;
&lt;br /&gt;
* --section=pre-data: dump what&#039;s needed before restoring the data. Of course, this can be combined with a -t for instance, to specify only one table&lt;br /&gt;
* --section=post-data : dump what&#039;s needed after restoring the data.&lt;br /&gt;
* --section=data: dump the data&lt;br /&gt;
* --exclude-table-data: dump everything, except THIS table&#039;s data. It means pg_dump will still dump other tables&#039; data.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:PostgreSQL 9.2]]&lt;/div&gt;</summary>
		<author><name>Intgr</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=What%27s_new_in_PostgreSQL_9.2&amp;diff=18295</id>
		<title>What&#039;s new in PostgreSQL 9.2</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=What%27s_new_in_PostgreSQL_9.2&amp;diff=18295"/>
		<updated>2012-09-25T12:40:10Z</updated>

		<summary type="html">&lt;p&gt;Intgr: /* Security barriers and Leakproof */ Add example plan with security_barrier views&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Languages}}&lt;br /&gt;
&lt;br /&gt;
This document showcases many of the latest developments in PostgreSQL 9.2, compared to the last major release &amp;amp;ndash; PostgreSQL 9.1. There are many improvements in this release, so this wiki page covers many of the more important changes in detail. The full list of changes is itemised in &#039;&#039;Release Notes&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Major new features=&lt;br /&gt;
&lt;br /&gt;
==Index-only scans &amp;lt;!-- Robert Haas, Ibrar Ahmed, Heikki Linnakangas, Tom Lane --&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
In PostgreSQL, indexes have no &amp;quot;visibility&amp;quot; information. It means that when you access a record by its index, PostgreSQL has to visit the real tuple in the table to be sure it is visible to you: the tuple the index points to may simply be an old version of the record you are looking for.&lt;br /&gt;
&lt;br /&gt;
It can be a very big performance problem: the index is mostly ordered, so accessing its records is quite efficient, while the records may be scattered all over the place (that&#039;s a reason why PostgreSQL has a cluster command, but that&#039;s another story). In 9.2, PostgreSQL will use an &amp;quot;Index Only Scan&amp;quot; when possible, and not access the record itself if it doesn&#039;t need to.&lt;br /&gt;
&lt;br /&gt;
There is still no visibility information in the index. So in order to do this, PostgreSQL uses the visibility map ([http://www.postgresql.org/docs/devel/static/storage-vm.html visibility map]) , which tells it whether the whole content of a (usually) 8K page is visible to all transactions or not. When the index record points to a tuple contained in an «all visible» page, PostgreSQL won&#039;t have to access the tuple, it will be able to build it directly from the index. Of course, all the columns requested by the query must be in the index.&lt;br /&gt;
&lt;br /&gt;
The visibility map is maintained by VACUUM (it sets the visible bit), and by the backends doing SQL work (they unset the visible bit).&lt;br /&gt;
&lt;br /&gt;
If the data has been read only since the last VACUUM then the data is All Visible and the index only scan feature can improve performance.&lt;br /&gt;
&lt;br /&gt;
Here is an example.&lt;br /&gt;
&lt;br /&gt;
  CREATE TABLE demo_ios (col1 float, col2 float, col3 text);&lt;br /&gt;
&lt;br /&gt;
In this table, we&#039;ll put random data, in order to have &amp;quot;scattered&amp;quot; data. We&#039;ll put 100 million records, to have a big recordset, and have it not fit in memory (that&#039;s a 4GB-ram machine). This is an ideal case, made for this demo. The gains won&#039;t be that big in real life.&lt;br /&gt;
&lt;br /&gt;
  INSERT INTO demo_ios SELECT generate_series(1,100000000),random(), &#039;mynotsolongstring&#039;;&lt;br /&gt;
  &lt;br /&gt;
  SELECT pg_size_pretty(pg_total_relation_size(&#039;demo_ios&#039;));&lt;br /&gt;
   pg_size_pretty &lt;br /&gt;
  ----------------&lt;br /&gt;
   6512 MB&lt;br /&gt;
&lt;br /&gt;
Let&#039;s pretend that the query is this:&lt;br /&gt;
&lt;br /&gt;
  SELECT col1,col2 FROM demo_ios where col2 BETWEEN 0.01 AND 0.02&lt;br /&gt;
&lt;br /&gt;
In order to use an index only scan on this query, we need an index on col2,col1 (col2 first, as it is used in the WHERE clause).&lt;br /&gt;
&lt;br /&gt;
  CREATE index idx_demo_ios on demo_ios(col2,col1);&lt;br /&gt;
&lt;br /&gt;
We vacuum the table, so that the visibility map to be up-to-date:&lt;br /&gt;
&lt;br /&gt;
  VACUUM demo_ios;&lt;br /&gt;
&lt;br /&gt;
All the timing you&#039;ll see below are done on a cold OS and PostgreSQL cache (that&#039;s where the gains are, as the purpose on Index Only Scans is to reduce I/O).&lt;br /&gt;
&lt;br /&gt;
Let&#039;s first try without Index Only Scans:&lt;br /&gt;
&lt;br /&gt;
  SET enable_indexonlyscan to off;&lt;br /&gt;
  &lt;br /&gt;
  EXPLAIN (analyze,buffers) select col1,col2 FROM demo_ios where col2 between 0.01 and 0.02;&lt;br /&gt;
                                                                 QUERY PLAN                                                               &lt;br /&gt;
  ----------------------------------------------------------------------------------------------------------------------------------------&lt;br /&gt;
   Bitmap Heap Scan on demo_ios  (cost=25643.01..916484.44 rows=993633 width=16) (actual time=763.391..362963.899 rows=1000392 loops=1)&lt;br /&gt;
     Recheck Cond: ((col2 &amp;gt;= 0.01::double precision) AND (col2 &amp;lt;= 0.02::double precision))&lt;br /&gt;
     Rows Removed by Index Recheck: 68098621&lt;br /&gt;
     Buffers: shared hit=2 read=587779&lt;br /&gt;
     -&amp;gt;  Bitmap Index Scan on idx_demo_ios  (cost=0.00..25394.60 rows=993633 width=0) (actual time=759.011..759.011 rows=1000392 loops=1)&lt;br /&gt;
           Index Cond: ((col2 &amp;gt;= 0.01::double precision) AND (col2 &amp;lt;= 0.02::double precision))&lt;br /&gt;
           Buffers: shared hit=2 read=3835&lt;br /&gt;
   Total runtime: 364390.127 ms&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
With Index Only Scans:&lt;br /&gt;
&lt;br /&gt;
  explain (analyze,buffers) select col1,col2 from demo_ios where col2 between 0.01 and 0.02;&lt;br /&gt;
                                                                    QUERY PLAN                                                                   &lt;br /&gt;
  -----------------------------------------------------------------------------------------------------------------------------------------------&lt;br /&gt;
   Index Only Scan using idx_demo_ios on demo_ios  (cost=0.00..35330.93 rows=993633 width=16) (actual time=58.100..3250.589 rows=1000392 loops=1)&lt;br /&gt;
     Index Cond: ((col2 &amp;gt;= 0.01::double precision) AND (col2 &amp;lt;= 0.02::double precision))&lt;br /&gt;
     Heap Fetches: 0&lt;br /&gt;
     Buffers: shared hit=923073 read=3848&lt;br /&gt;
   Total runtime: 4297.405 ms&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
As nothing is free, there are a few things to keep in mind:&lt;br /&gt;
&lt;br /&gt;
* Adding indexes for index only scans obviously adds indexes to your table. So updates will be slower.&lt;br /&gt;
* You will index columns that weren&#039;t indexed before. So there will be less opportunities for HOT updates.&lt;br /&gt;
* Gains will probably be smaller in real life situations, especially when data is changed between VACUUMs&lt;br /&gt;
&lt;br /&gt;
This required making visibility map changes crash-safe, so visibility map bit changes are now WAL-logged.&lt;br /&gt;
&lt;br /&gt;
==Replication improvements &amp;lt;!-- Fujii Masao, Simon Riggs, Magnus Hagander, Jun Ishizuka --&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
Streaming Replication becomes more polished with this release. &lt;br /&gt;
&lt;br /&gt;
One of the main remaining gripes about streaming replication is that all the slaves have to be connected to the same and unique master, consuming its resources. Moreover, in case of a failover, it could be complicated to reconnect all the remaining slaves to the newly promoted master, if one is not using a tool like repmgr. &lt;br /&gt;
&lt;br /&gt;
With 9.2, a  standby can also send replication changes, allowing cascading replication.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s build this. We start with an already working 9.2 database.&lt;br /&gt;
&lt;br /&gt;
We set it up for replication:&lt;br /&gt;
&lt;br /&gt;
postgresql.conf:&lt;br /&gt;
  wal_level=hot_standby #(could be archive too)&lt;br /&gt;
  max_wal_senders=5&lt;br /&gt;
  hot_standby=on&lt;br /&gt;
&lt;br /&gt;
You&#039;ll probably also want to activate archiving in production, it won&#039;t be done here.&lt;br /&gt;
&lt;br /&gt;
pg_hba.conf (do not use trust in production):&lt;br /&gt;
  host   replication replication_user          0.0.0.0/0                      md5&lt;br /&gt;
 &lt;br /&gt;
Create the user:&lt;br /&gt;
  create user replication_user replication password &#039;secret&#039;;&lt;br /&gt;
&lt;br /&gt;
Clone the cluster:&lt;br /&gt;
&lt;br /&gt;
  pg_basebackup -h localhost -U replication_user -D data2&lt;br /&gt;
  Password:&lt;br /&gt;
&lt;br /&gt;
We have a brand new cluster in the data2 directory. We&#039;ll change the port so that it can start (postgresql.conf), as both clusters are running on the same machine:&lt;br /&gt;
  port=5433&lt;br /&gt;
&lt;br /&gt;
We add a recovery.conf to tell it how to stream from the master database:&lt;br /&gt;
  standby_mode = on&lt;br /&gt;
  primary_conninfo = &#039;host=localhost port=5432 user=replication_user password=secret&#039; &lt;br /&gt;
&lt;br /&gt;
  pg_ctl -D data2 start&lt;br /&gt;
  server starting&lt;br /&gt;
  LOG:  database system was interrupted; last known up at 2012-07-03 17:58:09 CEST&lt;br /&gt;
  LOG:  creating missing WAL directory &amp;quot;pg_xlog/archive_status&amp;quot;&lt;br /&gt;
  LOG:  entering standby mode&lt;br /&gt;
  LOG:  streaming replication successfully connected to primary&lt;br /&gt;
  LOG:  redo starts at 0/9D000020&lt;br /&gt;
  LOG:  consistent recovery state reached at 0/9D0000B8&lt;br /&gt;
  LOG:  database system is ready to accept read only connections&lt;br /&gt;
&lt;br /&gt;
Now, let&#039;s add a second slave, which will use this slave:&lt;br /&gt;
&lt;br /&gt;
  pg_basebackup -h localhost -U replication_user -D data3 -p 5433&lt;br /&gt;
  Password: &lt;br /&gt;
&lt;br /&gt;
We edit data3&#039;s postgresql.conf to change the port:&lt;br /&gt;
  port=5434&lt;br /&gt;
&lt;br /&gt;
We modify the recovery.conf to stream from the slave:&lt;br /&gt;
  standby_mode = on&lt;br /&gt;
  primary_conninfo = &#039;host=localhost port=5433 user=replication_user password=secret&#039;             # e.g. &#039;host=localhost port=5432&#039;&lt;br /&gt;
&lt;br /&gt;
We start the third cluster:&lt;br /&gt;
  pg_ctl -D data3 start&lt;br /&gt;
  server starting&lt;br /&gt;
  LOG:  database system was interrupted while in recovery at log time 2012-07-03 17:58:09 CEST&lt;br /&gt;
  HINT:  If this has occurred more than once some data might be corrupted and you might need to choose an earlier recovery target.&lt;br /&gt;
  LOG:  creating missing WAL directory &amp;quot;pg_xlog/archive_status&amp;quot;&lt;br /&gt;
  LOG:  entering standby mode&lt;br /&gt;
  LOG:  streaming replication successfully connected to primary&lt;br /&gt;
  LOG:  redo starts at 0/9D000020&lt;br /&gt;
  LOG:  consistent recovery state reached at 0/9E000000&lt;br /&gt;
  LOG:  database system is ready to accept read only connections&lt;br /&gt;
&lt;br /&gt;
Now, everything modified on the master cluster get streamed to the first slave, and from there to the second slave. This second replication has to be monitored from the first slave (the master knows nothing about it).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
As you may have noticed from the example, pg_basebackup now works from slaves.&lt;br /&gt;
&lt;br /&gt;
There is another use case that wasn&#039;t covered: what if a user didn&#039;t care for having a full fledged slave, and only wanted to stream the WAL files to another location, to benefit from the reduced data loss without the burden of maintaining a slave ?&lt;br /&gt;
&lt;br /&gt;
pg_receivexlog is provided just for this purpose: it pretends to be a PostgreSQL slave, but only stores the log files as they are streamed, in a directory:&lt;br /&gt;
  pg_receivexlog -D /tmp/new_logs -h localhost -U replication_user&lt;br /&gt;
&lt;br /&gt;
will connect to the master (or a slave), and start creating files: &lt;br /&gt;
  ls /tmp/new_logs/&lt;br /&gt;
  00000001000000000000009E.partial&lt;br /&gt;
&lt;br /&gt;
Files are of the segment size, so they can be used for a normal recovery of the database. It&#039;s the same as an archive command, but with a much smaller granularity.&lt;br /&gt;
&lt;br /&gt;
Remember to rename the last segment to remove the .partial suffix before using it with a PITR restore or any other operation.&lt;br /&gt;
&lt;br /&gt;
The synchronous_commit parameter has a new value: remote_write. It can be used when there is a synchronous slave (synchronous_standby_names is set), meaning that the master doesn&#039;t have to wait for the slave to have written the data to disk, only for the slave to have acknowledged the data. With this set, data is protected from a crash on the master, but could still be lost if the slave crashed at the same time (i.e. before having written the in flight data to disk). As this is a quite remote possibility, and the performance improvement will be large, some people will be interested in this compromise.&lt;br /&gt;
&lt;br /&gt;
==JSON datatype==&lt;br /&gt;
&lt;br /&gt;
The JSON datatype is meant for storing JSON-structured data. It will validate that the input JSON string is correct JSON:&lt;br /&gt;
&lt;br /&gt;
  =# SELECT &#039;{&amp;quot;username&amp;quot;:&amp;quot;john&amp;quot;,&amp;quot;posts&amp;quot;:121,&amp;quot;emailaddress&amp;quot;:&amp;quot;john@nowhere.com&amp;quot;}&#039;::json;&lt;br /&gt;
                                 json                                &lt;br /&gt;
  -------------------------------------------------------------------&lt;br /&gt;
   {&amp;quot;username&amp;quot;:&amp;quot;john&amp;quot;,&amp;quot;posts&amp;quot;:121,&amp;quot;emailaddress&amp;quot;:&amp;quot;john@nowhere.com&amp;quot;}&lt;br /&gt;
  (1 row)&lt;br /&gt;
  &lt;br /&gt;
  =# SELECT &#039;{&amp;quot;username&amp;quot;,&amp;quot;posts&amp;quot;:121,&amp;quot;emailaddress&amp;quot;:&amp;quot;john@nowhere.com&amp;quot;}&#039;::json;&lt;br /&gt;
  ERROR:  invalid input syntax for type json at character 8&lt;br /&gt;
  DETAIL:  Expected &amp;quot;:&amp;quot;, but found &amp;quot;,&amp;quot;.&lt;br /&gt;
  CONTEXT:  JSON data, line 1: {&amp;quot;username&amp;quot;,...&lt;br /&gt;
  STATEMENT:  SELECT &#039;{&amp;quot;username&amp;quot;,&amp;quot;posts&amp;quot;:121,&amp;quot;emailaddress&amp;quot;:&amp;quot;john@nowhere.com&amp;quot;}&#039;::json;&lt;br /&gt;
  ERROR:  invalid input syntax for type json&lt;br /&gt;
  LINE 1: SELECT &#039;{&amp;quot;username&amp;quot;,&amp;quot;posts&amp;quot;:121,&amp;quot;emailaddress&amp;quot;:&amp;quot;john@nowhere...&lt;br /&gt;
                 ^&lt;br /&gt;
  DETAIL:  Expected &amp;quot;:&amp;quot;, but found &amp;quot;,&amp;quot;.&lt;br /&gt;
  CONTEXT:  JSON data, line 1: {&amp;quot;username&amp;quot;,...&lt;br /&gt;
&lt;br /&gt;
You can also convert a row type to JSON:&lt;br /&gt;
&lt;br /&gt;
  =#SELECT * FROM demo ;&lt;br /&gt;
   username | posts |    emailaddress     &lt;br /&gt;
  ----------+-------+---------------------&lt;br /&gt;
   john     |   121 | john@nowhere.com&lt;br /&gt;
   mickael  |   215 | mickael@nowhere.com&lt;br /&gt;
  (2 rows)&lt;br /&gt;
  &lt;br /&gt;
  =# SELECT row_to_json(demo) FROM demo;&lt;br /&gt;
                                 row_to_json                               &lt;br /&gt;
  -------------------------------------------------------------------------&lt;br /&gt;
   {&amp;quot;username&amp;quot;:&amp;quot;john&amp;quot;,&amp;quot;posts&amp;quot;:121,&amp;quot;emailaddress&amp;quot;:&amp;quot;john@nowhere.com&amp;quot;}&lt;br /&gt;
   {&amp;quot;username&amp;quot;:&amp;quot;mickael&amp;quot;,&amp;quot;posts&amp;quot;:215,&amp;quot;emailaddress&amp;quot;:&amp;quot;mickael@nowhere.com&amp;quot;}&lt;br /&gt;
  (2 rows)&lt;br /&gt;
&lt;br /&gt;
Or an array type:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  =# select array_to_json(array_agg(demo)) from demo;&lt;br /&gt;
                                                                  array_to_json                                                                &lt;br /&gt;
  ---------------------------------------------------------------------------------------------------------------------------------------------&lt;br /&gt;
   [{&amp;quot;username&amp;quot;:&amp;quot;john&amp;quot;,&amp;quot;posts&amp;quot;:121,&amp;quot;emailaddress&amp;quot;:&amp;quot;john@nowhere.com&amp;quot;},{&amp;quot;username&amp;quot;:&amp;quot;mickael&amp;quot;,&amp;quot;posts&amp;quot;:215,&amp;quot;emailaddress&amp;quot;:&amp;quot;mickael@nowhere.com&amp;quot;}]&lt;br /&gt;
  (1 row)&lt;br /&gt;
&lt;br /&gt;
== Range Types ==&lt;br /&gt;
&lt;br /&gt;
Range types are used to store a range of data of a given type. There are a few pre-defined types. They are integer (int4range), bigint (int8range), numeric (numrange), timestamp without timezone (tsrange), timestamp with timezone (tstzrange), and date (daterange).&lt;br /&gt;
&lt;br /&gt;
Ranges can be made of continuous (numeric, timestamp...) or discrete (integer, date...) data types. They can be open (the bound isn&#039;t part of the range) or closed (the bound is part of the range). A bound can also be infinite.&lt;br /&gt;
&lt;br /&gt;
Without these datatypes, most people solve the range problems by using two columns in a table. These range types are much more powerful, as you can use many operators on them.&lt;br /&gt;
&lt;br /&gt;
Here is the intersection between then 1000(open)-2000(closed) and 1000(closed)-1200(closed) numeric range:&lt;br /&gt;
&lt;br /&gt;
  SELECT &#039;(1000,2000]&#039;::numrange * &#039;[1000,1200]&#039;::numrange;&lt;br /&gt;
    ?column?   &lt;br /&gt;
  -------------&lt;br /&gt;
   (1000,1200]&lt;br /&gt;
  (1 row)&lt;br /&gt;
&lt;br /&gt;
So you can query on things like: «give me all ranges that intersect this»:&lt;br /&gt;
&lt;br /&gt;
  =# SELECT * from test_range ;&lt;br /&gt;
                         period                        &lt;br /&gt;
  -----------------------------------------------------&lt;br /&gt;
   [&amp;quot;2012-01-01 00:00:00+01&amp;quot;,&amp;quot;2012-01-02 12:00:00+01&amp;quot;]&lt;br /&gt;
   [&amp;quot;2012-01-01 00:00:00+01&amp;quot;,&amp;quot;2012-03-01 00:00:00+01&amp;quot;]&lt;br /&gt;
   [&amp;quot;2008-01-01 00:00:00+01&amp;quot;,&amp;quot;2015-01-01 00:00:00+01&amp;quot;]&lt;br /&gt;
  (3 rows)&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  =# SELECT * FROM test_range WHERE period &amp;amp;&amp;amp; &#039;[2012-01-03 00:00:00,2012-01-03 12:00:00]&#039;; &lt;br /&gt;
                         period                        &lt;br /&gt;
  -----------------------------------------------------&lt;br /&gt;
   [&amp;quot;2012-01-01 00:00:00+01&amp;quot;,&amp;quot;2012-03-01 00:00:00+01&amp;quot;]&lt;br /&gt;
   [&amp;quot;2008-01-01 00:00:00+01&amp;quot;,&amp;quot;2015-01-01 00:00:00+01&amp;quot;]&lt;br /&gt;
  (2 rows)&lt;br /&gt;
&lt;br /&gt;
This query could use an index defined like this:&lt;br /&gt;
&lt;br /&gt;
  =# CREATE INDEX idx_test_range on test_range USING gist (period);&lt;br /&gt;
&lt;br /&gt;
You can also use these range data types to define exclusion constraints:&lt;br /&gt;
&lt;br /&gt;
  CREATE EXTENSION btree_gist ;&lt;br /&gt;
  CREATE TABLE reservation (room_id int, period tstzrange);&lt;br /&gt;
  ALTER TABLE reservation ADD  EXCLUDE USING GIST (room_id WITH =, period WITH &amp;amp;&amp;amp;);&lt;br /&gt;
&lt;br /&gt;
This means that now it is forbidden to have two records in this table where room_id is equal and period overlaps. The extension btree_gist is required to create a GiST index on room_id (it&#039;s an integer, it is usually indexed with a btree index).&lt;br /&gt;
&lt;br /&gt;
  =# INSERT INTO reservation VALUES (1,&#039;(2012-08-23 14:00:00,2012-08-23 15:00:00)&#039;);&lt;br /&gt;
  INSERT 0 1&lt;br /&gt;
  =# INSERT INTO reservation VALUES (2,&#039;(2012-08-23 14:00:00,2012-08-23 15:00:00)&#039;);&lt;br /&gt;
  INSERT 0 1&lt;br /&gt;
  =# INSERT INTO reservation VALUES (1,&#039;(2012-08-23 14:45:00,2012-08-23 15:15:00)&#039;);&lt;br /&gt;
  ERROR:  conflicting key value violates exclusion constraint &amp;quot;reservation_room_id_period_excl&amp;quot;&lt;br /&gt;
  DETAIL:  Key (room_id, period)=(1, (&amp;quot;2012-08-23 14:45:00+02&amp;quot;,&amp;quot;2012-08-23 15:15:00+02&amp;quot;)) &lt;br /&gt;
  conflicts with existing key (room_id, period)=(1, (&amp;quot;2012-08-23 14:00:00+02&amp;quot;,&amp;quot;2012-08-23 15:00:00+02&amp;quot;)).&lt;br /&gt;
  STATEMENT:  INSERT INTO reservation VALUES (1,&#039;(2012-08-23 14:45:00,2012-08-23 15:15:00)&#039;);&lt;br /&gt;
&lt;br /&gt;
One can also declare new range types.&lt;br /&gt;
&lt;br /&gt;
=Performance improvements=&lt;br /&gt;
&lt;br /&gt;
This version has performance improvements on a very large range of domains (non-exaustive):&lt;br /&gt;
&lt;br /&gt;
* The most visible will probably be the Index Only Scans, which has already been introduced in this document.&lt;br /&gt;
&lt;br /&gt;
* The lock contention of several big locks has been significantly reduced, leading to better multi-processor scalability, for machines with over 32 cores mostly. &amp;lt;!-- Robert Haas --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* The performance of in-memory sorts has been improved by up to 25% in some situations, with certain specialized sort functions introduced. &amp;lt;!-- Peter Geoghegan --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* An idle PostgreSQL server now makes less wakeups, leading to lower power consumption&amp;lt;!--Peter Geoghegan--&amp;gt;. This is especially useful on virtualized and embedded environments.&lt;br /&gt;
&lt;br /&gt;
* COPY has been improved, it will generate less WAL volume and fewer locks of a table&#039;s pages. &amp;lt;!-- Heikki Linnakangas --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Statistics are collected on array contents&amp;lt;!-- Alexander Korotkov --&amp;gt;, allowing for better estimations of selectivity on array operations.&lt;br /&gt;
&lt;br /&gt;
* Text-to-anytype concatenation and quote_literal/quote_nullable functions are not volatile any more, enabling better optimization in some cases &amp;lt;!-- Marti Raudsepp --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* The system can now track IO durations &amp;lt;!--Ants Aasma --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This one deserves a little explanation, as it can be a little tricky. Tracking IO durations means asking repeatedly the time to the operating system. Depending on the operating system and the hardware, this can be quite cheap, or extremely costly. The most import factor here is where the system gets its time from. It could be directly retrieved from the processor (TSC), dedicated hardware such as HPET, or an ACPI call. What&#039;s most important is that the cost of getting time can vary from a factor of thousands.&lt;br /&gt;
&lt;br /&gt;
If you are interested in this timing data, it&#039;s better to first check if your system will support it without too much of a performance hit. PostgreSQL provides you with the pg_test_timing tool:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ pg_test_timing &lt;br /&gt;
Testing timing overhead for 3 seconds.&lt;br /&gt;
Per loop time including overhead: 28.02 nsec&lt;br /&gt;
Histogram of timing durations:&lt;br /&gt;
   &amp;lt; usec:      count   percent&lt;br /&gt;
       32:         41  0.00004%&lt;br /&gt;
       16:       1405  0.00131%&lt;br /&gt;
        8:        200  0.00019%&lt;br /&gt;
        4:        388  0.00036%&lt;br /&gt;
        2:    2982558  2.78523%&lt;br /&gt;
        1:  104100166 97.21287%&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here, everything is good: getting time costs around 28 nanoseconds, and has a very small variation. Anything under 100 nanoseconds should be good for production. If you get higher values, you may still find a way to tune your system. You&#039;d better check on the [http://www.postgresql.org/docs/9.2/static/pgtesttiming.html documentation].&lt;br /&gt;
&lt;br /&gt;
Anyway, here is the data you&#039;ll be able to collect if your system is ready for this:&lt;br /&gt;
&lt;br /&gt;
First, you&#039;ll get per-database statistics, which will now give accurate informations about which database is doing most I/O:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
=# SELECT * FROM pg_stat_database WHERE datname = &#039;mydb&#039;;&lt;br /&gt;
-[ RECORD 1 ]--+------------------------------&lt;br /&gt;
datid          | 16384&lt;br /&gt;
datname        | mydb&lt;br /&gt;
numbackends    | 1&lt;br /&gt;
xact_commit    | 270&lt;br /&gt;
xact_rollback  | 2&lt;br /&gt;
blks_read      | 1961&lt;br /&gt;
blks_hit       | 17944&lt;br /&gt;
tup_returned   | 269035&lt;br /&gt;
tup_fetched    | 8850&lt;br /&gt;
tup_inserted   | 16&lt;br /&gt;
tup_updated    | 4&lt;br /&gt;
tup_deleted    | 45&lt;br /&gt;
conflicts      | 0&lt;br /&gt;
temp_files     | 0&lt;br /&gt;
temp_bytes     | 0&lt;br /&gt;
deadlocks      | 0&lt;br /&gt;
blk_read_time  | 583.774&lt;br /&gt;
blk_write_time | 0&lt;br /&gt;
stats_reset    | 2012-07-03 17:18:54.796817+02&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
We see here that mydb has only consumed 583.774 milliseconds of read time.&lt;br /&gt;
&lt;br /&gt;
Explain will benefit from this too:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
=# EXPLAIN (analyze,buffers) SELECT count(*) FROM mots ;&lt;br /&gt;
                                                   QUERY PLAN&lt;br /&gt;
----------------------------------------------------------------------------------------------------------------&lt;br /&gt;
 Aggregate  (cost=1669.95..1669.96 rows=1 width=0) (actual time=21.943..21.943 rows=1 loops=1)&lt;br /&gt;
   Buffers: shared read=493&lt;br /&gt;
   I/O Timings: read=2.578&lt;br /&gt;
   -&amp;gt;  Seq Scan on mots  (cost=0.00..1434.56 rows=94156 width=0) (actual time=0.059..12.933 rows=94156 loops=1)&lt;br /&gt;
         Buffers: shared read=493&lt;br /&gt;
         I/O Timings: read=2.578&lt;br /&gt;
 Total runtime: 22.059 ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
We now have a separate information about the time taken to retrieve data from the operating system. Obviously, here, the data was in the operating system&#039;s cache (2 milliseconds to read 493 blocks).&lt;br /&gt;
&lt;br /&gt;
And last, if you have enabled pg_stat_statements:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
select * from pg_stat_statements where query ~ &#039;words&#039;;&lt;br /&gt;
-[ RECORD 1 ]-------+---------------------------&lt;br /&gt;
userid              | 10&lt;br /&gt;
dbid                | 16384&lt;br /&gt;
query               | select count(*) from words;&lt;br /&gt;
calls               | 2&lt;br /&gt;
total_time          | 78.332&lt;br /&gt;
rows                | 2&lt;br /&gt;
shared_blks_hit     | 0&lt;br /&gt;
shared_blks_read    | 986&lt;br /&gt;
shared_blks_dirtied | 0&lt;br /&gt;
shared_blks_written | 0&lt;br /&gt;
local_blks_hit      | 0&lt;br /&gt;
local_blks_read     | 0&lt;br /&gt;
local_blks_dirtied  | 0&lt;br /&gt;
local_blks_written  | 0&lt;br /&gt;
temp_blks_read      | 0&lt;br /&gt;
temp_blks_written   | 0&lt;br /&gt;
blk_read_time       | 58.427&lt;br /&gt;
blk_write_time      | 0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* As for every version, the optimizer has received its share of improvements &amp;lt;!-- Tom Lane--&amp;gt;&lt;br /&gt;
** Prepared statements used to be optimized once, without any knowledge of the parameters&#039; values. With 9.2, the planner will use specific plans regarding to the parameters sent (the query will be planned at execution), except if the query is executed several times and the planner decides that the generic plan is not too much more expensive than the specific plans.&lt;br /&gt;
** A new feature has been added: parameterized paths. Simply put, it means that a sub-part of a query plan can use parameters it has got from a parent node. It fixes several bad plans that could occur, especially when the optimizer couldn&#039;t reorder joins to put nested loops where it would have been efficient.&lt;br /&gt;
&lt;br /&gt;
This example is straight from the developpers mailing lists &amp;lt;!-- Andres Freund --&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE a (&lt;br /&gt;
    a_id serial PRIMARY KEY NOT NULL,&lt;br /&gt;
    b_id integer&lt;br /&gt;
);&lt;br /&gt;
CREATE INDEX a__b_id ON a USING btree (b_id);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
CREATE TABLE b (&lt;br /&gt;
    b_id serial NOT NULL,&lt;br /&gt;
    c_id integer&lt;br /&gt;
);&lt;br /&gt;
CREATE INDEX b__c_id ON b USING btree (c_id);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
CREATE TABLE c (&lt;br /&gt;
    c_id serial PRIMARY KEY NOT NULL,&lt;br /&gt;
    value integer UNIQUE&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
INSERT INTO b (b_id, c_id)&lt;br /&gt;
    SELECT g.i, g.i FROM generate_series(1, 50000) g(i);&lt;br /&gt;
&lt;br /&gt;
INSERT INTO a(b_id)&lt;br /&gt;
    SELECT g.i FROM generate_series(1, 50000) g(i);&lt;br /&gt;
&lt;br /&gt;
INSERT INTO c(c_id,value)&lt;br /&gt;
    VALUES (1,1);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So we have a referencing b, b referencing c.&lt;br /&gt;
&lt;br /&gt;
Here is an example of a query working badly with PostgreSQL 9.1:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
EXPLAIN ANALYZE SELECT 1&lt;br /&gt;
FROM&lt;br /&gt;
    c&lt;br /&gt;
WHERE&lt;br /&gt;
    EXISTS (&lt;br /&gt;
        SELECT *&lt;br /&gt;
        FROM a&lt;br /&gt;
            JOIN b USING (b_id)&lt;br /&gt;
        WHERE b.c_id = c.c_id)&lt;br /&gt;
    AND c.value = 1;&lt;br /&gt;
                                                      QUERY PLAN&lt;br /&gt;
-----------------------------------------------------------------------------------------------------------------------&lt;br /&gt;
 Nested Loop Semi Join  (cost=1347.00..3702.27 rows=1 width=0) (actual time=13.799..13.802 rows=1 loops=1)&lt;br /&gt;
   Join Filter: (c.c_id = b.c_id)&lt;br /&gt;
   -&amp;gt;  Index Scan using c_value_key on c  (cost=0.00..8.27 rows=1 width=4) (actual time=0.006..0.008 rows=1 loops=1)&lt;br /&gt;
         Index Cond: (value = 1)&lt;br /&gt;
   -&amp;gt;  Hash Join  (cost=1347.00..3069.00 rows=50000 width=4) (actual time=13.788..13.788 rows=1 loops=1)&lt;br /&gt;
         Hash Cond: (a.b_id = b.b_id)&lt;br /&gt;
         -&amp;gt;  Seq Scan on a  (cost=0.00..722.00 rows=50000 width=4) (actual time=0.007..0.007 rows=1 loops=1)&lt;br /&gt;
         -&amp;gt;  Hash  (cost=722.00..722.00 rows=50000 width=8) (actual time=13.760..13.760 rows=50000 loops=1)&lt;br /&gt;
               Buckets: 8192  Batches: 1  Memory Usage: 1954kB&lt;br /&gt;
               -&amp;gt;  Seq Scan on b  (cost=0.00..722.00 rows=50000 width=8) (actual time=0.008..5.702 rows=50000 loops=1)&lt;br /&gt;
 Total runtime: 13.842 ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Not that bad, 13 milliseconds. Still, we are doing sequential scans on a and b, when our common sense tells us that c.value=1 should be used to filter rows more aggressively.&lt;br /&gt;
&lt;br /&gt;
Here&#039;s what 9.2 does with this query:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                                                      QUERY PLAN&lt;br /&gt;
----------------------------------------------------------------------------------------------------------------------------&lt;br /&gt;
 Nested Loop Semi Join  (cost=0.00..16.97 rows=1 width=0) (actual time=0.035..0.037 rows=1 loops=1)&lt;br /&gt;
   -&amp;gt;  Index Scan using c_value_key on c  (cost=0.00..8.27 rows=1 width=4) (actual time=0.007..0.009 rows=1 loops=1)&lt;br /&gt;
         Index Cond: (value = 1)&lt;br /&gt;
   -&amp;gt;  Nested Loop  (cost=0.00..8.69 rows=1 width=4) (actual time=0.025..0.025 rows=1 loops=1)&lt;br /&gt;
         -&amp;gt;  Index Scan using b__c_id on b  (cost=0.00..8.33 rows=1 width=8) (actual time=0.007..0.007 rows=1 loops=1)&lt;br /&gt;
               Index Cond: (c_id = c.c_id)&lt;br /&gt;
         -&amp;gt;  Index Only Scan using a__b_id on a  (cost=0.00..0.35 rows=1 width=4) (actual time=0.014..0.014 rows=1 loops=1)&lt;br /&gt;
               Index Cond: (b_id = b.b_id)&lt;br /&gt;
 Total runtime: 0.089 ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The «parameterized path» is:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   -&amp;gt;  Nested Loop  (cost=0.00..8.69 rows=1 width=4) (actual time=0.025..0.025 rows=1 loops=1)&lt;br /&gt;
         -&amp;gt;  Index Scan using b__c_id on b  (cost=0.00..8.33 rows=1 width=8) (actual time=0.007..0.007 rows=1 loops=1)&lt;br /&gt;
               Index Cond: (c_id = c.c_id)&lt;br /&gt;
         -&amp;gt;  Index Only Scan using a__b_id on a  (cost=0.00..0.35 rows=1 width=4) (actual time=0.014..0.014 rows=1 loops=1)&lt;br /&gt;
               Index Cond: (b_id = b.b_id)&lt;br /&gt;
 Total runtime: 0.089 ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This part of the plan depends on a parent node (c_id=c.c_id). This part of the plan is called each time with a different parameter coming from the parent node.&lt;br /&gt;
&lt;br /&gt;
This plan is of course much faster, as there is no need to fully scan a, and to fully scan AND hash b.&lt;br /&gt;
&lt;br /&gt;
=SP-GiST=&lt;br /&gt;
&lt;br /&gt;
SP-GiST stands for Space Partitionned GiST, GiST being Generalized Search Tree. GiST is an index type, and has been available for quite a while in PostgreSQL. GiST is already very efficient at indexing complex data types, but performance tends to suffer when the source data isn&#039;t uniformly distributed. SP-GiST tries to fix that.&lt;br /&gt;
&lt;br /&gt;
As all indexing methods available in PostgreSQL, SP-GiST is a generic indexing method, meaning its purpose is to index whatever you&#039;ll throw at it, using operators you&#039;ll provide. It means that if you want to create a new datatype, and make it indexable through SP-GiST, you&#039;ll have to follow the documented API.&lt;br /&gt;
&lt;br /&gt;
SP-GiST can be used to implement 3 type of indexes: trie (suffix) indexing, Quadtree (data is divided into quadrants), and k-d tree (k-dimensional tree).&lt;br /&gt;
&lt;br /&gt;
For now, SP-GiST is provided with operator families called &amp;quot;quad_point_ops&amp;quot;, &amp;quot;kd_point_ops&amp;quot; and &amp;quot;text_ops&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
As their names indicate, the first one indexes point types, using a quadtree, the second one indexes point types using a k-d tree, and the third one indexes text, using suffix.&lt;br /&gt;
&lt;br /&gt;
=pg_stat_statements=&lt;br /&gt;
&lt;br /&gt;
This contrib module has received a lot of improvements in this version:&lt;br /&gt;
&lt;br /&gt;
* Queries are normalized: queries that are identical except for their constant values will be considered the same, as long as their post-parse analysis query tree (that is, the internal representation of the query before rule expansion) are the same. This also implies that differences that are not semantically essential to the query, such as variations in whitespace or alias names, or the use of one particular syntax over another equivalent one will not differentiate queries.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
=#SELECT * FROM words WHERE word= &#039;foo&#039;;&lt;br /&gt;
 word &lt;br /&gt;
------&lt;br /&gt;
(0 ligne)&lt;br /&gt;
&lt;br /&gt;
=# SELECT * FROM words WHERE word= &#039;bar&#039;;&lt;br /&gt;
 word &lt;br /&gt;
------&lt;br /&gt;
 bar&lt;br /&gt;
&lt;br /&gt;
=#select * from pg_stat_statements where query like &#039;%words where%&#039;;&lt;br /&gt;
-[ RECORD 1 ]-------+-----------------------------------&lt;br /&gt;
userid              | 10&lt;br /&gt;
dbid                | 16384&lt;br /&gt;
query               | SELECT * FROM words WHERE word= ?;&lt;br /&gt;
calls               | 2&lt;br /&gt;
total_time          | 142.314&lt;br /&gt;
rows                | 1&lt;br /&gt;
shared_blks_hit     | 3&lt;br /&gt;
shared_blks_read    | 5&lt;br /&gt;
shared_blks_dirtied | 0&lt;br /&gt;
shared_blks_written | 0&lt;br /&gt;
local_blks_hit      | 0&lt;br /&gt;
local_blks_read     | 0&lt;br /&gt;
local_blks_dirtied  | 0&lt;br /&gt;
local_blks_written  | 0&lt;br /&gt;
temp_blks_read      | 0&lt;br /&gt;
temp_blks_written   | 0&lt;br /&gt;
blk_read_time       | 142.165&lt;br /&gt;
blk_write_time      | 0&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The two queries are shown as one in pg_stat_statements.&lt;br /&gt;
&lt;br /&gt;
* For prepared statements, the execution part (execute statement) is charged on the prepare statement. That makes it is easier to interpret, and avoids the double-counting there was with PostgreSQL 9.1.&lt;br /&gt;
&lt;br /&gt;
* pg_stat_statements displays timing in milliseconds, to be consistent with other system views.&lt;br /&gt;
&lt;br /&gt;
= Explain improvements=&lt;br /&gt;
&lt;br /&gt;
* Timing can now be disabled with EXPLAIN (analyze on, timing off), leading to lower overhead on platforms where getting the current time is expensive &amp;lt;!--Tomas Vondra--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  =# EXPLAIN (analyze on,timing off) SELECT * FROM reservation ;&lt;br /&gt;
                                       QUERY PLAN                                       &lt;br /&gt;
  ----------------------------------------------------------------------------------------&lt;br /&gt;
   Seq Scan on reservation  (cost=0.00..22.30 rows=1230 width=36) (actual rows=2 loops=1)&lt;br /&gt;
   Total runtime: 0.045 ms&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Have EXPLAIN ANALYZE report the number of rows rejected by filter steps &amp;lt;!--(Marko Tiikkaja)--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This new feature makes it much easier to know how many rows are removed by a filter (and spot potential places to put indexes):&lt;br /&gt;
&lt;br /&gt;
  =# EXPLAIN ANALYZE SELECT * FROM test WHERE a ~ &#039;tra&#039;;&lt;br /&gt;
                                                    QUERY PLAN                                                   &lt;br /&gt;
  ---------------------------------------------------------------------------------------------------------------&lt;br /&gt;
   Seq Scan on test  (cost=0.00..106876.56 rows=2002 width=11) (actual time=2.914..8538.285 rows=120256 loops=1)&lt;br /&gt;
     Filter: (a ~ &#039;tra&#039;::text)&lt;br /&gt;
     Rows Removed by Filter: 5905600&lt;br /&gt;
   Total runtime: 8549.539 ms&lt;br /&gt;
  (4 rows)&lt;br /&gt;
&lt;br /&gt;
=Backward compatibility=&lt;br /&gt;
&lt;br /&gt;
These changes may incur regressions in your applications.&lt;br /&gt;
&lt;br /&gt;
==Ensure that xpath() escapes special characters in string values &amp;lt;!-- (Florian Pflug)--&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Before 9.2:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT (XPATH(&#039;/*/text()&#039;, &#039;&amp;lt;root&amp;gt;&amp;amp;amp;lt;&amp;lt;/root&amp;gt;&#039;))[1];&lt;br /&gt;
 xpath &lt;br /&gt;
-------&lt;br /&gt;
 &amp;lt;&lt;br /&gt;
&lt;br /&gt;
&#039;&amp;lt;&#039; Isn&#039;t valid XML.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
With 9.2:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT (XPATH(&#039;/*/text()&#039;, &#039;&amp;lt;root&amp;gt;&amp;amp;amp;lt;&amp;lt;/root&amp;gt;&#039;))[1];&lt;br /&gt;
 xpath &lt;br /&gt;
-------&lt;br /&gt;
 &amp;amp;amp;lt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Remove hstore&#039;s =&amp;gt; operator &amp;lt;!-- (Robert Haas)--&amp;gt;==&lt;br /&gt;
Up to 9.1, one could use the =&amp;gt; operator to create a hstore. Hstore is a contrib, used to store key/values pairs in a column.&lt;br /&gt;
&lt;br /&gt;
In 9.1:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
=# SELECT &#039;a&#039;=&amp;gt;&#039;b&#039;;&lt;br /&gt;
 ?column? &lt;br /&gt;
----------&lt;br /&gt;
 &amp;quot;a&amp;quot;=&amp;gt;&amp;quot;b&amp;quot;&lt;br /&gt;
(1 row)&lt;br /&gt;
&lt;br /&gt;
=# SELECT pg_typeof(&#039;a&#039;=&amp;gt;&#039;b&#039;);&lt;br /&gt;
 pg_typeof &lt;br /&gt;
-----------&lt;br /&gt;
 hstore&lt;br /&gt;
(1 row)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With 9.2:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT &#039;a&#039;=&amp;gt;&#039;b&#039;;&lt;br /&gt;
ERROR:  operator does not exist: unknown =&amp;gt; unknown at character 11&lt;br /&gt;
HINT:  No operator matches the given name and argument type(s). You might need to add explicit type casts.&lt;br /&gt;
STATEMENT:  SELECT &#039;a&#039;=&amp;gt;&#039;b&#039;;&lt;br /&gt;
ERROR:  operator does not exist: unknown =&amp;gt; unknown&lt;br /&gt;
LINE 1: SELECT &#039;a&#039;=&amp;gt;&#039;b&#039;;&lt;br /&gt;
                  ^&lt;br /&gt;
HINT:  No operator matches the given name and argument type(s). You might need to add explicit type casts.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It doesn&#039;t mean one cannot use &#039;=&amp;gt;&#039; in hstores, it just isn&#039;t an operator anymore:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
=# select hstore(&#039;a=&amp;gt;b&#039;);&lt;br /&gt;
  hstore  &lt;br /&gt;
----------&lt;br /&gt;
 &amp;quot;a&amp;quot;=&amp;gt;&amp;quot;b&amp;quot;&lt;br /&gt;
(1 row)&lt;br /&gt;
&lt;br /&gt;
=# select hstore(&#039;a&#039;,&#039;b&#039;);&lt;br /&gt;
  hstore  &lt;br /&gt;
----------&lt;br /&gt;
 &amp;quot;a&amp;quot;=&amp;gt;&amp;quot;b&amp;quot;&lt;br /&gt;
(1 row)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
are still two valid ways to input a hstore.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;=&amp;gt;&amp;quot; is removed as an operator as it is a reserved keyword in SQL.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Have pg_relation_size() and friends return NULL if the object does not exist  &amp;lt;!-- (Phil Sorber)--&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
A relation could be dropped by a concurrent session, while one was doing a pg_relation_size on it, leading to a SQL exception. Now, it merely returns NULL for this record.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Remove the spclocation field from pg_tablespace &amp;lt;!-- (Magnus Hagander)--&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
The spclocation field provided the real location of the tablespace. It was filled in during the CREATE or ALTER TABLESPACE command. So it could be wrong: somebody just had to shutdown the cluster, move the tablespace&#039;s directory, re-create the symlink in pg_tblspc, and forget to update the spclocation field. The cluster would still run, as the spclocation wasn&#039;t used.&lt;br /&gt;
&lt;br /&gt;
So this field has been removed. To get the tablespace&#039;s location, use pg_tablespace_location():&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
=# SELECT *, pg_tablespace_location(oid) AS spclocation FROM pg_tablespace;&lt;br /&gt;
  spcname   | spcowner | spcacl | spcoptions |  spclocation   &lt;br /&gt;
------------+----------+--------+------------+----------------&lt;br /&gt;
 pg_default |       10 |        |            | &lt;br /&gt;
 pg_global  |       10 |        |            | &lt;br /&gt;
 tmptblspc  |       10 |        |            | /tmp/tmptblspc&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Have EXTRACT of a non-timezone-aware value measure the epoch from local midnight, not UTC midnight &amp;lt;!-- (Tom Lane) --&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
With PostgreSQL 9.1:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
=#SELECT extract(epoch FROM &#039;2012-07-02 00:00:00&#039;::timestamp);&lt;br /&gt;
 date_part  &lt;br /&gt;
------------&lt;br /&gt;
 1341180000&lt;br /&gt;
(1 row)&lt;br /&gt;
&lt;br /&gt;
=# SELECT extract(epoch FROM &#039;2012-07-02 00:00:00&#039;::timestamptz);&lt;br /&gt;
 date_part  &lt;br /&gt;
------------&lt;br /&gt;
 1341180000&lt;br /&gt;
(1 row)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is no difference in behaviour between a timstamp with or without timezone.&lt;br /&gt;
&lt;br /&gt;
With 9.2:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
=#SELECT extract(epoch FROM &#039;2012-07-02 00:00:00&#039;::timestamp);&lt;br /&gt;
 date_part  &lt;br /&gt;
------------&lt;br /&gt;
 1341187200&lt;br /&gt;
(1 row)&lt;br /&gt;
&lt;br /&gt;
=# SELECT extract(epoch FROM &#039;2012-07-02 00:00:00&#039;::timestamptz);&lt;br /&gt;
 date_part  &lt;br /&gt;
------------&lt;br /&gt;
 1341180000&lt;br /&gt;
(1 row)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When the timestamp has no timezone, the epoch is calculated with the &amp;quot;local midnight&amp;quot;, meaning the 1st january of 1970 at midnight, local-time.&lt;br /&gt;
&lt;br /&gt;
==Fix to_date() and to_timestamp() to wrap incomplete dates toward 2020 &amp;lt;!-- (Bruce Momjian)--&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
The wrapping was not consistent between 2 digit dates and 3 digit dates: 2 digit dates always chose the date closest to 2020, 3 digit dates mapped dates from 100 to 999 on 1100 to 1999, and 000 to 099 on 2000 to 2099.&lt;br /&gt;
&lt;br /&gt;
Now PostgreSQL chooses the date closest to 2020, for 2 and 3 digit dates.&lt;br /&gt;
&lt;br /&gt;
With 9.1:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
=# SELECT to_date(&#039;200-07-02&#039;,&#039;YYY-MM-DD&#039;);&lt;br /&gt;
  to_date   &lt;br /&gt;
------------&lt;br /&gt;
 1200-07-02&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With 9.2:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT to_date(&#039;200-07-02&#039;,&#039;YYY-MM-DD&#039;);&lt;br /&gt;
  to_date   &lt;br /&gt;
------------&lt;br /&gt;
 2200-07-02&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==pg_stat_activity and pg_stat_replication&#039;s definitions have changed &amp;lt;!--Magnus Hagander --&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
The view pg_stat_activity has changed. It&#039;s not backward compatible, but let&#039;s see what this new definition brings us:&lt;br /&gt;
&lt;br /&gt;
* current_query disappears and is replaced by two columns:&lt;br /&gt;
** state: is the session running a query, waiting&lt;br /&gt;
** query: what is the last run (or still running if stat is &amp;quot;active&amp;quot;) query&lt;br /&gt;
* The column procpid is renamed to pid, to be consistent with other system views&lt;br /&gt;
&lt;br /&gt;
The benefit is mostly for tracking «idle in transaction» sessions. Up until now, all we could know was that one of these sessions was idle in transaction, meaning it has started a transaction, maybe done some operations, but still not committed. If that session stayed in this state for a while, there was no way of knowing how it got in this state.&lt;br /&gt;
&lt;br /&gt;
Here is an example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
-[ RECORD 1 ]----+---------------------------------&lt;br /&gt;
datid            | 16384&lt;br /&gt;
datname          | postgres&lt;br /&gt;
pid              | 20804&lt;br /&gt;
usesysid         | 10&lt;br /&gt;
usename          | postgres&lt;br /&gt;
application_name | psql&lt;br /&gt;
client_addr      | &lt;br /&gt;
client_hostname  | &lt;br /&gt;
client_port      | -1&lt;br /&gt;
backend_start    | 2012-07-02 15:02:51.146427+02&lt;br /&gt;
xact_start       | 2012-07-02 15:15:28.386865+02&lt;br /&gt;
query_start      | 2012-07-02 15:15:30.410834+02&lt;br /&gt;
state_change     | 2012-07-02 15:15:30.411287+02&lt;br /&gt;
waiting          | f&lt;br /&gt;
state            | idle in transaction&lt;br /&gt;
query            | DELETE FROM test;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With PostgreSQL 9.1, all we would have would be «idle in transaction».&lt;br /&gt;
&lt;br /&gt;
As this change was backward-incompatible, procpid was also renamed to pid, to be more consistent with other system views.&lt;br /&gt;
The view pg_stat_replication has also changed. The column procpid is renamed to pid, to also be consistent with other system views.&lt;br /&gt;
&lt;br /&gt;
==Change all SQL-level statistics timing values to float8-stored milliseconds &amp;lt;!-- (Tom Lane) --&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
pg_stat_user_functions.total_time, pg_stat_user_functions.self_time, pg_stat_xact_user_functions.total_time, pg_stat_xact_user_functions.self_time, and pg_stat_statements.total_time (contrib) are now in milliseconds, to be consistent with the rest of the timing values.&lt;br /&gt;
&lt;br /&gt;
==postgresql.conf parameters changes &amp;lt;!-- (Heikki Linnakangas, Tom Lane, Peter Eisentraut) --&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
* silent_mode has been removed. Use pg_ctl -l postmaster.log&lt;br /&gt;
* wal_sender_delay has been removed. It is no longer needed&lt;br /&gt;
* custom_variable_classes has been removed. All «classes» are accepted without declaration now&lt;br /&gt;
* ssl_ca_file, ssl_cert_file, ssl_crl_file, ssl_key_file have been added, meaning you can now specify the ssl files&lt;br /&gt;
&lt;br /&gt;
= Other new features =&lt;br /&gt;
&lt;br /&gt;
== DROP INDEX CONCURRENTLY ==&lt;br /&gt;
&lt;br /&gt;
The regular DROP INDEX command takes an exclusive lock on the table. Most of the time, this isn&#039;t a problem, because this lock is short-lived. The problem usually occurs when:&lt;br /&gt;
&lt;br /&gt;
* A long-running transaction is running, and has a (shared) lock on the table&lt;br /&gt;
* A DROP INDEX is run on this table in another session, asking for an exclusive lock (and waiting for it, as it won&#039;t be granted until the long-running transaction ends)&lt;br /&gt;
&lt;br /&gt;
At this point, all other transactions needing to take a shared lock on the table (for a simple SELECT for instance) will have to wait too: their lock acquisition is queued after the DROP INDEX&#039;s one.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
DROP INDEX CONCURRENTLY works around this and won&#039;t lock normal DML statements, just as CREATE INDEX CONCURRENTLY. The limitations are also the same: Since you can only DROP one index with the CONCURRENTLY option, and the CASCADE option is not supported.&lt;br /&gt;
&lt;br /&gt;
== NOT VALID CHECK constraints ==&lt;br /&gt;
&lt;br /&gt;
PostgreSQL 9.1 introduced «NOT VALID» foreign keys. This has been extended to CHECK constraints. Adding a «NOT VALID» constraint on a table means that current data won&#039;t be validated, only new and updated rows.&lt;br /&gt;
&lt;br /&gt;
  =# CREATE TABLE test (a int); &lt;br /&gt;
  CREATE TABLE&lt;br /&gt;
  =# INSERT INTO test SELECT generate_series(1,100);&lt;br /&gt;
  INSERT 0 100&lt;br /&gt;
  =# ALTER TABLE test ADD CHECK (a&amp;gt;100) NOT VALID;&lt;br /&gt;
  ALTER TABLE&lt;br /&gt;
  =# INSERT INTO test VALUES (99);&lt;br /&gt;
  ERROR:  new row for relation &amp;quot;test&amp;quot; violates check constraint &amp;quot;test_a_check&amp;quot;&lt;br /&gt;
  DETAIL:  Failing row contains (99).&lt;br /&gt;
  =# INSERT INTO test VALUES (101);&lt;br /&gt;
  INSERT 0 1&lt;br /&gt;
&lt;br /&gt;
Then, later, we can validate the whole table:&lt;br /&gt;
&lt;br /&gt;
  =# ALTER TABLE test VALIDATE CONSTRAINT test_a_check ;&lt;br /&gt;
  ERROR:  check constraint &amp;quot;test_a_check&amp;quot; is violated by some row&lt;br /&gt;
&lt;br /&gt;
Domains, which are types with added constraints, can also be declared as not valid, and validated later.&lt;br /&gt;
&lt;br /&gt;
Check constraints can also be renamed now:&lt;br /&gt;
&lt;br /&gt;
  =# ALTER TABLE test RENAME CONSTRAINT test_a_check TO validate_a;&lt;br /&gt;
  ALTER TABLE&lt;br /&gt;
&lt;br /&gt;
== NO INHERIT constraints ==&lt;br /&gt;
&lt;br /&gt;
Here is another improvement about constraints: they can be declared as not inheritable, which will be useful in partitioned environments. Let&#039;s take PostgreSQL documentation example, and see how it improves the situation:&lt;br /&gt;
&lt;br /&gt;
  CREATE TABLE measurement (&lt;br /&gt;
      city_id         int not null,&lt;br /&gt;
      logdate         date not null,&lt;br /&gt;
      peaktemp        int,&lt;br /&gt;
      unitsales       int,&lt;br /&gt;
      CHECK (logdate IS NULL) NO INHERIT&lt;br /&gt;
  );&lt;br /&gt;
  &lt;br /&gt;
  CREATE TABLE measurement_y2006m02 (&lt;br /&gt;
      CHECK ( logdate &amp;gt;= DATE &#039;2006-02-01&#039; AND logdate &amp;lt; DATE &#039;2006-03-01&#039; )&lt;br /&gt;
  ) INHERITS (measurement);&lt;br /&gt;
  CREATE TABLE measurement_y2006m03 (&lt;br /&gt;
      CHECK ( logdate &amp;gt;= DATE &#039;2006-03-01&#039; AND logdate &amp;lt; DATE &#039;2006-04-01&#039; )&lt;br /&gt;
  ) INHERITS (measurement);&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  INSERT INTO measurement VALUES (1,&#039;2006-02-20&#039;,1,1);&lt;br /&gt;
  ERROR:  new row for relation &amp;quot;measurement&amp;quot; violates check constraint &amp;quot;measurement_logdate_check&amp;quot;&lt;br /&gt;
  DETAIL:  Failing row contains (1, 2006-02-20, 1, 1).&lt;br /&gt;
  INSERT INTO measurement_y2006m02 VALUES (1,&#039;2006-02-20&#039;,1,1);&lt;br /&gt;
  INSERT 0 1&lt;br /&gt;
&lt;br /&gt;
Until now, every check constraint created on measurement would have been inherited by children tables. So adding a constraint forbidding inserts, or allowing only some of them, on the parent table was impossible.&lt;br /&gt;
&lt;br /&gt;
== Reduce ALTER TABLE rewrites ==&lt;br /&gt;
&lt;br /&gt;
A table won&#039;t get rewritten anymore during an ALTER TABLE when changing the type of a column in the following cases:&lt;br /&gt;
&lt;br /&gt;
* varchar(x) to varchar(y) when y&amp;gt;=x. It works too if going from varchar(x) to varchar or text (no size limitation)&lt;br /&gt;
* numeric(x,z) to numeric(y,z) when y&amp;gt;=x, or to numeric without specifier&lt;br /&gt;
* varbit(x) to varbit(y) when y&amp;gt;=x, or to varbit without specifier&lt;br /&gt;
* timestamp(x) to timestamp(y) when y&amp;gt;=x or timestamp without specifier&lt;br /&gt;
* timestamptz(x) to timestamptz(y) when y&amp;gt;=x or timestamptz without specifier&lt;br /&gt;
* interval(x) to interval(y) when y&amp;gt;=x or interval without specifier&lt;br /&gt;
&lt;br /&gt;
== Security barriers and Leakproof ==&lt;br /&gt;
&lt;br /&gt;
This new feature has to do with views security. First, let&#039;s explain the problem, with a very simplified example:&lt;br /&gt;
&lt;br /&gt;
  =# CREATE TABLE all_data (company_id int, company_data varchar);&lt;br /&gt;
  CREATE TABLE&lt;br /&gt;
  =# INSERT INTO all_data VALUES (1,&#039;secret_data_for_company_1&#039;);&lt;br /&gt;
  INSERT 0 1&lt;br /&gt;
  =# INSERT INTO all_data VALUES (2,&#039;secret_data_for_company_2&#039;);&lt;br /&gt;
  INSERT 0 1&lt;br /&gt;
  =# CREATE VIEW company1_data AS SELECT * FROM all_data WHERE company_id = 1;&lt;br /&gt;
  CREATE VIEW&lt;br /&gt;
&lt;br /&gt;
This is a quite classical way of giving access to only a part of a table to a user: we&#039;ll create a user for company_id 1, grant to him the right to access company1_data, and deny him the right to access all_data.&lt;br /&gt;
&lt;br /&gt;
The plan to this query is the following:&lt;br /&gt;
&lt;br /&gt;
  =# explain SELECT * FROM company1_data ;&lt;br /&gt;
                          QUERY PLAN                        &lt;br /&gt;
  ----------------------------------------------------------&lt;br /&gt;
   Seq Scan on all_data  (cost=0.00..25.38 rows=6 width=36)&lt;br /&gt;
     Filter: (company_id = 1)&lt;br /&gt;
&lt;br /&gt;
Even if there was more data, a sequential scan could still be forced: just &amp;quot;SET enable_indexscan to OFF&amp;quot; and the likes.&lt;br /&gt;
&lt;br /&gt;
So this query reads all the records from all_data, filters them, and returns to the user only the matching rows. There is a way to display scanned records before they are filtered: just create a function with a very low cost, and call it while doing the query:&lt;br /&gt;
&lt;br /&gt;
  CREATE OR REPLACE FUNCTION peek(text) RETURNS boolean LANGUAGE plpgsql AS&lt;br /&gt;
  $$&lt;br /&gt;
  BEGIN&lt;br /&gt;
    RAISE NOTICE &#039;%&#039;,$1;&lt;br /&gt;
    RETURN true;&lt;br /&gt;
  END&lt;br /&gt;
  $$&lt;br /&gt;
  COST 0.1;&lt;br /&gt;
&lt;br /&gt;
This function just has to cost less than the = operator, which costs 1, to be executed first.&lt;br /&gt;
&lt;br /&gt;
The result is this:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  =# SELECT * FROM company1_data WHERE peek(company1_data.company_data);&lt;br /&gt;
  NOTICE:  secret_data_for_company_1&lt;br /&gt;
  NOTICE:  secret_data_for_company_2&lt;br /&gt;
   company_id |       company_data        &lt;br /&gt;
  ------------+---------------------------&lt;br /&gt;
            1 | secret_data_for_company_1&lt;br /&gt;
  (1 row)&lt;br /&gt;
&lt;br /&gt;
We got access to the record from the second company (in the NOTICE messages).&lt;br /&gt;
&lt;br /&gt;
So this is the first new feature: the view can be declared as implementing &amp;quot;security barriers&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  =# CREATE VIEW company1_data WITH (security_barrier) AS SELECT * FROM all_data WHERE company_id = 1;&lt;br /&gt;
  CREATE VIEW&lt;br /&gt;
  =# SELECT * FROM company1_data WHERE peek(company1_data.company_data);&lt;br /&gt;
  NOTICE:  secret_data_for_company_1&lt;br /&gt;
   company_id |       company_data        &lt;br /&gt;
  ------------+---------------------------&lt;br /&gt;
            1 | secret_data_for_company_1&lt;br /&gt;
  (1 row)&lt;br /&gt;
&lt;br /&gt;
The view is not leaking anymore. The problem, of course, is that there is a performance impact: maybe the &amp;quot;peek&amp;quot; function could have made the query faster, by filtering lots of rows early in the plan. The rows are now filtered in two separate plan steps:&lt;br /&gt;
&lt;br /&gt;
  =# explain SELECT * FROM company1_data WHERE peek(company1_data.company_data);&lt;br /&gt;
                               QUERY PLAN                             &lt;br /&gt;
  --------------------------------------------------------------------&lt;br /&gt;
   Subquery Scan on company1_data  (cost=0.00..25.44 rows=2 width=36)&lt;br /&gt;
     Filter: peek((company1_data.company_data)::text)&lt;br /&gt;
     -&amp;gt;  Seq Scan on all_data  (cost=0.00..25.38 rows=6 width=36)&lt;br /&gt;
           Filter: (company_id = 1)&lt;br /&gt;
  (4 rows)&lt;br /&gt;
&lt;br /&gt;
This leads to the complementary feature: some function may be declared as &amp;quot;LEAKPROOF&amp;quot;, meaning that they won&#039;t leak the data they are passed into error or notice messages.&lt;br /&gt;
&lt;br /&gt;
Declaring our peek function as LEAKPROOF is a very bad idea, but let&#039;s do it just to demonstrate how it&#039;s used:&lt;br /&gt;
&lt;br /&gt;
  CREATE OR REPLACE FUNCTION peek(text) RETURNS boolean LEAKPROOF LANGUAGE plpgsql AS&lt;br /&gt;
  $$&lt;br /&gt;
  BEGIN&lt;br /&gt;
    RAISE NOTICE &#039;%&#039;,$1;&lt;br /&gt;
    RETURN true;&lt;br /&gt;
  END&lt;br /&gt;
  $$&lt;br /&gt;
  COST 0.1;&lt;br /&gt;
&lt;br /&gt;
A LEAKPROOF function is executed «normally»:&lt;br /&gt;
&lt;br /&gt;
  =# SELECT * FROM company1_data WHERE peek(company1_data.company_data);&lt;br /&gt;
  NOTICE:  secret_data_for_company_1&lt;br /&gt;
  NOTICE:  secret_data_for_company_2&lt;br /&gt;
   company_id |       company_data        &lt;br /&gt;
  ------------+---------------------------&lt;br /&gt;
            1 | secret_data_for_company_1&lt;br /&gt;
  (1 row)&lt;br /&gt;
&lt;br /&gt;
Of course, in our case, peek isn&#039;t LEAKPROOF and shouldn&#039;t be declared as such. Only superuser have the permission to declare a LEAKPROOF function.&lt;br /&gt;
&lt;br /&gt;
== New options for pg_dump ==&lt;br /&gt;
&lt;br /&gt;
Until now, one could ask pg_dump to dump a table&#039;s data, or a table&#039;s meta-data (DDL statements for creating the table&#039;s structure, indexes, constraints). Some meta-data is better restored before the data (the table&#039;s structure, check constraints), some is better after the data (indexes, unique constraints, foreign keys…), for performance reasons mostly.&lt;br /&gt;
&lt;br /&gt;
So there are now a few more options:&lt;br /&gt;
&lt;br /&gt;
* --section=pre-data: dump what&#039;s needed before restoring the data. Of course, this can be combined with a -t for instance, to specify only one table&lt;br /&gt;
* --section=post-data : dump what&#039;s needed after restoring the data.&lt;br /&gt;
* --section=data: dump the data&lt;br /&gt;
* --exclude-table-data: dump everything, except THIS table&#039;s data. It means pg_dump will still dump other tables&#039; data.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:PostgreSQL 9.2]]&lt;/div&gt;</summary>
		<author><name>Intgr</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=Using_pg_upgrade_on_Ubuntu/Debian&amp;diff=18159</id>
		<title>Using pg upgrade on Ubuntu/Debian</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=Using_pg_upgrade_on_Ubuntu/Debian&amp;diff=18159"/>
		<updated>2012-09-03T10:03:34Z</updated>

		<summary type="html">&lt;p&gt;Intgr: /* What next */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Instructions for how to convert/upgrade a PostgreSQL database cluster using pg_upgrade on Ubuntu or Debian. For the sake of example, I&#039;m upgrading from version 9.1 to 9.2, but it should work with any version. Replace any version numbers on the command lines.&lt;br /&gt;
&lt;br /&gt;
== WARNING! ==&lt;br /&gt;
&#039;&#039;&#039;These instructions are experimental!&#039;&#039;&#039;&lt;br /&gt;
* This way of upgrading is not yet supported by Ubuntu upstream. Do it at your own risk. I have tested this on Ubuntu 12.04.&lt;br /&gt;
* PostgreSQL 9.2 is still a testing release (currently at RC 1). Do not run it in production!&lt;br /&gt;
&lt;br /&gt;
When in doubt, use the old but slower pg_upgradecluster method.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
First you need to install relevant packages: postgresql-VER and postgresql-server-dev-VER. If you&#039;re using contrib extensions, you also need postgresql-contrib-VER, and possibly other modules like postgresql-plpython-VER...&lt;br /&gt;
&lt;br /&gt;
 sudo apt-get install postgresql-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; \&lt;br /&gt;
                      postgresql-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By default, Ubuntu creates a database cluster named &amp;quot;main&amp;quot; with each installed version. We will use these. Verify that these are configured:&lt;br /&gt;
&lt;br /&gt;
 # sudo pg_lsclusters&lt;br /&gt;
 Version Cluster   Port Status Owner    Data directory                     Log file&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      5432 down   postgres /var/lib/postgresql/9.1/main       /var/log/postgresql/postgresql-9.1-main.log&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      5433 down   postgres /var/lib/postgresql/9.2/main       /var/log/postgresql/postgresql-9.2-main.log&lt;br /&gt;
&lt;br /&gt;
== Upgrading ==&lt;br /&gt;
First you need to stop the relevant database clusters. To stop all clusters, run:&lt;br /&gt;
&lt;br /&gt;
 sudo /etc/init.d/postgresql stop&lt;br /&gt;
&lt;br /&gt;
(If you don&#039;t want to stop all clusters, you can also use pg_ctlcluster to manage them one by one)&lt;br /&gt;
&lt;br /&gt;
Do the upgrade... (For extra performance, you can use the --link option to pg_upgrade; please [http://www.postgresql.org/docs/current/static/pgupgrade.html read pg_upgrade documentation first])&lt;br /&gt;
&lt;br /&gt;
 cd /tmp&lt;br /&gt;
 sudo -H -u postgres /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/bin/pg_upgrade \&lt;br /&gt;
    -b /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -B /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -d /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -D /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -o &#039;-c config_file=/etc/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf&#039; \&lt;br /&gt;
    -O &#039;-c config_file=/etc/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf -F&#039;&lt;br /&gt;
&lt;br /&gt;
See if it worked...&lt;br /&gt;
&lt;br /&gt;
 sudo pg_ctlcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; start&lt;br /&gt;
 sudo -u postgres psql --cluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 postgres=# select version();&lt;br /&gt;
 PostgreSQL 9.2rc1 on x86_64-unknown-linux-gnu, compiled by gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3, 64-bit&lt;br /&gt;
 postgres=# \l+&lt;br /&gt;
 ... list of databases ...&lt;br /&gt;
&lt;br /&gt;
== What next ==&lt;br /&gt;
Don&#039;t forget to merge your configuration changes in postgresql.conf, pg_hba.conf and other files.&lt;br /&gt;
&lt;br /&gt;
If you upgraded from 9.0 or earlier and you&#039;re using contrib modules or other addons, it is recommended to migrate them to proper extensions. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;CREATE EXTENSION hstore SCHEMA public FROM unpackaged;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
==== New cluster database &amp;quot;XXX&amp;quot; is not empty ====&lt;br /&gt;
The new cluster version already contains some data. For example, if you want to &#039;&#039;&#039;delete all data&#039;&#039;&#039; in the 9.2 version cluster, run:&lt;br /&gt;
&lt;br /&gt;
 pg_dropcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
 pg_createcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Where do I get PostgreSQL 9.2? ====&lt;br /&gt;
On Ubuntu, you can simply install 9.2 from the semi-official &amp;quot;PPA&amp;quot; repository:&lt;br /&gt;
&lt;br /&gt;
 sudo apt-get install python-software-properties&lt;br /&gt;
 sudo apt-add-repository ppa:pitti/postgresql&lt;br /&gt;
 sudo apt-get update&lt;br /&gt;
 sudo apt-get install postgresql-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;&lt;/div&gt;</summary>
		<author><name>Intgr</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=Using_pg_upgrade_on_Ubuntu/Debian&amp;diff=18158</id>
		<title>Using pg upgrade on Ubuntu/Debian</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=Using_pg_upgrade_on_Ubuntu/Debian&amp;diff=18158"/>
		<updated>2012-09-03T09:59:15Z</updated>

		<summary type="html">&lt;p&gt;Intgr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Instructions for how to convert/upgrade a PostgreSQL database cluster using pg_upgrade on Ubuntu or Debian. For the sake of example, I&#039;m upgrading from version 9.1 to 9.2, but it should work with any version. Replace any version numbers on the command lines.&lt;br /&gt;
&lt;br /&gt;
== WARNING! ==&lt;br /&gt;
&#039;&#039;&#039;These instructions are experimental!&#039;&#039;&#039;&lt;br /&gt;
* This way of upgrading is not yet supported by Ubuntu upstream. Do it at your own risk. I have tested this on Ubuntu 12.04.&lt;br /&gt;
* PostgreSQL 9.2 is still a testing release (currently at RC 1). Do not run it in production!&lt;br /&gt;
&lt;br /&gt;
When in doubt, use the old but slower pg_upgradecluster method.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
First you need to install relevant packages: postgresql-VER and postgresql-server-dev-VER. If you&#039;re using contrib extensions, you also need postgresql-contrib-VER, and possibly other modules like postgresql-plpython-VER...&lt;br /&gt;
&lt;br /&gt;
 sudo apt-get install postgresql-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; \&lt;br /&gt;
                      postgresql-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By default, Ubuntu creates a database cluster named &amp;quot;main&amp;quot; with each installed version. We will use these. Verify that these are configured:&lt;br /&gt;
&lt;br /&gt;
 # sudo pg_lsclusters&lt;br /&gt;
 Version Cluster   Port Status Owner    Data directory                     Log file&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      5432 down   postgres /var/lib/postgresql/9.1/main       /var/log/postgresql/postgresql-9.1-main.log&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      5433 down   postgres /var/lib/postgresql/9.2/main       /var/log/postgresql/postgresql-9.2-main.log&lt;br /&gt;
&lt;br /&gt;
== Upgrading ==&lt;br /&gt;
First you need to stop the relevant database clusters. To stop all clusters, run:&lt;br /&gt;
&lt;br /&gt;
 sudo /etc/init.d/postgresql stop&lt;br /&gt;
&lt;br /&gt;
(If you don&#039;t want to stop all clusters, you can also use pg_ctlcluster to manage them one by one)&lt;br /&gt;
&lt;br /&gt;
Do the upgrade... (For extra performance, you can use the --link option to pg_upgrade; please [http://www.postgresql.org/docs/current/static/pgupgrade.html read pg_upgrade documentation first])&lt;br /&gt;
&lt;br /&gt;
 cd /tmp&lt;br /&gt;
 sudo -H -u postgres /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/bin/pg_upgrade \&lt;br /&gt;
    -b /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -B /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -d /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -D /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -o &#039;-c config_file=/etc/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf&#039; \&lt;br /&gt;
    -O &#039;-c config_file=/etc/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf -F&#039;&lt;br /&gt;
&lt;br /&gt;
See if it worked...&lt;br /&gt;
&lt;br /&gt;
 sudo pg_ctlcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; start&lt;br /&gt;
 sudo -u postgres psql --cluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 postgres=# select version();&lt;br /&gt;
 PostgreSQL 9.2rc1 on x86_64-unknown-linux-gnu, compiled by gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3, 64-bit&lt;br /&gt;
 postgres=# \l+&lt;br /&gt;
 ... list of databases ...&lt;br /&gt;
&lt;br /&gt;
== What next ==&lt;br /&gt;
Don&#039;t forget to merge your configuration changes in postgresql.conf, pg_hba.conf and other files.&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
==== New cluster database &amp;quot;XXX&amp;quot; is not empty ====&lt;br /&gt;
The new cluster version already contains some data. For example, if you want to &#039;&#039;&#039;delete all data&#039;&#039;&#039; in the 9.2 version cluster, run:&lt;br /&gt;
&lt;br /&gt;
 pg_dropcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
 pg_createcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Where do I get PostgreSQL 9.2? ====&lt;br /&gt;
On Ubuntu, you can simply install 9.2 from the semi-official &amp;quot;PPA&amp;quot; repository:&lt;br /&gt;
&lt;br /&gt;
 sudo apt-get install python-software-properties&lt;br /&gt;
 sudo apt-add-repository ppa:pitti/postgresql&lt;br /&gt;
 sudo apt-get update&lt;br /&gt;
 sudo apt-get install postgresql-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;&lt;/div&gt;</summary>
		<author><name>Intgr</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=Using_pg_upgrade_on_Ubuntu/Debian&amp;diff=18112</id>
		<title>Using pg upgrade on Ubuntu/Debian</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=Using_pg_upgrade_on_Ubuntu/Debian&amp;diff=18112"/>
		<updated>2012-08-29T18:28:12Z</updated>

		<summary type="html">&lt;p&gt;Intgr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Instructions for how to convert/upgrade a PostgreSQL database cluster using pg_upgrade on Ubuntu or Debian. For the sake of example, I&#039;m upgrading from version 9.1 to 9.2, but it should work with any version. Replace any version numbers on the command lines.&lt;br /&gt;
&lt;br /&gt;
== WARNING! ==&lt;br /&gt;
&#039;&#039;&#039;These instructions are experimental!&#039;&#039;&#039;&lt;br /&gt;
* This way of upgrading is not yet supported by Ubuntu upstream. Do it at your own risk. I have tested this on Ubuntu 12.04.&lt;br /&gt;
* PostgreSQL 9.2 is still a testing release (currently at RC 1). Do not run it in production!&lt;br /&gt;
&lt;br /&gt;
When in doubt, use the old but slower pg_upgradecluster method.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
First you need to install relevant packages: postgresql-VER and postgresql-server-dev-VER. If you&#039;re using contrib extensions, you also need postgresql-contrib-VER, and possibly other modules like postgresql-plpython-VER...&lt;br /&gt;
&lt;br /&gt;
 sudo apt-get install postgresql-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; \&lt;br /&gt;
                      postgresql-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By default, Ubuntu creates a database cluster named &amp;quot;main&amp;quot; with each installed version. We will use these. Verify that these are configured:&lt;br /&gt;
&lt;br /&gt;
 # sudo pg_lsclusters&lt;br /&gt;
 Version Cluster   Port Status Owner    Data directory                     Log file&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      5432 down   postgres /var/lib/postgresql/9.1/main       /var/log/postgresql/postgresql-9.1-main.log&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      5433 down   postgres /var/lib/postgresql/9.2/main       /var/log/postgresql/postgresql-9.2-main.log&lt;br /&gt;
&lt;br /&gt;
== Upgrading ==&lt;br /&gt;
First you need to stop the relevant database clusters. To stop all clusters, run:&lt;br /&gt;
&lt;br /&gt;
 sudo /etc/init.d/postgresql stop&lt;br /&gt;
&lt;br /&gt;
(If you don&#039;t want to stop all clusters, you can also use pg_ctlcluster to manage them one by one)&lt;br /&gt;
&lt;br /&gt;
Do the upgrade... (For extra performance, you can use the --link option to pg_upgrade; please [http://www.postgresql.org/docs/current/static/pgupgrade.html read pg_upgrade documentation first])&lt;br /&gt;
&lt;br /&gt;
 cd /tmp&lt;br /&gt;
 sudo -H -u postgres /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/bin/pg_upgrade \&lt;br /&gt;
    -b /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -B /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -d /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -D /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -o &#039;-c config_file=/etc/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf&#039; \&lt;br /&gt;
    -O &#039;-c config_file=/etc/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf -F&#039;&lt;br /&gt;
&lt;br /&gt;
See if it worked...&lt;br /&gt;
&lt;br /&gt;
 sudo pg_ctlcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; start&lt;br /&gt;
 sudo -u postgres psql --cluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 postgres=# select version();&lt;br /&gt;
 PostgreSQL 9.2rc1 on x86_64-unknown-linux-gnu, compiled by gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3, 64-bit&lt;br /&gt;
 postgres=# \l+&lt;br /&gt;
 ... list of databases ...&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
==== New cluster database &amp;quot;XXX&amp;quot; is not empty ====&lt;br /&gt;
The new cluster version already contains some data. For example, if you want to &#039;&#039;&#039;delete all data&#039;&#039;&#039; in the 9.2 version cluster, run:&lt;br /&gt;
&lt;br /&gt;
 pg_dropcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
 pg_createcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Where do I get PostgreSQL 9.2? ====&lt;br /&gt;
On Ubuntu, you can simply install 9.2 from the semi-official &amp;quot;PPA&amp;quot; repository:&lt;br /&gt;
&lt;br /&gt;
 sudo apt-get install python-software-properties&lt;br /&gt;
 sudo apt-add-repository ppa:pitti/postgresql&lt;br /&gt;
 sudo apt-get update&lt;br /&gt;
 sudo apt-get install postgresql-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;&lt;/div&gt;</summary>
		<author><name>Intgr</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=Using_pg_upgrade_on_Ubuntu/Debian&amp;diff=18111</id>
		<title>Using pg upgrade on Ubuntu/Debian</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=Using_pg_upgrade_on_Ubuntu/Debian&amp;diff=18111"/>
		<updated>2012-08-29T18:26:55Z</updated>

		<summary type="html">&lt;p&gt;Intgr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Instructions for how to convert/upgrade a PostgreSQL database cluster using pg_upgrade on Ubuntu or Debian. For the sake of example, I&#039;m upgrading from version 9.1 to 9.2, but it should work with any version. Replace any version numbers on the command lines.&lt;br /&gt;
&lt;br /&gt;
== WARNING! ==&lt;br /&gt;
&#039;&#039;&#039;These instructions are experimental!&#039;&#039;&#039;&lt;br /&gt;
* This way of upgrading is not yet supported by Ubuntu upstream. Do it at your own risk. I have only tested this on Ubuntu 12.04.&lt;br /&gt;
* PostgreSQL 9.2 is still a testing release (currently at RC 1). Do not run it in production!&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
First you need to install relevant packages: postgresql-VER and postgresql-server-dev-VER. If you&#039;re using contrib extensions, you also need postgresql-contrib-VER, and possibly other modules like postgresql-plpython-VER...&lt;br /&gt;
&lt;br /&gt;
 sudo apt-get install postgresql-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; \&lt;br /&gt;
                      postgresql-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By default, Ubuntu creates a database cluster named &amp;quot;main&amp;quot; with each installed version. We will use these. Verify that these are configured:&lt;br /&gt;
&lt;br /&gt;
 # sudo pg_lsclusters&lt;br /&gt;
 Version Cluster   Port Status Owner    Data directory                     Log file&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      5432 down   postgres /var/lib/postgresql/9.1/main       /var/log/postgresql/postgresql-9.1-main.log&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      5433 down   postgres /var/lib/postgresql/9.2/main       /var/log/postgresql/postgresql-9.2-main.log&lt;br /&gt;
&lt;br /&gt;
== Upgrading ==&lt;br /&gt;
First you need to stop the relevant database clusters. To stop all clusters, run:&lt;br /&gt;
&lt;br /&gt;
 sudo /etc/init.d/postgresql stop&lt;br /&gt;
&lt;br /&gt;
(If you don&#039;t want to stop all clusters, you can also use pg_ctlcluster to manage them one by one)&lt;br /&gt;
&lt;br /&gt;
Do the upgrade... (For extra performance, you can use the --link option to pg_upgrade; please [http://www.postgresql.org/docs/current/static/pgupgrade.html read pg_upgrade documentation first])&lt;br /&gt;
&lt;br /&gt;
 cd /tmp&lt;br /&gt;
 sudo -H -u postgres /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/bin/pg_upgrade \&lt;br /&gt;
    -b /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -B /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -d /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -D /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -o &#039;-c config_file=/etc/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf&#039; \&lt;br /&gt;
    -O &#039;-c config_file=/etc/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf -F&#039;&lt;br /&gt;
&lt;br /&gt;
See if it worked...&lt;br /&gt;
&lt;br /&gt;
 sudo pg_ctlcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; start&lt;br /&gt;
 sudo -u postgres psql --cluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 postgres=# select version();&lt;br /&gt;
 PostgreSQL 9.2rc1 on x86_64-unknown-linux-gnu, compiled by gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3, 64-bit&lt;br /&gt;
 postgres=# \l+&lt;br /&gt;
 ... list of databases ...&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
==== New cluster database &amp;quot;XXX&amp;quot; is not empty ====&lt;br /&gt;
The new cluster version already contains some data. For example, if you want to &#039;&#039;&#039;delete all data&#039;&#039;&#039; in the 9.2 version cluster, run:&lt;br /&gt;
&lt;br /&gt;
 pg_dropcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
 pg_createcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Where do I get PostgreSQL 9.2? ====&lt;br /&gt;
On Ubuntu, you can simply install 9.2 from the semi-official &amp;quot;PPA&amp;quot; repository:&lt;br /&gt;
&lt;br /&gt;
 sudo apt-get install python-software-properties&lt;br /&gt;
 sudo apt-add-repository ppa:pitti/postgresql&lt;br /&gt;
 sudo apt-get update&lt;br /&gt;
 sudo apt-get install postgresql-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;&lt;/div&gt;</summary>
		<author><name>Intgr</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=Using_pg_upgrade_on_Ubuntu/Debian&amp;diff=18110</id>
		<title>Using pg upgrade on Ubuntu/Debian</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=Using_pg_upgrade_on_Ubuntu/Debian&amp;diff=18110"/>
		<updated>2012-08-29T17:51:18Z</updated>

		<summary type="html">&lt;p&gt;Intgr: /* Upgrading */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Instructions for how to convert/upgrade a PostgreSQL database cluster using pg_upgrade on Ubuntu or Debian. For the sake of example, I&#039;m upgrading from version 9.1 to 9.2, but it should work with any version. Replace any version numbers on the command lines.&lt;br /&gt;
&lt;br /&gt;
== WARNING! ==&lt;br /&gt;
&#039;&#039;&#039;These instructions are experimental!&#039;&#039;&#039;&lt;br /&gt;
* This way of upgrading is not yet supported by Ubuntu upstream. Do it at your own risk. I have only tested this on Ubuntu 12.04.&lt;br /&gt;
* PostgreSQL 9.2 is still a testing release (currently at RC 1). Do not run it in production!&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
First you need to install relevant packages: postgresql-VER and postgresql-server-dev-VER. If you&#039;re using contrib extensions, you also need postgresql-contrib-VER, and possibly other modules like postgresql-plpython-VER...&lt;br /&gt;
&lt;br /&gt;
 sudo apt-get install postgresql-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; \&lt;br /&gt;
                      postgresql-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By default, Ubuntu creates a database cluster named &amp;quot;main&amp;quot; with each installed version. We will use these. Verify that these are configured:&lt;br /&gt;
&lt;br /&gt;
 # sudo pg_lsclusters&lt;br /&gt;
 Version Cluster   Port Status Owner    Data directory                     Log file&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      5432 down   postgres /var/lib/postgresql/9.1/main       /var/log/postgresql/postgresql-9.1-main.log&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      5433 down   postgres /var/lib/postgresql/9.2/main       /var/log/postgresql/postgresql-9.2-main.log&lt;br /&gt;
&lt;br /&gt;
== Upgrading ==&lt;br /&gt;
First you need to stop the relevant database clusters. To stop all clusters, run:&lt;br /&gt;
&lt;br /&gt;
 sudo /etc/init.d/postgresql stop&lt;br /&gt;
&lt;br /&gt;
(If you don&#039;t want to stop all clusters, you can also use pg_ctlcluster to manage them one by one)&lt;br /&gt;
&lt;br /&gt;
Do the upgrade....&lt;br /&gt;
&lt;br /&gt;
 cd /tmp&lt;br /&gt;
 sudo -H -u postgres /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/bin/pg_upgrade \&lt;br /&gt;
    -b /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -B /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -d /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -D /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -o &#039;-c config_file=/etc/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf&#039; \&lt;br /&gt;
    -O &#039;-c config_file=/etc/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf&#039;&lt;br /&gt;
&lt;br /&gt;
See if it worked...&lt;br /&gt;
&lt;br /&gt;
 sudo pg_ctlcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; start&lt;br /&gt;
 sudo -u postgres psql --cluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 postgres=# select version();&lt;br /&gt;
 PostgreSQL 9.2rc1 on x86_64-unknown-linux-gnu, compiled by gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3, 64-bit&lt;br /&gt;
 postgres=# \l+&lt;br /&gt;
 ... list of databases ...&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
==== New cluster database &amp;quot;XXX&amp;quot; is not empty ====&lt;br /&gt;
The new cluster version already contains some data. For example, if you want to &#039;&#039;&#039;delete all data&#039;&#039;&#039; in the 9.2 version cluster, run:&lt;br /&gt;
&lt;br /&gt;
 pg_dropcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
 pg_createcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Where do I get PostgreSQL 9.2? ====&lt;br /&gt;
On Ubuntu, you can simply install 9.2 from the semi-official &amp;quot;PPA&amp;quot; repository:&lt;br /&gt;
&lt;br /&gt;
 sudo apt-get install python-software-properties&lt;br /&gt;
 sudo apt-add-repository ppa:pitti/postgresql&lt;br /&gt;
 sudo apt-get update&lt;br /&gt;
 sudo apt-get install postgresql-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;&lt;/div&gt;</summary>
		<author><name>Intgr</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=Using_pg_upgrade_on_Ubuntu/Debian&amp;diff=18109</id>
		<title>Using pg upgrade on Ubuntu/Debian</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=Using_pg_upgrade_on_Ubuntu/Debian&amp;diff=18109"/>
		<updated>2012-08-29T17:50:35Z</updated>

		<summary type="html">&lt;p&gt;Intgr: /* Prerequisites */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Instructions for how to convert/upgrade a PostgreSQL database cluster using pg_upgrade on Ubuntu or Debian. For the sake of example, I&#039;m upgrading from version 9.1 to 9.2, but it should work with any version. Replace any version numbers on the command lines.&lt;br /&gt;
&lt;br /&gt;
== WARNING! ==&lt;br /&gt;
&#039;&#039;&#039;These instructions are experimental!&#039;&#039;&#039;&lt;br /&gt;
* This way of upgrading is not yet supported by Ubuntu upstream. Do it at your own risk. I have only tested this on Ubuntu 12.04.&lt;br /&gt;
* PostgreSQL 9.2 is still a testing release (currently at RC 1). Do not run it in production!&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
First you need to install relevant packages: postgresql-VER and postgresql-server-dev-VER. If you&#039;re using contrib extensions, you also need postgresql-contrib-VER, and possibly other modules like postgresql-plpython-VER...&lt;br /&gt;
&lt;br /&gt;
 sudo apt-get install postgresql-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; \&lt;br /&gt;
                      postgresql-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By default, Ubuntu creates a database cluster named &amp;quot;main&amp;quot; with each installed version. We will use these. Verify that these are configured:&lt;br /&gt;
&lt;br /&gt;
 # sudo pg_lsclusters&lt;br /&gt;
 Version Cluster   Port Status Owner    Data directory                     Log file&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      5432 down   postgres /var/lib/postgresql/9.1/main       /var/log/postgresql/postgresql-9.1-main.log&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      5433 down   postgres /var/lib/postgresql/9.2/main       /var/log/postgresql/postgresql-9.2-main.log&lt;br /&gt;
&lt;br /&gt;
== Upgrading ==&lt;br /&gt;
First you need to stop the relevant database clusters. To stop all clusters, run:&lt;br /&gt;
&lt;br /&gt;
 sudo /etc/init.d/postgresql stop&lt;br /&gt;
&lt;br /&gt;
(If you don&#039;t want to stop all clusters, you can also use pg_ctlcluster to manage them one by one)&lt;br /&gt;
&lt;br /&gt;
Do the upgrade....&lt;br /&gt;
&lt;br /&gt;
 cd /tmp&lt;br /&gt;
 sudo -H -u postgres /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/bin/pg_upgrade \&lt;br /&gt;
    -b /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -B /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -d /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -D /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -o &#039;-c config_file=/etc/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf&#039; \&lt;br /&gt;
    -O &#039;-c config_file=/etc/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf&#039;&lt;br /&gt;
&lt;br /&gt;
See if it worked...&lt;br /&gt;
&lt;br /&gt;
 sudo pg_ctlcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; start&lt;br /&gt;
 sudo -u postgres psql --cluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 postgres=# select version();&lt;br /&gt;
 PostgreSQL 9.2rc1 on x86_64-unknown-linux-gnu, compiled by gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3, 64-bit&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
==== New cluster database &amp;quot;XXX&amp;quot; is not empty ====&lt;br /&gt;
The new cluster version already contains some data. For example, if you want to &#039;&#039;&#039;delete all data&#039;&#039;&#039; in the 9.2 version cluster, run:&lt;br /&gt;
&lt;br /&gt;
 pg_dropcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
 pg_createcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Where do I get PostgreSQL 9.2? ====&lt;br /&gt;
On Ubuntu, you can simply install 9.2 from the semi-official &amp;quot;PPA&amp;quot; repository:&lt;br /&gt;
&lt;br /&gt;
 sudo apt-get install python-software-properties&lt;br /&gt;
 sudo apt-add-repository ppa:pitti/postgresql&lt;br /&gt;
 sudo apt-get update&lt;br /&gt;
 sudo apt-get install postgresql-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;&lt;/div&gt;</summary>
		<author><name>Intgr</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=Using_pg_upgrade_on_Ubuntu/Debian&amp;diff=18108</id>
		<title>Using pg upgrade on Ubuntu/Debian</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=Using_pg_upgrade_on_Ubuntu/Debian&amp;diff=18108"/>
		<updated>2012-08-29T17:42:57Z</updated>

		<summary type="html">&lt;p&gt;Intgr: /* Upgrading */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Instructions for how to convert/upgrade a PostgreSQL database cluster using pg_upgrade on Ubuntu or Debian. For the sake of example, I&#039;m upgrading from version 9.1 to 9.2, but it should work with any version. Replace any version numbers on the command lines.&lt;br /&gt;
&lt;br /&gt;
== WARNING! ==&lt;br /&gt;
&#039;&#039;&#039;These instructions are experimental!&#039;&#039;&#039;&lt;br /&gt;
* This way of upgrading is not yet supported by Ubuntu upstream. Do it at your own risk. I have only tested this on Ubuntu 12.04.&lt;br /&gt;
* PostgreSQL 9.2 is still a testing release (currently at RC 1). Do not run it in production!&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
First you need to install relevant packages: postgresql-VER and postgresql-server-dev-VER. If you&#039;re using contrib extensions, you also need postgresql-contrib-VER:&lt;br /&gt;
&lt;br /&gt;
 sudo apt-get install postgresql-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; \&lt;br /&gt;
                      postgresql-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By default, Ubuntu creates a database cluster named &amp;quot;main&amp;quot; with each installed version. We will use these. Verify that these are configured:&lt;br /&gt;
&lt;br /&gt;
 # sudo pg_lsclusters&lt;br /&gt;
 Version Cluster   Port Status Owner    Data directory                     Log file&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      5432 down   postgres /var/lib/postgresql/9.1/main       /var/log/postgresql/postgresql-9.1-main.log&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      5433 down   postgres /var/lib/postgresql/9.2/main       /var/log/postgresql/postgresql-9.2-main.log&lt;br /&gt;
&lt;br /&gt;
== Upgrading ==&lt;br /&gt;
First you need to stop the relevant database clusters. To stop all clusters, run:&lt;br /&gt;
&lt;br /&gt;
 sudo /etc/init.d/postgresql stop&lt;br /&gt;
&lt;br /&gt;
(If you don&#039;t want to stop all clusters, you can also use pg_ctlcluster to manage them one by one)&lt;br /&gt;
&lt;br /&gt;
Do the upgrade....&lt;br /&gt;
&lt;br /&gt;
 cd /tmp&lt;br /&gt;
 sudo -H -u postgres /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/bin/pg_upgrade \&lt;br /&gt;
    -b /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -B /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -d /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -D /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -o &#039;-c config_file=/etc/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf&#039; \&lt;br /&gt;
    -O &#039;-c config_file=/etc/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf&#039;&lt;br /&gt;
&lt;br /&gt;
See if it worked...&lt;br /&gt;
&lt;br /&gt;
 sudo pg_ctlcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; start&lt;br /&gt;
 sudo -u postgres psql --cluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 postgres=# select version();&lt;br /&gt;
 PostgreSQL 9.2rc1 on x86_64-unknown-linux-gnu, compiled by gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3, 64-bit&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
==== New cluster database &amp;quot;XXX&amp;quot; is not empty ====&lt;br /&gt;
The new cluster version already contains some data. For example, if you want to &#039;&#039;&#039;delete all data&#039;&#039;&#039; in the 9.2 version cluster, run:&lt;br /&gt;
&lt;br /&gt;
 pg_dropcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
 pg_createcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Where do I get PostgreSQL 9.2? ====&lt;br /&gt;
On Ubuntu, you can simply install 9.2 from the semi-official &amp;quot;PPA&amp;quot; repository:&lt;br /&gt;
&lt;br /&gt;
 sudo apt-get install python-software-properties&lt;br /&gt;
 sudo apt-add-repository ppa:pitti/postgresql&lt;br /&gt;
 sudo apt-get update&lt;br /&gt;
 sudo apt-get install postgresql-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;&lt;/div&gt;</summary>
		<author><name>Intgr</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=Using_pg_upgrade_on_Ubuntu/Debian&amp;diff=18107</id>
		<title>Using pg upgrade on Ubuntu/Debian</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=Using_pg_upgrade_on_Ubuntu/Debian&amp;diff=18107"/>
		<updated>2012-08-29T17:41:44Z</updated>

		<summary type="html">&lt;p&gt;Intgr: Created page with &amp;quot;Instructions for how to convert/upgrade a PostgreSQL database cluster using pg_upgrade on Ubuntu or Debian. For the sake of example, I&amp;#039;m upgrading from version 9.1 to 9.2, but it…&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Instructions for how to convert/upgrade a PostgreSQL database cluster using pg_upgrade on Ubuntu or Debian. For the sake of example, I&#039;m upgrading from version 9.1 to 9.2, but it should work with any version. Replace any version numbers on the command lines.&lt;br /&gt;
&lt;br /&gt;
== WARNING! ==&lt;br /&gt;
&#039;&#039;&#039;These instructions are experimental!&#039;&#039;&#039;&lt;br /&gt;
* This way of upgrading is not yet supported by Ubuntu upstream. Do it at your own risk. I have only tested this on Ubuntu 12.04.&lt;br /&gt;
* PostgreSQL 9.2 is still a testing release (currently at RC 1). Do not run it in production!&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
First you need to install relevant packages: postgresql-VER and postgresql-server-dev-VER. If you&#039;re using contrib extensions, you also need postgresql-contrib-VER:&lt;br /&gt;
&lt;br /&gt;
 sudo apt-get install postgresql-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt; \&lt;br /&gt;
                      postgresql-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By default, Ubuntu creates a database cluster named &amp;quot;main&amp;quot; with each installed version. We will use these. Verify that these are configured:&lt;br /&gt;
&lt;br /&gt;
 # sudo pg_lsclusters&lt;br /&gt;
 Version Cluster   Port Status Owner    Data directory                     Log file&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      5432 down   postgres /var/lib/postgresql/9.1/main       /var/log/postgresql/postgresql-9.1-main.log&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;     &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;      5433 down   postgres /var/lib/postgresql/9.2/main       /var/log/postgresql/postgresql-9.2-main.log&lt;br /&gt;
&lt;br /&gt;
== Upgrading ==&lt;br /&gt;
First you need to stop the relevant database clusters. To stop all clusters, run:&lt;br /&gt;
&lt;br /&gt;
 sudo /etc/init.d/postgresql stop&lt;br /&gt;
&lt;br /&gt;
(If you don&#039;t want to stop all clusters, you can also use pg_ctlcluster to manage them one by one)&lt;br /&gt;
&lt;br /&gt;
Do the upgrade....&lt;br /&gt;
&lt;br /&gt;
 cd /tmp&lt;br /&gt;
 sudo -H -u postgres /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/bin/pg_upgrade \&lt;br /&gt;
    -b /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -B /usr/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/bin \&lt;br /&gt;
    -d /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -D /var/lib/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; \&lt;br /&gt;
    -o &#039;-c config_file=/etc/postgresql/&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;9.1&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf&#039; \&lt;br /&gt;
    -O &#039;-c config_file=/etc/postgresql/&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;/postgresql.conf&#039;&lt;br /&gt;
&lt;br /&gt;
See if it worked...&lt;br /&gt;
&lt;br /&gt;
 sudo pg_ctlcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt; start&lt;br /&gt;
 sudo -u postgres psql --cluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;/&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
==== New cluster database &amp;quot;XXX&amp;quot; is not empty ====&lt;br /&gt;
The new cluster version already contains some data. For example, if you want to &#039;&#039;&#039;delete all data&#039;&#039;&#039; in the 9.2 version cluster, run:&lt;br /&gt;
&lt;br /&gt;
 pg_dropcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
 pg_createcluster &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;main&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Where do I get PostgreSQL 9.2? ====&lt;br /&gt;
On Ubuntu, you can simply install 9.2 from the semi-official &amp;quot;PPA&amp;quot; repository:&lt;br /&gt;
&lt;br /&gt;
 sudo apt-get install python-software-properties&lt;br /&gt;
 sudo apt-add-repository ppa:pitti/postgresql&lt;br /&gt;
 sudo apt-get update&lt;br /&gt;
 sudo apt-get install postgresql-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-contrib-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt; postgresql-server-dev-&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;9.2&amp;lt;/span&amp;gt;&lt;/div&gt;</summary>
		<author><name>Intgr</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=What%27s_new_in_PostgreSQL_9.2&amp;diff=18093</id>
		<title>What&#039;s new in PostgreSQL 9.2</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=What%27s_new_in_PostgreSQL_9.2&amp;diff=18093"/>
		<updated>2012-08-27T16:29:16Z</updated>

		<summary type="html">&lt;p&gt;Intgr: /* Performance improvements */ rm invisible trailing whitespace&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Languages}}&lt;br /&gt;
&lt;br /&gt;
This document showcases many of the latest developments in PostgreSQL 9.2, compared to the last major release &amp;amp;ndash; PostgreSQL 9.1. There are many improvements in this release, so this wiki page covers many of the more important changes in detail. The full list of changes is itemised in &#039;&#039;Release Notes&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Major new features=&lt;br /&gt;
&lt;br /&gt;
==Index-only scans &amp;lt;!-- Robert Haas, Ibrar Ahmed, Heikki Linnakangas, Tom Lane --&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
In PostgreSQL, indexes have no &amp;quot;visibility&amp;quot; information. It means that when you access a record by its index, PostgreSQL has to visit the real tuple in the table to be sure it is visible to you: the tuple the index points to may simply be an old version of the record you are looking for.&lt;br /&gt;
&lt;br /&gt;
It can be a very big performance problem: the index is mostly ordered, so accessing its records is quite efficient, while the records may be scattered all over the place (that&#039;s a reason why PostgreSQL has a cluster command, but that&#039;s another story). In 9.2, PostgreSQL will use an &amp;quot;Index Only Scan&amp;quot; when possible, and not access the record itself if it doesn&#039;t need to.&lt;br /&gt;
&lt;br /&gt;
There is still no visibility information in the index. So in order to do this, PostgreSQL uses the visibility map ([http://www.postgresql.org/docs/devel/static/storage-vm.html visibility map]) , which tells it whether the whole content of a (usually) 8K page is visible to all transactions or not. When the index record points to a tuple contained in an «all visible» page, PostgreSQL won&#039;t have to access the tuple, it will be able to build it directly from the index. Of course, all the columns requested by the query must be in the index.&lt;br /&gt;
&lt;br /&gt;
The visibility map is maintained by VACUUM (it sets the visible bit), and by the backends doing SQL work (they unset the visible bit).&lt;br /&gt;
&lt;br /&gt;
Here is an example.&lt;br /&gt;
&lt;br /&gt;
  CREATE TABLE demo_ios (col1 float, col2 float, col3 text);&lt;br /&gt;
&lt;br /&gt;
In this table, we&#039;ll put random data, in order to have &amp;quot;scattered&amp;quot; data. We&#039;ll put 100 million records, to have a big recordset, and have it not fit in memory (that&#039;s a 4GB-ram machine). This is an ideal case, made for this demo. The gains wont be that big in real life.&lt;br /&gt;
&lt;br /&gt;
  INSERT INTO demo_ios SELECT generate_series(1,100000000),random(), &#039;mynotsolongstring&#039;;&lt;br /&gt;
  &lt;br /&gt;
  SELECT pg_size_pretty(pg_total_relation_size(&#039;demo_ios&#039;));&lt;br /&gt;
   pg_size_pretty &lt;br /&gt;
  ----------------&lt;br /&gt;
   6512 MB&lt;br /&gt;
&lt;br /&gt;
Let&#039;s pretend that the query is this:&lt;br /&gt;
&lt;br /&gt;
  SELECT col1,col2 FROM demo_ios where col2 BETWEEN 0.01 AND 0.02&lt;br /&gt;
&lt;br /&gt;
In order to use an index only scan on this query, we need an index on col2,col1 (col2 first, as it is used in the WHERE clause).&lt;br /&gt;
&lt;br /&gt;
  CREATE index idx_demo_ios on demo_ios(col2,col1);&lt;br /&gt;
&lt;br /&gt;
We vacuum the visibility map to be up-to-date:&lt;br /&gt;
&lt;br /&gt;
  VACUUM demo_ios;&lt;br /&gt;
&lt;br /&gt;
All the timing you&#039;ll see below are done on a cold OS and PostgreSQL cache (that&#039;s where the gains are, as the purpose on Index Only Scans is to reduce I/O).&lt;br /&gt;
&lt;br /&gt;
Let&#039;s first try without Index Only Scans:&lt;br /&gt;
&lt;br /&gt;
  SET enable_indexonlyscan to off;&lt;br /&gt;
  &lt;br /&gt;
  EXPLAIN (analyze,buffers) select col1,col2 FROM demo_ios where col2 between 0.01 and 0.02;&lt;br /&gt;
                                                                 QUERY PLAN                                                               &lt;br /&gt;
  ----------------------------------------------------------------------------------------------------------------------------------------&lt;br /&gt;
   Bitmap Heap Scan on demo_ios  (cost=25643.01..916484.44 rows=993633 width=16) (actual time=763.391..362963.899 rows=1000392 loops=1)&lt;br /&gt;
     Recheck Cond: ((col2 &amp;gt;= 0.01::double precision) AND (col2 &amp;lt;= 0.02::double precision))&lt;br /&gt;
     Rows Removed by Index Recheck: 68098621&lt;br /&gt;
     Buffers: shared hit=2 read=587779&lt;br /&gt;
     -&amp;gt;  Bitmap Index Scan on idx_demo_ios  (cost=0.00..25394.60 rows=993633 width=0) (actual time=759.011..759.011 rows=1000392 loops=1)&lt;br /&gt;
           Index Cond: ((col2 &amp;gt;= 0.01::double precision) AND (col2 &amp;lt;= 0.02::double precision))&lt;br /&gt;
           Buffers: shared hit=2 read=3835&lt;br /&gt;
   Total runtime: 364390.127 ms&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
With Index Only Scans:&lt;br /&gt;
&lt;br /&gt;
  explain (analyze,buffers) select col1,col2 from demo_ios where col2 between 0.01 and 0.02;&lt;br /&gt;
                                                                    QUERY PLAN                                                                   &lt;br /&gt;
  -----------------------------------------------------------------------------------------------------------------------------------------------&lt;br /&gt;
   Index Only Scan using idx_demo_ios on demo_ios  (cost=0.00..35330.93 rows=993633 width=16) (actual time=58.100..3250.589 rows=1000392 loops=1)&lt;br /&gt;
     Index Cond: ((col2 &amp;gt;= 0.01::double precision) AND (col2 &amp;lt;= 0.02::double precision))&lt;br /&gt;
     Heap Fetches: 0&lt;br /&gt;
     Buffers: shared hit=923073 read=3848&lt;br /&gt;
   Total runtime: 4297.405 ms&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
As nothing is free, there are a few things to keep in mind:&lt;br /&gt;
&lt;br /&gt;
* Adding indexes for index only scans obviously adds indexes to your table. So updates will be slower.&lt;br /&gt;
* You will index columns that weren&#039;t indexed before. So there will be less opportunities for HOT updates.&lt;br /&gt;
* Gains will probably be smaller in real life situations.&lt;br /&gt;
&lt;br /&gt;
This required making visibility map changes crash-safe, so visibility map bit changes are now WAL-logged.&lt;br /&gt;
&lt;br /&gt;
==Replication improvements &amp;lt;!-- Fujii Masao, Simon Riggs, Magnus Hagander, Jun Ishizuka --&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
Streaming Replication is getting even more polished with this release. One on the main remaining gripes about streaming replication is that all the slaves have to be connected to the same and unique master, consuming its resources.&lt;br /&gt;
&lt;br /&gt;
Moreover, in case of a failover, it was very complicated to reconnect all the remaining slaves to the newly promoted master.&lt;br /&gt;
&lt;br /&gt;
To be on the safe side, it was easier to re-synchronize the slaves to the new masters from scratch, meaning that during this failover, only one server was active, and under heavy load, as it was used to rebuild all the slaves.&lt;br /&gt;
&lt;br /&gt;
* With 9.2, a slave can also be a replication master, allowing cascading replication.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s build this. We start with an already working 9.2 database.&lt;br /&gt;
&lt;br /&gt;
We set it up for replication:&lt;br /&gt;
&lt;br /&gt;
postgresql.conf:&lt;br /&gt;
  wal_level=hot_standby #(could be archive too)&lt;br /&gt;
  max_wal_senders=5&lt;br /&gt;
  hot_standby=on&lt;br /&gt;
&lt;br /&gt;
You&#039;ll probably also want to activate archiving in production, it won&#039;t be done here.&lt;br /&gt;
&lt;br /&gt;
pg_hba.conf (do not use trust in production):&lt;br /&gt;
  host   replication replication_user          0.0.0.0/0                      md5&lt;br /&gt;
 &lt;br /&gt;
Create the user:&lt;br /&gt;
  create user replication_user replication password &#039;secret&#039;;&lt;br /&gt;
&lt;br /&gt;
Clone the database:&lt;br /&gt;
&lt;br /&gt;
  pg_basebackup -h localhost -U replication_user -D data2&lt;br /&gt;
  Password:&lt;br /&gt;
&lt;br /&gt;
We have a brand new cluster in the data2 directory. We&#039;ll change the port so that it can start (postgresql.conf):&lt;br /&gt;
  port=5433&lt;br /&gt;
&lt;br /&gt;
We add a recovery.conf to tell it how to stream from the master database:&lt;br /&gt;
  standby_mode = on&lt;br /&gt;
  primary_conninfo = &#039;host=localhost port=5432 user=replication_user password=secret&#039; &lt;br /&gt;
&lt;br /&gt;
  pg_ctl -D data2 start&lt;br /&gt;
  server starting&lt;br /&gt;
  LOG:  database system was interrupted; last known up at 2012-07-03 17:58:09 CEST&lt;br /&gt;
  LOG:  creating missing WAL directory &amp;quot;pg_xlog/archive_status&amp;quot;&lt;br /&gt;
  LOG:  entering standby mode&lt;br /&gt;
  LOG:  streaming replication successfully connected to primary&lt;br /&gt;
  LOG:  redo starts at 0/9D000020&lt;br /&gt;
  LOG:  consistent recovery state reached at 0/9D0000B8&lt;br /&gt;
  LOG:  database system is ready to accept read only connections&lt;br /&gt;
&lt;br /&gt;
Now, let&#039;s add a second slave, which will use this slave:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  pg_basebackup -h localhost -U replication_user -D data3 -p 5433&lt;br /&gt;
  Password: &lt;br /&gt;
&lt;br /&gt;
We edit data3&#039;s postgresql.conf to change the port:&lt;br /&gt;
  port=5434&lt;br /&gt;
&lt;br /&gt;
We modify the recovery.conf to stream from the slave:&lt;br /&gt;
  standby_mode = on&lt;br /&gt;
  primary_conninfo = &#039;host=localhost port=5433 user=replication_user password=secret&#039;             # e.g. &#039;host=localhost port=5432&#039;&lt;br /&gt;
&lt;br /&gt;
We start the cluster:&lt;br /&gt;
  pg_ctl -D data3 start&lt;br /&gt;
  server starting&lt;br /&gt;
  LOG:  database system was interrupted while in recovery at log time 2012-07-03 17:58:09 CEST&lt;br /&gt;
  HINT:  If this has occurred more than once some data might be corrupted and you might need to choose an earlier recovery target.&lt;br /&gt;
  LOG:  creating missing WAL directory &amp;quot;pg_xlog/archive_status&amp;quot;&lt;br /&gt;
  LOG:  entering standby mode&lt;br /&gt;
  LOG:  streaming replication successfully connected to primary&lt;br /&gt;
  LOG:  redo starts at 0/9D000020&lt;br /&gt;
  LOG:  consistent recovery state reached at 0/9E000000&lt;br /&gt;
  LOG:  database system is ready to accept read only connections&lt;br /&gt;
&lt;br /&gt;
Now, everything modified on the master cluster get streamed to the first slave, and from there to the second slave. This second replication has to be monitored from the first slave (the master knows nothing about it).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* As you may have noticed from the examble, pg_basebackup now works from slaves.&lt;br /&gt;
&lt;br /&gt;
* There is another use case that wasn&#039;t covered: what if a user didn&#039;t care for having a full fledged slave, and only wanted to stream the WAL files to another location, to benefit from the reduced data loss without the burden of maintaining a slave ?&lt;br /&gt;
&lt;br /&gt;
pg_receivexlog is provided just for this purpose: it pretends to be a PostgreSQL slave, but only stores the log files as they are streamed, in a directory:&lt;br /&gt;
  pg_receivexlog -D /tmp/new_logs -h localhost -U replication_user&lt;br /&gt;
&lt;br /&gt;
will connect to the master (or a slave), and start creating files: &lt;br /&gt;
  ls /tmp/new_logs/&lt;br /&gt;
  00000001000000000000009E.partial&lt;br /&gt;
&lt;br /&gt;
Files are of the segment size, so they can be used for a normal recovery of the database. It&#039;s the same as an archive command, but with a much smaller granularity.&lt;br /&gt;
Remember to rename the last segment to remove the .partial suffix before using it with PITR or other.&lt;br /&gt;
&lt;br /&gt;
* synchronous_commit has a new value: remote_write. It can be used when there is a synchronous slave (synchronous_standby_names is set), meaning that the master doesn&#039;t have to wait for the slave to have written the data to disk, only for the slave to have acknowledged the data. With this set, data is protected from a crash on the master, but could still be lost if the slave crashed at the same time (i.e. before having written the in flight data to disk). As this is a quite remote possibility, some people will be interested in this compromise.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==JSON datatype==&lt;br /&gt;
&lt;br /&gt;
The JSON datatype is meant for storing JSON-structured data. It will validate that the input JSON string is correct JSON:&lt;br /&gt;
&lt;br /&gt;
  =# SELECT &#039;{&amp;quot;username&amp;quot;:&amp;quot;john&amp;quot;,&amp;quot;posts&amp;quot;:121,&amp;quot;emailaddress&amp;quot;:&amp;quot;john@nowhere.com&amp;quot;}&#039;::json;&lt;br /&gt;
                                 json                                &lt;br /&gt;
  -------------------------------------------------------------------&lt;br /&gt;
   {&amp;quot;username&amp;quot;:&amp;quot;john&amp;quot;,&amp;quot;posts&amp;quot;:121,&amp;quot;emailaddress&amp;quot;:&amp;quot;john@nowhere.com&amp;quot;}&lt;br /&gt;
  (1 row)&lt;br /&gt;
  &lt;br /&gt;
  =# SELECT &#039;{&amp;quot;username&amp;quot;,&amp;quot;posts&amp;quot;:121,&amp;quot;emailaddress&amp;quot;:&amp;quot;john@nowhere.com&amp;quot;}&#039;::json;&lt;br /&gt;
  ERROR:  invalid input syntax for type json at character 8&lt;br /&gt;
  DETAIL:  Expected &amp;quot;:&amp;quot;, but found &amp;quot;,&amp;quot;.&lt;br /&gt;
  CONTEXT:  JSON data, line 1: {&amp;quot;username&amp;quot;,...&lt;br /&gt;
  STATEMENT:  SELECT &#039;{&amp;quot;username&amp;quot;,&amp;quot;posts&amp;quot;:121,&amp;quot;emailaddress&amp;quot;:&amp;quot;john@nowhere.com&amp;quot;}&#039;::json;&lt;br /&gt;
  ERROR:  invalid input syntax for type json&lt;br /&gt;
  LINE 1: SELECT &#039;{&amp;quot;username&amp;quot;,&amp;quot;posts&amp;quot;:121,&amp;quot;emailaddress&amp;quot;:&amp;quot;john@nowhere...&lt;br /&gt;
                 ^&lt;br /&gt;
  DETAIL:  Expected &amp;quot;:&amp;quot;, but found &amp;quot;,&amp;quot;.&lt;br /&gt;
  CONTEXT:  JSON data, line 1: {&amp;quot;username&amp;quot;,...&lt;br /&gt;
&lt;br /&gt;
You can also convert a row type to JSON:&lt;br /&gt;
&lt;br /&gt;
  =#SELECT * FROM demo ;&lt;br /&gt;
   username | posts |    emailaddress     &lt;br /&gt;
  ----------+-------+---------------------&lt;br /&gt;
   john     |   121 | john@nowhere.com&lt;br /&gt;
   mickael  |   215 | mickael@nowhere.com&lt;br /&gt;
  (2 rows)&lt;br /&gt;
  &lt;br /&gt;
  =# SELECT row_to_json(demo) FROM demo;&lt;br /&gt;
                                 row_to_json                               &lt;br /&gt;
  -------------------------------------------------------------------------&lt;br /&gt;
   {&amp;quot;username&amp;quot;:&amp;quot;john&amp;quot;,&amp;quot;posts&amp;quot;:121,&amp;quot;emailaddress&amp;quot;:&amp;quot;john@nowhere.com&amp;quot;}&lt;br /&gt;
   {&amp;quot;username&amp;quot;:&amp;quot;mickael&amp;quot;,&amp;quot;posts&amp;quot;:215,&amp;quot;emailaddress&amp;quot;:&amp;quot;mickael@nowhere.com&amp;quot;}&lt;br /&gt;
  (2 rows)&lt;br /&gt;
&lt;br /&gt;
Or an array type:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  =# select array_to_json(array_agg(demo)) from demo;&lt;br /&gt;
                                                                  array_to_json                                                                &lt;br /&gt;
  ---------------------------------------------------------------------------------------------------------------------------------------------&lt;br /&gt;
   [{&amp;quot;username&amp;quot;:&amp;quot;john&amp;quot;,&amp;quot;posts&amp;quot;:121,&amp;quot;emailaddress&amp;quot;:&amp;quot;john@nowhere.com&amp;quot;},{&amp;quot;username&amp;quot;:&amp;quot;mickael&amp;quot;,&amp;quot;posts&amp;quot;:215,&amp;quot;emailaddress&amp;quot;:&amp;quot;mickael@nowhere.com&amp;quot;}]&lt;br /&gt;
  (1 row)&lt;br /&gt;
&lt;br /&gt;
== Range Types ==&lt;br /&gt;
&lt;br /&gt;
Range types are used to store a range of data of a given type. There are a few pre-defined types. They are integer (int4range), bigint (int8range), numeric (numrange), timestamp without timezone (tsrange), timestamp with timezone (tstzrange), and date (daterange).&lt;br /&gt;
&lt;br /&gt;
Ranges can be made of continuous (numeric, timestamp...) or discrete (integer, date...) data types. They can be open (the bound isn&#039;t part of the range) or closed (the bound is part of the range). A bound can also be infinite.&lt;br /&gt;
&lt;br /&gt;
Without these datatypes, most people solve the range problems by using two columns in a table. These range types are much more powerful, as you can use many operators on them:&lt;br /&gt;
&lt;br /&gt;
Here is the intersection between then 1000(open)-2000(closed) and 1000(closed)-1200(closed) numeric range:&lt;br /&gt;
&lt;br /&gt;
  SELECT &#039;(1000,2000]&#039;::numrange * &#039;[1000,1200]&#039;::numrange;&lt;br /&gt;
    ?column?   &lt;br /&gt;
  -------------&lt;br /&gt;
   (1000,1200]&lt;br /&gt;
  (1 row)&lt;br /&gt;
&lt;br /&gt;
So you can query on things like: «give me all ranges that intersect this»:&lt;br /&gt;
&lt;br /&gt;
  =# SELECT * from test_range ;&lt;br /&gt;
                         period                        &lt;br /&gt;
  -----------------------------------------------------&lt;br /&gt;
   [&amp;quot;2012-01-01 00:00:00+01&amp;quot;,&amp;quot;2012-01-02 12:00:00+01&amp;quot;]&lt;br /&gt;
   [&amp;quot;2012-01-01 00:00:00+01&amp;quot;,&amp;quot;2012-03-01 00:00:00+01&amp;quot;]&lt;br /&gt;
   [&amp;quot;2008-01-01 00:00:00+01&amp;quot;,&amp;quot;2015-01-01 00:00:00+01&amp;quot;]&lt;br /&gt;
  (3 rows)&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  =# SELECT * FROM test_range WHERE period &amp;amp;&amp;amp; &#039;[2012-01-03 00:00:00,2012-01-03 12:00:00]&#039;; &lt;br /&gt;
                         period                        &lt;br /&gt;
  -----------------------------------------------------&lt;br /&gt;
   [&amp;quot;2012-01-01 00:00:00+01&amp;quot;,&amp;quot;2012-03-01 00:00:00+01&amp;quot;]&lt;br /&gt;
   [&amp;quot;2008-01-01 00:00:00+01&amp;quot;,&amp;quot;2015-01-01 00:00:00+01&amp;quot;]&lt;br /&gt;
  (2 rows)&lt;br /&gt;
&lt;br /&gt;
This query could use an index defined like this:&lt;br /&gt;
&lt;br /&gt;
  =# CREATE INDEX idx_test_range on test_range USING gist (period);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You can also use these range data types to define exclusion constraints:&lt;br /&gt;
&lt;br /&gt;
  CREATE EXTENSION btree_gist ;&lt;br /&gt;
  CREATE TABLE reservation (room_id int, period tstzrange);&lt;br /&gt;
  ALTER TABLE reservation ADD  EXCLUDE USING GIST (room_id WITH =, period WITH &amp;amp;&amp;amp;);&lt;br /&gt;
&lt;br /&gt;
This means that now it is forbidden to have two records in this table where room_id is equal and period overlaps. The extension btree_gist is required to create a GiST index on room_id (it&#039;s an integer, it is usually indexed with a btree index).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  =# INSERT INTO reservation VALUES (1,&#039;(2012-08-23 14:00:00,2012-08-23 15:00:00)&#039;);&lt;br /&gt;
  INSERT 0 1&lt;br /&gt;
  =# INSERT INTO reservation VALUES (2,&#039;(2012-08-23 14:00:00,2012-08-23 15:00:00)&#039;);&lt;br /&gt;
  INSERT 0 1&lt;br /&gt;
  =# INSERT INTO reservation VALUES (1,&#039;(2012-08-23 14:45:00,2012-08-23 15:15:00)&#039;);&lt;br /&gt;
  ERROR:  conflicting key value violates exclusion constraint &amp;quot;reservation_room_id_period_excl&amp;quot;&lt;br /&gt;
  DETAIL:  Key (room_id, period)=(1, (&amp;quot;2012-08-23 14:45:00+02&amp;quot;,&amp;quot;2012-08-23 15:15:00+02&amp;quot;)) &lt;br /&gt;
  conflicts with existing key (room_id, period)=(1, (&amp;quot;2012-08-23 14:00:00+02&amp;quot;,&amp;quot;2012-08-23 15:00:00+02&amp;quot;)).&lt;br /&gt;
  STATEMENT:  INSERT INTO reservation VALUES (1,&#039;(2012-08-23 14:45:00,2012-08-23 15:15:00)&#039;);&lt;br /&gt;
&lt;br /&gt;
One can also declare new range types.&lt;br /&gt;
&lt;br /&gt;
=Performance improvements=&lt;br /&gt;
&lt;br /&gt;
This version has performance improvements on a very large range of domains (non-exaustive):&lt;br /&gt;
&lt;br /&gt;
* The most visible will probably be the Index Only Scans, which has already been introduced in this document.&lt;br /&gt;
&lt;br /&gt;
* The lock contention of several big locks has been significantly reduced, leading to better multi-processor scalability, for machines with over 32 cores mostly. &amp;lt;!-- Robert Haas --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* The performance of in-memory sorts has been improved by up to 25% in some situations, with certain specialized sort functions introduced. &amp;lt;!-- Peter Geoghegan --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* An idle PostgreSQL server now makes less wakeups, leading to lower power consumption&amp;lt;!--Peter Geoghegan--&amp;gt;. This is especially useful on virtualized and embedded environments.&lt;br /&gt;
&lt;br /&gt;
* COPY has been improved, it will generate less WAL volume and less locks of tables&#039;s pages. &amp;lt;!-- Heikki Linnakangas --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Statistics are collected on array contents&amp;lt;!-- Alexander Korotkov --&amp;gt;, allowing for better estimations of selectivity on array operations.&lt;br /&gt;
&lt;br /&gt;
* Text-to-anytype concatenation and quote_literal/quote_nullable functions are not volatile any more, enabling better optimization in some cases &amp;lt;!-- Marti Raudsepp --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* The system can now track IO durations &amp;lt;!--Ants Aasma --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This one deserves a little explanation, as it can be a little tricky. Tracking IO durations means asking repeatedly the time to the operating system. Depending on the operating system and the hardware, this can be quite cheap, or extremely costly. The most import factor here is where the system gets its time from. It could be directly retrieved from the processor (TSC), dedicated hardware such as HPET, or an ACPI call. What&#039;s most important is that the cost of getting time can vary from a factor of thousands.&lt;br /&gt;
&lt;br /&gt;
If you are interested in this timing data, it&#039;s better to first check if your system will support it without to much of a performance hit. PostgreSQL provides you with the pg_test_timing tool:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ pg_test_timing &lt;br /&gt;
Testing timing overhead for 3 seconds.&lt;br /&gt;
Per loop time including overhead: 28.02 nsec&lt;br /&gt;
Histogram of timing durations:&lt;br /&gt;
   &amp;lt; usec:      count   percent&lt;br /&gt;
       32:         41  0.00004%&lt;br /&gt;
       16:       1405  0.00131%&lt;br /&gt;
        8:        200  0.00019%&lt;br /&gt;
        4:        388  0.00036%&lt;br /&gt;
        2:    2982558  2.78523%&lt;br /&gt;
        1:  104100166 97.21287%&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here, everything is good: getting time costs around 28 nanoseconds, and has a very small variation. Anything under 100 nanoseconds should be good for production. If you get higher values, you may still find a way to tune your system. You&#039;d better check on the [http://www.postgresql.org/docs/9.2/static/pgtesttiming.html documentation].&lt;br /&gt;
&lt;br /&gt;
Anyway, here is the data you&#039;ll be able to collect if your system is ready for this:&lt;br /&gt;
&lt;br /&gt;
First, you&#039;ll get per-database statistics, which will now give accurate informations about which database is doing most I/O:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
=# SELECT * FROM pg_stat_database WHERE datname = &#039;mydb&#039;;&lt;br /&gt;
-[ RECORD 1 ]--+------------------------------&lt;br /&gt;
datid          | 16384&lt;br /&gt;
datname        | mydb&lt;br /&gt;
numbackends    | 1&lt;br /&gt;
xact_commit    | 270&lt;br /&gt;
xact_rollback  | 2&lt;br /&gt;
blks_read      | 1961&lt;br /&gt;
blks_hit       | 17944&lt;br /&gt;
tup_returned   | 269035&lt;br /&gt;
tup_fetched    | 8850&lt;br /&gt;
tup_inserted   | 16&lt;br /&gt;
tup_updated    | 4&lt;br /&gt;
tup_deleted    | 45&lt;br /&gt;
conflicts      | 0&lt;br /&gt;
temp_files     | 0&lt;br /&gt;
temp_bytes     | 0&lt;br /&gt;
deadlocks      | 0&lt;br /&gt;
blk_read_time  | 583.774&lt;br /&gt;
blk_write_time | 0&lt;br /&gt;
stats_reset    | 2012-07-03 17:18:54.796817+02&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
We see here that mydb has only consumed 583.774 milliseconds of read time.&lt;br /&gt;
&lt;br /&gt;
Explain will benefit from this too:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
=# EXPLAIN (analyze,buffers) SELECT count(*) FROM mots ;&lt;br /&gt;
                                                   QUERY PLAN&lt;br /&gt;
----------------------------------------------------------------------------------------------------------------&lt;br /&gt;
 Aggregate  (cost=1669.95..1669.96 rows=1 width=0) (actual time=21.943..21.943 rows=1 loops=1)&lt;br /&gt;
   Buffers: shared read=493&lt;br /&gt;
   I/O Timings: read=2.578&lt;br /&gt;
   -&amp;gt;  Seq Scan on mots  (cost=0.00..1434.56 rows=94156 width=0) (actual time=0.059..12.933 rows=94156 loops=1)&lt;br /&gt;
         Buffers: shared read=493&lt;br /&gt;
         I/O Timings: read=2.578&lt;br /&gt;
 Total runtime: 22.059 ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
We now have a separate information about the time taken to retrieve data from the operating system. Obviously, here, the data was in the operating system&#039;s cache (2 milliseconds to read 493 blocks).&lt;br /&gt;
&lt;br /&gt;
And last, if you have enabled pg_stat_statements:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
select * from pg_stat_statements where query ~ &#039;words&#039;;&lt;br /&gt;
-[ RECORD 1 ]-------+---------------------------&lt;br /&gt;
userid              | 10&lt;br /&gt;
dbid                | 16384&lt;br /&gt;
query               | select count(*) from words;&lt;br /&gt;
calls               | 2&lt;br /&gt;
total_time          | 78.332&lt;br /&gt;
rows                | 2&lt;br /&gt;
shared_blks_hit     | 0&lt;br /&gt;
shared_blks_read    | 986&lt;br /&gt;
shared_blks_dirtied | 0&lt;br /&gt;
shared_blks_written | 0&lt;br /&gt;
local_blks_hit      | 0&lt;br /&gt;
local_blks_read     | 0&lt;br /&gt;
local_blks_dirtied  | 0&lt;br /&gt;
local_blks_written  | 0&lt;br /&gt;
temp_blks_read      | 0&lt;br /&gt;
temp_blks_written   | 0&lt;br /&gt;
blk_read_time       | 58.427&lt;br /&gt;
blk_write_time      | 0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* As for every version, the optimizer has received its share of improvements &amp;lt;!-- Tom Lane--&amp;gt;&lt;br /&gt;
** Prepared statements used to be optimized once, without any knowledge of the parameters&#039; values. With 9.2, the planner will use specific plans regarding to the parameters sent (the query will be planned at execution), except if the query is executed several times and the planner decides that the generic plan is not too much more expensive than the specific plans.&lt;br /&gt;
** A new feature has been added: parameterized paths. Simply put, it means that a sub-part of a query plan can use parameters it has got from a parent node. It fixes several bad plans that could occur, especially when the optimizer couldn&#039;t reorder joins to put nested loops where it would have been efficient.&lt;br /&gt;
&lt;br /&gt;
This example is straight from the developpers mailing lists &amp;lt;!-- Andres Freund --&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE a (&lt;br /&gt;
    a_id serial PRIMARY KEY NOT NULL,&lt;br /&gt;
    b_id integer&lt;br /&gt;
);&lt;br /&gt;
CREATE INDEX a__b_id ON a USING btree (b_id);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
CREATE TABLE b (&lt;br /&gt;
    b_id serial NOT NULL,&lt;br /&gt;
    c_id integer&lt;br /&gt;
);&lt;br /&gt;
CREATE INDEX b__c_id ON b USING btree (c_id);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
CREATE TABLE c (&lt;br /&gt;
    c_id serial PRIMARY KEY NOT NULL,&lt;br /&gt;
    value integer UNIQUE&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
INSERT INTO b (b_id, c_id)&lt;br /&gt;
    SELECT g.i, g.i FROM generate_series(1, 50000) g(i);&lt;br /&gt;
&lt;br /&gt;
INSERT INTO a(b_id)&lt;br /&gt;
    SELECT g.i FROM generate_series(1, 50000) g(i);&lt;br /&gt;
&lt;br /&gt;
INSERT INTO c(c_id,value)&lt;br /&gt;
    VALUES (1,1);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So we have a referencing b, b referencing c.&lt;br /&gt;
&lt;br /&gt;
Here is an example of a query working badly with PostgreSQL 9.1:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
EXPLAIN ANALYZE SELECT 1&lt;br /&gt;
FROM&lt;br /&gt;
    c&lt;br /&gt;
WHERE&lt;br /&gt;
    EXISTS (&lt;br /&gt;
        SELECT *&lt;br /&gt;
        FROM a&lt;br /&gt;
            JOIN b USING (b_id)&lt;br /&gt;
        WHERE b.c_id = c.c_id)&lt;br /&gt;
    AND c.value = 1;&lt;br /&gt;
                                                      QUERY PLAN&lt;br /&gt;
-----------------------------------------------------------------------------------------------------------------------&lt;br /&gt;
 Nested Loop Semi Join  (cost=1347.00..3702.27 rows=1 width=0) (actual time=13.799..13.802 rows=1 loops=1)&lt;br /&gt;
   Join Filter: (c.c_id = b.c_id)&lt;br /&gt;
   -&amp;gt;  Index Scan using c_value_key on c  (cost=0.00..8.27 rows=1 width=4) (actual time=0.006..0.008 rows=1 loops=1)&lt;br /&gt;
         Index Cond: (value = 1)&lt;br /&gt;
   -&amp;gt;  Hash Join  (cost=1347.00..3069.00 rows=50000 width=4) (actual time=13.788..13.788 rows=1 loops=1)&lt;br /&gt;
         Hash Cond: (a.b_id = b.b_id)&lt;br /&gt;
         -&amp;gt;  Seq Scan on a  (cost=0.00..722.00 rows=50000 width=4) (actual time=0.007..0.007 rows=1 loops=1)&lt;br /&gt;
         -&amp;gt;  Hash  (cost=722.00..722.00 rows=50000 width=8) (actual time=13.760..13.760 rows=50000 loops=1)&lt;br /&gt;
               Buckets: 8192  Batches: 1  Memory Usage: 1954kB&lt;br /&gt;
               -&amp;gt;  Seq Scan on b  (cost=0.00..722.00 rows=50000 width=8) (actual time=0.008..5.702 rows=50000 loops=1)&lt;br /&gt;
 Total runtime: 13.842 ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Not that bad, 13 milliseconds. Still, we are doing sequential scans on a and b, when our common sense tells us that c.value=1 should be used to filter rows more aggressively.&lt;br /&gt;
&lt;br /&gt;
Here&#039;s what 9.2 does with this query:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                                                      QUERY PLAN&lt;br /&gt;
----------------------------------------------------------------------------------------------------------------------------&lt;br /&gt;
 Nested Loop Semi Join  (cost=0.00..16.97 rows=1 width=0) (actual time=0.035..0.037 rows=1 loops=1)&lt;br /&gt;
   -&amp;gt;  Index Scan using c_value_key on c  (cost=0.00..8.27 rows=1 width=4) (actual time=0.007..0.009 rows=1 loops=1)&lt;br /&gt;
         Index Cond: (value = 1)&lt;br /&gt;
   -&amp;gt;  Nested Loop  (cost=0.00..8.69 rows=1 width=4) (actual time=0.025..0.025 rows=1 loops=1)&lt;br /&gt;
         -&amp;gt;  Index Scan using b__c_id on b  (cost=0.00..8.33 rows=1 width=8) (actual time=0.007..0.007 rows=1 loops=1)&lt;br /&gt;
               Index Cond: (c_id = c.c_id)&lt;br /&gt;
         -&amp;gt;  Index Only Scan using a__b_id on a  (cost=0.00..0.35 rows=1 width=4) (actual time=0.014..0.014 rows=1 loops=1)&lt;br /&gt;
               Index Cond: (b_id = b.b_id)&lt;br /&gt;
 Total runtime: 0.089 ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The «parameterized path» is:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   -&amp;gt;  Nested Loop  (cost=0.00..8.69 rows=1 width=4) (actual time=0.025..0.025 rows=1 loops=1)&lt;br /&gt;
         -&amp;gt;  Index Scan using b__c_id on b  (cost=0.00..8.33 rows=1 width=8) (actual time=0.007..0.007 rows=1 loops=1)&lt;br /&gt;
               Index Cond: (c_id = c.c_id)&lt;br /&gt;
         -&amp;gt;  Index Only Scan using a__b_id on a  (cost=0.00..0.35 rows=1 width=4) (actual time=0.014..0.014 rows=1 loops=1)&lt;br /&gt;
               Index Cond: (b_id = b.b_id)&lt;br /&gt;
 Total runtime: 0.089 ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This part of the plan depends on a parent node (c_id=c.c_id). This part of the plan is called each time with a different parameter coming from the parent node.&lt;br /&gt;
&lt;br /&gt;
This plan is of course much faster, as there is no need to fully scan a, and to fully scan AND hash b.&lt;br /&gt;
&lt;br /&gt;
=SP-GiST=&lt;br /&gt;
&lt;br /&gt;
SP-GiST stands for Space Partitionned GiST, GiST being Generalized Search Tree. GiST is an index type, and has been available for quite a while in PostgreSQL. GiST is already very efficient at indexing complex data types, but performance tends to suffer when the source data isn&#039;t uniformly distributed. SP-GiST tries to fix that.&lt;br /&gt;
&lt;br /&gt;
As all indexing methods available in PostgreSQL, SP-GiST is a generic indexing method, meaning its purpose is to index whatever you&#039;ll throw at it, using operators you&#039;ll provide. It means that if you want to create a new datatype, and make it indexable through SP-GiST, you&#039;ll have to follow the documented API.&lt;br /&gt;
&lt;br /&gt;
SP-GiST can be used to implement 3 type of indexes: trie (suffix) indexing, Quadtree (data is divided into quadrants), and k-d tree (k-dimensional tree).&lt;br /&gt;
&lt;br /&gt;
For now, SP-GiST is provided with operator families called &amp;quot;quad_point_ops&amp;quot;, &amp;quot;kd_point_ops&amp;quot; and &amp;quot;text_ops&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
As their names indicate, the first one indexes point types, using a quadtree, the second one indexes point types using a k-d tree, and the third one indexes text, using suffix.&lt;br /&gt;
&lt;br /&gt;
=pg_stat_statements=&lt;br /&gt;
&lt;br /&gt;
This contrib module has received a lot of improvements in this version:&lt;br /&gt;
&lt;br /&gt;
* Queries are normalized: queries that are identical except for their constant values will be considered the same, as long as their post-parse analysis query tree (that is, the internal representation of the query before rule expansion) are the same. This also implies that differences that are not semantically essential to the query, such as variations in whitespace or alias names, or the use of one particular syntax over another equivalent one will not differentiate queries.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
=#SELECT * FROM words WHERE word= &#039;foo&#039;;&lt;br /&gt;
 word &lt;br /&gt;
------&lt;br /&gt;
(0 ligne)&lt;br /&gt;
&lt;br /&gt;
=# SELECT * FROM words WHERE word= &#039;bar&#039;;&lt;br /&gt;
 word &lt;br /&gt;
------&lt;br /&gt;
 bar&lt;br /&gt;
&lt;br /&gt;
=#select * from pg_stat_statements where query like &#039;%words where%&#039;;&lt;br /&gt;
-[ RECORD 1 ]-------+-----------------------------------&lt;br /&gt;
userid              | 10&lt;br /&gt;
dbid                | 16384&lt;br /&gt;
query               | SELECT * FROM words WHERE word= ?;&lt;br /&gt;
calls               | 2&lt;br /&gt;
total_time          | 142.314&lt;br /&gt;
rows                | 1&lt;br /&gt;
shared_blks_hit     | 3&lt;br /&gt;
shared_blks_read    | 5&lt;br /&gt;
shared_blks_dirtied | 0&lt;br /&gt;
shared_blks_written | 0&lt;br /&gt;
local_blks_hit      | 0&lt;br /&gt;
local_blks_read     | 0&lt;br /&gt;
local_blks_dirtied  | 0&lt;br /&gt;
local_blks_written  | 0&lt;br /&gt;
temp_blks_read      | 0&lt;br /&gt;
temp_blks_written   | 0&lt;br /&gt;
blk_read_time       | 142.165&lt;br /&gt;
blk_write_time      | 0&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The two queries are shown as one in pg_stat_statements.&lt;br /&gt;
&lt;br /&gt;
* For prepared statements, the execution part (execute statement) is charged on the prepare statement. That way it is easier to use, and avoids the double-counting there was with PostgreSQL 9.1.&lt;br /&gt;
&lt;br /&gt;
* pg_stat_statements displays timing in milliseconds, to be consistent with other system views.&lt;br /&gt;
&lt;br /&gt;
= Explain improvements=&lt;br /&gt;
&lt;br /&gt;
* Timing can now be disabled with EXPLAIN (analyze on, timing off), leading to lower overhead on platforms where getting the current time is expensive &amp;lt;!--Tomas Vondra--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  =# EXPLAIN (analyze on,timing off) SELECT * FROM reservation ;&lt;br /&gt;
                                       QUERY PLAN                                       &lt;br /&gt;
  ----------------------------------------------------------------------------------------&lt;br /&gt;
   Seq Scan on reservation  (cost=0.00..22.30 rows=1230 width=36) (actual rows=2 loops=1)&lt;br /&gt;
   Total runtime: 0.045 ms&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Have EXPLAIN ANALYZE report the number of rows rejected by filter steps &amp;lt;!--(Marko Tiikkaja)--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This new feature makes it much easier to know how many rows are removed by a filter (and spot potential places to put indexes):&lt;br /&gt;
&lt;br /&gt;
  =# EXPLAIN ANALYZE SELECT * FROM test WHERE a ~ &#039;tra&#039;;&lt;br /&gt;
                                                    QUERY PLAN                                                   &lt;br /&gt;
  ---------------------------------------------------------------------------------------------------------------&lt;br /&gt;
   Seq Scan on test  (cost=0.00..106876.56 rows=2002 width=11) (actual time=2.914..8538.285 rows=120256 loops=1)&lt;br /&gt;
     Filter: (a ~ &#039;tra&#039;::text)&lt;br /&gt;
     Rows Removed by Filter: 5905600&lt;br /&gt;
   Total runtime: 8549.539 ms&lt;br /&gt;
  (4 rows)&lt;br /&gt;
&lt;br /&gt;
=Backward compatibility=&lt;br /&gt;
&lt;br /&gt;
These changes may incur regressions in your applications.&lt;br /&gt;
&lt;br /&gt;
==Ensure that xpath() escapes special characters in string values &amp;lt;!-- (Florian Pflug)--&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Before 9.2:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT (XPATH(&#039;/*/text()&#039;, &#039;&amp;lt;root&amp;gt;&amp;amp;amp;lt;&amp;lt;/root&amp;gt;&#039;))[1];&lt;br /&gt;
 xpath &lt;br /&gt;
-------&lt;br /&gt;
 &amp;lt;&lt;br /&gt;
&lt;br /&gt;
&#039;&amp;lt;&#039; Isn&#039;t valid XML.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
With 9.2:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT (XPATH(&#039;/*/text()&#039;, &#039;&amp;lt;root&amp;gt;&amp;amp;amp;lt;&amp;lt;/root&amp;gt;&#039;))[1];&lt;br /&gt;
 xpath &lt;br /&gt;
-------&lt;br /&gt;
 &amp;amp;amp;lt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Remove hstore&#039;s =&amp;gt; operator &amp;lt;!-- (Robert Haas)--&amp;gt;==&lt;br /&gt;
Up to 9.1, one could use the =&amp;gt; operator to create a hstore. Hstore is a contrib, used to store key/values pairs in a column.&lt;br /&gt;
&lt;br /&gt;
In 9.1:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
=# SELECT &#039;a&#039;=&amp;gt;&#039;b&#039;;&lt;br /&gt;
 ?column? &lt;br /&gt;
----------&lt;br /&gt;
 &amp;quot;a&amp;quot;=&amp;gt;&amp;quot;b&amp;quot;&lt;br /&gt;
(1 row)&lt;br /&gt;
&lt;br /&gt;
=# SELECT pg_typeof(&#039;a&#039;=&amp;gt;&#039;b&#039;);&lt;br /&gt;
 pg_typeof &lt;br /&gt;
-----------&lt;br /&gt;
 hstore&lt;br /&gt;
(1 row)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With 9.2:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT &#039;a&#039;=&amp;gt;&#039;b&#039;;&lt;br /&gt;
ERROR:  operator does not exist: unknown =&amp;gt; unknown at character 11&lt;br /&gt;
HINT:  No operator matches the given name and argument type(s). You might need to add explicit type casts.&lt;br /&gt;
STATEMENT:  SELECT &#039;a&#039;=&amp;gt;&#039;b&#039;;&lt;br /&gt;
ERROR:  operator does not exist: unknown =&amp;gt; unknown&lt;br /&gt;
LINE 1: SELECT &#039;a&#039;=&amp;gt;&#039;b&#039;;&lt;br /&gt;
                  ^&lt;br /&gt;
HINT:  No operator matches the given name and argument type(s). You might need to add explicit type casts.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It doesn&#039;t mean one cannot use &#039;=&amp;gt;&#039; in hstores, it just isn&#039;t an operator anymore:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
=# select hstore(&#039;a=&amp;gt;b&#039;);&lt;br /&gt;
  hstore  &lt;br /&gt;
----------&lt;br /&gt;
 &amp;quot;a&amp;quot;=&amp;gt;&amp;quot;b&amp;quot;&lt;br /&gt;
(1 row)&lt;br /&gt;
&lt;br /&gt;
=# select hstore(&#039;a&#039;,&#039;b&#039;);&lt;br /&gt;
  hstore  &lt;br /&gt;
----------&lt;br /&gt;
 &amp;quot;a&amp;quot;=&amp;gt;&amp;quot;b&amp;quot;&lt;br /&gt;
(1 row)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
are still two valid ways to input a hstore.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;=&amp;gt;&amp;quot; is removed as an operator as it is a reserved keyword in SQL.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Have pg_relation_size() and friends return NULL if the object does not exist  &amp;lt;!-- (Phil Sorber)--&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
A relation could be dropped by a concurrent session, while one was doing a pg_relation_size on it, leading to a SQL exception. Now, it merely returns NULL for this record.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Remove the spclocation field from pg_tablespace &amp;lt;!-- (Magnus Hagander)--&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
The spclocation field provided the real location of the tablespace. It was filled in during the CREATE or ALTER TABLESPACE command. So it could be wrong: somebody just had to shutdown the cluster, move the tablespace&#039;s directory, re-create the symlink in pg_tblspc, and forget to update the spclocation field. The cluster would still run, as the spclocation wasn&#039;t used.&lt;br /&gt;
&lt;br /&gt;
So this field has been removed. To get the tablespace&#039;s location, use pg_tablespace_location():&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
=# SELECT *, pg_tablespace_location(oid) AS spclocation FROM pg_tablespace;&lt;br /&gt;
  spcname   | spcowner | spcacl | spcoptions |  spclocation   &lt;br /&gt;
------------+----------+--------+------------+----------------&lt;br /&gt;
 pg_default |       10 |        |            | &lt;br /&gt;
 pg_global  |       10 |        |            | &lt;br /&gt;
 tmptblspc  |       10 |        |            | /tmp/tmptblspc&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Have EXTRACT of a non-timezone-aware value measure the epoch from local midnight, not UTC midnight &amp;lt;!-- (Tom Lane) --&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
With PostgreSQL 9.1:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
=#SELECT extract(epoch FROM &#039;2012-07-02 00:00:00&#039;::timestamp);&lt;br /&gt;
 date_part  &lt;br /&gt;
------------&lt;br /&gt;
 1341180000&lt;br /&gt;
(1 row)&lt;br /&gt;
&lt;br /&gt;
=# SELECT extract(epoch FROM &#039;2012-07-02 00:00:00&#039;::timestamptz);&lt;br /&gt;
 date_part  &lt;br /&gt;
------------&lt;br /&gt;
 1341180000&lt;br /&gt;
(1 row)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is no difference in behaviour between a timstamp with or without timezone.&lt;br /&gt;
&lt;br /&gt;
With 9.1:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
=#SELECT extract(epoch FROM &#039;2012-07-02 00:00:00&#039;::timestamp);&lt;br /&gt;
 date_part  &lt;br /&gt;
------------&lt;br /&gt;
 1341187200&lt;br /&gt;
(1 row)&lt;br /&gt;
&lt;br /&gt;
=# SELECT extract(epoch FROM &#039;2012-07-02 00:00:00&#039;::timestamptz);&lt;br /&gt;
 date_part  &lt;br /&gt;
------------&lt;br /&gt;
 1341180000&lt;br /&gt;
(1 row)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When the timestamp has no timezone, the epoch is calculated with the &amp;quot;local midnight&amp;quot;, meaning the 1st january of 1970 at midnight, local-time.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Fix to_date() and to_timestamp() to wrap incomplete dates toward 2020 &amp;lt;!-- (Bruce Momjian)--&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
The wrapping was not consistent between 2 digit dates and 3 digit dates: 2 digit dates always chose the date closest to 2020, 3 digit dates mapped dates from 100 to 999 on 1100 to 1999, and 000 to 099 on 2000 to 2099.&lt;br /&gt;
&lt;br /&gt;
Now PostgreSQL chooses the date closest to 2020, for 2 and 3 digit dates.&lt;br /&gt;
&lt;br /&gt;
With 9.1:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
=# SELECT to_date(&#039;200-07-02&#039;,&#039;YYY-MM-DD&#039;);&lt;br /&gt;
  to_date   &lt;br /&gt;
------------&lt;br /&gt;
 1200-07-02&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With 9.2:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT to_date(&#039;200-07-02&#039;,&#039;YYY-MM-DD&#039;);&lt;br /&gt;
  to_date   &lt;br /&gt;
------------&lt;br /&gt;
 2200-07-02&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==pg_stat_activity and pg_stat_replication&#039;s definitions have changed &amp;lt;!--Magnus Hagander --&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
The view pg_stat_activity has changed. It&#039;s not backward compatible, but let&#039;s see what this new definition brings us:&lt;br /&gt;
&lt;br /&gt;
* current_query disappears and is replaced by two columns:&lt;br /&gt;
** state: is the session running a query, waiting&lt;br /&gt;
** query: what is the last run (or still running if stat is &amp;quot;active&amp;quot;) query&lt;br /&gt;
* The column procpid is renamed to pid, to be consistent with other system views&lt;br /&gt;
&lt;br /&gt;
The benefit is mostly for tracking «idle in transaction» sessions. Up until now, all we could know was that one of these sessions was idle in transaction, meaning it has started a transaction, maybe done some operations, but still not committed. If that session stayed in this state for a while, there was no way of knowing how it got in this state.&lt;br /&gt;
&lt;br /&gt;
Here is an example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
-[ RECORD 1 ]----+---------------------------------&lt;br /&gt;
datid            | 16384&lt;br /&gt;
datname          | postgres&lt;br /&gt;
pid              | 20804&lt;br /&gt;
usesysid         | 10&lt;br /&gt;
usename          | postgres&lt;br /&gt;
application_name | psql&lt;br /&gt;
client_addr      | &lt;br /&gt;
client_hostname  | &lt;br /&gt;
client_port      | -1&lt;br /&gt;
backend_start    | 2012-07-02 15:02:51.146427+02&lt;br /&gt;
xact_start       | 2012-07-02 15:15:28.386865+02&lt;br /&gt;
query_start      | 2012-07-02 15:15:30.410834+02&lt;br /&gt;
state_change     | 2012-07-02 15:15:30.411287+02&lt;br /&gt;
waiting          | f&lt;br /&gt;
state            | idle in transaction&lt;br /&gt;
query            | DELETE FROM test;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With PostgreSQL 9.1, all we would have would be «idle in transaction».&lt;br /&gt;
&lt;br /&gt;
As this change was backward-incompatible, procpid was also renamed to pid, to be more consistent with other system views.&lt;br /&gt;
The view pg_stat_replication has also changed. The column procpid is renamed to pid, to also be consistent with other system views.&lt;br /&gt;
&lt;br /&gt;
==Change all SQL-level statistics timing values to float8-stored milliseconds &amp;lt;!-- (Tom Lane) --&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
pg_stat_user_functions.total_time, pg_stat_user_functions.self_time, pg_stat_xact_user_functions.total_time, pg_stat_xact_user_functions.self_time, and pg_stat_statements.total_time (contrib) are now in milliseconds, to be consistent with the rest of the timing values.&lt;br /&gt;
&lt;br /&gt;
==postgresql.conf parameters changes &amp;lt;!-- (Heikki Linnakangas, Tom Lane, Peter Eisentraut) --&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
* silent_mode has been removed. Use pg_ctl -l postmaster.log&lt;br /&gt;
* wal_sender_delay has been removed. It is no longer needed&lt;br /&gt;
* custom_variable_classes has been removed. All «classes» are accepted without declaration now&lt;br /&gt;
* ssl_ca_file, ssl_cert_file, ssl_crl_file, ssl_key_file have been added, meaning you can now specify the ssl files&lt;br /&gt;
&lt;br /&gt;
= Other new features =&lt;br /&gt;
&lt;br /&gt;
== DROP INDEX CONCURRENTLY ==&lt;br /&gt;
&lt;br /&gt;
The regular DROP INDEX command takes an exclusive lock on the table. Most of the time, this isn&#039;t a problem, because this lock is short-lived. The problem usually occurs when:&lt;br /&gt;
&lt;br /&gt;
* A long-running transaction is running, and has a (shared) lock on the table&lt;br /&gt;
* A DROP INDEX is run on this table in another session, asking for an exclusive lock (and waiting for it, as it won&#039;t be granted until the long-running transaction ends)&lt;br /&gt;
&lt;br /&gt;
At this point, all other transactions needing to take a shared lock on the table (for a simple SELECT for instance) will have to wait too: their lock acquisition is queued after the DROP INDEX&#039;s one.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
DROP INDEX CONCURRENTLY works around this and won&#039;t lock normal DML statements, just as CREATE INDEX CONCURRENTLY. The main limitation is the same: DROP INDEX CONCURRENTLY can&#039;t be run in a transaction. Moreover, you can only DROP one index with CONCURRENTLY, and CASCADE isn&#039;t supported either.&lt;br /&gt;
&lt;br /&gt;
== NOT VALID CHECK constraints ==&lt;br /&gt;
&lt;br /&gt;
PostgreSQL 9.1 introduced «NOT VALID» foreign keys. This has been extended to CHECK constraints. Adding a «NOT VALID» constraint on a table means that current data won&#039;t be validated, only new and updated rows.&lt;br /&gt;
&lt;br /&gt;
  =# CREATE TABLE test (a int); &lt;br /&gt;
  CREATE TABLE&lt;br /&gt;
  =# INSERT INTO test SELECT generate_series(1,100);&lt;br /&gt;
  INSERT 0 100&lt;br /&gt;
  =# ALTER TABLE test ADD CHECK (a&amp;gt;100) NOT VALID;&lt;br /&gt;
  ALTER TABLE&lt;br /&gt;
  =# INSERT INTO test VALUES (99);&lt;br /&gt;
  ERROR:  new row for relation &amp;quot;test&amp;quot; violates check constraint &amp;quot;test_a_check&amp;quot;&lt;br /&gt;
  DETAIL:  Failing row contains (99).&lt;br /&gt;
  =# INSERT INTO test VALUES (101);&lt;br /&gt;
  INSERT 0 1&lt;br /&gt;
&lt;br /&gt;
Then, later, we can validate the whole table:&lt;br /&gt;
&lt;br /&gt;
  =# ALTER TABLE test VALIDATE CONSTRAINT test_a_check ;&lt;br /&gt;
  ERROR:  check constraint &amp;quot;test_a_check&amp;quot; is violated by some row&lt;br /&gt;
&lt;br /&gt;
Domains, which are types with added constraints, can also be declared as not valid, and validated later.&lt;br /&gt;
&lt;br /&gt;
Check constraints can also be renamed now:&lt;br /&gt;
&lt;br /&gt;
  =# ALTER TABLE test RENAME CONSTRAINT test_a_check TO validate_a;&lt;br /&gt;
  ALTER TABLE&lt;br /&gt;
&lt;br /&gt;
Last, but not least, constraints can be declared as not inheritable, which will be useful in partitioned environments. Let&#039;s take PostgreSQL documentation example, and see how it improves the situation:&lt;br /&gt;
&lt;br /&gt;
  CREATE TABLE measurement (&lt;br /&gt;
      city_id         int not null,&lt;br /&gt;
      logdate         date not null,&lt;br /&gt;
      peaktemp        int,&lt;br /&gt;
      unitsales       int,&lt;br /&gt;
      CHECK (logdate IS NULL) NO INHERIT&lt;br /&gt;
  );&lt;br /&gt;
  &lt;br /&gt;
  CREATE TABLE measurement_y2006m02 (&lt;br /&gt;
      CHECK ( logdate &amp;gt;= DATE &#039;2006-02-01&#039; AND logdate &amp;lt; DATE &#039;2006-03-01&#039; )&lt;br /&gt;
  ) INHERITS (measurement);&lt;br /&gt;
  CREATE TABLE measurement_y2006m03 (&lt;br /&gt;
      CHECK ( logdate &amp;gt;= DATE &#039;2006-03-01&#039; AND logdate &amp;lt; DATE &#039;2006-04-01&#039; )&lt;br /&gt;
  ) INHERITS (measurement);&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  INSERT INTO measurement VALUES (1,&#039;2006-02-20&#039;,1,1);&lt;br /&gt;
  ERROR:  new row for relation &amp;quot;measurement&amp;quot; violates check constraint &amp;quot;measurement_logdate_check&amp;quot;&lt;br /&gt;
  DETAIL:  Failing row contains (1, 2006-02-20, 1, 1).&lt;br /&gt;
  INSERT INTO measurement_y2006m02 VALUES (1,&#039;2006-02-20&#039;,1,1);&lt;br /&gt;
  INSERT 0 1&lt;br /&gt;
&lt;br /&gt;
Until now, every check constraint created on measurement would have been inherited by children tables. So adding a constraint forbidding inserts, or allowing only some of them, on the parent table was impossible.&lt;br /&gt;
&lt;br /&gt;
== Reduce ALTER TABLE rewrites ==&lt;br /&gt;
&lt;br /&gt;
A table won&#039;t get rewritten anymore during an ALTER TABLE when changing the type of a column in the following cases:&lt;br /&gt;
&lt;br /&gt;
* varchar(x) to varchar(y) when y &amp;gt; x. It works too if going from varchar(x) to varchar or text (no size limitation)&lt;br /&gt;
* numeric(x,z) to numeric(y,z) when y&amp;gt;x, or to numeric without specifier&lt;br /&gt;
* varbit(x) to varbit(y) when y&amp;gt;x, or to varbit without specifier&lt;br /&gt;
* timestamp(x) to timestamp(y) when y&amp;gt;x or timestamp without specifier&lt;br /&gt;
* timestamptz(x) to timestamptz(y) when y&amp;gt;x or timestamptz without specifier&lt;br /&gt;
* interval(x) to interval(y) when y&amp;gt;x or interval without specifier&lt;br /&gt;
&lt;br /&gt;
== Security barriers and Leakproof ==&lt;br /&gt;
&lt;br /&gt;
This new feature has to do with views security. First, let&#039;s explain the problem, with a very simplified example:&lt;br /&gt;
&lt;br /&gt;
  =# CREATE TABLE all_data (company_id int, company_data varchar);&lt;br /&gt;
  CREATE TABLE&lt;br /&gt;
  # INSERT INTO all_data VALUES (1,&#039;secret_data_for_company_1&#039;);&lt;br /&gt;
  INSERT 0 1&lt;br /&gt;
  =# INSERT INTO all_data VALUES (2,&#039;secret_data_for_company_2&#039;);&lt;br /&gt;
  INSERT 0 1&lt;br /&gt;
  =# CREATE VIEW company1_data AS SELECT * FROM all_data WHERE company_id = 1;&lt;br /&gt;
  CREATE VIEW&lt;br /&gt;
&lt;br /&gt;
This is a quite classical way of giving access to only a part of a table to a user: we&#039;ll create a user for company_id 1, grant to him the right to access company1_data, and deny him the right to access all_data.&lt;br /&gt;
&lt;br /&gt;
The plan to this query is the following:&lt;br /&gt;
&lt;br /&gt;
  =# explain SELECT * FROM company1_data ;&lt;br /&gt;
                          QUERY PLAN                        &lt;br /&gt;
  ----------------------------------------------------------&lt;br /&gt;
   Seq Scan on all_data  (cost=0.00..25.38 rows=6 width=36)&lt;br /&gt;
     Filter: (company_id = 1)&lt;br /&gt;
&lt;br /&gt;
Even if there was more data, a sequential scan could still be forced: just &amp;quot;SET enable_indexscan to OFF&amp;quot; and the likes.&lt;br /&gt;
&lt;br /&gt;
So this query reads all the records from all_data, filters them, and returns to the user only the matching rows. There is a way to display scanned records before they are filtered: just create a function with a very low cost, and call it while doing the query:&lt;br /&gt;
&lt;br /&gt;
  CREATE OR REPLACE FUNCTION peek(text) RETURNS boolean LANGUAGE plpgsql AS&lt;br /&gt;
  $$&lt;br /&gt;
  BEGIN&lt;br /&gt;
    RAISE NOTICE &#039;%&#039;,$1;&lt;br /&gt;
    RETURN true;&lt;br /&gt;
  END&lt;br /&gt;
  $$&lt;br /&gt;
  COST 0.1;&lt;br /&gt;
&lt;br /&gt;
This function just has to cost less than the = operator, which costs 1, to be executed first.&lt;br /&gt;
&lt;br /&gt;
The result is this:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  =# SELECT * FROM company1_data WHERE peek(company1_data.company_data);&lt;br /&gt;
  NOTICE:  secret_data_for_company_1&lt;br /&gt;
  NOTICE:  secret_data_for_company_2&lt;br /&gt;
   company_id |       company_data        &lt;br /&gt;
  ------------+---------------------------&lt;br /&gt;
            1 | secret_data_for_company_1&lt;br /&gt;
  (1 row)&lt;br /&gt;
&lt;br /&gt;
We got access to the record from the second company (in the NOTICE messages).&lt;br /&gt;
&lt;br /&gt;
So this is the first new feature: the view can be declared as implementing &amp;quot;security barriers&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  =# CREATE VIEW company1_data WITH (security_barrier) AS SELECT * FROM all_data WHERE company_id = 1;&lt;br /&gt;
  CREATE VIEW&lt;br /&gt;
  =# SELECT * FROM company1_data WHERE peek(company1_data.company_data);&lt;br /&gt;
  NOTICE:  secret_data_for_company_1&lt;br /&gt;
   company_id |       company_data        &lt;br /&gt;
  ------------+---------------------------&lt;br /&gt;
            1 | secret_data_for_company_1&lt;br /&gt;
  (1 row)&lt;br /&gt;
&lt;br /&gt;
The view&#039;s not leaking anymore. The problem, of course, is that there is a performance impact: maybe the &amp;quot;peek&amp;quot; function could have made the query faster, by filtering lots of rows early in the plan.&lt;br /&gt;
&lt;br /&gt;
This leads to the complementary feature: some function may be declared as &amp;quot;LEAKPROOF&amp;quot;, meaning that they won&#039;t leak the data they are passed into error or notice messages.&lt;br /&gt;
&lt;br /&gt;
Declaring our peek function as LEAKPROOF is a very bad idea, but let&#039;s do it just to demonstrate how it&#039;s used:&lt;br /&gt;
&lt;br /&gt;
  CREATE OR REPLACE FUNCTION peek(text) RETURNS boolean LEAKPROOF LANGUAGE plpgsql AS&lt;br /&gt;
  $$&lt;br /&gt;
  BEGIN&lt;br /&gt;
    RAISE NOTICE &#039;%&#039;,$1;&lt;br /&gt;
    RETURN true;&lt;br /&gt;
  END&lt;br /&gt;
  $$&lt;br /&gt;
  COST 0.1;&lt;br /&gt;
&lt;br /&gt;
A LEAKPROOF function is executed «normally»:&lt;br /&gt;
&lt;br /&gt;
  =# SELECT * FROM company1_data WHERE peek(company1_data.company_data);&lt;br /&gt;
  NOTICE:  secret_data_for_company_1&lt;br /&gt;
  NOTICE:  secret_data_for_company_2&lt;br /&gt;
   company_id |       company_data        &lt;br /&gt;
  ------------+---------------------------&lt;br /&gt;
            1 | secret_data_for_company_1&lt;br /&gt;
  (1 row)&lt;br /&gt;
&lt;br /&gt;
Of course, in our case, peek isn&#039;t LEAKPROOF and shouldn&#039;t be declared as such. Only superuser have the permission to declare a LEAKPROOF function.&lt;br /&gt;
&lt;br /&gt;
== New options for pg_dump ==&lt;br /&gt;
&lt;br /&gt;
Until now, one could ask pg_dump to dump a table&#039;s data, or a table&#039;s meta-data (DDL statements for creating the table&#039;s structure, indexes, constraints). Some meta-data is better restored before the data (the table&#039;s structure, check constraints), some is better after the data (indexes, unique constraints, foreign keys…), for performance reasons mostly.&lt;br /&gt;
&lt;br /&gt;
So there are now a few more options:&lt;br /&gt;
&lt;br /&gt;
* --section=pre-data: dump what&#039;s needed before restoring the data. Of course, this can be combined with a -t for instance, to specify one table&lt;br /&gt;
* --section=post-data : dump what&#039;s needed after restoring the data.&lt;br /&gt;
* --section=data: dump the data&lt;br /&gt;
* --exclude-table-data: dump everything, except THIS table&#039;s data. It means pg_dump will still dump other tables&#039; data.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:PostgreSQL 9.2]]&lt;/div&gt;</summary>
		<author><name>Intgr</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=What%27s_new_in_PostgreSQL_9.2&amp;diff=18092</id>
		<title>What&#039;s new in PostgreSQL 9.2</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=What%27s_new_in_PostgreSQL_9.2&amp;diff=18092"/>
		<updated>2012-08-27T16:02:48Z</updated>

		<summary type="html">&lt;p&gt;Intgr: /* Performance improvements */ Per 3db6524fe63f0598dcb2b307bb422bc126f2b15d: textanycat, anytextcat, quote_literal, and quote_nullable are now stable&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Languages}}&lt;br /&gt;
&lt;br /&gt;
This document showcases many of the latest developments in PostgreSQL 9.2, compared to the last major release &amp;amp;ndash; PostgreSQL 9.1. There are many improvements in this release, so this wiki page covers many of the more important changes in detail. The full list of changes is itemised in &#039;&#039;Release Notes&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Major new features=&lt;br /&gt;
&lt;br /&gt;
==Index-only scans &amp;lt;!-- Robert Haas, Ibrar Ahmed, Heikki Linnakangas, Tom Lane --&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
In PostgreSQL, indexes have no &amp;quot;visibility&amp;quot; information. It means that when you access a record by its index, PostgreSQL has to visit the real tuple in the table to be sure it is visible to you: the tuple the index points to may simply be an old version of the record you are looking for.&lt;br /&gt;
&lt;br /&gt;
It can be a very big performance problem: the index is mostly ordered, so accessing its records is quite efficient, while the records may be scattered all over the place (that&#039;s a reason why PostgreSQL has a cluster command, but that&#039;s another story). In 9.2, PostgreSQL will use an &amp;quot;Index Only Scan&amp;quot; when possible, and not access the record itself if it doesn&#039;t need to.&lt;br /&gt;
&lt;br /&gt;
There is still no visibility information in the index. So in order to do this, PostgreSQL uses the visibility map ([http://www.postgresql.org/docs/devel/static/storage-vm.html visibility map]) , which tells it whether the whole content of a (usually) 8K page is visible to all transactions or not. When the index record points to a tuple contained in an «all visible» page, PostgreSQL won&#039;t have to access the tuple, it will be able to build it directly from the index. Of course, all the columns requested by the query must be in the index.&lt;br /&gt;
&lt;br /&gt;
The visibility map is maintained by VACUUM (it sets the visible bit), and by the backends doing SQL work (they unset the visible bit).&lt;br /&gt;
&lt;br /&gt;
Here is an example.&lt;br /&gt;
&lt;br /&gt;
  CREATE TABLE demo_ios (col1 float, col2 float, col3 text);&lt;br /&gt;
&lt;br /&gt;
In this table, we&#039;ll put random data, in order to have &amp;quot;scattered&amp;quot; data. We&#039;ll put 100 million records, to have a big recordset, and have it not fit in memory (that&#039;s a 4GB-ram machine). This is an ideal case, made for this demo. The gains wont be that big in real life.&lt;br /&gt;
&lt;br /&gt;
  INSERT INTO demo_ios SELECT generate_series(1,100000000),random(), &#039;mynotsolongstring&#039;;&lt;br /&gt;
  &lt;br /&gt;
  SELECT pg_size_pretty(pg_total_relation_size(&#039;demo_ios&#039;));&lt;br /&gt;
   pg_size_pretty &lt;br /&gt;
  ----------------&lt;br /&gt;
   6512 MB&lt;br /&gt;
&lt;br /&gt;
Let&#039;s pretend that the query is this:&lt;br /&gt;
&lt;br /&gt;
  SELECT col1,col2 FROM demo_ios where col2 BETWEEN 0.01 AND 0.02&lt;br /&gt;
&lt;br /&gt;
In order to use an index only scan on this query, we need an index on col2,col1 (col2 first, as it is used in the WHERE clause).&lt;br /&gt;
&lt;br /&gt;
  CREATE index idx_demo_ios on demo_ios(col2,col1);&lt;br /&gt;
&lt;br /&gt;
We vacuum the visibility map to be up-to-date:&lt;br /&gt;
&lt;br /&gt;
  VACUUM demo_ios;&lt;br /&gt;
&lt;br /&gt;
All the timing you&#039;ll see below are done on a cold OS and PostgreSQL cache (that&#039;s where the gains are, as the purpose on Index Only Scans is to reduce I/O).&lt;br /&gt;
&lt;br /&gt;
Let&#039;s first try without Index Only Scans:&lt;br /&gt;
&lt;br /&gt;
  SET enable_indexonlyscan to off;&lt;br /&gt;
  &lt;br /&gt;
  EXPLAIN (analyze,buffers) select col1,col2 FROM demo_ios where col2 between 0.01 and 0.02;&lt;br /&gt;
                                                                 QUERY PLAN                                                               &lt;br /&gt;
  ----------------------------------------------------------------------------------------------------------------------------------------&lt;br /&gt;
   Bitmap Heap Scan on demo_ios  (cost=25643.01..916484.44 rows=993633 width=16) (actual time=763.391..362963.899 rows=1000392 loops=1)&lt;br /&gt;
     Recheck Cond: ((col2 &amp;gt;= 0.01::double precision) AND (col2 &amp;lt;= 0.02::double precision))&lt;br /&gt;
     Rows Removed by Index Recheck: 68098621&lt;br /&gt;
     Buffers: shared hit=2 read=587779&lt;br /&gt;
     -&amp;gt;  Bitmap Index Scan on idx_demo_ios  (cost=0.00..25394.60 rows=993633 width=0) (actual time=759.011..759.011 rows=1000392 loops=1)&lt;br /&gt;
           Index Cond: ((col2 &amp;gt;= 0.01::double precision) AND (col2 &amp;lt;= 0.02::double precision))&lt;br /&gt;
           Buffers: shared hit=2 read=3835&lt;br /&gt;
   Total runtime: 364390.127 ms&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
With Index Only Scans:&lt;br /&gt;
&lt;br /&gt;
  explain (analyze,buffers) select col1,col2 from demo_ios where col2 between 0.01 and 0.02;&lt;br /&gt;
                                                                    QUERY PLAN                                                                   &lt;br /&gt;
  -----------------------------------------------------------------------------------------------------------------------------------------------&lt;br /&gt;
   Index Only Scan using idx_demo_ios on demo_ios  (cost=0.00..35330.93 rows=993633 width=16) (actual time=58.100..3250.589 rows=1000392 loops=1)&lt;br /&gt;
     Index Cond: ((col2 &amp;gt;= 0.01::double precision) AND (col2 &amp;lt;= 0.02::double precision))&lt;br /&gt;
     Heap Fetches: 0&lt;br /&gt;
     Buffers: shared hit=923073 read=3848&lt;br /&gt;
   Total runtime: 4297.405 ms&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
As nothing is free, there are a few things to keep in mind:&lt;br /&gt;
&lt;br /&gt;
* Adding indexes for index only scans obviously adds indexes to your table. So updates will be slower.&lt;br /&gt;
* You will index columns that weren&#039;t indexed before. So there will be less opportunities for HOT updates.&lt;br /&gt;
* Gains will probably be smaller in real life situations.&lt;br /&gt;
&lt;br /&gt;
This required making visibility map changes crash-safe, so visibility map bit changes are now WAL-logged.&lt;br /&gt;
&lt;br /&gt;
==Replication improvements &amp;lt;!-- Fujii Masao, Simon Riggs, Magnus Hagander, Jun Ishizuka --&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
Streaming Replication is getting even more polished with this release. One on the main remaining gripes about streaming replication is that all the slaves have to be connected to the same and unique master, consuming its resources.&lt;br /&gt;
&lt;br /&gt;
Moreover, in case of a failover, it was very complicated to reconnect all the remaining slaves to the newly promoted master.&lt;br /&gt;
&lt;br /&gt;
To be on the safe side, it was easier to re-synchronize the slaves to the new masters from scratch, meaning that during this failover, only one server was active, and under heavy load, as it was used to rebuild all the slaves.&lt;br /&gt;
&lt;br /&gt;
* With 9.2, a slave can also be a replication master, allowing cascading replication.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s build this. We start with an already working 9.2 database.&lt;br /&gt;
&lt;br /&gt;
We set it up for replication:&lt;br /&gt;
&lt;br /&gt;
postgresql.conf:&lt;br /&gt;
  wal_level=hot_standby #(could be archive too)&lt;br /&gt;
  max_wal_senders=5&lt;br /&gt;
  hot_standby=on&lt;br /&gt;
&lt;br /&gt;
You&#039;ll probably also want to activate archiving in production, it won&#039;t be done here.&lt;br /&gt;
&lt;br /&gt;
pg_hba.conf (do not use trust in production):&lt;br /&gt;
  host   replication replication_user          0.0.0.0/0                      md5&lt;br /&gt;
 &lt;br /&gt;
Create the user:&lt;br /&gt;
  create user replication_user replication password &#039;secret&#039;;&lt;br /&gt;
&lt;br /&gt;
Clone the database:&lt;br /&gt;
&lt;br /&gt;
  pg_basebackup -h localhost -U replication_user -D data2&lt;br /&gt;
  Password:&lt;br /&gt;
&lt;br /&gt;
We have a brand new cluster in the data2 directory. We&#039;ll change the port so that it can start (postgresql.conf):&lt;br /&gt;
  port=5433&lt;br /&gt;
&lt;br /&gt;
We add a recovery.conf to tell it how to stream from the master database:&lt;br /&gt;
  standby_mode = on&lt;br /&gt;
  primary_conninfo = &#039;host=localhost port=5432 user=replication_user password=secret&#039; &lt;br /&gt;
&lt;br /&gt;
  pg_ctl -D data2 start&lt;br /&gt;
  server starting&lt;br /&gt;
  LOG:  database system was interrupted; last known up at 2012-07-03 17:58:09 CEST&lt;br /&gt;
  LOG:  creating missing WAL directory &amp;quot;pg_xlog/archive_status&amp;quot;&lt;br /&gt;
  LOG:  entering standby mode&lt;br /&gt;
  LOG:  streaming replication successfully connected to primary&lt;br /&gt;
  LOG:  redo starts at 0/9D000020&lt;br /&gt;
  LOG:  consistent recovery state reached at 0/9D0000B8&lt;br /&gt;
  LOG:  database system is ready to accept read only connections&lt;br /&gt;
&lt;br /&gt;
Now, let&#039;s add a second slave, which will use this slave:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  pg_basebackup -h localhost -U replication_user -D data3 -p 5433&lt;br /&gt;
  Password: &lt;br /&gt;
&lt;br /&gt;
We edit data3&#039;s postgresql.conf to change the port:&lt;br /&gt;
  port=5434&lt;br /&gt;
&lt;br /&gt;
We modify the recovery.conf to stream from the slave:&lt;br /&gt;
  standby_mode = on&lt;br /&gt;
  primary_conninfo = &#039;host=localhost port=5433 user=replication_user password=secret&#039;             # e.g. &#039;host=localhost port=5432&#039;&lt;br /&gt;
&lt;br /&gt;
We start the cluster:&lt;br /&gt;
  pg_ctl -D data3 start&lt;br /&gt;
  server starting&lt;br /&gt;
  LOG:  database system was interrupted while in recovery at log time 2012-07-03 17:58:09 CEST&lt;br /&gt;
  HINT:  If this has occurred more than once some data might be corrupted and you might need to choose an earlier recovery target.&lt;br /&gt;
  LOG:  creating missing WAL directory &amp;quot;pg_xlog/archive_status&amp;quot;&lt;br /&gt;
  LOG:  entering standby mode&lt;br /&gt;
  LOG:  streaming replication successfully connected to primary&lt;br /&gt;
  LOG:  redo starts at 0/9D000020&lt;br /&gt;
  LOG:  consistent recovery state reached at 0/9E000000&lt;br /&gt;
  LOG:  database system is ready to accept read only connections&lt;br /&gt;
&lt;br /&gt;
Now, everything modified on the master cluster get streamed to the first slave, and from there to the second slave. This second replication has to be monitored from the first slave (the master knows nothing about it).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* As you may have noticed from the examble, pg_basebackup now works from slaves.&lt;br /&gt;
&lt;br /&gt;
* There is another use case that wasn&#039;t covered: what if a user didn&#039;t care for having a full fledged slave, and only wanted to stream the WAL files to another location, to benefit from the reduced data loss without the burden of maintaining a slave ?&lt;br /&gt;
&lt;br /&gt;
pg_receivexlog is provided just for this purpose: it pretends to be a PostgreSQL slave, but only stores the log files as they are streamed, in a directory:&lt;br /&gt;
  pg_receivexlog -D /tmp/new_logs -h localhost -U replication_user&lt;br /&gt;
&lt;br /&gt;
will connect to the master (or a slave), and start creating files: &lt;br /&gt;
  ls /tmp/new_logs/&lt;br /&gt;
  00000001000000000000009E.partial&lt;br /&gt;
&lt;br /&gt;
Files are of the segment size, so they can be used for a normal recovery of the database. It&#039;s the same as an archive command, but with a much smaller granularity.&lt;br /&gt;
Remember to rename the last segment to remove the .partial suffix before using it with PITR or other.&lt;br /&gt;
&lt;br /&gt;
* synchronous_commit has a new value: remote_write. It can be used when there is a synchronous slave (synchronous_standby_names is set), meaning that the master doesn&#039;t have to wait for the slave to have written the data to disk, only for the slave to have acknowledged the data. With this set, data is protected from a crash on the master, but could still be lost if the slave crashed at the same time (i.e. before having written the in flight data to disk). As this is a quite remote possibility, some people will be interested in this compromise.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==JSON datatype==&lt;br /&gt;
&lt;br /&gt;
The JSON datatype is meant for storing JSON-structured data. It will validate that the input JSON string is correct JSON:&lt;br /&gt;
&lt;br /&gt;
  =# SELECT &#039;{&amp;quot;username&amp;quot;:&amp;quot;john&amp;quot;,&amp;quot;posts&amp;quot;:121,&amp;quot;emailaddress&amp;quot;:&amp;quot;john@nowhere.com&amp;quot;}&#039;::json;&lt;br /&gt;
                                 json                                &lt;br /&gt;
  -------------------------------------------------------------------&lt;br /&gt;
   {&amp;quot;username&amp;quot;:&amp;quot;john&amp;quot;,&amp;quot;posts&amp;quot;:121,&amp;quot;emailaddress&amp;quot;:&amp;quot;john@nowhere.com&amp;quot;}&lt;br /&gt;
  (1 row)&lt;br /&gt;
  &lt;br /&gt;
  =# SELECT &#039;{&amp;quot;username&amp;quot;,&amp;quot;posts&amp;quot;:121,&amp;quot;emailaddress&amp;quot;:&amp;quot;john@nowhere.com&amp;quot;}&#039;::json;&lt;br /&gt;
  ERROR:  invalid input syntax for type json at character 8&lt;br /&gt;
  DETAIL:  Expected &amp;quot;:&amp;quot;, but found &amp;quot;,&amp;quot;.&lt;br /&gt;
  CONTEXT:  JSON data, line 1: {&amp;quot;username&amp;quot;,...&lt;br /&gt;
  STATEMENT:  SELECT &#039;{&amp;quot;username&amp;quot;,&amp;quot;posts&amp;quot;:121,&amp;quot;emailaddress&amp;quot;:&amp;quot;john@nowhere.com&amp;quot;}&#039;::json;&lt;br /&gt;
  ERROR:  invalid input syntax for type json&lt;br /&gt;
  LINE 1: SELECT &#039;{&amp;quot;username&amp;quot;,&amp;quot;posts&amp;quot;:121,&amp;quot;emailaddress&amp;quot;:&amp;quot;john@nowhere...&lt;br /&gt;
                 ^&lt;br /&gt;
  DETAIL:  Expected &amp;quot;:&amp;quot;, but found &amp;quot;,&amp;quot;.&lt;br /&gt;
  CONTEXT:  JSON data, line 1: {&amp;quot;username&amp;quot;,...&lt;br /&gt;
&lt;br /&gt;
You can also convert a row type to JSON:&lt;br /&gt;
&lt;br /&gt;
  =#SELECT * FROM demo ;&lt;br /&gt;
   username | posts |    emailaddress     &lt;br /&gt;
  ----------+-------+---------------------&lt;br /&gt;
   john     |   121 | john@nowhere.com&lt;br /&gt;
   mickael  |   215 | mickael@nowhere.com&lt;br /&gt;
  (2 rows)&lt;br /&gt;
  &lt;br /&gt;
  =# SELECT row_to_json(demo) FROM demo;&lt;br /&gt;
                                 row_to_json                               &lt;br /&gt;
  -------------------------------------------------------------------------&lt;br /&gt;
   {&amp;quot;username&amp;quot;:&amp;quot;john&amp;quot;,&amp;quot;posts&amp;quot;:121,&amp;quot;emailaddress&amp;quot;:&amp;quot;john@nowhere.com&amp;quot;}&lt;br /&gt;
   {&amp;quot;username&amp;quot;:&amp;quot;mickael&amp;quot;,&amp;quot;posts&amp;quot;:215,&amp;quot;emailaddress&amp;quot;:&amp;quot;mickael@nowhere.com&amp;quot;}&lt;br /&gt;
  (2 rows)&lt;br /&gt;
&lt;br /&gt;
Or an array type:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  =# select array_to_json(array_agg(demo)) from demo;&lt;br /&gt;
                                                                  array_to_json                                                                &lt;br /&gt;
  ---------------------------------------------------------------------------------------------------------------------------------------------&lt;br /&gt;
   [{&amp;quot;username&amp;quot;:&amp;quot;john&amp;quot;,&amp;quot;posts&amp;quot;:121,&amp;quot;emailaddress&amp;quot;:&amp;quot;john@nowhere.com&amp;quot;},{&amp;quot;username&amp;quot;:&amp;quot;mickael&amp;quot;,&amp;quot;posts&amp;quot;:215,&amp;quot;emailaddress&amp;quot;:&amp;quot;mickael@nowhere.com&amp;quot;}]&lt;br /&gt;
  (1 row)&lt;br /&gt;
&lt;br /&gt;
== Range Types ==&lt;br /&gt;
&lt;br /&gt;
Range types are used to store a range of data of a given type. There are a few pre-defined types. They are integer (int4range), bigint (int8range), numeric (numrange), timestamp without timezone (tsrange), timestamp with timezone (tstzrange), and date (daterange).&lt;br /&gt;
&lt;br /&gt;
Ranges can be made of continuous (numeric, timestamp...) or discrete (integer, date...) data types. They can be open (the bound isn&#039;t part of the range) or closed (the bound is part of the range). A bound can also be infinite.&lt;br /&gt;
&lt;br /&gt;
Without these datatypes, most people solve the range problems by using two columns in a table. These range types are much more powerful, as you can use many operators on them:&lt;br /&gt;
&lt;br /&gt;
Here is the intersection between then 1000(open)-2000(closed) and 1000(closed)-1200(closed) numeric range:&lt;br /&gt;
&lt;br /&gt;
  SELECT &#039;(1000,2000]&#039;::numrange * &#039;[1000,1200]&#039;::numrange;&lt;br /&gt;
    ?column?   &lt;br /&gt;
  -------------&lt;br /&gt;
   (1000,1200]&lt;br /&gt;
  (1 row)&lt;br /&gt;
&lt;br /&gt;
So you can query on things like: «give me all ranges that intersect this»:&lt;br /&gt;
&lt;br /&gt;
  =# SELECT * from test_range ;&lt;br /&gt;
                         period                        &lt;br /&gt;
  -----------------------------------------------------&lt;br /&gt;
   [&amp;quot;2012-01-01 00:00:00+01&amp;quot;,&amp;quot;2012-01-02 12:00:00+01&amp;quot;]&lt;br /&gt;
   [&amp;quot;2012-01-01 00:00:00+01&amp;quot;,&amp;quot;2012-03-01 00:00:00+01&amp;quot;]&lt;br /&gt;
   [&amp;quot;2008-01-01 00:00:00+01&amp;quot;,&amp;quot;2015-01-01 00:00:00+01&amp;quot;]&lt;br /&gt;
  (3 rows)&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  =# SELECT * FROM test_range WHERE period &amp;amp;&amp;amp; &#039;[2012-01-03 00:00:00,2012-01-03 12:00:00]&#039;; &lt;br /&gt;
                         period                        &lt;br /&gt;
  -----------------------------------------------------&lt;br /&gt;
   [&amp;quot;2012-01-01 00:00:00+01&amp;quot;,&amp;quot;2012-03-01 00:00:00+01&amp;quot;]&lt;br /&gt;
   [&amp;quot;2008-01-01 00:00:00+01&amp;quot;,&amp;quot;2015-01-01 00:00:00+01&amp;quot;]&lt;br /&gt;
  (2 rows)&lt;br /&gt;
&lt;br /&gt;
This query could use an index defined like this:&lt;br /&gt;
&lt;br /&gt;
  =# CREATE INDEX idx_test_range on test_range USING gist (period);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You can also use these range data types to define exclusion constraints:&lt;br /&gt;
&lt;br /&gt;
  CREATE EXTENSION btree_gist ;&lt;br /&gt;
  CREATE TABLE reservation (room_id int, period tstzrange);&lt;br /&gt;
  ALTER TABLE reservation ADD  EXCLUDE USING GIST (room_id WITH =, period WITH &amp;amp;&amp;amp;);&lt;br /&gt;
&lt;br /&gt;
This means that now it is forbidden to have two records in this table where room_id is equal and period overlaps. The extension btree_gist is required to create a GiST index on room_id (it&#039;s an integer, it is usually indexed with a btree index).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  =# INSERT INTO reservation VALUES (1,&#039;(2012-08-23 14:00:00,2012-08-23 15:00:00)&#039;);&lt;br /&gt;
  INSERT 0 1&lt;br /&gt;
  =# INSERT INTO reservation VALUES (2,&#039;(2012-08-23 14:00:00,2012-08-23 15:00:00)&#039;);&lt;br /&gt;
  INSERT 0 1&lt;br /&gt;
  =# INSERT INTO reservation VALUES (1,&#039;(2012-08-23 14:45:00,2012-08-23 15:15:00)&#039;);&lt;br /&gt;
  ERROR:  conflicting key value violates exclusion constraint &amp;quot;reservation_room_id_period_excl&amp;quot;&lt;br /&gt;
  DETAIL:  Key (room_id, period)=(1, (&amp;quot;2012-08-23 14:45:00+02&amp;quot;,&amp;quot;2012-08-23 15:15:00+02&amp;quot;)) &lt;br /&gt;
  conflicts with existing key (room_id, period)=(1, (&amp;quot;2012-08-23 14:00:00+02&amp;quot;,&amp;quot;2012-08-23 15:00:00+02&amp;quot;)).&lt;br /&gt;
  STATEMENT:  INSERT INTO reservation VALUES (1,&#039;(2012-08-23 14:45:00,2012-08-23 15:15:00)&#039;);&lt;br /&gt;
&lt;br /&gt;
One can also declare new range types.&lt;br /&gt;
&lt;br /&gt;
=Performance improvements=&lt;br /&gt;
&lt;br /&gt;
This version has performance improvements on a very large range of domains (non-exaustive):&lt;br /&gt;
&lt;br /&gt;
* The most visible will probably be the Index Only Scans, which has already been introduced in this document.&lt;br /&gt;
&lt;br /&gt;
* The lock contention of several big locks has been significantly reduced, leading to better multi-processor scalability, for machines with over 32 cores mostly. &amp;lt;!-- Robert Haas --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* The performance of in-memory sorts has been improved by up to 25% in some situations, with certain specialized sort functions introduced. &amp;lt;!-- Peter Geoghegan --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* An idle PostgreSQL server now makes less wakeups, leading to lower power consumption&amp;lt;!--Peter Geoghegan--&amp;gt;. This is especially useful on virtualized and embedded environments.&lt;br /&gt;
&lt;br /&gt;
* COPY has been improved, it will generate less WAL volume and less locks of tables&#039;s pages. &amp;lt;!-- Heikki Linnakangas --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Statistics are collected on array contents&amp;lt;!-- Alexander Korotkov --&amp;gt;, allowing for better estimations of selectivity on array operations.&lt;br /&gt;
&lt;br /&gt;
* Text-to-anytype concatenation and quote_literal/quote_nullable functions are not volatile any more, enabling better optimization in some cases &amp;lt;!-- Marti Raudsepp --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* The system can now track IO durations &amp;lt;!--Ants Aasma --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This one deserves a little explanation, as it can be a little tricky. Tracking IO durations means asking repeatedly the time to the operating system. Depending on the operating system and the hardware, this can be quite cheap, or extremely costly. The most import factor here is where the system gets its time from. It could be directly retrieved from the processor (TSC), dedicated hardware such as HPET, or an ACPI call. What&#039;s most important is that the cost of getting time can vary from a factor of thousands.&lt;br /&gt;
&lt;br /&gt;
If you are interested in this timing data, it&#039;s better to first check if your system will support it without to much of a performance hit. PostgreSQL provides you with the pg_test_timing tool:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ pg_test_timing &lt;br /&gt;
Testing timing overhead for 3 seconds.&lt;br /&gt;
Per loop time including overhead: 28.02 nsec&lt;br /&gt;
Histogram of timing durations:&lt;br /&gt;
   &amp;lt; usec:      count   percent&lt;br /&gt;
       32:         41  0.00004%&lt;br /&gt;
       16:       1405  0.00131%&lt;br /&gt;
        8:        200  0.00019%&lt;br /&gt;
        4:        388  0.00036%&lt;br /&gt;
        2:    2982558  2.78523%&lt;br /&gt;
        1:  104100166 97.21287%&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here, everything is good: getting time costs around 28 nanoseconds, and has a very small variation. Anything under 100 nanoseconds should be good for production. If you get higher values, you may still find a way to tune your system. You&#039;d better check on the [http://www.postgresql.org/docs/9.2/static/pgtesttiming.html documentation].&lt;br /&gt;
&lt;br /&gt;
Anyway, here is the data you&#039;ll be able to collect if your system is ready for this:&lt;br /&gt;
&lt;br /&gt;
First, you&#039;ll get per-database statistics, which will now give accurate informations about which database is doing most I/O:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
=# SELECT * FROM pg_stat_database WHERE datname = &#039;mydb&#039;;&lt;br /&gt;
-[ RECORD 1 ]--+------------------------------&lt;br /&gt;
datid          | 16384&lt;br /&gt;
datname        | mydb&lt;br /&gt;
numbackends    | 1&lt;br /&gt;
xact_commit    | 270&lt;br /&gt;
xact_rollback  | 2&lt;br /&gt;
blks_read      | 1961&lt;br /&gt;
blks_hit       | 17944&lt;br /&gt;
tup_returned   | 269035&lt;br /&gt;
tup_fetched    | 8850&lt;br /&gt;
tup_inserted   | 16&lt;br /&gt;
tup_updated    | 4&lt;br /&gt;
tup_deleted    | 45&lt;br /&gt;
conflicts      | 0&lt;br /&gt;
temp_files     | 0&lt;br /&gt;
temp_bytes     | 0&lt;br /&gt;
deadlocks      | 0&lt;br /&gt;
blk_read_time  | 583.774&lt;br /&gt;
blk_write_time | 0&lt;br /&gt;
stats_reset    | 2012-07-03 17:18:54.796817+02&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
We see here that mydb has only consumed 583.774 milliseconds of read time.&lt;br /&gt;
&lt;br /&gt;
Explain will benefit from this too:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
=# EXPLAIN (analyze,buffers) SELECT count(*) FROM mots ;&lt;br /&gt;
                                                   QUERY PLAN                                                   &lt;br /&gt;
----------------------------------------------------------------------------------------------------------------&lt;br /&gt;
 Aggregate  (cost=1669.95..1669.96 rows=1 width=0) (actual time=21.943..21.943 rows=1 loops=1)&lt;br /&gt;
   Buffers: shared read=493&lt;br /&gt;
   I/O Timings: read=2.578&lt;br /&gt;
   -&amp;gt;  Seq Scan on mots  (cost=0.00..1434.56 rows=94156 width=0) (actual time=0.059..12.933 rows=94156 loops=1)&lt;br /&gt;
         Buffers: shared read=493&lt;br /&gt;
         I/O Timings: read=2.578&lt;br /&gt;
 Total runtime: 22.059 ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
We now have a separate information about the time taken to retrieve data from the operating system. Obviously, here, the data was in the operating system&#039;s cache (2 milliseconds to read 493 blocks).&lt;br /&gt;
&lt;br /&gt;
And last, if you have enabled pg_stat_statements:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
select * from pg_stat_statements where query ~ &#039;words&#039;;&lt;br /&gt;
-[ RECORD 1 ]-------+---------------------------&lt;br /&gt;
userid              | 10&lt;br /&gt;
dbid                | 16384&lt;br /&gt;
query               | select count(*) from words;&lt;br /&gt;
calls               | 2&lt;br /&gt;
total_time          | 78.332&lt;br /&gt;
rows                | 2&lt;br /&gt;
shared_blks_hit     | 0&lt;br /&gt;
shared_blks_read    | 986&lt;br /&gt;
shared_blks_dirtied | 0&lt;br /&gt;
shared_blks_written | 0&lt;br /&gt;
local_blks_hit      | 0&lt;br /&gt;
local_blks_read     | 0&lt;br /&gt;
local_blks_dirtied  | 0&lt;br /&gt;
local_blks_written  | 0&lt;br /&gt;
temp_blks_read      | 0&lt;br /&gt;
temp_blks_written   | 0&lt;br /&gt;
blk_read_time       | 58.427&lt;br /&gt;
blk_write_time      | 0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* As for every version, the optimizer has received its share of improvements &amp;lt;!-- Tom Lane--&amp;gt;&lt;br /&gt;
** Prepared statements used to be optimized once, without any knowledge of the parameters&#039; values. With 9.2, the planner will use specific plans regarding to the parameters sent (the query will be planned at execution), except if the query is executed several times and the planner decides that the generic plan is not too much more expensive than the specific plans.&lt;br /&gt;
** A new feature has been added: parameterized paths. Simply put, it means that a sub-part of a query plan can use parameters it has got from a parent node. It fixes several bad plans that could occur, especially when the optimizer couldn&#039;t reorder joins to put nested loops where it would have been efficient.&lt;br /&gt;
&lt;br /&gt;
This example is straight from the developpers mailing lists &amp;lt;!-- Andres Freund --&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE a (&lt;br /&gt;
    a_id serial PRIMARY KEY NOT NULL,&lt;br /&gt;
    b_id integer&lt;br /&gt;
);&lt;br /&gt;
CREATE INDEX a__b_id ON a USING btree (b_id);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
CREATE TABLE b (&lt;br /&gt;
    b_id serial NOT NULL,&lt;br /&gt;
    c_id integer&lt;br /&gt;
);&lt;br /&gt;
CREATE INDEX b__c_id ON b USING btree (c_id);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
CREATE TABLE c (&lt;br /&gt;
    c_id serial PRIMARY KEY NOT NULL,&lt;br /&gt;
    value integer UNIQUE&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
INSERT INTO b (b_id, c_id)&lt;br /&gt;
    SELECT g.i, g.i FROM generate_series(1, 50000) g(i);&lt;br /&gt;
&lt;br /&gt;
INSERT INTO a(b_id)&lt;br /&gt;
    SELECT g.i FROM generate_series(1, 50000) g(i);&lt;br /&gt;
&lt;br /&gt;
INSERT INTO c(c_id,value)&lt;br /&gt;
    VALUES (1,1);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So we have a referencing b, b referencing c.&lt;br /&gt;
&lt;br /&gt;
Here is an example of a query working badly with PostgreSQL 9.1:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
EXPLAIN ANALYZE SELECT 1                                                                           &lt;br /&gt;
FROM                                    &lt;br /&gt;
    c&lt;br /&gt;
WHERE&lt;br /&gt;
    EXISTS (&lt;br /&gt;
        SELECT *   &lt;br /&gt;
        FROM a&lt;br /&gt;
            JOIN b USING (b_id)&lt;br /&gt;
        WHERE b.c_id = c.c_id)&lt;br /&gt;
    AND c.value = 1;&lt;br /&gt;
                                                      QUERY PLAN                                                       &lt;br /&gt;
-----------------------------------------------------------------------------------------------------------------------&lt;br /&gt;
 Nested Loop Semi Join  (cost=1347.00..3702.27 rows=1 width=0) (actual time=13.799..13.802 rows=1 loops=1)&lt;br /&gt;
   Join Filter: (c.c_id = b.c_id)&lt;br /&gt;
   -&amp;gt;  Index Scan using c_value_key on c  (cost=0.00..8.27 rows=1 width=4) (actual time=0.006..0.008 rows=1 loops=1)&lt;br /&gt;
         Index Cond: (value = 1)&lt;br /&gt;
   -&amp;gt;  Hash Join  (cost=1347.00..3069.00 rows=50000 width=4) (actual time=13.788..13.788 rows=1 loops=1)&lt;br /&gt;
         Hash Cond: (a.b_id = b.b_id)&lt;br /&gt;
         -&amp;gt;  Seq Scan on a  (cost=0.00..722.00 rows=50000 width=4) (actual time=0.007..0.007 rows=1 loops=1)&lt;br /&gt;
         -&amp;gt;  Hash  (cost=722.00..722.00 rows=50000 width=8) (actual time=13.760..13.760 rows=50000 loops=1)&lt;br /&gt;
               Buckets: 8192  Batches: 1  Memory Usage: 1954kB&lt;br /&gt;
               -&amp;gt;  Seq Scan on b  (cost=0.00..722.00 rows=50000 width=8) (actual time=0.008..5.702 rows=50000 loops=1)&lt;br /&gt;
 Total runtime: 13.842 ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Not that bad, 13 milliseconds. Still, we are doing sequential scans on a and b, when our common sense tells us that c.value=1 should be used to filter rows more aggressively.&lt;br /&gt;
&lt;br /&gt;
Here&#039;s what 9.2 does with this query:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                                                      QUERY PLAN     &lt;br /&gt;
----------------------------------------------------------------------------------------------------------------------------&lt;br /&gt;
 Nested Loop Semi Join  (cost=0.00..16.97 rows=1 width=0) (actual time=0.035..0.037 rows=1 loops=1)&lt;br /&gt;
   -&amp;gt;  Index Scan using c_value_key on c  (cost=0.00..8.27 rows=1 width=4) (actual time=0.007..0.009 rows=1 loops=1)&lt;br /&gt;
         Index Cond: (value = 1)&lt;br /&gt;
   -&amp;gt;  Nested Loop  (cost=0.00..8.69 rows=1 width=4) (actual time=0.025..0.025 rows=1 loops=1)&lt;br /&gt;
         -&amp;gt;  Index Scan using b__c_id on b  (cost=0.00..8.33 rows=1 width=8) (actual time=0.007..0.007 rows=1 loops=1)&lt;br /&gt;
               Index Cond: (c_id = c.c_id)&lt;br /&gt;
         -&amp;gt;  Index Only Scan using a__b_id on a  (cost=0.00..0.35 rows=1 width=4) (actual time=0.014..0.014 rows=1 loops=1)&lt;br /&gt;
               Index Cond: (b_id = b.b_id)&lt;br /&gt;
 Total runtime: 0.089 ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The «parameterized path» is:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   -&amp;gt;  Nested Loop  (cost=0.00..8.69 rows=1 width=4) (actual time=0.025..0.025 rows=1 loops=1)&lt;br /&gt;
         -&amp;gt;  Index Scan using b__c_id on b  (cost=0.00..8.33 rows=1 width=8) (actual time=0.007..0.007 rows=1 loops=1)&lt;br /&gt;
               Index Cond: (c_id = c.c_id)&lt;br /&gt;
         -&amp;gt;  Index Only Scan using a__b_id on a  (cost=0.00..0.35 rows=1 width=4) (actual time=0.014..0.014 rows=1 loops=1)&lt;br /&gt;
               Index Cond: (b_id = b.b_id)&lt;br /&gt;
 Total runtime: 0.089 ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This part of the plan depends on a parent node (c_id=c.c_id). This part of the plan is called each time with a different parameter coming from the parent node.&lt;br /&gt;
&lt;br /&gt;
This plan is of course much faster, as there is no need to fully scan a, and to fully scan AND hash b.&lt;br /&gt;
&lt;br /&gt;
=SP-GiST=&lt;br /&gt;
&lt;br /&gt;
SP-GiST stands for Space Partitionned GiST, GiST being Generalized Search Tree. GiST is an index type, and has been available for quite a while in PostgreSQL. GiST is already very efficient at indexing complex data types, but performance tends to suffer when the source data isn&#039;t uniformly distributed. SP-GiST tries to fix that.&lt;br /&gt;
&lt;br /&gt;
As all indexing methods available in PostgreSQL, SP-GiST is a generic indexing method, meaning its purpose is to index whatever you&#039;ll throw at it, using operators you&#039;ll provide. It means that if you want to create a new datatype, and make it indexable through SP-GiST, you&#039;ll have to follow the documented API.&lt;br /&gt;
&lt;br /&gt;
SP-GiST can be used to implement 3 type of indexes: trie (suffix) indexing, Quadtree (data is divided into quadrants), and k-d tree (k-dimensional tree).&lt;br /&gt;
&lt;br /&gt;
For now, SP-GiST is provided with operator families called &amp;quot;quad_point_ops&amp;quot;, &amp;quot;kd_point_ops&amp;quot; and &amp;quot;text_ops&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
As their names indicate, the first one indexes point types, using a quadtree, the second one indexes point types using a k-d tree, and the third one indexes text, using suffix.&lt;br /&gt;
&lt;br /&gt;
=pg_stat_statements=&lt;br /&gt;
&lt;br /&gt;
This contrib module has received a lot of improvements in this version:&lt;br /&gt;
&lt;br /&gt;
* Queries are normalized: queries that are identical except for their constant values will be considered the same, as long as their post-parse analysis query tree (that is, the internal representation of the query before rule expansion) are the same. This also implies that differences that are not semantically essential to the query, such as variations in whitespace or alias names, or the use of one particular syntax over another equivalent one will not differentiate queries.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
=#SELECT * FROM words WHERE word= &#039;foo&#039;;&lt;br /&gt;
 word &lt;br /&gt;
------&lt;br /&gt;
(0 ligne)&lt;br /&gt;
&lt;br /&gt;
=# SELECT * FROM words WHERE word= &#039;bar&#039;;&lt;br /&gt;
 word &lt;br /&gt;
------&lt;br /&gt;
 bar&lt;br /&gt;
&lt;br /&gt;
=#select * from pg_stat_statements where query like &#039;%words where%&#039;;&lt;br /&gt;
-[ RECORD 1 ]-------+-----------------------------------&lt;br /&gt;
userid              | 10&lt;br /&gt;
dbid                | 16384&lt;br /&gt;
query               | SELECT * FROM words WHERE word= ?;&lt;br /&gt;
calls               | 2&lt;br /&gt;
total_time          | 142.314&lt;br /&gt;
rows                | 1&lt;br /&gt;
shared_blks_hit     | 3&lt;br /&gt;
shared_blks_read    | 5&lt;br /&gt;
shared_blks_dirtied | 0&lt;br /&gt;
shared_blks_written | 0&lt;br /&gt;
local_blks_hit      | 0&lt;br /&gt;
local_blks_read     | 0&lt;br /&gt;
local_blks_dirtied  | 0&lt;br /&gt;
local_blks_written  | 0&lt;br /&gt;
temp_blks_read      | 0&lt;br /&gt;
temp_blks_written   | 0&lt;br /&gt;
blk_read_time       | 142.165&lt;br /&gt;
blk_write_time      | 0&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The two queries are shown as one in pg_stat_statements.&lt;br /&gt;
&lt;br /&gt;
* For prepared statements, the execution part (execute statement) is charged on the prepare statement. That way it is easier to use, and avoids the double-counting there was with PostgreSQL 9.1.&lt;br /&gt;
&lt;br /&gt;
* pg_stat_statements displays timing in milliseconds, to be consistent with other system views.&lt;br /&gt;
&lt;br /&gt;
= Explain improvements=&lt;br /&gt;
&lt;br /&gt;
* Timing can now be disabled with EXPLAIN (analyze on, timing off), leading to lower overhead on platforms where getting the current time is expensive &amp;lt;!--Tomas Vondra--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  =# EXPLAIN (analyze on,timing off) SELECT * FROM reservation ;&lt;br /&gt;
                                       QUERY PLAN                                       &lt;br /&gt;
  ----------------------------------------------------------------------------------------&lt;br /&gt;
   Seq Scan on reservation  (cost=0.00..22.30 rows=1230 width=36) (actual rows=2 loops=1)&lt;br /&gt;
   Total runtime: 0.045 ms&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Have EXPLAIN ANALYZE report the number of rows rejected by filter steps &amp;lt;!--(Marko Tiikkaja)--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This new feature makes it much easier to know how many rows are removed by a filter (and spot potential places to put indexes):&lt;br /&gt;
&lt;br /&gt;
  =# EXPLAIN ANALYZE SELECT * FROM test WHERE a ~ &#039;tra&#039;;&lt;br /&gt;
                                                    QUERY PLAN                                                   &lt;br /&gt;
  ---------------------------------------------------------------------------------------------------------------&lt;br /&gt;
   Seq Scan on test  (cost=0.00..106876.56 rows=2002 width=11) (actual time=2.914..8538.285 rows=120256 loops=1)&lt;br /&gt;
     Filter: (a ~ &#039;tra&#039;::text)&lt;br /&gt;
     Rows Removed by Filter: 5905600&lt;br /&gt;
   Total runtime: 8549.539 ms&lt;br /&gt;
  (4 rows)&lt;br /&gt;
&lt;br /&gt;
=Backward compatibility=&lt;br /&gt;
&lt;br /&gt;
These changes may incur regressions in your applications.&lt;br /&gt;
&lt;br /&gt;
==Ensure that xpath() escapes special characters in string values &amp;lt;!-- (Florian Pflug)--&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Before 9.2:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT (XPATH(&#039;/*/text()&#039;, &#039;&amp;lt;root&amp;gt;&amp;amp;amp;lt;&amp;lt;/root&amp;gt;&#039;))[1];&lt;br /&gt;
 xpath &lt;br /&gt;
-------&lt;br /&gt;
 &amp;lt;&lt;br /&gt;
&lt;br /&gt;
&#039;&amp;lt;&#039; Isn&#039;t valid XML.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
With 9.2:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT (XPATH(&#039;/*/text()&#039;, &#039;&amp;lt;root&amp;gt;&amp;amp;amp;lt;&amp;lt;/root&amp;gt;&#039;))[1];&lt;br /&gt;
 xpath &lt;br /&gt;
-------&lt;br /&gt;
 &amp;amp;amp;lt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Remove hstore&#039;s =&amp;gt; operator &amp;lt;!-- (Robert Haas)--&amp;gt;==&lt;br /&gt;
Up to 9.1, one could use the =&amp;gt; operator to create a hstore. Hstore is a contrib, used to store key/values pairs in a column.&lt;br /&gt;
&lt;br /&gt;
In 9.1:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
=# SELECT &#039;a&#039;=&amp;gt;&#039;b&#039;;&lt;br /&gt;
 ?column? &lt;br /&gt;
----------&lt;br /&gt;
 &amp;quot;a&amp;quot;=&amp;gt;&amp;quot;b&amp;quot;&lt;br /&gt;
(1 row)&lt;br /&gt;
&lt;br /&gt;
=# SELECT pg_typeof(&#039;a&#039;=&amp;gt;&#039;b&#039;);&lt;br /&gt;
 pg_typeof &lt;br /&gt;
-----------&lt;br /&gt;
 hstore&lt;br /&gt;
(1 row)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With 9.2:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT &#039;a&#039;=&amp;gt;&#039;b&#039;;&lt;br /&gt;
ERROR:  operator does not exist: unknown =&amp;gt; unknown at character 11&lt;br /&gt;
HINT:  No operator matches the given name and argument type(s). You might need to add explicit type casts.&lt;br /&gt;
STATEMENT:  SELECT &#039;a&#039;=&amp;gt;&#039;b&#039;;&lt;br /&gt;
ERROR:  operator does not exist: unknown =&amp;gt; unknown&lt;br /&gt;
LINE 1: SELECT &#039;a&#039;=&amp;gt;&#039;b&#039;;&lt;br /&gt;
                  ^&lt;br /&gt;
HINT:  No operator matches the given name and argument type(s). You might need to add explicit type casts.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It doesn&#039;t mean one cannot use &#039;=&amp;gt;&#039; in hstores, it just isn&#039;t an operator anymore:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
=# select hstore(&#039;a=&amp;gt;b&#039;);&lt;br /&gt;
  hstore  &lt;br /&gt;
----------&lt;br /&gt;
 &amp;quot;a&amp;quot;=&amp;gt;&amp;quot;b&amp;quot;&lt;br /&gt;
(1 row)&lt;br /&gt;
&lt;br /&gt;
=# select hstore(&#039;a&#039;,&#039;b&#039;);&lt;br /&gt;
  hstore  &lt;br /&gt;
----------&lt;br /&gt;
 &amp;quot;a&amp;quot;=&amp;gt;&amp;quot;b&amp;quot;&lt;br /&gt;
(1 row)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
are still two valid ways to input a hstore.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;=&amp;gt;&amp;quot; is removed as an operator as it is a reserved keyword in SQL.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Have pg_relation_size() and friends return NULL if the object does not exist  &amp;lt;!-- (Phil Sorber)--&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
A relation could be dropped by a concurrent session, while one was doing a pg_relation_size on it, leading to a SQL exception. Now, it merely returns NULL for this record.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Remove the spclocation field from pg_tablespace &amp;lt;!-- (Magnus Hagander)--&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
The spclocation field provided the real location of the tablespace. It was filled in during the CREATE or ALTER TABLESPACE command. So it could be wrong: somebody just had to shutdown the cluster, move the tablespace&#039;s directory, re-create the symlink in pg_tblspc, and forget to update the spclocation field. The cluster would still run, as the spclocation wasn&#039;t used.&lt;br /&gt;
&lt;br /&gt;
So this field has been removed. To get the tablespace&#039;s location, use pg_tablespace_location():&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
=# SELECT *, pg_tablespace_location(oid) AS spclocation FROM pg_tablespace;&lt;br /&gt;
  spcname   | spcowner | spcacl | spcoptions |  spclocation   &lt;br /&gt;
------------+----------+--------+------------+----------------&lt;br /&gt;
 pg_default |       10 |        |            | &lt;br /&gt;
 pg_global  |       10 |        |            | &lt;br /&gt;
 tmptblspc  |       10 |        |            | /tmp/tmptblspc&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Have EXTRACT of a non-timezone-aware value measure the epoch from local midnight, not UTC midnight &amp;lt;!-- (Tom Lane) --&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
With PostgreSQL 9.1:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
=#SELECT extract(epoch FROM &#039;2012-07-02 00:00:00&#039;::timestamp);&lt;br /&gt;
 date_part  &lt;br /&gt;
------------&lt;br /&gt;
 1341180000&lt;br /&gt;
(1 row)&lt;br /&gt;
&lt;br /&gt;
=# SELECT extract(epoch FROM &#039;2012-07-02 00:00:00&#039;::timestamptz);&lt;br /&gt;
 date_part  &lt;br /&gt;
------------&lt;br /&gt;
 1341180000&lt;br /&gt;
(1 row)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is no difference in behaviour between a timstamp with or without timezone.&lt;br /&gt;
&lt;br /&gt;
With 9.1:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
=#SELECT extract(epoch FROM &#039;2012-07-02 00:00:00&#039;::timestamp);&lt;br /&gt;
 date_part  &lt;br /&gt;
------------&lt;br /&gt;
 1341187200&lt;br /&gt;
(1 row)&lt;br /&gt;
&lt;br /&gt;
=# SELECT extract(epoch FROM &#039;2012-07-02 00:00:00&#039;::timestamptz);&lt;br /&gt;
 date_part  &lt;br /&gt;
------------&lt;br /&gt;
 1341180000&lt;br /&gt;
(1 row)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When the timestamp has no timezone, the epoch is calculated with the &amp;quot;local midnight&amp;quot;, meaning the 1st january of 1970 at midnight, local-time.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Fix to_date() and to_timestamp() to wrap incomplete dates toward 2020 &amp;lt;!-- (Bruce Momjian)--&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
The wrapping was not consistent between 2 digit dates and 3 digit dates: 2 digit dates always chose the date closest to 2020, 3 digit dates mapped dates from 100 to 999 on 1100 to 1999, and 000 to 099 on 2000 to 2099.&lt;br /&gt;
&lt;br /&gt;
Now PostgreSQL chooses the date closest to 2020, for 2 and 3 digit dates.&lt;br /&gt;
&lt;br /&gt;
With 9.1:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
=# SELECT to_date(&#039;200-07-02&#039;,&#039;YYY-MM-DD&#039;);&lt;br /&gt;
  to_date   &lt;br /&gt;
------------&lt;br /&gt;
 1200-07-02&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With 9.2:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT to_date(&#039;200-07-02&#039;,&#039;YYY-MM-DD&#039;);&lt;br /&gt;
  to_date   &lt;br /&gt;
------------&lt;br /&gt;
 2200-07-02&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==pg_stat_activity and pg_stat_replication&#039;s definitions have changed &amp;lt;!--Magnus Hagander --&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
The view pg_stat_activity has changed. It&#039;s not backward compatible, but let&#039;s see what this new definition brings us:&lt;br /&gt;
&lt;br /&gt;
* current_query disappears and is replaced by two columns:&lt;br /&gt;
** state: is the session running a query, waiting&lt;br /&gt;
** query: what is the last run (or still running if stat is &amp;quot;active&amp;quot;) query&lt;br /&gt;
* The column procpid is renamed to pid, to be consistent with other system views&lt;br /&gt;
&lt;br /&gt;
The benefit is mostly for tracking «idle in transaction» sessions. Up until now, all we could know was that one of these sessions was idle in transaction, meaning it has started a transaction, maybe done some operations, but still not committed. If that session stayed in this state for a while, there was no way of knowing how it got in this state.&lt;br /&gt;
&lt;br /&gt;
Here is an example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
-[ RECORD 1 ]----+---------------------------------&lt;br /&gt;
datid            | 16384&lt;br /&gt;
datname          | postgres&lt;br /&gt;
pid              | 20804&lt;br /&gt;
usesysid         | 10&lt;br /&gt;
usename          | postgres&lt;br /&gt;
application_name | psql&lt;br /&gt;
client_addr      | &lt;br /&gt;
client_hostname  | &lt;br /&gt;
client_port      | -1&lt;br /&gt;
backend_start    | 2012-07-02 15:02:51.146427+02&lt;br /&gt;
xact_start       | 2012-07-02 15:15:28.386865+02&lt;br /&gt;
query_start      | 2012-07-02 15:15:30.410834+02&lt;br /&gt;
state_change     | 2012-07-02 15:15:30.411287+02&lt;br /&gt;
waiting          | f&lt;br /&gt;
state            | idle in transaction&lt;br /&gt;
query            | DELETE FROM test;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With PostgreSQL 9.1, all we would have would be «idle in transaction».&lt;br /&gt;
&lt;br /&gt;
As this change was backward-incompatible, procpid was also renamed to pid, to be more consistent with other system views.&lt;br /&gt;
The view pg_stat_replication has also changed. The column procpid is renamed to pid, to also be consistent with other system views.&lt;br /&gt;
&lt;br /&gt;
==Change all SQL-level statistics timing values to float8-stored milliseconds &amp;lt;!-- (Tom Lane) --&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
pg_stat_user_functions.total_time, pg_stat_user_functions.self_time, pg_stat_xact_user_functions.total_time, pg_stat_xact_user_functions.self_time, and pg_stat_statements.total_time (contrib) are now in milliseconds, to be consistent with the rest of the timing values.&lt;br /&gt;
&lt;br /&gt;
==postgresql.conf parameters changes &amp;lt;!-- (Heikki Linnakangas, Tom Lane, Peter Eisentraut) --&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
* silent_mode has been removed. Use pg_ctl -l postmaster.log&lt;br /&gt;
* wal_sender_delay has been removed. It is no longer needed&lt;br /&gt;
* custom_variable_classes has been removed. All «classes» are accepted without declaration now&lt;br /&gt;
* ssl_ca_file, ssl_cert_file, ssl_crl_file, ssl_key_file have been added, meaning you can now specify the ssl files&lt;br /&gt;
&lt;br /&gt;
= Other new features =&lt;br /&gt;
&lt;br /&gt;
== DROP INDEX CONCURRENTLY ==&lt;br /&gt;
&lt;br /&gt;
The regular DROP INDEX command takes an exclusive lock on the table. Most of the time, this isn&#039;t a problem, because this lock is short-lived. The problem usually occurs when:&lt;br /&gt;
&lt;br /&gt;
* A long-running transaction is running, and has a (shared) lock on the table&lt;br /&gt;
* A DROP INDEX is run on this table in another session, asking for an exclusive lock (and waiting for it, as it won&#039;t be granted until the long-running transaction ends)&lt;br /&gt;
&lt;br /&gt;
At this point, all other transactions needing to take a shared lock on the table (for a simple SELECT for instance) will have to wait too: their lock acquisition is queued after the DROP INDEX&#039;s one.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
DROP INDEX CONCURRENTLY works around this and won&#039;t lock normal DML statements, just as CREATE INDEX CONCURRENTLY. The main limitation is the same: DROP INDEX CONCURRENTLY can&#039;t be run in a transaction. Moreover, you can only DROP one index with CONCURRENTLY, and CASCADE isn&#039;t supported either.&lt;br /&gt;
&lt;br /&gt;
== NOT VALID CHECK constraints ==&lt;br /&gt;
&lt;br /&gt;
PostgreSQL 9.1 introduced «NOT VALID» foreign keys. This has been extended to CHECK constraints. Adding a «NOT VALID» constraint on a table means that current data won&#039;t be validated, only new and updated rows.&lt;br /&gt;
&lt;br /&gt;
  =# CREATE TABLE test (a int); &lt;br /&gt;
  CREATE TABLE&lt;br /&gt;
  =# INSERT INTO test SELECT generate_series(1,100);&lt;br /&gt;
  INSERT 0 100&lt;br /&gt;
  =# ALTER TABLE test ADD CHECK (a&amp;gt;100) NOT VALID;&lt;br /&gt;
  ALTER TABLE&lt;br /&gt;
  =# INSERT INTO test VALUES (99);&lt;br /&gt;
  ERROR:  new row for relation &amp;quot;test&amp;quot; violates check constraint &amp;quot;test_a_check&amp;quot;&lt;br /&gt;
  DETAIL:  Failing row contains (99).&lt;br /&gt;
  =# INSERT INTO test VALUES (101);&lt;br /&gt;
  INSERT 0 1&lt;br /&gt;
&lt;br /&gt;
Then, later, we can validate the whole table:&lt;br /&gt;
&lt;br /&gt;
  =# ALTER TABLE test VALIDATE CONSTRAINT test_a_check ;&lt;br /&gt;
  ERROR:  check constraint &amp;quot;test_a_check&amp;quot; is violated by some row&lt;br /&gt;
&lt;br /&gt;
Domains, which are types with added constraints, can also be declared as not valid, and validated later.&lt;br /&gt;
&lt;br /&gt;
Check constraints can also be renamed now:&lt;br /&gt;
&lt;br /&gt;
  =# ALTER TABLE test RENAME CONSTRAINT test_a_check TO validate_a;&lt;br /&gt;
  ALTER TABLE&lt;br /&gt;
&lt;br /&gt;
Last, but not least, constraints can be declared as not inheritable, which will be useful in partitioned environments. Let&#039;s take PostgreSQL documentation example, and see how it improves the situation:&lt;br /&gt;
&lt;br /&gt;
  CREATE TABLE measurement (&lt;br /&gt;
      city_id         int not null,&lt;br /&gt;
      logdate         date not null,&lt;br /&gt;
      peaktemp        int,&lt;br /&gt;
      unitsales       int,&lt;br /&gt;
      CHECK (logdate IS NULL) NO INHERIT&lt;br /&gt;
  );&lt;br /&gt;
  &lt;br /&gt;
  CREATE TABLE measurement_y2006m02 (&lt;br /&gt;
      CHECK ( logdate &amp;gt;= DATE &#039;2006-02-01&#039; AND logdate &amp;lt; DATE &#039;2006-03-01&#039; )&lt;br /&gt;
  ) INHERITS (measurement);&lt;br /&gt;
  CREATE TABLE measurement_y2006m03 (&lt;br /&gt;
      CHECK ( logdate &amp;gt;= DATE &#039;2006-03-01&#039; AND logdate &amp;lt; DATE &#039;2006-04-01&#039; )&lt;br /&gt;
  ) INHERITS (measurement);&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  INSERT INTO measurement VALUES (1,&#039;2006-02-20&#039;,1,1);&lt;br /&gt;
  ERROR:  new row for relation &amp;quot;measurement&amp;quot; violates check constraint &amp;quot;measurement_logdate_check&amp;quot;&lt;br /&gt;
  DETAIL:  Failing row contains (1, 2006-02-20, 1, 1).&lt;br /&gt;
  INSERT INTO measurement_y2006m02 VALUES (1,&#039;2006-02-20&#039;,1,1);&lt;br /&gt;
  INSERT 0 1&lt;br /&gt;
&lt;br /&gt;
Until now, every check constraint created on measurement would have been inherited by children tables. So adding a constraint forbidding inserts, or allowing only some of them, on the parent table was impossible.&lt;br /&gt;
&lt;br /&gt;
== Reduce ALTER TABLE rewrites ==&lt;br /&gt;
&lt;br /&gt;
A table won&#039;t get rewritten anymore during an ALTER TABLE when changing the type of a column in the following cases:&lt;br /&gt;
&lt;br /&gt;
* varchar(x) to varchar(y) when y &amp;gt; x. It works too if going from varchar(x) to varchar or text (no size limitation)&lt;br /&gt;
* numeric(x,z) to numeric(y,z) when y&amp;gt;x, or to numeric without specifier&lt;br /&gt;
* varbit(x) to varbit(y) when y&amp;gt;x, or to varbit without specifier&lt;br /&gt;
* timestamp(x) to timestamp(y) when y&amp;gt;x or timestamp without specifier&lt;br /&gt;
* timestamptz(x) to timestamptz(y) when y&amp;gt;x or timestamptz without specifier&lt;br /&gt;
* interval(x) to interval(y) when y&amp;gt;x or interval without specifier&lt;br /&gt;
&lt;br /&gt;
== Security barriers and Leakproof ==&lt;br /&gt;
&lt;br /&gt;
This new feature has to do with views security. First, let&#039;s explain the problem, with a very simplified example:&lt;br /&gt;
&lt;br /&gt;
  =# CREATE TABLE all_data (company_id int, company_data varchar);&lt;br /&gt;
  CREATE TABLE&lt;br /&gt;
  # INSERT INTO all_data VALUES (1,&#039;secret_data_for_company_1&#039;);&lt;br /&gt;
  INSERT 0 1&lt;br /&gt;
  =# INSERT INTO all_data VALUES (2,&#039;secret_data_for_company_2&#039;);&lt;br /&gt;
  INSERT 0 1&lt;br /&gt;
  =# CREATE VIEW company1_data AS SELECT * FROM all_data WHERE company_id = 1;&lt;br /&gt;
  CREATE VIEW&lt;br /&gt;
&lt;br /&gt;
This is a quite classical way of giving access to only a part of a table to a user: we&#039;ll create a user for company_id 1, grant to him the right to access company1_data, and deny him the right to access all_data.&lt;br /&gt;
&lt;br /&gt;
The plan to this query is the following:&lt;br /&gt;
&lt;br /&gt;
  =# explain SELECT * FROM company1_data ;&lt;br /&gt;
                          QUERY PLAN                        &lt;br /&gt;
  ----------------------------------------------------------&lt;br /&gt;
   Seq Scan on all_data  (cost=0.00..25.38 rows=6 width=36)&lt;br /&gt;
     Filter: (company_id = 1)&lt;br /&gt;
&lt;br /&gt;
Even if there was more data, a sequential scan could still be forced: just &amp;quot;SET enable_indexscan to OFF&amp;quot; and the likes.&lt;br /&gt;
&lt;br /&gt;
So this query reads all the records from all_data, filters them, and returns to the user only the matching rows. There is a way to display scanned records before they are filtered: just create a function with a very low cost, and call it while doing the query:&lt;br /&gt;
&lt;br /&gt;
  CREATE OR REPLACE FUNCTION peek(text) RETURNS boolean LANGUAGE plpgsql AS&lt;br /&gt;
  $$&lt;br /&gt;
  BEGIN&lt;br /&gt;
    RAISE NOTICE &#039;%&#039;,$1;&lt;br /&gt;
    RETURN true;&lt;br /&gt;
  END&lt;br /&gt;
  $$&lt;br /&gt;
  COST 0.1;&lt;br /&gt;
&lt;br /&gt;
This function just has to cost less than the = operator, which costs 1, to be executed first.&lt;br /&gt;
&lt;br /&gt;
The result is this:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  =# SELECT * FROM company1_data WHERE peek(company1_data.company_data);&lt;br /&gt;
  NOTICE:  secret_data_for_company_1&lt;br /&gt;
  NOTICE:  secret_data_for_company_2&lt;br /&gt;
   company_id |       company_data        &lt;br /&gt;
  ------------+---------------------------&lt;br /&gt;
            1 | secret_data_for_company_1&lt;br /&gt;
  (1 row)&lt;br /&gt;
&lt;br /&gt;
We got access to the record from the second company (in the NOTICE messages).&lt;br /&gt;
&lt;br /&gt;
So this is the first new feature: the view can be declared as implementing &amp;quot;security barriers&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  =# CREATE VIEW company1_data WITH (security_barrier) AS SELECT * FROM all_data WHERE company_id = 1;&lt;br /&gt;
  CREATE VIEW&lt;br /&gt;
  =# SELECT * FROM company1_data WHERE peek(company1_data.company_data);&lt;br /&gt;
  NOTICE:  secret_data_for_company_1&lt;br /&gt;
   company_id |       company_data        &lt;br /&gt;
  ------------+---------------------------&lt;br /&gt;
            1 | secret_data_for_company_1&lt;br /&gt;
  (1 row)&lt;br /&gt;
&lt;br /&gt;
The view&#039;s not leaking anymore. The problem, of course, is that there is a performance impact: maybe the &amp;quot;peek&amp;quot; function could have made the query faster, by filtering lots of rows early in the plan.&lt;br /&gt;
&lt;br /&gt;
This leads to the complementary feature: some function may be declared as &amp;quot;LEAKPROOF&amp;quot;, meaning that they won&#039;t leak the data they are passed into error or notice messages.&lt;br /&gt;
&lt;br /&gt;
Declaring our peek function as LEAKPROOF is a very bad idea, but let&#039;s do it just to demonstrate how it&#039;s used:&lt;br /&gt;
&lt;br /&gt;
  CREATE OR REPLACE FUNCTION peek(text) RETURNS boolean LEAKPROOF LANGUAGE plpgsql AS&lt;br /&gt;
  $$&lt;br /&gt;
  BEGIN&lt;br /&gt;
    RAISE NOTICE &#039;%&#039;,$1;&lt;br /&gt;
    RETURN true;&lt;br /&gt;
  END&lt;br /&gt;
  $$&lt;br /&gt;
  COST 0.1;&lt;br /&gt;
&lt;br /&gt;
A LEAKPROOF function is executed «normally»:&lt;br /&gt;
&lt;br /&gt;
  =# SELECT * FROM company1_data WHERE peek(company1_data.company_data);&lt;br /&gt;
  NOTICE:  secret_data_for_company_1&lt;br /&gt;
  NOTICE:  secret_data_for_company_2&lt;br /&gt;
   company_id |       company_data        &lt;br /&gt;
  ------------+---------------------------&lt;br /&gt;
            1 | secret_data_for_company_1&lt;br /&gt;
  (1 row)&lt;br /&gt;
&lt;br /&gt;
Of course, in our case, peek isn&#039;t LEAKPROOF and shouldn&#039;t be declared as such. Only superuser have the permission to declare a LEAKPROOF function.&lt;br /&gt;
&lt;br /&gt;
== New options for pg_dump ==&lt;br /&gt;
&lt;br /&gt;
Until now, one could ask pg_dump to dump a table&#039;s data, or a table&#039;s meta-data (DDL statements for creating the table&#039;s structure, indexes, constraints). Some meta-data is better restored before the data (the table&#039;s structure, check constraints), some is better after the data (indexes, unique constraints, foreign keys…), for performance reasons mostly.&lt;br /&gt;
&lt;br /&gt;
So there are now a few more options:&lt;br /&gt;
&lt;br /&gt;
* --section=pre-data: dump what&#039;s needed before restoring the data. Of course, this can be combined with a -t for instance, to specify one table&lt;br /&gt;
* --section=post-data : dump what&#039;s needed after restoring the data.&lt;br /&gt;
* --section=data: dump the data&lt;br /&gt;
* --exclude-table-data: dump everything, except THIS table&#039;s data. It means pg_dump will still dump other tables&#039; data.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:PostgreSQL 9.2]]&lt;/div&gt;</summary>
		<author><name>Intgr</name></author>
	</entry>
</feed>