Using PostgreSQL as a Web Server and Content Management System - - PowerPoint PPT Presentation

using postgresql as a web server and content management
SMART_READER_LITE
LIVE PREVIEW

Using PostgreSQL as a Web Server and Content Management System - - PowerPoint PPT Presentation

Using PostgreSQL as a Web Server and Content Management System About Me Tim Colles Deputy Head of Computing Head of Research and Teaching Computing Unit School of Informatics University of Edinburgh https://blogs.ed.ac.uk/timc


slide-1
SLIDE 1

Using PostgreSQL as a Web Server and Content Management System

slide-2
SLIDE 2

About Me

Tim Colles

Deputy Head of Computing Head of Research and Teaching Computing Unit School of Informatics University of Edinburgh

https://blogs.ed.ac.uk/timc https://blogs.ed.ac.uk/timc/category/postgresql

slide-3
SLIDE 3

The Problem to Solve

in a nutshell multiple systems and multiple sources of information but also GDPR ...

slide-4
SLIDE 4

Our Solution

“personalised information portal” important that data was “mastered” in satellite systems but authorisation was centralised in one system

slide-5
SLIDE 5

Demo ...

but this talk is not really about this specific service … … instead its about the implementation

slide-6
SLIDE 6

Just Use PostgreSQL

Build the service entirely within PostgreSQL using no other technologies or frameworks (well almost) … Why?

(and why not)

slide-7
SLIDE 7

Just Use PostgreSQL

Why Containment Change Management Common Paths Performance Isolation Features

slide-8
SLIDE 8

Just Use PostgreSQL

Why Containment Change Management Common Paths Performance Isolation Features Why Not Complex Time Options Versioning

slide-9
SLIDE 9

Just Use PostgreSQL

Features (for free) Authorisation Management PL/PGSQL Procedural Language Other Languages Transactional (atomicity) Foreign Data Wrappers Performance Control

slide-10
SLIDE 10

Do a Demo ...

WIP

slide-11
SLIDE 11

POSTGRESQL WSGI BROWSER

slide-12
SLIDE 12

def root(path): if request.method == 'POST': qs = request.query_string with Database.cursor(commit=True) as cur: sql = cur.mogrify("SELECT path, page FROM pip_page_return(%s, %s)", (path, qs)) try: cur.execute(sql) rows = cur.fetchall() except: abort(404) return('', 302, {'location': rows[0]['path']}) else: qs = request.query_string with Database.cursor() as cur: sql = cur.mogrify("SELECT page FROM pip_page(%s,%s)", (path, qs)) try: cur.execute(sql) rows = cur.fetchall() except: abort(404) resp = make_response(rows[0]['page']) return resp

slide-13
SLIDE 13

POSTGRESQL SHEX SUPPLY RETURN PG PG PG PG MYSQL FILE RENDER BROWSER GET POST

slide-14
SLIDE 14

Gurgle

Yet Another Template Processor GNU Report Generator PostgreSQL Extension

slide-15
SLIDE 15

FILE:/tmp/test.grg @database “pg_c.sql” SELECT * FROM pg_catalog.pg_class createdb gtest psql gtest > create extension gurgle; > select gurgle('/tmp/test.grg'); FILE:/tmp/test.tex

sql_languages 13086 13228 0 10 0 13227 0 1 4 1 13229 f f p r 7 0 f f f f f f t d f 0 561 1 {timcolles=arwdDxt/timcolles,=r/timcolles} pg_toast_13232 99 13235 0 10 0 13234 0 0 0 0 0 t f p t 3 0 f f f f f f t n f 0 561 1 pg_toast_13232_index 99 0 0 10 403 13236 0 1 0 0 0 f f p i 2 0 f f f f f f t n f 0 0 0 sql_packages 13086 13233 0 10 0 13232 0 1 10 1 13234 f f p r 5 0 f f f f f f t d f 0 561 1 {timcolles=arwdDxt/timcolles,=r/timcolles} pg_toast_13237 99 13240 0 10 0 13239 0 0 0 0 0 t f p t 3 0 f f f f f f t n f 0 561 1 pg_toast_13237_index 99 0 0 10 403 13241 0 1 0 0 0 f f p i 2 0 f f f f f f t n f 0 0 0 sql_parts 13086 13238 0 10 0 13237 0 1 9 1 13239 f f p r 5 0 f f f f f f t d f 0 561 1 pg_toast_13242 99 13245 0 10 0 13244 0 0 0 0 0 t f p t 3 0 f f f f f f t n f 0 561 1 pg_toast_13242_index 99 0 0 10 403 13246 0 1 0 0 0 f f p i 2 0 f f f f f f t n f 0 0 0 ...

