52.2. 消息流

本节描述消息流和每种消息类型的语义。 (每个消息的确切表示的详细信息显示在Section 52.7中。)根据连接状态,有几个不同的子协议:启动,查询,函数调用,COPY和终止。对于异步操作(包括通知响应和命令取消),还有一些特殊规定,这些规定可以在启动阶段之后的任何时间发生。

52.2.1. Start-up

要开始会话,前端会打开与服务器的连接并发送启动消息。该消息包括用户名和用户想要连接的数据库的名称;它还标识要使用的特定协议版本。 (可选地,启动消息可以包括运行时参数的其他设置.)然后,服务器使用此信息及其配置文件的内容(例如pg_hba.conf)来确定连接是否临时可接受,以及需要进行哪些附加身份验证。 (如果有)。

然后,服务器发送适当的身份验证请求消息,前端必须以适当的身份验证响应消息(例如密码)来答复该消息。对于除 GSSAPI,SSPI 和 SASL 之外的所有身份验证方法,最多只有一个请求和一个响应。在某些方法中,根本不需要来自前端的响应,因此不会发生身份验证请求。对于 GSSAPI,SSPI 和 SASL,可能需要多次交换数据包才能完成身份验证。

身份验证周期以服务器拒绝连接尝试(ErrorResponse)或发送 AuthenticationOk 结束。

在此阶段,来自服务器的可能消息是:

  • ErrorResponse

    • 连接尝试已被拒绝。然后,服务器立即关闭连接。
  • AuthenticationOk

    • 认证交换成功完成。
  • AuthenticationKerberosV5

    • 前端现在必须与服务器一起参与 Kerberos V5 身份验证对话框(此处未描述,这是 Kerberos 规范的一部分)。如果成功,则服务器以 AuthenticationOk 响应,否则以 ErrorResponse 响应。不再支持。
  • AuthenticationCleartextPassword

    • 前端现在必须发送包含明文形式密码的 PasswordMessage。如果这是正确的密码,则服务器以 AuthenticationOk 响应,否则以 ErrorResponse 响应。
  • AuthenticationMD5Password

    • 前端现在必须发送一个包含通过 MD5 加密的密码(带有用户名)的 PasswordMessage,然后使用 AuthenticationMD5Password 消息中指定的 4 字节随机盐再次加密。如果这是正确的密码,则服务器以 AuthenticationOk 响应,否则以 ErrorResponse 响应。实际的 PasswordMessage 可以在 SQL 中以concat('md5', md5(concat(md5(concat(password, username)), random-salt)))计算。 (请记住,md5()函数以十六进制字符串形式返回其结果.)
  • AuthenticationSCMCredential

    • 只有在支持 SCM 凭据消息的平台上的本地 Unix 域连接上,此响应才可能。前端必须发出 SCM 凭证消息,然后发送单个数据字节。 (数据字节的内容没有意义;它仅用于确保服务器 await 足够长的时间以接收凭据消息.)如果凭据可接受,则服务器以 AuthenticationOk 响应,否则以 ErrorResponse 响应。 (此消息类型仅由 9.1 之前的服务器发布.最终可能会从协议规范中删除.)
  • AuthenticationGSS

    • 前端现在必须启动 GSSAPI 协商。对此,前端将与 GSSAPI 数据流的第一部分一起发送 GSSResponse 消息。如果需要更多消息,服务器将以 AuthenticationGSSContinue 响应。
  • AuthenticationSSPI

    • 前端现在必须启动 SSPI 协商。响应于此,前端将与 SSPI 数据流的第一部分一起发送 GSSResponse。如果需要更多消息,服务器将以 AuthenticationGSSContinue 响应。
  • AuthenticationGSSContinue

    • 该消息包含来自 GSSAPI 或 SSPI 协商的上一步的响应数据(AuthenticationGSS,AuthenticationSSPI 或先前的 AuthenticationGSSContinue)。如果此消息中的 GSSAPI 或 SSPI 数据指示需要更多数据来完成身份验证,则前端必须将该数据作为另一个 GSSResponse 消息发送。如果通过此消息完成了 GSSAPI 或 SSPI 身份验证,则服务器将接下来发送 AuthenticationOk 来指示成功的身份验证或 ErrorResponse 来指示失败。
  • AuthenticationSASL

    • 前端现在必须使用消息中列出的 SASL 机制之一来启动 SASL 协商。前端将发送带有所选机制名称的 SASLInitialResponse,以及响应于此的 SASL 数据流的第一部分。如果需要更多消息,服务器将以 AuthenticationSASLContinue 进行响应。有关详情,请参见Section 52.3
  • AuthenticationSASLContinue

    • 此消息包含来自 SASL 协商的上一步(AuthenticationSASL 或先前的 AuthenticationSASLContinue)的质询数据。前端必须以 SASLResponse 消息进行响应。
  • AuthenticationSASLFinal

    • SASL 身份验证已完成,并带有 Client 端的其他特定于机制的数据。接下来,服务器将发送 AuthenticationOk 来指示认证成功,或者发送 ErrorResponse 来指示失败。仅当 SASL 机制指定在完成时从服务器发送到 Client 端的其他数据时,才发送此消息。
  • NegotiateProtocolVersion

    • 服务器不支持 Client 端请求的次要协议版本,但是支持较早版本的协议。此消息表示支持的最高次要版本。如果 Client 端在启动数据包中请求了不受支持的协议选项(即以_pq_.开头),也会发送此消息。该消息后将跟随一个 ErrorResponse 或指示认证成功或失败的消息。

