jbe@352: #include jbe@352: #include jbe@352: #include jbe@352: #include jbe@352: #include jbe@352: jbe@352: static char *escapeLiteral(PGconn *conn, const char *str, size_t len) { jbe@352: // provides compatibility for PostgreSQL versions prior 9.0 jbe@352: // in future: return PQescapeLiteral(conn, str, len); jbe@352: char *res; jbe@352: size_t res_len; jbe@352: res = malloc(2*len+3); jbe@352: res[0] = '\''; jbe@352: res_len = PQescapeStringConn(conn, res+1, str, len, NULL); jbe@352: res[res_len+1] = '\''; jbe@352: res[res_len+2] = 0; jbe@352: return res; jbe@352: } jbe@352: jbe@352: static void freemem(void *ptr) { jbe@352: // to be used for "escapeLiteral" function jbe@352: // provides compatibility for PostgreSQL versions prior 9.0 jbe@352: // in future: PQfreemem(ptr); jbe@352: free(ptr); jbe@352: } jbe@352: jbe@352: #define COL_MEMBER_ID 0 jbe@352: #define COL_WEIGHT 1 jbe@352: #define COL_PREFERENCE 2 jbe@352: #define COL_SUGGESTION_ID 3 jbe@352: jbe@353: struct candidate { jbe@353: char *key; jbe@353: double score; jbe@353: int seat; jbe@353: }; jbe@353: jbe@353: static int compare_candidate(struct candidate *c1, struct candidate *c2) { jbe@353: return strcmp(c1->key, c2->key); jbe@353: } jbe@352: jbe@353: static int candidate_count; jbe@353: static struct candidate *candidates; jbe@353: jbe@353: static void register_candidate(char **candidate_key, VISIT visit, int level) { jbe@352: if (visit == postorder || visit == leaf) { jbe@353: struct candidate *candidate; jbe@353: candidate = candidates + (candidate_count++); jbe@353: candidate->key = *candidate_key; jbe@353: candidate->score = 0.0; jbe@353: candidate->seat = 0; jbe@352: } jbe@352: } jbe@352: jbe@353: static struct candidate *candidate_by_key(char *candidate_key) { jbe@353: struct candidate *candidate; jbe@353: struct candidate compare; jbe@353: compare.key = candidate_key; jbe@353: candidate = bsearch(&compare, candidates, candidate_count, sizeof(struct candidate), (void *)compare_candidate); jbe@353: if (!candidate) { jbe@352: fprintf(stderr, "Candidate not found (should not happen)\n"); jbe@352: abort(); jbe@352: } jbe@353: return candidate; jbe@352: } jbe@352: jbe@352: struct ballot_section { jbe@352: int count; jbe@353: struct candidate **candidates; jbe@352: }; jbe@352: jbe@352: struct ballot { jbe@352: int weight; jbe@352: struct ballot_section sections[4]; jbe@352: }; jbe@352: jbe@352: static void process_initiative(PGresult *res) { jbe@352: int ballot_count = 0; jbe@355: int i; jbe@355: struct ballot *ballots; jbe@355: { jbe@355: void *candidate_tree = NULL; jbe@355: int tuple_count; jbe@355: char *old_member_id = NULL; jbe@355: struct ballot *ballot; jbe@355: int candidates_in_sections[4] = {0, }; jbe@355: candidate_count = 0; jbe@355: tuple_count = PQntuples(res); jbe@355: for (i=0; i<=tuple_count; i++) { jbe@355: char *member_id, *suggestion_id; jbe@355: if (i 4) { jbe@352: fprintf(stderr, "Unexpected preference value\n"); jbe@352: abort(); jbe@352: } jbe@352: preference--; jbe@355: ballot->weight = weight; jbe@355: ballot->sections[preference].count++; jbe@355: if (old_member_id && strcmp(old_member_id, member_id)) ballot++; jbe@355: old_member_id = member_id; jbe@355: } jbe@355: for (i=0; i 4) { jbe@355: fprintf(stderr, "Unexpected preference value\n"); jbe@355: abort(); jbe@355: } jbe@355: preference--; jbe@355: ballot->sections[preference].candidates[candidates_in_sections[preference]++] = candidate_by_key(suggestion_id); jbe@355: } jbe@355: if (i==tuple_count || (old_member_id && strcmp(old_member_id, member_id))) { jbe@355: ballot++; jbe@355: candidates_in_sections[0] = 0; jbe@355: candidates_in_sections[1] = 0; jbe@355: candidates_in_sections[2] = 0; jbe@355: candidates_in_sections[3] = 0; jbe@355: } jbe@355: old_member_id = member_id; jbe@352: } jbe@352: } jbe@355: jbe@354: free(candidates); jbe@354: for (i=0; i\n", argv[0]); jbe@352: fprintf(stdout, "\n"); jbe@352: fprintf(stdout, " is specified by PostgreSQL's libpq,\n"); jbe@352: fprintf(stdout, "see http://www.postgresql.org/docs/9.1/static/libpq-connect.html\n"); jbe@352: fprintf(stdout, "\n"); jbe@352: fprintf(stdout, "Example: %s dbname=liquid_feedback\n", argv[0]); jbe@352: fprintf(stdout, "\n"); jbe@352: return argc == 1 ? 1 : 0; jbe@352: } jbe@352: { jbe@352: size_t len = 0; jbe@352: for (i=1; i1) strcat(conninfo, " "); jbe@352: strcat(conninfo, argv[i]); jbe@352: } jbe@352: } jbe@352: jbe@352: // connect to database: jbe@352: db = PQconnectdb(conninfo); jbe@352: if (!db) { jbe@352: fprintf(stderr, "Error: Could not create database handle\n"); jbe@352: return 1; jbe@352: } jbe@352: if (PQstatus(db) != CONNECTION_OK) { jbe@352: fprintf(stderr, "Could not open connection:\n%s", PQerrorMessage(db)); jbe@352: return 1; jbe@352: } jbe@352: jbe@352: // check initiatives: jbe@352: res = PQexec(db, "SELECT \"initiative_id\", \"final\" FROM \"initiative_suggestion_order_calculation\""); jbe@352: if (!res) { jbe@352: fprintf(stderr, "Error in pqlib while sending SQL command selecting open issues\n"); jbe@352: err = 1; jbe@352: } else if (PQresultStatus(res) != PGRES_TUPLES_OK) { jbe@352: fprintf(stderr, "Error while executing SQL command selecting open issues:\n%s", PQresultErrorMessage(res)); jbe@352: err = 1; jbe@352: PQclear(res); jbe@352: } else { jbe@352: count = PQntuples(res); jbe@352: printf("Number of initiatives to process: %i\n", count); jbe@352: for (i=0; i