Prior to PostgreSQL 9.3, trying to execute a DML on a view results in an error. The view is not able to execute directly a query to its parent table.
For example, you can see this kind of behavior in 9.2.
postgres=# CREATE TABLE aa (a int, b int);
CREATE TABLE
postgres=# CREATE VIEW aav AS SELECT * FROM aa;
CREATE VIEW
postgres=# INSERT INTO aav VALUES (1,2);
ERROR: cannot insert into view "aav"
HINT: You need an unconditional ON INSERT DO INSTEAD rule or an INSTEAD OF INSERT trigger.

Solving that is a matter of using triggers or rules on this view to redirect the given query (INSERT, UPDATE or DELETE) to the wanted parent relation. Here for example by using an INSTEAD rule.
postgres=# CREATE RULE aav_insert AS ON INSERT TO aav
postgres-# DO INSTEAD INSERT INTO aa VALUES (NEW.a, NEW.b);
CREATE RULE
postgres=# INSERT INTO aav VALUES (1,2);
INSERT 0 1
postgres=# select * from aa;
a | b
---+---
1 | 2
(1 row)
postgres=# DROP rule aav_insert ON aav;
DROP RULE

Or with an INSTEAD trigger (trigger on views have been introduced in 9.1).
postgres=# CREATE FUNCTION aav_insert() RETURNS TRIGGER AS $$
DECLARE
 query varchar;
BEGIN
 -- Execute action only for an INSERT
 IF TG_OP = 'INSERT' then
  query := 'INSERT INTO aa VALUES(' || NEW.a || ', ' || NEW.b || ');';
  EXECUTE query;
 END IF;
 RETURN NULL;
END;
$$ LANGUAGE plpgsql;
postgres=# CREATE TRIGGER aav_insert_tr INSTEAD OF INSERT ON aav
postgres=# FOR EACH ROW EXECUTE PROCEDURE aav_insert();
postgres=# INSERT INTO aav VALUES (7,99);
INSERT 0 0
postgres=# select * from aav;
a | b
---+----
1 | 2
7 | 99
(2 rows)

PostgreSQL 9.3 introduces a new functionality that allows application programmers not to care anymore about using rules or triggers when executing INSERT, UPDATE or DELETE on views. This feature has been introduced by this commit and is called auto-updatable views.
commit a99c42f291421572aef2b0a9360294c7d89b8bc7
Author: Tom Lane
Date: Sat Dec 8 18:25:48 2012 -0500
 
Support automatically-updatable views.
 
This patch makes "simple" views automatically updatable, without the need
to create either INSTEAD OF triggers or INSTEAD rules. "Simple" views
are those classified as updatable according to SQL-92 rules. The rewriter
transforms INSERT/UPDATE/DELETE commands on such views directly into an
equivalent command on the underlying table, which will generally have
noticeably better performance than is possible with either triggers or
user-written rules. A view that has INSTEAD OF triggers or INSTEAD rules
continues to operate the same as before.
 
For the moment, security_barrier views are not considered simple.
Also, we do not support WITH CHECK OPTION. These features may be
added in future.
 
Dean Rasheed, reviewed by Amit Kapila

This feature presents the advantage to facilitate the maintenance work of the rules and triggers that the application has to write prior to 9.3 in order to run an INSERT/UPDATE/DELETE query directly on a view.

There are multiple cases where views containing cannot be auto-updatable, a couple of examples being views containing clauses like GROUP BY, LIMIT, OFFSET, DISTINCT or HAVING. There are other restrictions so be sure to refer to the documentation for that.

Now let’s have a look at this feature.
postgres=# CREATE TABLE aa (a int, b int);
CREATE TABLE
postgres=# CREATE VIEW aav1 AS SELECT * FROM aa;
CREATE VIEW

Two new system functions called pg_view_is_insertable and pg_view_is_updatable have been introduced to check if a view can receive an INSERT or UPDATE directly.
postgres=# select pg_view_is_updatable('aav1'::regclass),
postgres-# pg_view_is_insertable('aav1'::regclass);
pg_view_is_updatable | pg_view_is_insertable
----------------------+-----------------------
t | t
(1 row)