如果前端不支持服务器请求的身份验证方法,则它应立即关闭连接。

收到 AuthenticationOk 后,前端必须 await 服务器发出的更多消息。在这个阶段,后端过程正在启动,前端只是一个感兴趣的旁观者。启动尝试仍然可能失败(ErrorResponse)或服务器拒绝对所请求的次要协议版本(NegotiateProtocolVersion)的支持,但是在正常情况下,后端将发送一些 ParameterStatus 消息,BackendKeyData,最后发送 ReadyForQuery。

在此阶段,后端将尝试应用启动消息中给出的所有其他运行时参数设置。如果成功,这些值将成为会话默认值。错误导致 ErrorResponse 并退出。

在此阶段中,来自后端的可能消息是:

  • BackendKeyData

    • 此消息提供了前端要在以后发出取消请求时必须保存的密钥数据。前端不应响应此消息,但应 continue 侦听 ReadyForQuery 消息。
  • ParameterStatus

    • 该消息通知前端有关后端参数(例如client_encodingDateStyle)的当前(初始)设置的信息。前端可以忽略此消息,或记录其设置以备将来使用。有关更多详细信息,请参见Section 52.2.6。前端不应响应此消息,但应 continue 侦听 ReadyForQuery 消息。
  • ReadyForQuery

    • 启动完成。前端现在可以发出命令。
  • ErrorResponse

    • 启动失败。发送此消息后,连接将关闭。
  • NoticeResponse

    • 已发出警告消息。前端应显示该消息,但 continue 侦听 ReadyForQuery 或 ErrorResponse。

ReadyForQuery 消息与后端在每个命令周期后发出的消息相同。根据前端的编码需求,可以将 ReadyForQuery 视为开始一个命令周期,或者将 ReadyForQuery 视为结束启动阶段和每个后续命令周期是合理的。

52 .2.2. 简单查询

通过前端向后端发送查询消息来启动一个简单的查询周期。该消息包括表示为文本字符串的一个或多个 SQL 命令。然后,后端根据查询命令字符串的内容发送一个或多个响应消息,最后发送 ReadyForQuery 响应消息。 ReadyForQuery 通知前端它可以安全地发送新命令。 (实际上,前端在发出另一个命令之前不必 awaitReadyForQuery,但是前端必须负责弄清楚如果较早的命令失败而已发出的较新命令成功,将会发生什么情况.)

来自后端的可能的响应消息是:

  • CommandComplete

    • SQL 命令正常完成。
  • CopyInResponse

    • 后端已准备好将数据从前端复制到表中;参见Section 52.2.5
  • CopyOutResponse

    • 后端已准备好将数据从表复制到前端。参见Section 52.2.5
  • RowDescription

    • 表示将要响应SELECTFETCH等查询返回行。该消息的内容描述了行的列布局。对于返回到前端的每一行,将紧随其后的是 DataRow 消息。
  • DataRow

    • SELECTFETCH等查询返回的一组行之一。
  • EmptyQueryResponse

    • 识别出空查询字符串。
  • ErrorResponse

    • 发生了错误。
  • ReadyForQuery

    • 查询字符串的处理完成。因为查询字符串可能包含多个 SQL 命令,所以会发送一条单独的消息来表明这一点。 (CommandComplete 标记处理一个 SQL 命令的结束,而不是整个字符串的结束.)无论处理成功终止还是发生错误,ReadyForQuery 都会始终发送。
  • NoticeResponse

    • 已发出有关该查询的警告消息。除其他响应外,还需注意其他事项,即后端将 continue 处理该命令。

