Eric Radman : a Journal

Late Binding Views

In my view, the most significant feature missing from PostgreSQL is the ability to create views without hard dependencies. Views reference objects by oid not by name, hence creating a view always has the potential to break automated schema updates.

Amazon Redshift solves this using late binding views

CREATE VIEW ... WITH NO SCHEMA BINDING;

Redshift keeps a record of column types in a separate table

SELECT pg_get_late_binding_view_cols();

(public,myview,tag_id,integer,1)
(public,myview,name,"character varying(20)",2)
(public,myview,created,"timestamp with time zone",3)

Rules

Internally PostgreSQL implements views using the rule system. Prior to PostgreSQL 16 tables were converted to views when an ON SELECT rule was added

CREATE TABLE tag (
  tag_id integer NOT NULL,
  name varchar(20) NOT NULL,
  created timestamp with time zone NOT NULL DEFAULT now()
);

CREATE TABLE tag2 (
  tag_id integer NOT NULL,
  name varchar(20) NOT NULL,
  created timestamp with time zone NOT NULL DEFAULT now()
);

CREATE RULE "_RETURN" AS
    ON SELECT TO tag
    DO INSTEAD
        SELECT * FROM tag2;

Removing Dependencies

It is possible, but not advisable to remove view dependencies manually

test=# select relname,oid,relkind from pg_catalog.pg_class where relname in ('tag', 'tag2');
 relname |  oid  | relkind
---------+-------+---------
 tag     | 16385 | v
 tag2    | 16390 | r
(2 rows)

test=# DELETE FROM pg_depend WHERE refobjid='tag2'::regclass;
DELETE 7
test=# DROP TABLE tag2;
DROP TABLE
test=# SELECT * FROM tag ;
ERROR:  could not open relation with OID 16390

Solutions

It would be possible to skip dependencies when a rule is created

--- a/src/backend/rewrite/rewriteDefine.c
+++ b/src/backend/rewrite/rewriteDefine.c
@@ -162,6 +162,7 @@ InsertRule(const char *rulname,
    referenced.objectId = eventrel_oid;
    referenced.objectSubId = 0;

+#if 0
    recordDependencyOn(&myself, &referenced,
                       (evtype == CMD_SELECT) ? DEPENDENCY_INTERNAL : DEPENDENCY_AUTO);

@@ -170,6 +171,7 @@ InsertRule(const char *rulname,
     */
    recordDependencyOnExpr(&myself, (Node *) action, NIL,
                           DEPENDENCY_NORMAL);
+#endif

    if (event_qual != NULL)
    {

This almost works, but the view definition can no longer described with \d+. Feel free to contact me with ideas!

Further Reading

pg_depend, pg_attribute

The dependency ladder by Federico Campoli