Edgewall Software

TracMultipleProjects/ComprehensiveSolution: create_multitrac_db.sql

File create_multitrac_db.sql, 3.5 KB (added by Dave Abrahams <dave@…>, 2 years ago)

The SQL I used to initialize my PostgreSQL database

Line 
1-- clean out some flotsam that may remain from previous runs
2-- CAUTION!  THIS WIPES OUT THE POSTGRESQL TRAC DATABASE --
3DROP DATABASE trac;
4DROP ROLE trac;
5DROP ROLE trac_instance;
6DROP ROLE trac_instance_master;
7
8-- create a root user for the master Trac instance
9-- that can create new roles
10CREATE ROLE trac
11NOSUPERUSER NOCREATEDB CREATEROLE LOGIN
12PASSWORD :tracpass ;
13
14-- create the database
15CREATE DATABASE trac WITH OWNER trac ENCODING 'UTF8';
16
17-- connect to it.
18\c trac
19
20-- create a role in which all instance database users will have
21-- membership.
22CREATE ROLE trac_instance
23NOSUPERUSER NOCREATEDB NOCREATEROLE NOLOGIN;
24
25-- create a role for the master trac instance
26CREATE ROLE trac_instance_master
27NOSUPERUSER LOGIN
28PASSWORD :tracpass IN ROLE trac_instance;
29
30GRANT trac_instance_master to trac;
31
32-- The sqlite2pg script will sign in as the user
33-- of each trac instance and attempt to create a schema
34-- for that user.  Later on these users will not need
35-- the ability to to create schemas, so at that point
36-- we can revoke it from the trac_instance role all at
37-- once.
38GRANT CREATE ON DATABASE trac TO trac_instance;
39
40-- This table is only used to declare the return values of the
41-- following function.
42CREATE TABLE projects ( project TEXT );
43
44-- Returns a table containing the names of all the schemata used by trac instances.
45CREATE OR REPLACE FUNCTION trac_projects()
46    RETURNS SETOF projects
47    AS
48$body$
49    SELECT substring(schema_name FROM 'trac_instance_(.*)') AS project
50    FROM information_schema.schemata
51    WHERE position('trac_instance_' in schema_name) = 1;
52$body$
53    LANGUAGE sql;
54
55-- Needed in order to declare the cross-schema query functions.  My
56-- SQL fu is too weak to know why we can't use the regular sql
57-- language here; this formula was kindly given to me by Pedro Gimeno
58-- Fortea <parigalo-at-formauri.es>.
59create language plpgsql;
60
61-- This function declares another function that does queries across
62-- trac instances.
63--
64-- We need to do this dynamically so that trac-admin can update the
65-- ticket schema in the future without breaking our multitrac queries. 
66-- There's no way to declare the return type without knowing the format
67-- of the 'ticket' table rows.
68CREATE OR REPLACE FUNCTION declare_multitrac_query()
69    RETURNS void
70    AS
71$declare_multitrac_query$
72BEGIN
73    EXECUTE $declarations$
74        -- declare a table type that's just like the master instance's ticket
75        -- table type, but with an extra text column for the schema name.
76        CREATE TEMP TABLE fat_ticket ( LIKE trac_instance_master.ticket );
77        ALTER TABLE fat_ticket ADD COLUMN project text;
78
79        -- declare a function returning said type that aggregates the results
80        -- of doing the query across all projects
81        CREATE OR REPLACE FUNCTION multitrac_query(criteria TEXT)
82            RETURNS SETOF fat_ticket
83            AS
84        $multitrac_query$
85        DECLARE
86           p RECORD;
87           result RECORD;
88        BEGIN
89           FOR p IN SELECT * FROM trac_projects() LOOP
90             FOR result IN EXECUTE 'SELECT '
91                 || 'trac_instance_' || p.project || '.ticket.*' 
92                 || ',''' || p.project || '''::text AS project'
93                 || ' FROM trac_instance_' || p.project || '.ticket'
94                 || ' WHERE ' || criteria
95                 LOOP
96               RETURN NEXT result;
97             END LOOP;
98           END LOOP;
99           RETURN;
100        END;
101        $multitrac_query$
102           LANGUAGE plpgsql;
103    $declarations$ ;
104
105END;
106$declare_multitrac_query$
107    LANGUAGE plpgsql;
108