SELECT查询(或其他返回行集的查询,例如EXPLAINSHOW)的响应通常由 RowDescription,零个或多个 DataRow 消息以及 CommandComplete 组成。 COPY到前端或从前端发出的COPY调用特殊协议,如Section 52.2.5中所述。所有其他查询类型通常只产生 CommandComplete 消息。

由于查询字符串可能包含多个查询(用分号分隔),因此在后端完成对查询字符串的处理之前,可能会有多个这样的响应序列。当处理完整个字符串并且后端准备接受新的查询字符串时,发出 ReadyForQuery。

如果接收到一个完全为空的查询字符串(除空格外没有其他内容),则响应为 EmptyQueryResponse,后跟 ReadyForQuery。

如果发生错误,则会发出 ErrorResponse,然后发出 ReadyForQuery。该查询字符串的所有进一步处理都会被 ErrorResponse 中止(即使其中还有更多查询)。请注意,这可能发生在单个查询生成的消息序列的中间。

在简单查询模式下,除非给定命令是使用BINARY选项声明的游标中的FETCH,否则检索到的值的格式始终为文本。在这种情况下,检索到的值是二进制格式。 RowDescription 消息中给出的格式代码告诉您正在使用哪种格式。

前端必须准备好在需要任何其他类型的消息时接受 ErrorResponse 和 NoticeResponse 消息。另请参阅Section 52.2.6有关后端可能由于外部事件而生成的消息的信息。

推荐的做法是以状态机样式编码前端,该前端将在可能的任何时候接受任何消息类型,而不是根据消息的确切 Sequences 进行假设。

52 .2.3. 扩展查询

扩展查询协议将上述简单查询协议分解为多个步骤。准备步骤的结果可以重复使用多次,以提高效率。此外,还有其他功能可用,例如可以将数据值作为单独的参数提供,而不必将其直接插入查询字符串中。

在扩展协议中,前端首先发送一个 Parse 消息,其中包含文本查询字符串,可选的一些有关参数占位符的数据类型的信息以及目标预处理语句对象的名称(空字符串选择未命名的预处理语句) 。响应是 ParseComplete 或 ErrorResponse。参数数据类型可以通过 OID 来指定;如果未给出,则解析器尝试以与处理无类型 Literals 字符串常量相同的方式推断数据类型。

Note

通过将参数数据类型设置为零,或使参数类型 OID 的数组短于查询字符串中使用的参数符号($ * n *)的数量,可以保留未指定的参数数据类型。另一个特殊情况是可以将参数的类型指定为void(即void伪类型的 OID)。这意味着允许将参数符号用于实际上是 OUT 参数的功能参数。通常,没有上下文可以使用void参数,但是如果这样的参数符号出现在函数的参数列表中,则会被有效地忽略。例如,如果$3$4被指定为void类型,则诸如foo($1,$2,$3,$4)之类的函数调用可以与具有两个 IN 和两个 OUT 参数的函数匹配。

Note

解析消息中包含的查询字符串不能包含多个 SQL 语句。否则报告语法错误。此限制在简单查询协议中不存在,但在扩展协议中确实存在,因为允许准备好的语句或门户包含多个命令将使协议过于复杂。

如果创建成功,一个命名的 prepared-statement 对象将持续到当前会话结束,除非已明确销毁。未命名的准备好的语句仅持续到下一个将未命名的语句指定为目的地的 Parse 语句发出为止。 (请注意,简单的查询消息也会破坏未命名的语句.)已命名的准备好的语句必须先显式关闭,然后才能由另一个 Parse 消息重新定义它们,但这对于未命名的语句不是必需的。还可以使用PREPAREEXECUTE在 SQL 命令级别创建和访问命名的准备好的语句。

