liquid_feedback_core
view update/core-update.v2.0.12-v2.1.0.sql @ 346:6c8209b711af
Set harmonic_weight for all issues in update script to v2.2.0
| author | jbe | 
|---|---|
| date | Thu Feb 21 20:05:42 2013 +0100 (2013-02-21) | 
| parents | 5c98265b39a0 | 
| children | 
 line source
     1 BEGIN;
     4 -- update version number
     6 CREATE OR REPLACE VIEW "liquid_feedback_version" AS
     7   SELECT * FROM (VALUES ('2.1.0', 2, 1, 0))
     8   AS "subquery"("string", "major", "minor", "revision");
    11 -- old API tables are now deprecated
    13 COMMENT ON TYPE "application_access_level" IS 'DEPRECATED, WILL BE REMOVED! Access privileges for applications using the API';
    14 COMMENT ON TABLE "member_application" IS 'DEPRECATED, WILL BE REMOVED! Registered application being allowed to use the API';
    17 -- new polling mode and changed privileges
    19 ALTER TABLE "policy" ADD COLUMN "polling" BOOLEAN NOT NULL DEFAULT FALSE;
    20 ALTER TABLE "policy" ALTER COLUMN "admission_time"    DROP NOT NULL;
    21 ALTER TABLE "policy" ALTER COLUMN "discussion_time"   DROP NOT NULL;
    22 ALTER TABLE "policy" ALTER COLUMN "verification_time" DROP NOT NULL;
    23 ALTER TABLE "policy" ALTER COLUMN "voting_time"       DROP NOT NULL;
    24 ALTER TABLE "policy" ALTER COLUMN "issue_quorum_num"  DROP NOT NULL;
    25 ALTER TABLE "policy" ALTER COLUMN "issue_quorum_den"  DROP NOT NULL;
    26 ALTER TABLE "policy" ADD CONSTRAINT "timing" CHECK (
    27           ( "polling" = FALSE AND
    28             "admission_time" NOTNULL AND "discussion_time" NOTNULL AND
    29             "verification_time" NOTNULL AND "voting_time" NOTNULL ) OR
    30           ( "polling" = TRUE AND
    31             "admission_time" ISNULL AND "discussion_time" NOTNULL AND
    32             "verification_time" NOTNULL AND "voting_time" NOTNULL ) OR
    33           ( "polling" = TRUE AND
    34             "admission_time" ISNULL AND "discussion_time" ISNULL AND
    35             "verification_time" ISNULL AND "voting_time" ISNULL ) );
    36 ALTER TABLE "policy" ADD CONSTRAINT "issue_quorum_if_and_only_if_not_polling" CHECK (
    37           "polling" = "issue_quorum_num" ISNULL AND
    38           "polling" = "issue_quorum_den" ISNULL );
    39 COMMENT ON COLUMN "policy"."polling" IS 'TRUE = special policy for non-user-generated issues without issue quorum, where certain initiatives (those having the "polling" flag set) do not need to pass the initiative quorum; "admission_time" MUST be set to NULL, the other timings may be set to NULL altogether, allowing individual timing for those issues';
    41 ALTER TABLE "issue" ALTER COLUMN "admission_time" DROP NOT NULL;
    42 ALTER TABLE "issue" ADD CONSTRAINT "admission_time_not_null_unless_instantly_accepted" CHECK (
    43   "admission_time" NOTNULL OR ("accepted" NOTNULL AND "accepted" = "created") );
    45 ALTER TABLE "initiative" ADD COLUMN "polling" BOOLEAN NOT NULL DEFAULT FALSE;
    46 COMMENT ON COLUMN "initiative"."polling" IS 'Initiative does not need to pass the initiative quorum (see "policy"."polling")';
    48 ALTER TABLE "privilege" RENAME COLUMN "voting_right_manager" TO "member_manager";
    49 ALTER TABLE "privilege" ADD COLUMN "initiative_right" BOOLEAN NOT NULL DEFAULT TRUE;
    50 ALTER TABLE "privilege" ADD COLUMN "polling_right"    BOOLEAN NOT NULL DEFAULT FALSE;
    51 UPDATE "privilege" SET "initiative_right" = "voting_right";
    52 COMMENT ON COLUMN "privilege"."admin_manager"    IS 'Grant/revoke any privileges to/from other members';
    53 COMMENT ON COLUMN "privilege"."member_manager"   IS 'Adding/removing members from the unit, granting or revoking "initiative_right" and "voting_right"';
    54 COMMENT ON COLUMN "privilege"."initiative_right" IS 'Right to create an initiative';
    55 COMMENT ON COLUMN "privilege"."voting_right"     IS 'Right to support initiatives, create and rate suggestions, and to vote';
    56 COMMENT ON COLUMN "privilege"."polling_right"    IS 'Right to create issues with policies having the "policy"."polling" flag set, and to add initiatives having the "initiative"."polling" flag set to those issues';
    58 DROP VIEW "member_contingent_left";
    59 DROP VIEW "member_contingent";
    60 ALTER TABLE "contingent" DROP CONSTRAINT "contingent_pkey";
    61 ALTER TABLE "contingent" ALTER COLUMN "time_frame" DROP NOT NULL;
    62 ALTER TABLE "contingent" ADD COLUMN "polling" BOOLEAN DEFAULT FALSE;
    63 ALTER TABLE "contingent" ADD PRIMARY KEY ("polling", "time_frame");
    64 ALTER TABLE "contingent" ALTER COLUMN "polling" DROP DEFAULT;
    65 COMMENT ON COLUMN "contingent"."polling" IS 'Determines if settings are for creating initiatives and new drafts of initiatives with "polling" flag set';
    67 CREATE VIEW "member_contingent" AS
    68   SELECT
    69     "member"."id" AS "member_id",
    70     "contingent"."polling",
    71     "contingent"."time_frame",
    72     CASE WHEN "contingent"."text_entry_limit" NOTNULL THEN
    73       (
    74         SELECT count(1) FROM "draft"
    75         JOIN "initiative" ON "initiative"."id" = "draft"."initiative_id"
    76         WHERE "draft"."author_id" = "member"."id"
    77         AND "initiative"."polling" = "contingent"."polling"
    78         AND "draft"."created" > now() - "contingent"."time_frame"
    79       ) + (
    80         SELECT count(1) FROM "suggestion"
    81         JOIN "initiative" ON "initiative"."id" = "suggestion"."initiative_id"
    82         WHERE "suggestion"."author_id" = "member"."id"
    83         AND "contingent"."polling" = FALSE
    84         AND "suggestion"."created" > now() - "contingent"."time_frame"
    85       )
    86     ELSE NULL END AS "text_entry_count",
    87     "contingent"."text_entry_limit",
    88     CASE WHEN "contingent"."initiative_limit" NOTNULL THEN (
    89       SELECT count(1) FROM "opening_draft" AS "draft"
    90         JOIN "initiative" ON "initiative"."id" = "draft"."initiative_id"
    91       WHERE "draft"."author_id" = "member"."id"
    92       AND "initiative"."polling" = "contingent"."polling"
    93       AND "draft"."created" > now() - "contingent"."time_frame"
    94     ) ELSE NULL END AS "initiative_count",
    95     "contingent"."initiative_limit"
    96   FROM "member" CROSS JOIN "contingent";
    98 COMMENT ON VIEW "member_contingent" IS 'Actual counts of text entries and initiatives are calculated per member for each limit in the "contingent" table.';
   100 COMMENT ON COLUMN "member_contingent"."text_entry_count" IS 'Only calculated when "text_entry_limit" is not null in the same row';
   101 COMMENT ON COLUMN "member_contingent"."initiative_count" IS 'Only calculated when "initiative_limit" is not null in the same row';
   103 CREATE VIEW "member_contingent_left" AS
   104   SELECT
   105     "member_id",
   106     "polling",
   107     max("text_entry_limit" - "text_entry_count") AS "text_entries_left",
   108     max("initiative_limit" - "initiative_count") AS "initiatives_left"
   109   FROM "member_contingent" GROUP BY "member_id", "polling";
   111 COMMENT ON VIEW "member_contingent_left" IS 'Amount of text entries or initiatives which can be posted now instantly by a member. This view should be used by a frontend to determine, if the contingent for posting is exhausted.';
   113 CREATE OR REPLACE FUNCTION "freeze_after_snapshot"
   114   ( "issue_id_p" "issue"."id"%TYPE )
   115   RETURNS VOID
   116   LANGUAGE 'plpgsql' VOLATILE AS $$
   117     DECLARE
   118       "issue_row"      "issue"%ROWTYPE;
   119       "policy_row"     "policy"%ROWTYPE;
   120       "initiative_row" "initiative"%ROWTYPE;
   121     BEGIN
   122       SELECT * INTO "issue_row" FROM "issue" WHERE "id" = "issue_id_p";
   123       SELECT * INTO "policy_row"
   124         FROM "policy" WHERE "id" = "issue_row"."policy_id";
   125       PERFORM "set_snapshot_event"("issue_id_p", 'full_freeze');
   126       FOR "initiative_row" IN
   127         SELECT * FROM "initiative"
   128         WHERE "issue_id" = "issue_id_p" AND "revoked" ISNULL
   129       LOOP
   130         IF
   131           "initiative_row"."polling" OR (
   132             "initiative_row"."satisfied_supporter_count" > 0 AND
   133             "initiative_row"."satisfied_supporter_count" *
   134             "policy_row"."initiative_quorum_den" >=
   135             "issue_row"."population" * "policy_row"."initiative_quorum_num"
   136           )
   137         THEN
   138           UPDATE "initiative" SET "admitted" = TRUE
   139             WHERE "id" = "initiative_row"."id";
   140         ELSE
   141           UPDATE "initiative" SET "admitted" = FALSE
   142             WHERE "id" = "initiative_row"."id";
   143         END IF;
   144       END LOOP;
   145       IF EXISTS (
   146         SELECT NULL FROM "initiative"
   147         WHERE "issue_id" = "issue_id_p" AND "admitted" = TRUE
   148       ) THEN
   149         UPDATE "issue" SET
   150           "state"        = 'voting',
   151           "accepted"     = coalesce("accepted", now()),
   152           "half_frozen"  = coalesce("half_frozen", now()),
   153           "fully_frozen" = now()
   154           WHERE "id" = "issue_id_p";
   155       ELSE
   156         UPDATE "issue" SET
   157           "state"           = 'canceled_no_initiative_admitted',
   158           "accepted"        = coalesce("accepted", now()),
   159           "half_frozen"     = coalesce("half_frozen", now()),
   160           "fully_frozen"    = now(),
   161           "closed"          = now(),
   162           "ranks_available" = TRUE
   163           WHERE "id" = "issue_id_p";
   164         -- NOTE: The following DELETE statements have effect only when
   165         --       issue state has been manipulated
   166         DELETE FROM "direct_voter"     WHERE "issue_id" = "issue_id_p";
   167         DELETE FROM "delegating_voter" WHERE "issue_id" = "issue_id_p";
   168         DELETE FROM "battle"           WHERE "issue_id" = "issue_id_p";
   169       END IF;
   170       RETURN;
   171     END;
   172   $$;
   175 -- issue comments removed, voting comments integrated in "direct_voter" table
   177 ALTER TABLE "direct_voter" ADD COLUMN "comment_changed"   TIMESTAMPTZ;
   178 ALTER TABLE "direct_voter" ADD COLUMN "formatting_engine" TEXT;
   179 ALTER TABLE "direct_voter" ADD COLUMN "comment"           TEXT;
   180 ALTER TABLE "direct_voter" ADD COLUMN "text_search_data"  TSVECTOR;
   181 CREATE INDEX "direct_voter_text_search_data_idx" ON "direct_voter" USING gin ("text_search_data");
   182 CREATE TRIGGER "update_text_search_data"
   183   BEFORE INSERT OR UPDATE ON "direct_voter"
   184   FOR EACH ROW EXECUTE PROCEDURE
   185   tsvector_update_trigger('text_search_data', 'pg_catalog.simple', "comment");
   187 COMMENT ON COLUMN "direct_voter"."comment_changed"   IS 'Shall be set on comment change, to indicate a comment being modified after voting has been finished; Automatically set to NULL after voting phase; Automatically set to NULL by trigger, if "comment" is set to NULL';
   188 COMMENT ON COLUMN "direct_voter"."formatting_engine" IS 'Allows different formatting engines (i.e. wiki formats) to be used for "direct_voter"."comment"; Automatically set to NULL by trigger, if "comment" is set to NULL';
   189 COMMENT ON COLUMN "direct_voter"."comment"           IS 'Is to be set or updated by the frontend, if comment was inserted or updated AFTER the issue has been closed. Otherwise it shall be set to NULL.';
   191 CREATE TABLE "rendered_voter_comment" (
   192         PRIMARY KEY ("issue_id", "member_id", "format"),
   193         FOREIGN KEY ("issue_id", "member_id")
   194           REFERENCES "direct_voter" ("issue_id", "member_id")
   195           ON DELETE CASCADE ON UPDATE CASCADE,
   196         "issue_id"              INT4,
   197         "member_id"             INT4,
   198         "format"                TEXT,
   199         "content"               TEXT            NOT NULL );
   201 COMMENT ON TABLE "rendered_voter_comment" IS 'This table may be used by frontends to cache "rendered" voter comments (e.g. HTML output generated from wiki text)';
   203 DROP TABLE "rendered_issue_comment";
   204 DROP TABLE "issue_comment";
   205 DROP TABLE "rendered_voting_comment";
   206 DROP TABLE "voting_comment";
   208 CREATE FUNCTION "voter_comment_fields_only_set_when_voter_comment_is_set_trigger"()
   209   RETURNS TRIGGER
   210   LANGUAGE 'plpgsql' VOLATILE AS $$
   211     BEGIN
   212       IF NEW."comment" ISNULL THEN
   213         NEW."comment_changed" := NULL;
   214         NEW."formatting_engine" := NULL;
   215       END IF;
   216       RETURN NEW;
   217     END;
   218   $$;
   220 CREATE TRIGGER "voter_comment_fields_only_set_when_voter_comment_is_set"
   221   BEFORE INSERT OR UPDATE ON "direct_voter"
   222   FOR EACH ROW EXECUTE PROCEDURE
   223   "voter_comment_fields_only_set_when_voter_comment_is_set_trigger"();
   225 COMMENT ON FUNCTION "voter_comment_fields_only_set_when_voter_comment_is_set_trigger"() IS 'Implementation of trigger "voter_comment_fields_only_set_when_voter_comment_is_set" ON table "direct_voter"';
   226 COMMENT ON TRIGGER "voter_comment_fields_only_set_when_voter_comment_is_set" ON "direct_voter" IS 'If "comment" is set to NULL, then other comment related fields are also set to NULL.';
   228 CREATE OR REPLACE FUNCTION "forbid_changes_on_closed_issue_trigger"()
   229   RETURNS TRIGGER
   230   LANGUAGE 'plpgsql' VOLATILE AS $$
   231     DECLARE
   232       "issue_id_v" "issue"."id"%TYPE;
   233       "issue_row"  "issue"%ROWTYPE;
   234     BEGIN
   235       IF TG_RELID = 'direct_voter'::regclass AND TG_OP = 'UPDATE' THEN
   236         IF
   237           OLD."issue_id"  = NEW."issue_id"  AND
   238           OLD."member_id" = NEW."member_id" AND
   239           OLD."weight"    = NEW."weight"
   240         THEN
   241           RETURN NULL;  -- allows changing of voter comment
   242         END IF;
   243       END IF;
   244       IF TG_OP = 'DELETE' THEN
   245         "issue_id_v" := OLD."issue_id";
   246       ELSE
   247         "issue_id_v" := NEW."issue_id";
   248       END IF;
   249       SELECT INTO "issue_row" * FROM "issue"
   250         WHERE "id" = "issue_id_v" FOR SHARE;
   251       IF "issue_row"."closed" NOTNULL THEN
   252         RAISE EXCEPTION 'Tried to modify data belonging to a closed issue.';
   253       END IF;
   254       RETURN NULL;
   255     END;
   256   $$;
   258 CREATE OR REPLACE FUNCTION "close_voting"("issue_id_p" "issue"."id"%TYPE)
   259   RETURNS VOID
   260   LANGUAGE 'plpgsql' VOLATILE AS $$
   261     DECLARE
   262       "area_id_v"   "area"."id"%TYPE;
   263       "unit_id_v"   "unit"."id"%TYPE;
   264       "member_id_v" "member"."id"%TYPE;
   265     BEGIN
   266       PERFORM "lock_issue"("issue_id_p");
   267       SELECT "area_id" INTO "area_id_v" FROM "issue" WHERE "id" = "issue_id_p";
   268       SELECT "unit_id" INTO "unit_id_v" FROM "area"  WHERE "id" = "area_id_v";
   269       -- delete timestamp of voting comment:
   270       UPDATE "direct_voter" SET "comment_changed" = NULL
   271         WHERE "issue_id" = "issue_id_p";
   272       -- delete delegating votes (in cases of manual reset of issue state):
   273       DELETE FROM "delegating_voter"
   274         WHERE "issue_id" = "issue_id_p";
   275       -- delete votes from non-privileged voters:
   276       DELETE FROM "direct_voter"
   277         USING (
   278           SELECT
   279             "direct_voter"."member_id"
   280           FROM "direct_voter"
   281           JOIN "member" ON "direct_voter"."member_id" = "member"."id"
   282           LEFT JOIN "privilege"
   283           ON "privilege"."unit_id" = "unit_id_v"
   284           AND "privilege"."member_id" = "direct_voter"."member_id"
   285           WHERE "direct_voter"."issue_id" = "issue_id_p" AND (
   286             "member"."active" = FALSE OR
   287             "privilege"."voting_right" ISNULL OR
   288             "privilege"."voting_right" = FALSE
   289           )
   290         ) AS "subquery"
   291         WHERE "direct_voter"."issue_id" = "issue_id_p"
   292         AND "direct_voter"."member_id" = "subquery"."member_id";
   293       -- consider delegations:
   294       UPDATE "direct_voter" SET "weight" = 1
   295         WHERE "issue_id" = "issue_id_p";
   296       PERFORM "add_vote_delegations"("issue_id_p");
   297       -- set voter count and mark issue as being calculated:
   298       UPDATE "issue" SET
   299         "state"  = 'calculation',
   300         "closed" = now(),
   301         "voter_count" = (
   302           SELECT coalesce(sum("weight"), 0)
   303           FROM "direct_voter" WHERE "issue_id" = "issue_id_p"
   304         )
   305         WHERE "id" = "issue_id_p";
   306       -- materialize battle_view:
   307       -- NOTE: "closed" column of issue must be set at this point
   308       DELETE FROM "battle" WHERE "issue_id" = "issue_id_p";
   309       INSERT INTO "battle" (
   310         "issue_id",
   311         "winning_initiative_id", "losing_initiative_id",
   312         "count"
   313       ) SELECT
   314         "issue_id",
   315         "winning_initiative_id", "losing_initiative_id",
   316         "count"
   317         FROM "battle_view" WHERE "issue_id" = "issue_id_p";
   318       -- copy "positive_votes" and "negative_votes" from "battle" table:
   319       UPDATE "initiative" SET
   320         "positive_votes" = "battle_win"."count",
   321         "negative_votes" = "battle_lose"."count"
   322         FROM "battle" AS "battle_win", "battle" AS "battle_lose"
   323         WHERE
   324           "battle_win"."issue_id" = "issue_id_p" AND
   325           "battle_win"."winning_initiative_id" = "initiative"."id" AND
   326           "battle_win"."losing_initiative_id" ISNULL AND
   327           "battle_lose"."issue_id" = "issue_id_p" AND
   328           "battle_lose"."losing_initiative_id" = "initiative"."id" AND
   329           "battle_lose"."winning_initiative_id" ISNULL;
   330     END;
   331   $$;
   333 CREATE OR REPLACE FUNCTION "clean_issue"("issue_id_p" "issue"."id"%TYPE)
   334   RETURNS VOID
   335   LANGUAGE 'plpgsql' VOLATILE AS $$
   336     DECLARE
   337       "issue_row" "issue"%ROWTYPE;
   338     BEGIN
   339       SELECT * INTO "issue_row"
   340         FROM "issue" WHERE "id" = "issue_id_p"
   341         FOR UPDATE;
   342       IF "issue_row"."cleaned" ISNULL THEN
   343         UPDATE "issue" SET
   344           "state"           = 'voting',
   345           "closed"          = NULL,
   346           "ranks_available" = FALSE
   347           WHERE "id" = "issue_id_p";
   348         DELETE FROM "delegating_voter"
   349           WHERE "issue_id" = "issue_id_p";
   350         DELETE FROM "direct_voter"
   351           WHERE "issue_id" = "issue_id_p";
   352         DELETE FROM "delegating_interest_snapshot"
   353           WHERE "issue_id" = "issue_id_p";
   354         DELETE FROM "direct_interest_snapshot"
   355           WHERE "issue_id" = "issue_id_p";
   356         DELETE FROM "delegating_population_snapshot"
   357           WHERE "issue_id" = "issue_id_p";
   358         DELETE FROM "direct_population_snapshot"
   359           WHERE "issue_id" = "issue_id_p";
   360         DELETE FROM "non_voter"
   361           WHERE "issue_id" = "issue_id_p";
   362         DELETE FROM "delegation"
   363           WHERE "issue_id" = "issue_id_p";
   364         DELETE FROM "supporter"
   365           WHERE "issue_id" = "issue_id_p";
   366         UPDATE "issue" SET
   367           "state"           = "issue_row"."state",
   368           "closed"          = "issue_row"."closed",
   369           "ranks_available" = "issue_row"."ranks_available",
   370           "cleaned"         = now()
   371           WHERE "id" = "issue_id_p";
   372       END IF;
   373       RETURN;
   374     END;
   375   $$;
   378 -- "non_voter" deletes "direct_voter" and vice versa
   380 CREATE FUNCTION "non_voter_deletes_direct_voter_trigger"()
   381   RETURNS TRIGGER
   382   LANGUAGE 'plpgsql' VOLATILE AS $$
   383     BEGIN
   384       DELETE FROM "direct_voter"
   385         WHERE "issue_id" = NEW."issue_id" AND "member_id" = NEW."member_id";
   386       RETURN NULL;
   387     END;
   388   $$;
   390 CREATE TRIGGER "non_voter_deletes_direct_voter"
   391   AFTER INSERT OR UPDATE ON "non_voter"
   392   FOR EACH ROW EXECUTE PROCEDURE
   393   "non_voter_deletes_direct_voter_trigger"();
   395 COMMENT ON FUNCTION "non_voter_deletes_direct_voter_trigger"()     IS 'Implementation of trigger "non_voter_deletes_direct_voter" on table "non_voter"';
   396 COMMENT ON TRIGGER "non_voter_deletes_direct_voter" ON "non_voter" IS 'An entry in the "non_voter" table deletes an entry in the "direct_voter" table (and vice versa due to trigger "direct_voter_deletes_non_voter" on table "direct_voter")';
   398 CREATE FUNCTION "direct_voter_deletes_non_voter_trigger"()
   399   RETURNS TRIGGER
   400   LANGUAGE 'plpgsql' VOLATILE AS $$
   401     BEGIN
   402       DELETE FROM "non_voter"
   403         WHERE "issue_id" = NEW."issue_id" AND "member_id" = NEW."member_id";
   404       RETURN NULL;
   405     END;
   406   $$;
   408 CREATE TRIGGER "direct_voter_deletes_non_voter"
   409   AFTER INSERT OR UPDATE ON "direct_voter"
   410   FOR EACH ROW EXECUTE PROCEDURE
   411   "direct_voter_deletes_non_voter_trigger"();
   413 COMMENT ON FUNCTION "direct_voter_deletes_non_voter_trigger"()        IS 'Implementation of trigger "direct_voter_deletes_non_voter" on table "direct_voter"';
   414 COMMENT ON TRIGGER "direct_voter_deletes_non_voter" ON "direct_voter" IS 'An entry in the "direct_voter" table deletes an entry in the "non_voter" table (and vice versa due to trigger "non_voter_deletes_direct_voter" on table "non_voter")';
   417 -- different locking levels and different locking order to avoid deadlocks
   419 CREATE OR REPLACE FUNCTION "lock_issue"
   420   ( "issue_id_p" "issue"."id"%TYPE )
   421   RETURNS VOID
   422   LANGUAGE 'plpgsql' VOLATILE AS $$
   423     BEGIN
   424       -- The following locking order is used:
   425       -- 1st) row-level lock on the issue
   426       -- 2nd) table-level locks in order of occurrence in the core.sql file
   427       PERFORM NULL FROM "issue" WHERE "id" = "issue_id_p" FOR UPDATE;
   428       -- NOTE: The row-level exclusive lock in combination with the
   429       -- share_row_lock_issue(_via_initiative)_trigger functions (which
   430       -- acquire a row-level share lock on the issue) ensure that no data
   431       -- is changed, which could affect calculation of snapshots or
   432       -- counting of votes. Table "delegation" must be table-level-locked,
   433       -- as it also contains issue- and global-scope delegations.
   434       PERFORM NULL FROM "member" WHERE "active" FOR SHARE;
   435       -- NOTE: As we later cause implicit row-level share locks on many
   436       -- active members, we lock them before locking any other table
   437       -- to avoid deadlocks
   438       LOCK TABLE "member"     IN SHARE MODE;
   439       LOCK TABLE "privilege"  IN SHARE MODE;
   440       LOCK TABLE "membership" IN SHARE MODE;
   441       LOCK TABLE "policy"     IN SHARE MODE;
   442       LOCK TABLE "delegation" IN SHARE MODE;
   443       LOCK TABLE "direct_population_snapshot"     IN EXCLUSIVE MODE;
   444       LOCK TABLE "delegating_population_snapshot" IN EXCLUSIVE MODE;
   445       LOCK TABLE "direct_interest_snapshot"       IN EXCLUSIVE MODE;
   446       LOCK TABLE "delegating_interest_snapshot"   IN EXCLUSIVE MODE;
   447       LOCK TABLE "direct_supporter_snapshot"      IN EXCLUSIVE MODE;
   448       RETURN;
   449     END;
   450   $$;
   453 -- new comment on function "delete_private_data"()
   455 COMMENT ON FUNCTION "delete_private_data"() IS 'Used by lf_export script. DO NOT USE on productive database, but only on a copy! This function deletes all data which should not be publicly available, and can be used to create a database dump for publication. See source code to see which data is deleted. If you need a different behaviour, copy this function and modify lf_export accordingly, to avoid data-leaks after updating.';
   458 -- NOTE: The first version of the previous update script didn't
   459 -- remove the "vote_ratio" function.
   460 -- The function is therefore removed here as well, if existent.
   462 DROP FUNCTION IF EXISTS "vote_ratio"
   463   ( "initiative"."positive_votes"%TYPE,
   464     "initiative"."negative_votes"%TYPE );
   467 COMMIT;
