jbe@256: BEGIN; jbe@256: jbe@256: CREATE OR REPLACE VIEW "liquid_feedback_version" AS jbe@256: SELECT * FROM (VALUES ('2.0.11', 2, 0, 11)) jbe@256: AS "subquery"("string", "major", "minor", "revision"); jbe@256: jbe@256: DROP FUNCTION "delegation_info" jbe@256: ( "member"."id"%TYPE, jbe@256: "unit"."id"%TYPE, jbe@256: "area"."id"%TYPE, jbe@256: "issue"."id"%TYPE, jbe@256: "member"."id"%TYPE ); jbe@256: jbe@256: DROP FUNCTION "delegation_chain" jbe@256: ( "member"."id"%TYPE, jbe@256: "unit"."id"%TYPE, jbe@256: "area"."id"%TYPE, jbe@256: "issue"."id"%TYPE, jbe@256: "member"."id"%TYPE ); jbe@256: jbe@256: CREATE FUNCTION "delegation_chain" jbe@256: ( "member_id_p" "member"."id"%TYPE, jbe@256: "unit_id_p" "unit"."id"%TYPE, jbe@256: "area_id_p" "area"."id"%TYPE, jbe@256: "issue_id_p" "issue"."id"%TYPE, jbe@256: "simulate_trustee_id_p" "member"."id"%TYPE DEFAULT NULL, jbe@256: "simulate_default_p" BOOLEAN DEFAULT FALSE ) jbe@256: RETURNS SETOF "delegation_chain_row" jbe@256: LANGUAGE 'plpgsql' STABLE AS $$ jbe@256: DECLARE jbe@256: "scope_v" "delegation_scope"; jbe@256: "unit_id_v" "unit"."id"%TYPE; jbe@256: "area_id_v" "area"."id"%TYPE; jbe@256: "issue_row" "issue"%ROWTYPE; jbe@256: "visited_member_ids" INT4[]; -- "member"."id"%TYPE[] jbe@256: "loop_member_id_v" "member"."id"%TYPE; jbe@256: "output_row" "delegation_chain_row"; jbe@256: "output_rows" "delegation_chain_row"[]; jbe@256: "simulate_v" BOOLEAN; jbe@256: "simulate_here_v" BOOLEAN; jbe@256: "delegation_row" "delegation"%ROWTYPE; jbe@256: "row_count" INT4; jbe@256: "i" INT4; jbe@256: "loop_v" BOOLEAN; jbe@256: BEGIN jbe@256: IF "simulate_trustee_id_p" NOTNULL AND "simulate_default_p" THEN jbe@256: RAISE EXCEPTION 'Both "simulate_trustee_id_p" is set, and "simulate_default_p" is true'; jbe@256: END IF; jbe@256: IF "simulate_trustee_id_p" NOTNULL OR "simulate_default_p" THEN jbe@256: "simulate_v" := TRUE; jbe@256: ELSE jbe@256: "simulate_v" := FALSE; jbe@256: END IF; jbe@256: IF jbe@256: "unit_id_p" NOTNULL AND jbe@256: "area_id_p" ISNULL AND jbe@256: "issue_id_p" ISNULL jbe@256: THEN jbe@256: "scope_v" := 'unit'; jbe@256: "unit_id_v" := "unit_id_p"; jbe@256: ELSIF jbe@256: "unit_id_p" ISNULL AND jbe@256: "area_id_p" NOTNULL AND jbe@256: "issue_id_p" ISNULL jbe@256: THEN jbe@256: "scope_v" := 'area'; jbe@256: "area_id_v" := "area_id_p"; jbe@256: SELECT "unit_id" INTO "unit_id_v" jbe@256: FROM "area" WHERE "id" = "area_id_v"; jbe@256: ELSIF jbe@256: "unit_id_p" ISNULL AND jbe@256: "area_id_p" ISNULL AND jbe@256: "issue_id_p" NOTNULL jbe@256: THEN jbe@256: SELECT INTO "issue_row" * FROM "issue" WHERE "id" = "issue_id_p"; jbe@256: IF "issue_row"."id" ISNULL THEN jbe@256: RETURN; jbe@256: END IF; jbe@256: IF "issue_row"."closed" NOTNULL THEN jbe@256: IF "simulate_v" THEN jbe@256: RAISE EXCEPTION 'Tried to simulate delegation chain for closed issue.'; jbe@256: END IF; jbe@256: FOR "output_row" IN jbe@256: SELECT * FROM jbe@256: "delegation_chain_for_closed_issue"("member_id_p", "issue_id_p") jbe@256: LOOP jbe@256: RETURN NEXT "output_row"; jbe@256: END LOOP; jbe@256: RETURN; jbe@256: END IF; jbe@256: "scope_v" := 'issue'; jbe@256: SELECT "area_id" INTO "area_id_v" jbe@256: FROM "issue" WHERE "id" = "issue_id_p"; jbe@256: SELECT "unit_id" INTO "unit_id_v" jbe@256: FROM "area" WHERE "id" = "area_id_v"; jbe@256: ELSE jbe@256: RAISE EXCEPTION 'Exactly one of unit_id_p, area_id_p, or issue_id_p must be NOTNULL.'; jbe@256: END IF; jbe@256: "visited_member_ids" := '{}'; jbe@256: "loop_member_id_v" := NULL; jbe@256: "output_rows" := '{}'; jbe@256: "output_row"."index" := 0; jbe@256: "output_row"."member_id" := "member_id_p"; jbe@256: "output_row"."member_valid" := TRUE; jbe@256: "output_row"."participation" := FALSE; jbe@256: "output_row"."overridden" := FALSE; jbe@256: "output_row"."disabled_out" := FALSE; jbe@256: "output_row"."scope_out" := NULL; jbe@256: LOOP jbe@256: IF "visited_member_ids" @> ARRAY["output_row"."member_id"] THEN jbe@256: "loop_member_id_v" := "output_row"."member_id"; jbe@256: ELSE jbe@256: "visited_member_ids" := jbe@256: "visited_member_ids" || "output_row"."member_id"; jbe@256: END IF; jbe@256: IF "output_row"."participation" ISNULL THEN jbe@256: "output_row"."overridden" := NULL; jbe@256: ELSIF "output_row"."participation" THEN jbe@256: "output_row"."overridden" := TRUE; jbe@256: END IF; jbe@256: "output_row"."scope_in" := "output_row"."scope_out"; jbe@256: "output_row"."member_valid" := EXISTS ( jbe@256: SELECT NULL FROM "member" JOIN "privilege" jbe@256: ON "privilege"."member_id" = "member"."id" jbe@256: AND "privilege"."unit_id" = "unit_id_v" jbe@256: WHERE "id" = "output_row"."member_id" jbe@256: AND "member"."active" AND "privilege"."voting_right" jbe@256: ); jbe@256: "simulate_here_v" := ( jbe@256: "simulate_v" AND jbe@256: "output_row"."member_id" = "member_id_p" jbe@256: ); jbe@256: "delegation_row" := ROW(NULL); jbe@256: IF "output_row"."member_valid" OR "simulate_here_v" THEN jbe@256: IF "scope_v" = 'unit' THEN jbe@256: IF NOT "simulate_here_v" THEN jbe@256: SELECT * INTO "delegation_row" FROM "delegation" jbe@256: WHERE "truster_id" = "output_row"."member_id" jbe@256: AND "unit_id" = "unit_id_v"; jbe@256: END IF; jbe@256: ELSIF "scope_v" = 'area' THEN jbe@256: "output_row"."participation" := EXISTS ( jbe@256: SELECT NULL FROM "membership" jbe@256: WHERE "area_id" = "area_id_p" jbe@256: AND "member_id" = "output_row"."member_id" jbe@256: ); jbe@256: IF "simulate_here_v" THEN jbe@256: IF "simulate_trustee_id_p" ISNULL THEN jbe@256: SELECT * INTO "delegation_row" FROM "delegation" jbe@256: WHERE "truster_id" = "output_row"."member_id" jbe@256: AND "unit_id" = "unit_id_v"; jbe@256: END IF; jbe@256: ELSE jbe@256: SELECT * INTO "delegation_row" FROM "delegation" jbe@256: WHERE "truster_id" = "output_row"."member_id" jbe@256: AND ( jbe@256: "unit_id" = "unit_id_v" OR jbe@256: "area_id" = "area_id_v" jbe@256: ) jbe@256: ORDER BY "scope" DESC; jbe@256: END IF; jbe@256: ELSIF "scope_v" = 'issue' THEN jbe@256: IF "issue_row"."fully_frozen" ISNULL THEN jbe@256: "output_row"."participation" := EXISTS ( jbe@256: SELECT NULL FROM "interest" jbe@256: WHERE "issue_id" = "issue_id_p" jbe@256: AND "member_id" = "output_row"."member_id" jbe@256: ); jbe@256: ELSE jbe@256: IF "output_row"."member_id" = "member_id_p" THEN jbe@256: "output_row"."participation" := EXISTS ( jbe@256: SELECT NULL FROM "direct_voter" jbe@256: WHERE "issue_id" = "issue_id_p" jbe@256: AND "member_id" = "output_row"."member_id" jbe@256: ); jbe@256: ELSE jbe@256: "output_row"."participation" := NULL; jbe@256: END IF; jbe@256: END IF; jbe@256: IF "simulate_here_v" THEN jbe@256: IF "simulate_trustee_id_p" ISNULL THEN jbe@256: SELECT * INTO "delegation_row" FROM "delegation" jbe@256: WHERE "truster_id" = "output_row"."member_id" jbe@256: AND ( jbe@256: "unit_id" = "unit_id_v" OR jbe@256: "area_id" = "area_id_v" jbe@256: ) jbe@256: ORDER BY "scope" DESC; jbe@256: END IF; jbe@256: ELSE jbe@256: SELECT * INTO "delegation_row" FROM "delegation" jbe@256: WHERE "truster_id" = "output_row"."member_id" jbe@256: AND ( jbe@256: "unit_id" = "unit_id_v" OR jbe@256: "area_id" = "area_id_v" OR jbe@256: "issue_id" = "issue_id_p" jbe@256: ) jbe@256: ORDER BY "scope" DESC; jbe@256: END IF; jbe@256: END IF; jbe@256: ELSE jbe@256: "output_row"."participation" := FALSE; jbe@256: END IF; jbe@256: IF "simulate_here_v" AND "simulate_trustee_id_p" NOTNULL THEN jbe@256: "output_row"."scope_out" := "scope_v"; jbe@256: "output_rows" := "output_rows" || "output_row"; jbe@256: "output_row"."member_id" := "simulate_trustee_id_p"; jbe@256: ELSIF "delegation_row"."trustee_id" NOTNULL THEN jbe@256: "output_row"."scope_out" := "delegation_row"."scope"; jbe@256: "output_rows" := "output_rows" || "output_row"; jbe@256: "output_row"."member_id" := "delegation_row"."trustee_id"; jbe@256: ELSIF "delegation_row"."scope" NOTNULL THEN jbe@256: "output_row"."scope_out" := "delegation_row"."scope"; jbe@256: "output_row"."disabled_out" := TRUE; jbe@256: "output_rows" := "output_rows" || "output_row"; jbe@256: EXIT; jbe@256: ELSE jbe@256: "output_row"."scope_out" := NULL; jbe@256: "output_rows" := "output_rows" || "output_row"; jbe@256: EXIT; jbe@256: END IF; jbe@256: EXIT WHEN "loop_member_id_v" NOTNULL; jbe@256: "output_row"."index" := "output_row"."index" + 1; jbe@256: END LOOP; jbe@256: "row_count" := array_upper("output_rows", 1); jbe@256: "i" := 1; jbe@256: "loop_v" := FALSE; jbe@256: LOOP jbe@256: "output_row" := "output_rows"["i"]; jbe@256: EXIT WHEN "output_row" ISNULL; -- NOTE: ISNULL and NOT ... NOTNULL produce different results! jbe@256: IF "loop_v" THEN jbe@256: IF "i" + 1 = "row_count" THEN jbe@256: "output_row"."loop" := 'last'; jbe@256: ELSIF "i" = "row_count" THEN jbe@256: "output_row"."loop" := 'repetition'; jbe@256: ELSE jbe@256: "output_row"."loop" := 'intermediate'; jbe@256: END IF; jbe@256: ELSIF "output_row"."member_id" = "loop_member_id_v" THEN jbe@256: "output_row"."loop" := 'first'; jbe@256: "loop_v" := TRUE; jbe@256: END IF; jbe@256: IF "scope_v" = 'unit' THEN jbe@256: "output_row"."participation" := NULL; jbe@256: END IF; jbe@256: RETURN NEXT "output_row"; jbe@256: "i" := "i" + 1; jbe@256: END LOOP; jbe@256: RETURN; jbe@256: END; jbe@256: $$; jbe@256: jbe@256: COMMENT ON FUNCTION "delegation_chain" jbe@256: ( "member"."id"%TYPE, jbe@256: "unit"."id"%TYPE, jbe@256: "area"."id"%TYPE, jbe@256: "issue"."id"%TYPE, jbe@256: "member"."id"%TYPE, jbe@256: BOOLEAN ) jbe@256: IS 'Shows a delegation chain for unit, area, or issue; See "delegation_chain_row" type for more information'; jbe@256: jbe@256: CREATE FUNCTION "delegation_info" jbe@256: ( "member_id_p" "member"."id"%TYPE, jbe@256: "unit_id_p" "unit"."id"%TYPE, jbe@256: "area_id_p" "area"."id"%TYPE, jbe@256: "issue_id_p" "issue"."id"%TYPE, jbe@256: "simulate_trustee_id_p" "member"."id"%TYPE DEFAULT NULL, jbe@256: "simulate_default_p" BOOLEAN DEFAULT FALSE ) jbe@256: RETURNS "delegation_info_type" jbe@256: LANGUAGE 'plpgsql' STABLE AS $$ jbe@256: DECLARE jbe@256: "current_row" "delegation_chain_row"; jbe@256: "result" "delegation_info_type"; jbe@256: BEGIN jbe@256: "result"."own_participation" := FALSE; jbe@256: FOR "current_row" IN jbe@256: SELECT * FROM "delegation_chain"( jbe@256: "member_id_p", jbe@256: "unit_id_p", "area_id_p", "issue_id_p", jbe@256: "simulate_trustee_id_p", "simulate_default_p") jbe@256: LOOP jbe@256: IF jbe@256: "result"."participating_member_id" ISNULL AND jbe@256: "current_row"."participation" jbe@256: THEN jbe@256: "result"."participating_member_id" := "current_row"."member_id"; jbe@256: END IF; jbe@256: IF "current_row"."member_id" = "member_id_p" THEN jbe@256: "result"."own_participation" := "current_row"."participation"; jbe@256: "result"."own_delegation_scope" := "current_row"."scope_out"; jbe@256: IF "current_row"."loop" = 'first' THEN jbe@256: "result"."delegation_loop" := 'own'; jbe@256: END IF; jbe@256: ELSIF jbe@256: "current_row"."member_valid" AND jbe@256: ( "current_row"."loop" ISNULL OR jbe@256: "current_row"."loop" != 'repetition' ) jbe@256: THEN jbe@256: IF "result"."first_trustee_id" ISNULL THEN jbe@256: "result"."first_trustee_id" := "current_row"."member_id"; jbe@256: "result"."first_trustee_participation" := "current_row"."participation"; jbe@256: "result"."first_trustee_ellipsis" := FALSE; jbe@256: IF "current_row"."loop" = 'first' THEN jbe@256: "result"."delegation_loop" := 'first'; jbe@256: END IF; jbe@256: ELSIF "result"."other_trustee_id" ISNULL THEN jbe@256: IF "current_row"."participation" AND NOT "current_row"."overridden" THEN jbe@256: "result"."other_trustee_id" := "current_row"."member_id"; jbe@256: "result"."other_trustee_participation" := TRUE; jbe@256: "result"."other_trustee_ellipsis" := FALSE; jbe@256: IF "current_row"."loop" = 'first' THEN jbe@256: "result"."delegation_loop" := 'other'; jbe@256: END IF; jbe@256: ELSE jbe@256: "result"."first_trustee_ellipsis" := TRUE; jbe@256: IF "current_row"."loop" = 'first' THEN jbe@256: "result"."delegation_loop" := 'first_ellipsis'; jbe@256: END IF; jbe@256: END IF; jbe@256: ELSE jbe@256: "result"."other_trustee_ellipsis" := TRUE; jbe@256: IF "current_row"."loop" = 'first' THEN jbe@256: "result"."delegation_loop" := 'other_ellipsis'; jbe@256: END IF; jbe@256: END IF; jbe@256: END IF; jbe@256: END LOOP; jbe@256: RETURN "result"; jbe@256: END; jbe@256: $$; jbe@256: jbe@256: COMMENT ON FUNCTION "delegation_info" jbe@256: ( "member"."id"%TYPE, jbe@256: "unit"."id"%TYPE, jbe@256: "area"."id"%TYPE, jbe@256: "issue"."id"%TYPE, jbe@256: "member"."id"%TYPE, jbe@256: BOOLEAN ) jbe@256: IS 'Notable information about a delegation chain for unit, area, or issue; See "delegation_info_type" for more information'; jbe@256: jbe@256: COMMIT;