一旦准备好的语句存在,就可以使用绑定消息将其准备好执行。 Bind 消息给出了源预准备语句的名称(空字符串表示未命名的预准备语句),目标门户的名称(空字符串表示未命名的门户)以及用于预准备语句中存在的任何参数占位符的值。提供的参数集必须与预处理语句所需的参数集匹配。 (如果在 Parse 消息中声明了任何void参数,则在 Bind 消息中为它们传递 NULL 值.)Bind 还指定用于查询返回的任何数据的格式;格式可以整体指定,也可以按列指定。响应是 BindComplete 或 ErrorResponse。

Note

文本和二进制输出之间的选择取决于 Bind 中给出的格式代码,而与所涉及的 SQL 命令无关。使用扩展查询协议时,游标声明中的BINARY属性无关紧要。

查询计划通常在处理绑定消息时进行。如果准备好的语句没有参数,或者重复执行,则服务器可能会保存创建的计划,并在随后的绑定消息中为同一准备好的语句重新使用它。但是,只有在发现可以创建通用计划的情况下,该通用计划的效率不会比依赖于所提供的特定参数值的计划低很多。就协议而言,这是透明发生的。

如果创建成功,则命名门户对象将持续到当前事务结束,除非已明确销毁。在事务结束时或发出下一个将未命名门户指定为目标的下一个 Bind 语句时,会破坏未命名门户。 (请注意,简单的查询消息也会破坏未命名的门户.)必须先显式关闭已命名的门户,然后才能用另一条 Bind 消息重新定义已命名的门户,但这对于未命名的门户不是必需的。还可以使用DECLARE CURSORFETCH在 SQL 命令级别创建和访问命名门户。

门户一旦存在,便可以使用“执行”消息来执行。 Execute 消息指定门户名称(空字符串表示未命名的门户)和最大结果行数(零表示“获取所有行”)。结果行计数仅对包含返回行集的命令的门户有意义;在其他情况下,该命令始终执行完毕,并且行数将被忽略。对 Execute 的可能响应与上述通过简单查询协议发出的查询所描述的响应相同,除了 Execute 不会导致发出 ReadyForQuery 或 RowDescription。

如果 Execute 在完成门户网站执行之前终止(由于达到非零结果行计数),它将发送 PortalSuspended 消息;否则,将发送 PortalSuspended 消息。该消息的出现告诉前端,应该针对同一门户网站发布另一个 Execute,以完成该操作。在门户网站执行完成之前,不会发送指示源 SQL 命令完成的 CommandComplete 消息。因此,执行阶段总是由以下消息之一的出现而终止:CommandComplete,EmptyQueryResponse(如果门户是从空查询字符串创建的),ErrorResponse 或 PortalSuspended。

在完成每个系列的扩展查询消息后,前端应发出同步消息。如果后端不在BEGIN/COMMIT事务块中,则此无参数消息将导致后端关闭当前事务(“ close”表示在没有错误的情况下提交,或在出现错误的情况下回滚)。然后发出 ReadyForQuery 响应。同步的目的是为错误恢复提供一个重新同步点。当在处理任何扩展查询消息时检测到错误时,后端将发出 ErrorResponse,然后读取并丢弃消息,直到达到同步为止,然后发出 ReadyForQuery 并返回到正常消息处理。 (但是请注意,如果在处理 Sync 时检测到错误,则不会发生跳过-这可确保每次 Sync 仅发送一个 ReadyForQuery.)

Note

同步不会导致以BEGIN打开的事务块被关闭。由于 ReadyForQuery 消息包含事务状态信息,因此可以检测到这种情况。

除了这些基本的必需操作之外,扩展查询协议还可以使用几种可选操作。

描述消息(门户变体)指定现有门户的名称(或未命名门户的空字符串)。响应是 RowDescription 消息,描述了通过执行门户将返回的行;如果门户网站不包含将返回行的查询,则返回 NoData 消息;或 ErrorResponse(如果没有此类门户)。

Description 消息(语句变体)指定现有预备语句的名称(或未命名预备语句的空字符串)。响应是描述语句所需参数的 ParameterDescription 消息,然后是描述最终执行语句时将返回的行的 RowDescription 消息(如果语句不返回行,则返回 NoData 消息)。如果没有这样的准备好的语句,则会发出 ErrorResponse。请注意,由于尚未发布 Bind,因此后端尚不知道用于返回的列的格式。在这种情况下,RowDescription 消息中的格式代码字段将为零。

Tip

在大多数情况下,前端应在发出 Execute 之前发出 Describe 的一个或另一个变体,以确保它知道如何解释将返回的结果。