So it looks to be the case for the view aav1, then let’s try it.
postgres=# INSERT INTO aav1 VALUES (1,2);
INSERT 0 1
postgres=# SELECT * FROM aa;
a | b
---+---
1 | 2
(1 row)
postgres=# UPDATE aav1 SET b = 50 WHERE a = 1;
UPDATE 1
postgres=# SELECT * FROM aa;
a | b
---+----
1 | 50
(1 row)
postgres=# DELETE FROM aav1 WHERE a = 1;
DELETE 1
postgres=# SELECT * FROM aa;
a | b
---+---
(0 rows)

INSERT, UPDATE and DELETE queries have been executed without the need of additional triggers or rules. Yeah.

One last thing, it is possible to check if a view is auto-updatable by looking at its information in information_schema.tables. Let’s add here also the example of a view that cannot be auto-updatable.
postgres=# CREATE VIEW aav2 AS SELECT count(*) FROM aa;
CREATE VIEW
postgres=# SELECT table_name, is_insertable_into
postgres-# FROM information_schema.tables
postgres-# WHERE table_name LIKE 'aav%';
table_name | is_insertable_into
------------+--------------------
aav1 | YES
aav2 | NO
(2 rows)

And I think that’s all about auto-updatable views.
Enjoy!

First you need to download the latest version of Postgres-XC from here.

Then open the tarball and install the binaries as you would do with a normal PostgresSQL.
configure --prefix=$INSTALL_FOLDER
make
make install

$INSTALL_FOLDER is the folder where to install the sources. In this post $PATH redirects to $INSTALL_FOLDER so no need to specify a folder when launching commands.

Next, the goal is to install a cluster when few simple commands. Once you are done, your cluster will have the same shape as picture below.
Simple 1 Coordinator/2Datanode cluster
Assuming that you are familiar with Postgres-XC architecture, this cluster is made with 1 Coordinator (to which your application connects), 2 Datanodes (meaning that your table data can be distributed up to 2 nodes) and a GTM, mandatory unique component distributing transaction ID and snapshot in the cluster.
If you are not familiar with the architecture, you can still refer to documents located here. Among the documents available, the tutorial done at PGCon 2012 is a good beginning.
For simplicity’s sake, all the nodes are installed on a local machine.

Like PostgreSQL, each node of Postgres-XC needs a data folder. All of them are located in $DATA_FOLDER.
So let’s move in and initialize each node.
cd $HOME/pgsql
initgtm -Z gtm -D gtm # Initialize GTM
initdb -D datanode1 --nodename dn1 # Initialize Datanode 1
initdb -D datanode2 --nodename dn2 # Initialize Datanode 2
initdb -D coord1 --nodename co1 # Initialize Coordinator 1

Then you need to modify manually the port value of Datanode 1 and Datanode 2 in each postgresql.conf.
cd datanode1 # or `cd datanode2`
vim postgresql.conf

Then change the line “#port = 5432″ by “port = 15432″ for Datanode 1, and “port = 15433″ for Datanode 2.

Then it is time to start up the cluster.
gtm -D gtm & # Start-up GTM
postgres -X -D datanode1 -i & # Start Datanode 1
postgres -X -D datanode2 -i & # Start Datanode 2
postgres -C -D coord1 -i & # Start Coordinator 1

What remains is to set up the Coordinator to make him know about Datanode 1 and 2.
So connect to coordinator 1.
psql postgres
Then launch that to finish setting up cluster:
CREATE NODE dn1 WITH (TYPE='datanode', PORT=15432);
CREATE NODE dn2 WITH (TYPE='datanode', PORT=15433);
select pgxc_pool_reload();

And you are done.
Now you can connect to Coordinator 1 and test your newly-made cluster.
12 short commands have been enough once binaries have been installed.

PostgreSQL 9.1 is out, you can download it source code from here or use latest GIT repository as I did like this:
mkdir postgres
git remote add postgres http://git.postgresql.org/git/postgresql.git
git fetch postgres
git branch --track master postgres/master
git checkout master

