52.8. pg_authid
В каталоге pg_authid
содержится информация об идентификаторах для авторизации (ролях). Роль включает в себя концепции «пользователей» и «групп». Пользователь по существу представляет собой частный случай роли, с флагом rolcanlogin
. Любая роль (с или без флага rolcanlogin
) может включать другие роли в качестве членов; см. pg_auth_members
.
Так как в этом каталоге содержатся пароли, он не должен быть открыт для всех. Для общего пользования предназначено представление pg_roles
на базе pg_authid
, в котором поле пароля очищено.
За подробной информацией о пользователях и управлении правами обратитесь к Главе 22.
Так как пользователи определяются глобально, каталог pg_authid
разделяется всеми базами данных кластера; есть только единственная копия pg_authid
в кластере, а не отдельные в каждой базе данных.
Таблица 52.8. Столбцы pg_authid
Тип столбца Описание |
---|
Идентификатор строки |
Имя роли |
Роли имеет права суперпользователя |
Роль автоматически наследует права ролей, в которые она включена |
Роль может создавать другие роли |
Роль может создавать базы данных |
Роль может подключаться к серверу. То есть эта роль может быть указана в качестве начального идентификатора авторизации сеанса. |
Роль является ролью репликации. Такие роли могут устанавливать соединения для репликации и создавать/удалять слоты репликации. |
Роль не подчиняется никаким политикам защиты на уровне строк; за подробностями обратитесь к Разделу 5.8. |
Для ролей, которые могут подключаться к серверу, это значение задаёт максимально разрешённое для этой роли число одновременных подключений. При значении -1 ограничения нет. |
Пароль (возможно зашифрованный); NULL, если он не задан. Его формат зависит от используемого вида шифрования. |
Срок действия пароля (используется только при аутентификации по паролю); NULL, если срок действия не ограничен |
Если пароль зашифрован MD5, значение в rolpassword
начинается со строки md5
, за которой идёт 32-символьный шестнадцатеричный хеш MD5. Этот хеш вычисляется для пароля пользователя с добавленным за ним его именем. Например, если у пользователя joe
пароль xyzzy
, PostgreSQL сохранит в этом поле md5-хеш строки xyzzyjoe
.
Если пароль зашифрован по алгоритму SCRAM-SHA-256, он имеет формат:
SCRAM-SHA-256$<число итераций>
:<соль>
$<СохранённыйКлюч>
:<КлючСервера>
Здесь соль
, СохранённыйКлюч
и КлючСервера
кодируются в формате Base64. Этот формат соответствует стандарту RFC 5803.
Пароль, не удовлетворяющий ни одному из этих форматов, считается незашифрованным.
45.8. Explicit Subtransactions
Recovering from errors caused by database access as described in Section 45.7.2 can lead to an undesirable situation where some operations succeed before one of them fails, and after recovering from that error the data is left in an inconsistent state. PL/Python offers a solution to this problem in the form of explicit subtransactions.
45.8.1. Subtransaction Context Managers
Consider a function that implements a transfer between two accounts:
CREATE FUNCTION transfer_funds() RETURNS void AS $$ try: plpy.execute("UPDATE accounts SET balance = balance - 100 WHERE account_name = 'joe'") plpy.execute("UPDATE accounts SET balance = balance + 100 WHERE account_name = 'mary'") except plpy.SPIError as e: result = "error transferring funds: %s" % e.args else: result = "funds transferred correctly" plan = plpy.prepare("INSERT INTO operations (result) VALUES ($1)", ["text"]) plpy.execute(plan, [result]) $$ LANGUAGE plpythonu;
If the second UPDATE
statement results in an exception being raised, this function will report the error, but the result of the first UPDATE
will nevertheless be committed. In other words, the funds will be withdrawn from Joe's account, but will not be transferred to Mary's account.
To avoid such issues, you can wrap your plpy.execute
calls in an explicit subtransaction. The plpy
module provides a helper object to manage explicit subtransactions that gets created with the plpy.subtransaction()
function. Objects created by this function implement the context manager interface. Using explicit subtransactions we can rewrite our function as:
CREATE FUNCTION transfer_funds2() RETURNS void AS $$ try: with plpy.subtransaction(): plpy.execute("UPDATE accounts SET balance = balance - 100 WHERE account_name = 'joe'") plpy.execute("UPDATE accounts SET balance = balance + 100 WHERE account_name = 'mary'") except plpy.SPIError as e: result = "error transferring funds: %s" % e.args else: result = "funds transferred correctly" plan = plpy.prepare("INSERT INTO operations (result) VALUES ($1)", ["text"]) plpy.execute(plan, [result]) $$ LANGUAGE plpythonu;
Note that the use of try
/except
is still required. Otherwise the exception would propagate to the top of the Python stack and would cause the whole function to abort with a PostgreSQL error, so that the operations
table would not have any row inserted into it. The subtransaction context manager does not trap errors, it only assures that all database operations executed inside its scope will be atomically committed or rolled back. A rollback of the subtransaction block occurs on any kind of exception exit, not only ones caused by errors originating from database access. A regular Python exception raised inside an explicit subtransaction block would also cause the subtransaction to be rolled back.
45.8.2. Older Python Versions
Context managers syntax using the with
keyword is available by default in Python 2.6. For compatibility with older Python versions, you can call the subtransaction manager's __enter__
and __exit__
functions using the enter
and exit
convenience aliases. The example function that transfers funds could be written as:
CREATE FUNCTION transfer_funds_old() RETURNS void AS $$ try: subxact = plpy.subtransaction() subxact.enter() try: plpy.execute("UPDATE accounts SET balance = balance - 100 WHERE account_name = 'joe'") plpy.execute("UPDATE accounts SET balance = balance + 100 WHERE account_name = 'mary'") except: import sys subxact.exit(*sys.exc_info()) raise else: subxact.exit(None, None, None) except plpy.SPIError as e: result = "error transferring funds: %s" % e.args else: result = "funds transferred correctly" plan = plpy.prepare("INSERT INTO operations (result) VALUES ($1)", ["text"]) plpy.execute(plan, [result]) $$ LANGUAGE plpythonu;