* BuildRoleInheritanceTable fetches all roles and their parent relationships * and builds an in-memory hash table for efficient lookups. * * Role System Overview: * - pg_roles contains information about both user roles and groups. * - pg_auth_members tracks role membership: which roles are members of which * parent roles. Note that parent roles can themselves have parents * * Query Logic
| 1442 | * - parentRoles: List of internal parent role names this role inherits from |
| 1443 | */ |
| 1444 | static HTAB * |
| 1445 | BuildRoleInheritanceTable(void) |
| 1446 | { |
| 1447 | HASHCTL hashCtl; |
| 1448 | memset(&hashCtl, 0, sizeof(hashCtl)); |
| 1449 | hashCtl.keysize = NAMEDATALEN; |
| 1450 | hashCtl.entrysize = sizeof(RoleParentEntry); |
| 1451 | hashCtl.hcxt = CurrentMemoryContext; |
| 1452 | |
| 1453 | HTAB *roleInheritanceTable = hash_create("RoleInheritanceTable", |
| 1454 | 64, |
| 1455 | &hashCtl, |
| 1456 | HASH_ELEM | HASH_STRINGS | HASH_CONTEXT); |
| 1457 | |
| 1458 | /* |
| 1459 | * Query returns all built-in and custom roles with their direct parent roles, all in internal role names. |
| 1460 | */ |
| 1461 | const char *inheritanceQuery = FormatSqlQuery( |
| 1462 | "SELECT ARRAY_AGG(%s.row_get_bson(r)) FROM (" |
| 1463 | " SELECT " |
| 1464 | " child.rolname::text AS child_role, " |
| 1465 | " ARRAY_AGG(parent.rolname::text) " |
| 1466 | " FILTER (WHERE parent.rolname IS NOT NULL AND parent.oid >= %d) AS parent_roles " |
| 1467 | " FROM pg_roles child " |
| 1468 | " LEFT JOIN pg_auth_members am ON am.member = child.oid " |
| 1469 | " LEFT JOIN pg_roles parent ON parent.oid = am.roleid " |
| 1470 | " WHERE child.oid >= %d " |
| 1471 | " AND (NOT child.rolcanlogin OR child.rolname = '%s') " |
| 1472 | " GROUP BY child.rolname" |
| 1473 | ") r;", |
| 1474 | CoreSchemaName, |
| 1475 | FirstNormalObjectId, |
| 1476 | FirstNormalObjectId, |
| 1477 | ApiRootInternalRole); |
| 1478 | |
| 1479 | bool readOnly = true; |
| 1480 | bool isNull = false; |
| 1481 | |
| 1482 | Datum resultDatum = ExtensionExecuteQueryViaSPI(inheritanceQuery, readOnly, |
| 1483 | SPI_OK_SELECT, &isNull); |
| 1484 | |
| 1485 | /* |
| 1486 | * If result is NULL, no roles matched the query, which should never happen. |
| 1487 | */ |
| 1488 | if (isNull) |
| 1489 | { |
| 1490 | ereport(ERROR, (errcode(ERRCODE_DOCUMENTDB_INTERNALERROR), |
| 1491 | errmsg("Role inheritance query returned NULL result."))); |
| 1492 | } |
| 1493 | |
| 1494 | ArrayType *resultArray = DatumGetArrayTypeP(resultDatum); |
| 1495 | |
| 1496 | Datum *rowDatums; |
| 1497 | bool *rowNulls; |
| 1498 | int rowCount; |
| 1499 | deconstruct_array(resultArray, BsonTypeId(), -1, false, TYPALIGN_INT, |
| 1500 | &rowDatums, &rowNulls, &rowCount); |
| 1501 |
no test coverage detected