Обзор
Протокол имеет отдельные фазы для запуска и нормальной работы. На этапе запуска фронтенд открывает соединение с сервером и аутентифицирует себя, чтобы удовлетворить сервер. (Это может быть одно сообщение или несколько сообщений в зависимости от используемого метода аутентификации). Если все прошло успешно, сервер отправляет фронтенду информацию о состоянии и, наконец, переходит в нормальный режим работы. За исключением начального сообщения startup-request, эта часть протокола управляется сервером.
При нормальной работе фронтенд посылает запросы и другие команды бэкенду, а бэкенд отправляет результаты запросов и другие ответы. Есть несколько случаев (например, NOTIFY
), когда бэкенд отправляет незапрашиваемые сообщения, но в основном эта часть сессии управляется запросами фронтенда.
Завершение сессии обычно происходит по выбору фронтенда, но в некоторых случаях может быть принудительным со стороны бэкенда. В любом случае, когда бэкэнд закрывает соединение, он откатывает все открытые (незавершенные) транзакции перед выходом.
В обычном режиме работы команды SQL могут выполняться по одному из двух подпротоколов. В протоколе «простой запрос» фронтенд просто отправляет текстовую строку запроса, которая анализируется и немедленно выполняется бэкендом. В протоколе «расширенный запрос» обработка запросов разделяется на несколько этапов: разбор, привязка значений параметров и выполнение. Это обеспечивает гибкость и повышение производительности, но при этом требует дополнительной сложности.
Нормал ьная работа имеет дополнительные подпротоколы для специальных операций, таких как COPY
.
Обзор системы обмена сообщениями
Вся коммуникация осуществляется через поток сообщений. Первый байт сообщения идентифицирует тип сообщения, а следующие четыре байта определяют длину остальной части сообщения (в эту длину входит сам байт, но не байт типа сообщения). Остальное содержимое сообщения определяется параметром тип сообщения. По историческим причинам самое первое сообщение, отправляемое клиентом (стартовое сообщение), не имеет начального байта типа сообщения.
Чтобы избежать потери синхронизации с потоком сообщений, и серверы, и клиенты обычно считывают все сообщение в буфер (используя счетчик байтов), прежде чем пытаться обработать его содержимое. Это позволяет легко восстановить сообщение, если при его обработке была обнаружена ошибка. В экстремальных ситуаци ях (например, при нехватке памяти для буферизации сообщения) приемник может использовать счетчик байтов, чтобы определить, сколько входных данных нужно пропустить, прежде чем возобновить чтение сообщений.
И наоборот, и серверы, и клиенты должны следить за тем, чтобы никогда не отправлять неполное сообщение. Для этого обычно используется маршалинг всего сообщения в буфер перед началом его отправки. Если в процессе отправки или получения сообщения произошел сбой связи, единственной разумной реакцией будет разрыв соединения, поскольку надежда на восстановление синхронизации границ сообщений невелика.
Обзор расширенных запросов
В протоколе расширенных запросов выполнение команд SQL делится на несколько шагов. Состояние, сохраняемое между этапами, представлено двумя типами объектов: подготовленными операторами и порталами. Подготовленный оператор представляет собой результат синтаксического и семантического анализа текстовой строки запроса. Подготовленный оператор сам по себе не готов к выполнению, поскольку в нем могут отсутствовать конкретные значения параметров. Портал представляет собой готовый к выполнению или уже частично выполненный оператор, в котором заполнены все недостающие значения параметров. (Для операторов SELECT
портал эквивалентен открытому курсору, но мы решили использовать другой термин, поскольку курсоры не работают с операторами, отличными от SELECT
).
Общий цикл выполнения состоит из шага parse, который создает подготовленный оператор из текстовой строки запроса; шага bind, который создает портал, используя подготовленный оператор и значения необходимых параметров; и шага execute, который выполняет запрос портала. В случае запроса, возвращающего строки (SELECT
, SHOW
и т. д.), шагу execute можно указать, что он должен получить только ограниченное количество строк, так что для завершения операции может потребоваться несколько шагов execute.
Бэкэнд может отслеживать несколько подготовленных заявлений и порталов (но учтите, что они существуют только в рамках одной сессии и никогда не передаются между сессиями). На существующие подготовленные заявления и порталы ссылаются по именам, присвоенным при их создании. Кроме того, существует «безымянный» подготовленный отчет и портал. Хотя они ведут себя в основном так же, как и именованные объекты, операции над ними оптимизированы для случая выполнения запроса только один раз и последующего его отбрасывания, в то время как операции над именованными объектами оптимизированы в расчете на многократное использование.
Форматы и коды форматов
Данные определенного типа могут передаваться в любом из нескольких различных форматов. В PostgreSQL 7.4 поддерживаются только «текстовый» и «двоичный» форматы, но протокол предусматривает возможность будущих расширений. Желаемый формат для любого значения задается кодом формата. Клиенты могут указывать код формата для каждого передаваемого значения параметра и для каждого столбца результата запроса. Текстовый код формата равен нулю, двоичный код формата равен единице, а все остальные коды формата зарезервированы для будущего определения.
Текстовое представление значений - это те строки, которые выдаются и принимаются функциями преобразования ввода-вывода для конкретного типа данных. В передаваемом представлении нет нулевого символа; фронтенд должен добавить его к полученным значениям, если хочет обработать их как строки C. (Кстати, текстовый формат не допускает встроенных нулей).
В двоичном представлении целых чисел используется сетевой порядок байтов (старший байт первый). Для других типов данных обратитесь к документации или исходному коду, чтобы узнать о двоичном представлении. Помните, что двоичные представления сложных типов данных могут меняться в разных версиях сервера; текстовый формат обычно является более переносимым вариантом.