“关闭”消息关闭现有的准备好的语句或门户并释放资源。对不存在的语句或门户网站名称发出“关闭”不是错误。响应通常是 CloseComplete,但是如果释放资源时遇到一些困难,则可能是 ErrorResponse。请注意,关闭准备好的语句会隐式关闭从该语句构造的所有打开的门户。

刷新消息不会导致生成任何特定的输出,但是会强制后端传递任何在其输出缓冲区中挂起的数据。如果前端希望在发出更多命令之前检查该命令的结果,则必须在“同步”以外的任何扩展查询命令之后发送“刷新”。如果不使用 Flush,则后端返回的消息将合并到最小数量的数据包中,以最大程度地减少网络开销。

Note

简单的查询消息使用未命名的准备好的语句和门户网站对象,并且不带任何参数,大约相当于“解析,绑定,门户网站描述,执行,关闭,同步”系列。一个区别是它将接受查询字符串中的多个 SQL 语句,从而自动为每个序列连续执行绑定/描述/执行序列。另一个区别是它将不返回 ParseComplete,BindComplete,CloseComplete 或 NoData 消息。

52 .2.4. 函数调用

函数调用子协议允许 Client 端请求直接调用数据库的pg_proc系统目录中存在的任何函数。Client 端必须具有该功能的执行权限。

Note

函数调用子协议是一项旧功能,最好在新代码中避免使用。通过设置执行SELECT function($1, ...)的准备好的语句可以实现类似的结果。然后可以将“函数调用”周期替换为“绑定/执行”。

通过前端向后端发送 FunctionCall 消息来启动功能调用周期。然后,后端根据函数调用的结果发送一个或多个响应消息,最后发送 ReadyForQuery 响应消息。 ReadyForQuery 通知前端它可以安全地发送新的查询或函数调用。

来自后端的可能的响应消息是:

  • ErrorResponse

    • 发生了错误。
  • FunctionCallResponse

    • 函数调用已完成,并返回了消息中给出的结果。 (请注意,函数调用协议只能处理单个标量结果,而不能处理行类型或结果集.)
  • ReadyForQuery

    • 函数调用的处理完成。无论处理成功终止还是发生错误,都会始终发送 ReadyForQuery。
  • NoticeResponse

    • 已发出有关函数调用的警告消息。除其他响应外,还需注意其他事项,即后端将 continue 处理该命令。

52 .2.5. 复印操作

COPY命令允许与服务器之间的高速批量数据传输。复制和复制操作分别将连接切换到不同的子协议,该子协议一直持续到操作完成为止。

当后端执行COPY FROM STDIN SQL 语句时,将启动复制模式(数据传输到服务器)。后端将 CopyInResponse 消息发送到前端。然后,前端应发送零个或多个 CopyData 消息,从而形成 Importing 数据流。 (虽然通常这是一个合理的选择,但消息边界不需要与行边界有任何关系.)前端可以通过发送 CopyDone 消息(允许成功终止)或 CopyFail 消息来终止复制模式。这将导致COPY SQL 语句失败并显示错误)。后端然后恢复到启动COPY之前的命令处理模式,这将是简单查询协议或扩展查询协议。接下来它将发送 CommandComplete(如果成功)或 ErrorResponse(如果失败)。

如果在复制模式下后端检测到错误(包括收到 CopyFail 消息),则后端将发出 ErrorResponse 消息。如果COPY命令是通过扩展查询消息发出的,则后端现在将丢弃前端消息,直到收到 Sync 消息为止,然后它将发出 ReadyForQuery 并返回正常处理。如果在简单的查询消息中发出了COPY命令,则该消息的其余部分将被丢弃,并发出 ReadyForQuery。无论哪种情况,前端发出的任何后续 CopyData,CopyDone 或 CopyFail 消息都将被丢弃。

后端将忽略在复制模式下收到的“刷新和同步”消息。接收到任何其他非复制消息类型都会构成一个错误,该错误将如上所述中止复制状态。 (“刷新和同步”exception 是为了方便总是在执行消息之后发送“刷新”或“同步”的 Client 端库,而无需检查要执行的命令是否为COPY FROM STDIN.)

当后端执行COPY TO STDOUT SQL 语句时,将启动复制模式(从服务器进行数据传输)。后端向前端发送一个 CopyOutResponse 消息,然后是零个或多个 CopyData 消息(每行总是一个),然后是 CopyDone。然后,后端恢复为COPY启动之前的命令处理模式,并发送 CommandComplete。前端不能中止传输(通过关闭连接或发出“取消”请求除外),但是它可以丢弃不需要的 CopyData 和 CopyDone 消息。

