当前位置: 首页 > Database, postgresql > 正文

postgresql 扩展查询

postgresql 是使用扩展协议进行prepare/bind方式查询的

在扩展的协议里,前端首先发送一个 Parse 消息,它包含一个文本查询字串, 另外还有一些有关参数占位符的数据类型的信息,以及一个最终准备好的语句对象的名字(一个空字串选择未命名的准备好的语句)。 响应要么是一个 ParseComplete 要么是 ErrorResponse。 参数数据类型可以用 OID 来声明;如果没有给出, 那么分析器将试图用它对付无类型的字串常量的方法来推导其数据类型。

如果 Parse 消息没有定义参数,那么无名的准备好语句很可能自于 Parse 处理的时候规划。 但是如果有参数,那么查询规划就会推迟到该语句的第一个 Bind 消息。 规划器在对该查询进行规划的时候将考虑在 Bind 消息里提供的实际参数值。

注意: 在一个 Parse 消息里包含的查询字串不能包含超过一个 SQL 语句; 否则就会报告一个语法错误。这个限制在简单查询协议中并不存在, 但是它存在于扩展的协议中,因为允许准备好的语句或者入口包含多个命令将导致协议过度地复杂。

如果成功创建了一个命名的准备好语句对象,那么它将持续到当前会话结束, 除非明确删除。一个未命名的准备好语句只持续到下一个声明未命名的语句为目标的 Parse 语句发出为止。 (请注意一个简单的查询消息也删除未命名语句。)命名的语句必须明确地关闭,然后才能用一个 Parse 消息重新定义, 但是未命名的语句并不要求这个动作。命名的准备好语句也可以在 SQL 命令级创建和访问, 方法是使用 PREPARE 和 EXECUTE。

只要准备好的语句还存在,那么我们就可以使用 Bind 消息很容易地使之进入执行状态。 Bind 消息给出源准备好语句的名字(空字串表示未命名的准备好语句), 目标入口的名字(空字串表示未命名的入口),以及用于那些在准备好的语句中出现的所有参数占位符的数值。 提供的参数集必须匹配那些准备好的语句需要的东西。 (如果你在 Parse 消息里声明任何 void 参数,那么在 Bind 消息里给它们传递 NULL 值。) Bind 还声明用于查询返回的任何数据的格式; 格式可以一次声明,也可以每个字段进行声明。响应要么是 BindComplete 要么是 ErrorResponse。

注意: 输出的格式是文本还是二进制是由 Bind 里给出的格式代码决定的, 不管用的是什么 SQL 命令。在使用扩展的查询协议的时候,游标声明里的 BINARY 属性是无关的。

如果成功创建了一个入口对象,那么它将持续到当前事务的结尾, 除非明确删除。一个未命名的入口在事务的结尾删除,或者是在发出的下一个 Bind 语句声明了一个未命名的入口作为目标为止。 (请注意一个简单查询效益也会删除这个未命名的入口。)命名的入口在可以用一个 Bind 消息重新定义之前必须明确关闭, 但是未命名的入口不要求这个动作。命名的入口也可以在 SQL 创建和访问, 方法是使用 DECLARE CURSOR 和 FETCH。

只要存在一个入口,那么就可以用一个 Execute 消息执行它。 Execute 消息声明入口的名字(空字串表示未命名入口)和一个最大的结果行计数(零表示”抓取所有行”)。 结果行计数只对包含返回结果集的入口有意义;在其它情况下,该命令总是执行到结束, 而行计数会被忽略。Execute 可能的响应和那些通过简单查询协议发出的查询一样, 只不过 Execute 不会导致后端发出 ReadyForQuery 或者 RowDescription。

如果 Execute 在一个入口的执行完成之前终止(因为达到了一个非零的结果行计数), 它将发送一个 PortalSuspended 消息;这个消息的出现告诉前端应该在同一个入口上发出另外一个 Execute 以完成操作。 在入口的执行完成之前,不会发出表示源 SQL 命令结束的 CommandComplete 消息。 因此 Execute 阶段总是由下列消息之一出现标志着结束的: CommandComplete,EmptyQueryResponse(如果入口是从一个空字串创建出来的),ErrorResponse,或者 PortalSuspended。

