+ qsort(auth_info, total_roles, sizeof(auth_entry), oid_compar);
+ qsort(authmem_info, total_mem, sizeof(authmem_entry), mem_compar);
+
+ /*
+ * For each role, find what it belongs to.
+ */
+ for (curr_role = 0; curr_role < total_roles; curr_role++)
+ {
+ List *roles_list;
+ List *roles_names_list = NIL;
+ ListCell *mem;
+
+ /* We can skip this for non-login roles */
+ if (!auth_info[curr_role].rolcanlogin)
+ continue;
+
+ /*
+ * This search algorithm is the same as in is_member_of_role; we
+ * are just working with a different input data structure.
+ */
+ roles_list = list_make1_oid(auth_info[curr_role].roleid);
+
+ foreach(mem, roles_list)
+ {
+ authmem_entry key;
+ authmem_entry *found_mem;
+ int first_found,
+ last_found,
+ i;
+
+ key.memberid = lfirst_oid(mem);
+ found_mem = bsearch(&key, authmem_info, total_mem,
+ sizeof(authmem_entry), mem_compar);
+ if (!found_mem)
+ continue;
+
+ /*
+ * bsearch found a match for us; but if there were multiple
+ * matches it could have found any one of them. Locate first
+ * and last match.
+ */
+ first_found = last_found = (found_mem - authmem_info);
+ while (first_found > 0 &&
+ mem_compar(&key, &authmem_info[first_found - 1]) == 0)
+ first_found--;
+ while (last_found + 1 < total_mem &&
+ mem_compar(&key, &authmem_info[last_found + 1]) == 0)
+ last_found++;
+
+ /*
+ * Now add all the new roles to roles_list.
+ */
+ for (i = first_found; i <= last_found; i++)
+ roles_list = list_append_unique_oid(roles_list,
+ authmem_info[i].roleid);
+ }
+
+ /*
+ * Convert list of role Oids to list of role names. We must do
+ * this before re-sorting auth_info.
+ *
+ * We skip the first list element (curr_role itself) since there
+ * is no point in writing that a role is a member of itself.
+ */
+ for_each_cell(mem, lnext(list_head(roles_list)))
+ {
+ auth_entry key_auth;
+ auth_entry *found_role;
+
+ key_auth.roleid = lfirst_oid(mem);
+ found_role = bsearch(&key_auth, auth_info, total_roles,
+ sizeof(auth_entry), oid_compar);
+ if (found_role) /* paranoia */
+ roles_names_list = lappend(roles_names_list,
+ found_role->rolname);
+ }
+ auth_info[curr_role].member_of = roles_names_list;
+ list_free(roles_list);
+ }
+ }
+
+ /*
+ * Now sort auth_info into rolname order for output, and write the file.
+ */
+ qsort(auth_info, total_roles, sizeof(auth_entry), name_compar);
+
+ for (curr_role = 0; curr_role < total_roles; curr_role++)
+ {
+ auth_entry *arole = &auth_info[curr_role];
+
+ if (arole->rolcanlogin)
+ {
+ ListCell *mem;
+
+ fputs_quote(arole->rolname, fp);
+ fputs(" ", fp);
+ fputs_quote(arole->rolpassword, fp);
+ fputs(" ", fp);
+ fputs_quote(arole->rolvaliduntil, fp);
+
+ foreach(mem, arole->member_of)
+ {
+ fputs(" ", fp);
+ fputs_quote((char *) lfirst(mem), fp);
+ }
+
+ fputs("\n", fp);
+ }