| 1 | -- clean out some flotsam that may remain from previous runs |
|---|
| 2 | -- CAUTION! THIS WIPES OUT THE POSTGRESQL TRAC DATABASE -- |
|---|
| 3 | DROP DATABASE trac; |
|---|
| 4 | DROP ROLE trac; |
|---|
| 5 | DROP ROLE trac_instance; |
|---|
| 6 | DROP ROLE trac_instance_master; |
|---|
| 7 | |
|---|
| 8 | -- create a root user for the master Trac instance |
|---|
| 9 | -- that can create new roles |
|---|
| 10 | CREATE ROLE trac |
|---|
| 11 | NOSUPERUSER NOCREATEDB CREATEROLE LOGIN |
|---|
| 12 | PASSWORD :tracpass ; |
|---|
| 13 | |
|---|
| 14 | -- create the database |
|---|
| 15 | CREATE 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. |
|---|
| 22 | CREATE ROLE trac_instance |
|---|
| 23 | NOSUPERUSER NOCREATEDB NOCREATEROLE NOLOGIN; |
|---|
| 24 | |
|---|
| 25 | -- create a role for the master trac instance |
|---|
| 26 | CREATE ROLE trac_instance_master |
|---|
| 27 | NOSUPERUSER LOGIN |
|---|
| 28 | PASSWORD :tracpass IN ROLE trac_instance; |
|---|
| 29 | |
|---|
| 30 | GRANT 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. |
|---|
| 38 | GRANT CREATE ON DATABASE trac TO trac_instance; |
|---|
| 39 | |
|---|
| 40 | -- This table is only used to declare the return values of the |
|---|
| 41 | -- following function. |
|---|
| 42 | CREATE TABLE projects ( project TEXT ); |
|---|
| 43 | |
|---|
| 44 | -- Returns a table containing the names of all the schemata used by trac instances. |
|---|
| 45 | CREATE 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>. |
|---|
| 59 | create 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. |
|---|
| 68 | CREATE OR REPLACE FUNCTION declare_multitrac_query() |
|---|
| 69 | RETURNS void |
|---|
| 70 | AS |
|---|
| 71 | $declare_multitrac_query$ |
|---|
| 72 | BEGIN |
|---|
| 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 | |
|---|
| 105 | END; |
|---|
| 106 | $declare_multitrac_query$ |
|---|
| 107 | LANGUAGE plpgsql; |
|---|
| 108 | |
|---|