slide-16
SLIDE 16

FILE:/tmp/test.grg @database “pg_c.sql” SELECT * FROM pg_catalog.pg_class @define NAMCOL @record %RELNAME %RELNAMESPACE %RELTYPE > select gurgle('/tmp/test.grg'); FILE:/tmp/test.tex

pg_statistic 11 11319 pg_toast_2604 99 11583 pg_toast_2604_index 99 0 pg_toast_2606 99 11584 pg_toast_2606_index 99 0 pg_toast_2609 99 11585 pg_toast_2609_index 99 0 ...

slide-17
SLIDE 17

FILE:/tmp/test.grg @database “pg_c.sql” SELECT * FROM pg_catalog.pg_class @define NAMCOL @define TEXEXT .html @header <table> <tr> <th>Name</th> <th>Namespace</th> <th>Type</th> <tr> @record <tr> <td>%RELNAME</td> <td>%RELNAMESPACE</td> <td>%RELTYPE</td> </tr> @footer </table> > select gurgle('/tmp/test.grg'); FILE:/tmp/test.html

<table> <tr> <th>Name</th> <th>Namespace</th> <th>Type</th> <tr> <tr> <td>pg_statistic</td> <td>11</td> <td>11319</td> </tr> ...

slide-18
SLIDE 18

FILE:/tmp/test.grg @database “pg_c.sql” SELECT * FROM pg_catalog.pg_class @define NAMCOL @define TEXEXT .html @header <table> <tr> <th>Name</th> <th>Namespace</th> <th>Type</th> <tr> @record <tr> <td>%RELNAME</td> <td>%RELNAMESPACE</td> <td>%RELTYPE</td> </tr> @footer </table> @define PGCAPTURE @define PGVIRTUAL > select * from gurgle('/tmp/test.grg');

path | data

  • ---------------+--------------------------------------------------------

/tmp/test.html | <table> + | <tr> + | <th>Name</th> + | <th>Namespace</th> + | <th>Type</th> + | <tr> + | <tr> + | <td>pg_statistic</td> + | <td>11</td> + | <td>11319</td> + | </tr> + ...

cat /tmp/test.html

No such file or directory

slide-19
SLIDE 19

POSTGRESQL SHEX SUPPLY RETURN PG PG PG PG MYSQL FILE RENDER BROWSER GET POST

slide-20
SLIDE 20

POSTGRESQL SHEX SUPPLY RETURN PG PG PG PG MYSQL FILE RENDER BROWSER GET POST

slide-21
SLIDE 21

POSTGRESQL SHEX SUPPLY RETURN PG PG PG PG MYSQL FILE RENDER BROWSER GET POST

slide-22
SLIDE 22

POSTGRESQL SHEX SUPPLY RETURN PG PG PG PG MYSQL FILE RENDER BROWSER GET POST

slide-23
SLIDE 23

POSTGRESQL SHEX SUPPLY RETURN PG PG PG PG MYSQL FILE RENDER BROWSER GET POST

slide-24
SLIDE 24

POSTGRESQL SHEX SUPPLY RETURN PG PG PG PG MYSQL FILE RENDER BROWSER GET POST

slide-25
SLIDE 25

POSTGRESQL SHEX SUPPLY RETURN PG PG PG PG MYSQL FILE RENDER BROWSER GET POST

slide-26
SLIDE 26

POSTGRESQL SHEX SUPPLY RETURN PG PG PG PG MYSQL FILE RENDER BROWSER GET POST

slide-27
SLIDE 27

POSTGRESQL SHEX SUPPLY RETURN PG PG PG PG MYSQL FILE RENDER BROWSER GET POST

slide-28
SLIDE 28

POSTGRESQL SHEX SUPPLY RETURN PG PG PG PG MYSQL FILE RENDER BROWSER GET POST

slide-29
SLIDE 29

POSTGRESQL SHEX SUPPLY RETURN PG PG PG PG MYSQL FILE RENDER BROWSER GET POST

slide-30
SLIDE 30

POSTGRESQL SHEX SUPPLY RETURN PG PG PG PG MYSQL FILE RENDER BROWSER GET POST

slide-31
SLIDE 31