如果在复制模式下后端检测到错误,则后端将发出 ErrorResponse 消息并恢复到正常处理。前端应将 ErrorResponse 的接收视为终止复制模式。

NoticeResponse 和 ParameterStatus 消息可能散布在 CopyData 消息之间;前端必须处理这些情况,并且还应该为其他异步消息类型做好准备(请参见Section 52.2.6)。否则,除 CopyData 或 CopyDone 以外的任何消息类型都可以视为终止复制输出模式。

还有另一种与复制相关的模式,称为 copy-both,它允许高速批量数据从服务器传输到。当 walsender 模式的后端执行START_REPLICATION语句时,将启动双向复制模式。后端将 CopyBothResponse 消息发送到前端。后端和前端都可以发送 CopyData 消息,直到任一端发送 CopyDone 消息为止。Client 端发送 CopyDone 消息后,连接将从复制两种模式转到复制输出模式,并且 Client 端可能不再发送任何 CopyData 消息。同样,当服务器发送 CopyDone 消息时,连接进入复制模式,并且服务器可能不再发送任何 CopyData 消息。双方发送 CopyDone 消息后,复制模式终止,后端恢复为命令处理模式。如果在同时复制模式期间后端检测到错误,则后端将发出 ErrorResponse 消息,丢弃前端消息直到收到 Sync 消息,然后发出 ReadyForQuery 并返回正常处理。前端应将 ErrorResponse 的接收视为双向终止副本。在这种情况下,不应发送 CopyDone。有关通过双向复制模式传输的子协议的更多信息,请参见Section 52.4

CopyInResponse,CopyOutResponse 和 CopyBothResponse 消息包括一些字段,这些字段通知前端每行的列数以及每列使用的格式代码。 (从当前的实现开始,给定的COPY操作中的所有列都将使用相同的格式,但是消息设计并未假定这样做.)

52 .2.6. 异步操作

在许多情况下,后端将发送前端命令流未特别提示的消息。前端必须随时准备处理这些消息,即使不参与查询也是如此。至少,应该在开始读取查询响应之前检查这些情况。

由于外部活动,可能会生成 NoticeResponse 消息。例如,如果数据库 Management 员命令“快速”关闭数据库,则后端将在关闭连接之前发送 NoticeResponse 指示此事实。因此,即使连接名义上处于空闲状态,前端也应始终准备接受和显示 NoticeResponse 消息。

只要后端认为前端应该知道的任何参数的有效值发生变化,就会生成 ParameterStatus 消息。最常见的是,这是响应前端执行的SET SQL 命令而发生的,这种情况实际上是同步的-但也可能发生参数状态更改,因为 Management 员更改了配置文件,然后向服务器发送了 SIGHUPsignal。同样,如果回退SET命令,将生成适当的 ParameterStatus 消息以报告当前有效值。

当前,存在一组将为其生成 ParameterStatus 的硬连接参数:它们是server_versionserver_encodingclient_encodingapplication_nameis_superusersession_authorizationDateStyleIntervalStyleTimeZoneinteger_datetimesstandard_conforming_strings。 (8.0 之前的版本未报告server_encodingTimeZoneinteger_datetimes; 8.1 之前的版本未报告standard_conforming_strings; 8.4 之前的版本未报告IntervalStyle; 9.0 之前的版本未报告application_name.)请注意server_versionserver_encodinginteger_datetimes是伪参数,启动后无法更改。此设置将来可能会更改,甚至可以配置。因此,前端应该简单地忽略其不了解或关心的参数的 ParameterStatus。

如果前端发出LISTEN命令,则每当对同一通道名称执行NOTIFY命令时,后端就会发送 NotificationResponse 消息(不要与 NoticeResponse 混淆!)。

Note

目前,NotificationResponse 只能在事务外部发送,因此它不会出现在命令响应系列的中间,尽管它可能恰好在 ReadyForQuery 之前发生。但是,设计以此为前提的前端逻辑是不明智的。优良作法是能够在协议中的任何时候接受 NotificationResponse。

52 .2.7. 取消进行中的请求