Asynchronous streaming replication is here since 9.0, but as I keep being always busy with development stuff of Postgres-XC, I have not taken time to play around with streaming replication and HOT Standby.
As now synchronous streaming replication is going to be released soon (beta 1 at the moment of this post), and that Postgres-XC will soon be merged with PostgreSQL 9.1, I tried to set up a synchronous streaming replication server. This functionality could be used to extend XC so as to make it a full HA solution based on Postgres.

So, let’s give it a try.

To be honest, I have been surprised by how easy it is to set it up. PostgreSQL developers have really done a good job on it. As a beta 1, it is not completely polished, but it looks close to completion. Here are the main steps you need to do to set up your server.
First download code, and compile it (written above).
./configure --prefix=$HOME/bin/postgres
make
make install

In my case my installation is located at $HOME/bin/postgres, and I use the following folder for all my settings. You can of course use the folder you prefer, even for slave, master or archive data folders.

To understand what has to be set where, let’s first have a look at the configuration parameters.
This is important to understand how to set your own servers, without depending on this post.
Settings are different for slave and master servers.

Here are the parameters you have to set for postgresql.conf file of master.
wal_level = hot_standby
archive_mode = on
archive_command = 'cp -i %p $HOME/bin/postgres/archive/%f'
max_wal_senders = 10

archive_command is the command used when launching pg_start_backup. This allows slave to restore master data not from scratch, really accelerating slave’s start up. In this case, directory for archives is $HOME/bin/postgres/archive.
max_wal_senders is the number of processes allowed to send WAL data, it cannot be 0, or master cannot send data to slave.
For the time being synchronous_standby_names is not set to avoid master hanging on a slave commit.
It is also necessary to set up your master to authorize connection from slave for replication purposes. In this case, you have to add those lines in pg_hba.conf:
host replication michael 127.0.0.1/32 trust
host replication michael ::1/128 trust

This setup is OK if slave and master are on local host.

In case you want to have a slave with the same configuration parameters as the master, you should copy copy the master’s configuration file. Then modify the following parameters to make it a slave. In postgresql.conf:
hot_standby = on
port = 5433

It is also necessary to add an additional configuration file called recovery.conf in slave’s data folder. You can find a sample of this file in share/ called recovery.conf.sample.
Rename it to recovery.conf and copy it to the slave’s data folder. Then modify the following parameters in it.
standby_mode = on
primary_conninfo = 'host=localhost port=5432 application_name=slave1'
restore_command = 'cp -i $HOME/bin/postgres/archive/%f %p'

primary_conninfo contains all the connection parameters to allow slave to connect to master, for streaming replication purposes. In this parameter, application_name is the name used to identify slave on master.
restore_command contains a shell command that is used to copy archive files. This helps in speeding up slave startup by not having to copy all the WAL from scratch. In this case restore command picks up archive files in the same place where it has been saved by master.

Now, let’s have a look at how to use your master/slave configuration.
Master port is 5432 (PostgreSQL default). Slave port is 5433.

This is the script I used to automatize the whole setup.

#!/bin/bash
#Master has port 5432
#Slave has port 5433
PSQL_FOLDER=$HOME/bin/postgres
PSQL_BIN=$PSQL_FOLDER/bin #Binary folder
PSQL_CONFIG=$PSQL_FOLDER/config #Folder containing all the configuration files
PSQL_MASTER=$PSQL_FOLDER/master #Master data folder
PSQL_SLAVE=$PSQL_FOLDER/slave #Slave data folder
PSQL_ARCHIVE=$PSQL_FOLDER/archive #Archive folder
 
#clean up, take down violently all the processes
killall postgres
rm -rf $PSQL_MASTER $PSQL_SLAVE $PSQL_ARCHIVE
mkdir $PSQL_MASTER $PSQL_SLAVE $PSQL_ARCHIVE
sleep 1
 
#Initialize master
$PSQL_BIN/initdb -D $PSQL_MASTER
cp $PSQL_CONFIG/postgresql.conf.master $PSQL_MASTER/postgresql.conf
cp $PSQL_CONFIG/pg_hba.conf.master $PSQL_MASTER/pg_hba.conf
#Start master
$PSQL_BIN/postgres -D $PSQL_MASTER &
 