SATELLITE POSTGRESQL DATABASE (PIP SCHEMA) PIP SERVER POSTGRESQL DATABASE MULTIPLE SUPPLY CHANNELS ONE RETURN CHANNEL

SATELLITE PRESENCE TABLES (*)

SHEX

SERVER PRESENCE (FDW) (*) DYNAMICALLY CREATED DDL USER DATA AND/OR CONFIG DATA OPTIONAL SATELLITE PRESENCE (FDW) (*) SATELLITE RETURN TABLE

slide-32
SLIDE 32

SATELLITE

PIP SERVER POSTGRESQL DATABASE

SHEX

SUPPLY

CONFIG

ACCOUNT QUALITY LHS+RHS APPLICABILITY USER CONFIG THEON COUPLER

slide-33
SLIDE 33

SATELLITE POSTGRESQL DATABASE PIP.* FDW FDW FILE ORACLE SUPPLY FDW

TRIGGERS ON CHANGE SCHEDULED VIA pg_cron

PIP.*

CHANNEL FDW

slide-34
SLIDE 34

SATELLITE POSTGRESQL DATABASE PIP.* FDW FDW FILE ORACLE RETURN TABLE

TRIGGERS CALLBACK FUNCTION ON NEW REQUEST

PIP.*

CHANNEL FDW

CUSTOM CALLBACK FUNCTION DOES STUFF REGISTERS CALLBACK NAMES

slide-35
SLIDE 35

pip-register \

  • -name "demo" \
  • -info "Just a Demo" \
  • -db "demo" \
  • -host "localhost"

name = demo id = 143607031172249350 info = Just a Demo host = localhost db = demo auth token = 100ad48d-293a-4398-ae69- 9f205adf7288

psql pip

slide-36
SLIDE 36

pip-register \

  • -name "demo" \
  • -info "Just a Demo" \
  • -db "demo" \
  • -host "localhost"

name = demo id = 143607031172249350 info = Just a Demo host = localhost db = demo auth token = 100ad48d-293a-4398-ae69- 9f205adf7288

psql pip > select * from satellite where name = 'demo';

  • [ RECORD 1 ]--+-------------------------------------

id | 6 name | demo server_host | localhost definition | Just a Demo connection_key | 100ad48d-293a-4398-ae69-9f205adf7288 disabled | f server_db | demo

slide-37
SLIDE 37

createdb demo psql demo psql pip

slide-38
SLIDE 38

createdb demo psql demo > create extension pip cascade; psql pip

slide-39
SLIDE 39

createdb demo psql demo > create extension pip cascade; > \d pip. pip.channel pip.connection_unq pip.server_pages pip.server_satellite pip.connection pip.return pip.server_qualities_lhs pip.supply pip.connection_pkey pip.server_channels pip.server_qualities_rhs psql pip

slide-40
SLIDE 40

createdb demo psql demo > create extension pip cascade; > \d pip. pip.channel pip.connection_unq pip.server_pages pip.server_satellite pip.connection pip.return pip.server_qualities_lhs pip.supply pip.connection_pkey pip.server_channels pip.server_qualities_rhs > select

pip.connect('demo','/tmp','pi p','100ad48d-293a-4398-ae69- 9f205adf7288');

connect

  • (1 row)

psql pip

slide-41
SLIDE 41

createdb demo psql demo > create extension pip cascade; > \d pip. pip.channel pip.connection_unq pip.server_pages pip.server_satellite pip.connection pip.return pip.server_qualities_lhs pip.supply pip.connection_pkey pip.server_channels pip.server_qualities_rhs > select

pip.connect('demo','/tmp','pi p','100ad48d-293a-4398-ae69- 9f205adf7288');

connect

  • (1 row)

psql pip

> \d pipshex.

pipshex._th_theon pipshex.channel_pgconfeu pipshex.qualities_lhs pipshex.return_pgconfeu pipshex.supply_demo pipshex.channel pipshex.channel_test pipshex.qualities_rhs pipshex.return_test pipshex.supply_marriot pipshex.channel_demo pipshex.channels pipshex.return_demo pipshex.satellite pipshex.supply_pgconfeu pipshex.channel_marriot pipshex.pages pipshex.return_marriot pipshex.supply pipshex.supply_test

slide-42
SLIDE 42

> select * from pip.server_channels;

  • [ RECORD 1 ]----------------------------------

name | applicability info | Internal Server Configuration Channel blocked | t

  • [ RECORD 2 ]----------------------------------

name | page info | Internal Server Configuration Channel blocked | t

  • [ RECORD 3 ]----------------------------------