在查询处理期间,前端可能会请求取消查询。出于实现效率的考虑,取消请求不会直接在与后端的开放连接上发送:我们不希望后端在查询处理过程中不断检查前端的新 Importing。取消请求应该相对少见,因此为了避免在正常情况下受到惩罚,我们将它们变得有些繁琐。

要发出取消请求,前端将打开与服务器的新连接并发送 CancelRequest 消息,而不是通常通过新连接发送的 StartupMessage 消息。服务器将处理此请求,然后关闭连接。出于安全原因,不会直接回复取消请求消息。

除非包含在连接启动期间传递给前端的相同密钥数据(PID 和 Secret 密钥),否则 CancelRequest 消息将被忽略。如果请求与当前执行的后端的 PID 和密钥匹配,则当前查询的处理将中止。 (在现有实现中,这是通过向处理查询的后端进程发送特殊 signal 来完成的.)

取消 signal 可能会或可能不会有任何效果-例如,如果它在后端完成查询处理之后到达,则它将没有效果。如果取消有效,则会导致当前命令提前终止并显示错误消息。

所有这一切的结果是,出于安全性和效率两方面的考虑,前端无法直接判断取消请求是否成功。它必须 continueawait 后端响应查询。发出取消只是提高了当前查询即将完成的几率,并且提高了因错误消息而不是成功而失败的几率。

由于取消请求是通过与服务器的新连接发送的,而不是通过常规前端/后端通信链接发送的,因此取消请求可以通过任何进程发出,而不仅是要取消其查询的前端。在构建多进程应用程序时,这可能会提供额外的灵 Active。它还会带来安全风险,因为未经授权的人员可能会尝试取消查询。通过要求在取消请求中提供动态生成的密钥来解决安全风险。

52.2.8. Termination

正常,正常的终止过程是前端发送一个 Terminate 消息并立即关闭连接。收到此消息后,后端将关闭连接并终止。

在极少数情况下(例如,Management 员命令数据库关闭),后端可能会断开连接而没有任何前端请求。在这种情况下,后端将在关闭连接之前尝试发送错误或通知消息,说明断开的原因。

其他终止方案是由各种故障情况引起的,例如一端或另一端发生核心转储,通信链路丢失,消息边界同步丢失等。如果前端或后端发现连接意外关闭,则应该清理并终止。如果前端服务器不希望终止自身,则可以选择通过重新联系服务器来启动新的后端。如果收到无法识别的消息类型,则建议关闭连接,因为这可能表示消息边界同步丢失。

无论是正常终止还是异常终止,任何打开的事务都会回滚而不提交。但是,应该注意的是,如果在处理非SELECT查询的过程中前端断开连接,则后端可能会在注意到断开连接之前完成查询。如果查询在任何事务块(BEGIN ... COMMIT序列)之外,则可能会在确认断开连接之前提交其结果。

52 .2.9. SSL 会话加密

如果 PostgreSQL 是使用 SSL 支持构建的,则可以使用 SSL 对前端/后端通信进行加密。这在攻击者可能能够捕获会话流量的环境中提供了通信安全性。有关使用 SSL 加密 PostgreSQL 会话的更多信息,请参见Section 18.9

为了启动 SSL 加密的连接,前端首先发送 SSLRequest 消息,而不是 StartupMessage。然后,服务器以包含SN的单个字节作为响应,分别表示它愿意或不愿意执行 SSL。如果前端对响应不满意,则此时可能会关闭连接。要在S之后 continue,请与服务器执行 SSL 启动握手(此处未描述,这是 SSL 规范的一部分)。如果成功,则 continue 发送通常的 StartupMessage。在这种情况下,StartupMessage 和所有后续数据将被 SSL 加密。要在N之后 continue,请发送通常的 StartupMessage 并 continue 进行而不进行加密。

前端也应该准备好处理服务器对 SSLRequest 的 ErrorMessage 响应。仅当服务器早于向 PostgreSQL 添加 SSL 支持时,才会发生这种情况。 (这种服务器现在非常古老,并且可能不再存在.)在这种情况下,必须关闭连接,但是前端可以选择打开一个新的连接,然后 continue 进行而无需请求 SSL。

初始 SSLRequest 也可以用于正在打开的 Connecting,以发送 CancelRequest 消息。

虽然协议本身并未为服务器提供强制 SSL 加密的方法,但 Management 员可以将服务器配置为拒绝未加密的会话,这是身份验证检查的副产品。