#Wait a little before server start up, let it finish initialization
echo "Master started"
sleep 2
 
#Initialize slave
#This is used to start the backup so as slave does not have to recover from
#scratch when being build. It definitely accelerates standby start up
$PSQL_BIN/psql postgres -c "select pg_start_backup('backup')"
cp -pr $PSQL_MASTER/* $PSQL_SLAVE/
$PSQL_BIN/psql postgres -c "select pg_stop_backup()"
sleep 1
echo "Backup performed"
 
#Setup synchronous commit mode on master
echo "synchronous_standby_names='slave1'" >> $PSQL_MASTER/postgresql.conf
$PSQL_BIN/pg_ctl reload -D $PSQL_MASTER
echo "Force master to synchronize mode"
sleep 1
 
#Then finish by copying all the configuration files for slave
cp -r $PSQL_MASTER/* $PSQL_SLAVE
cp $PSQL_CONFIG/postgresql.conf.slave $PSQL_SLAVE/postgresql.conf
cp $PSQL_CONFIG/recovery.conf.slave $PSQL_SLAVE/recovery.conf
rm $PSQL_SLAVE/postmaster.pid
rm -r $PSQL_SLAVE/pg_xlog/*
 
#Start Slave
chmod 700 $PSQL_SLAVE
$PSQL_BIN/postgres -D $PSQL_SLAVE &
echo "Slave started"
exit 0

With this script, you can set up your own master/slave server based on streaming replication.

If you have finished wetting up your environment, let’s check if it is working as planned. Slave can just perform read operations (no DML or DDL), and each write operation performed or master has to be seen on slave.
Let’s first create a database.
michael@lucid-virtual:~/bin/postgres $ ./bin/createdb test
Then create a table on master and fill it with some data.
michael@lucid-virtual:~/bin/postgres $ ./bin/psql test
psql (9.1beta1)
Type "help" for help.
test=# create table aa (a int);
CREATE TABLE
test=# insert into aa values (1);
INSERT 0 1
test=# select * from aa;
a
---
1
(1 row)

And what happens on slave?
michael@lucid-virtual:~/bin/postgres $ ./bin/psql -p 5433 test
psql (9.1beta1)
Type "help" for help.
test=# select * from aa;
a
---
1
(1 row)
test=# insert into aa values (2);
ERROR: cannot execute INSERT in a read-only transaction

This works as expected (Oh, no configuration miss), slave has received all the data from master and cannot perform any write operations.

On master you can check if slave is synchronized with master correctly.
test=# select application_name,state,sync_priority,sync_state from pg_stat_replication;
application_name | state | sync_priority | sync_state
------------------+-----------+---------------+------------
slave1 | streaming | 1 | sync
(1 row)

The keyword sync means that master and slave have synchronized commits.
If it were not the case, this would be in async mode.

The main point of a slave is to take care of the database operations in case master crashes or becomes inoperative.
So let’s imagine master crashes with something like.
kill -9 `ps ux | grep "postgres/master" | cut -d " " -f 3`
Now only slave is running, but it cannot perform any write operation, so fallback can be done by:
echo "standby_mode = off" >> slave/recovery.conf
echo "port = 5432" >> slave/postgresql.conf
./bin/pg_ctl -D slave restart

Setting standby_mode to off makes the slave react as a new master.
After restarting, recovery.conf has its name changed to recovery.done to prevent to reenter to a new backup.
After that a new master is up, based on the old slave. You can connect to it as if it was a normal master, and perform normal operations on it.

If you want to set up your own servers, here are the Standby setup files (tar archive) used in this post. It contains the following files:

  • Configuration files (saved in $PSQL_CONFIG for the automatized process)
    • Master: postgresql.conf file
    • Master: pg_hba.conf file
    • Slave: postgresql.conf file
    • Slave: recovery,conf file
  • Scripts
    • Setup Master/Slave servers
    • Fallback to Slave
  • ©2010-2013 Michael Paquier All content is ©Copyright of Otacoo.com 2010-2013. Privacy Policy - Terms of Use