name | quality-lhs info | Internal Server Configuration Channel blocked | t

  • [ RECORD 4 ]----------------------------------

name | quality-rhs info | Internal Server Configuration Channel blocked | t

  • [ RECORD 5 ]----------------------------------

name | account info | Internal Server Configuration Channel blocked | t

slide-43
SLIDE 43
  • - create a view for channel supply

> CREATE VIEW local_food AS SELECT 'local-food'::text AS channel, ARRAY['person/account'::text] AS visibility, NULL::text AS page, NULL::text AS format, 'record'::text AS type, ARRAY[name,address,distance,rating]::text[] AS value, row_number() OVER (ORDER BY name) AS place, data.name::text AS ident, NULL::text AS bunch FROM data UNION ALL SELECT 'local-food'::text AS channel, ARRAY['person/account'::text] AS visibility, NULL::text AS page, NULL::text AS format, 'header'::text AS type, ARRAY['Restaurant'::text, 'Address'::text, 'Distance'::text, 'Rating'::text] AS value, NULL::integer AS place, 'h'::text AS ident, NULL::text AS bunch;

slide-44
SLIDE 44
  • - create channel

> INSERT INTO pip.channel (name, info, page, visibility, supply_visibility, c_expose, c_onpage, c_opened) VALUES ('local-food', 'Local Eating Places', 'home', ARRAY['person/account'], ARRAY['person/account'], TRUE,TRUE,TRUE); psql pip

slide-45
SLIDE 45
  • - create channel

> INSERT INTO pip.channel (name, info, page, visibility, supply_visibility, c_expose, c_onpage, c_opened) VALUES ('local-food', 'Local Eating Places', 'home', ARRAY['person/account'], ARRAY['person/account'], TRUE,TRUE,TRUE); psql pip > select * from channel where name = 'local-food';

  • [ RECORD 1 ]------+--------------------

id | 31 satellite | demo name | local-food definition | Local Eating Places page | home hidden | fallback | f

  • npage | t
  • nmenu |

expanded | t visibility | {person/account} content_visibility | {person/account} included | t place | 0.09375 adjust | csv | export | f proto | callbacks | exportable | f disabled | f updated_at | sortable | f vsplitat | 0 csvfrom |

slide-46
SLIDE 46
  • - create channel

> INSERT INTO pip.channel (name, info, page, visibility, supply_visibility, c_expose, c_onpage, c_opened) VALUES ('local-food', 'Local Eating Places', 'home', ARRAY['person/account'], ARRAY['person/account'], TRUE,TRUE,TRUE);

  • - refresh supply

> SELECT pip.refresh('local_food');

refresh

  • (1 row)

psql pip > select * from channel where name = 'local-food';

  • [ RECORD 1 ]------+--------------------

id | 31 satellite | demo name | local-food definition | Local Eating Places page | home hidden | fallback | f

  • npage | t
  • nmenu |

expanded | t visibility | {person/account} content_visibility | {person/account} included | t place | 0.09375 adjust | csv | export | f proto | callbacks | exportable | f disabled | f updated_at | sortable | f vsplitat | 0 csvfrom |

slide-47
SLIDE 47
  • - create channel

> INSERT INTO pip.channel (name, info, page, visibility, supply_visibility, c_expose, c_onpage, c_opened) VALUES ('local-food', 'Local Eating Places', 'home', ARRAY['person/account'], ARRAY['person/account'], TRUE,TRUE,TRUE);

  • - refresh supply

> SELECT pip.refresh('local_food');

refresh

  • (1 row)

psql pip > select * from channel where name = 'local-food';

  • [ RECORD 1 ]------+--------------------

id | 31 satellite | demo name | local-food definition | Local Eating Places page | home hidden | fallback | f

  • npage | t
  • nmenu |

expanded | t visibility | {person/account} content_visibility | {person/account} included | t place | 0.09375 adjust | csv | export | f proto | callbacks | exportable | f disabled | f updated_at | sortable | f vsplitat | 0 csvfrom |

> select count(*) from supply where channel = 'local-food';

count

  • 4

(1 row)

slide-48
SLIDE 48

Takeaway

PostgreSQL is not just an RDBMS

https://groups.inf.ed.ac.uk/theon https://groups.inf.ed.ac.uk/theon/download/gurgle-2.0.3.tar.gz git://afsgit.inf.ed.ac.uk/timc/gurgle

https://2019.pgconf.eu/f