每个扩展查询消息序列完成后,前端都应该发出一条 Sync 消息。 这个无参数的消息导致后端关闭当前事务——如果当前事务不是在一个BEGIN/COMMIT 事务块中的话(”关闭”的意思就是在没有错误的情况下提交, 或者是有错误的情况下回滚)。然后响应一条 ReadyForQuery 消息。 Sync 的目的是提供一个错误恢复的重新同步的点。 如果在处理任何扩展查询消息的时候侦测到任何错误,那么后端发出 ErrorResponse, 然后读取并抛弃消息,直到一个 sync 的到来,然后发出 ReadyForQuery 并且返回到正常的消息处理中。 (但是要注意如果正在处理 Sync 的时候发生了错误,那么不会忽略任何东西 — 这样就保证了为每个 Sync 发出一个并且只是一个的 ReadyForQuery。)

注意: Sync 并不导致一个用 BEGIN 打开的事务块关闭。 我们可以侦测到这种情况,因为 ReadyForQuery 消息包含事务状态信息。

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

Describe 消息(入口变体)声明一个现有的入口的名字(或者一个未命名入口就是空字串)。 响应是一个 RowDescription 消息,它描述了执行入口将要返回的行; 或者是一个 NoData 消息——如果入口并不包含会返回行的查询;或者是一个 ErrorResponse——如果没有这个入口。

Describe 消息(语句变体)声明一个现有的准备好语句的名字(如果是一个未命名的准备好语句则是一个空字串)。 响应是一个描述该语句需要的参数的 ParameterDescription 消息, 后面跟着一个描述语句最终执行后返回的行的 RowDescription 消息(或者是 NoData 消息,如果该语句不返回行)。 如果没有这样的准备好语句,则返回 ErrorResponse。请注意因为还没有发出 Bind, 所以后端还不知道用于返回字段的格式;在这种情况下,RowDescription 消息里面的格式代码字段将是零。

提示: 在大多数情况下,前端在发出 Execute 之前应该发出某种 Describe 的变体, 以保证它知道如何解析它将得到的结果。

Close 消息关闭一个现有的准备好的语句或者入口,并且释放资源。 对一个不存在的语句或者入口名字发出 Close 不是一个错误。 响应通常是 CloseComplete,但如果在释放资源的时候发生了一些困难也可以是 ErrorResponse。 请注意关闭一个准备好地语句隐含地关闭任何从该语句构造出来地打开的入口。

Flush 消息并不导致任何特定的输出的生成, 但是强制后端发送任何还在它的输出缓冲区中停留的数据。 Flush 必须在除 Sync 外的任何扩展查询命令后面发出——如果前端希望在发出更多的命令之前检查该命令的结果的话。 如果不 Flush,后端返回的消息将组合成最小可能的数据包个数,以减少网络负荷。

注意: 简单查询消息大概等于一系列使用未命名的准备好的语句和无参数的入口对象的 Parse,Bind,入口 Describe,Execute,Close,Sync。 一个区别是它会在查询字串中接受多个 SQL 语句,并在会话中为每个语句自动执行绑定/描述/执行序列。 另外一个区别是它不会返回 ParseComplete,Bindcomplete,CloseComplete,或者 NoData 消息。

    分享到:

本文固定链接: http://klwang.info/postgresql-extend-query/ | 数据库|Linux|软件开发

该日志由 klwang 于2014年01月25日发表在 Database, postgresql 分类下, 你可以发表评论,并在保留原文地址及作者的情况下引用到你的网站或博客。
原创文章转载请注明: postgresql 扩展查询 | 数据库|Linux|软件开发
关键字: ,

postgresql 扩展查询:等您坐沙发呢!

发表评论

*
快捷键:Ctrl+Enter