提交 f2dcdade 编写于 作者: 李少辉-开发者's avatar 李少辉-开发者 🎧

出版翻译完毕

上级 962eb70b
此差异已折叠。
## 36.9.预处理器指令
[36.9.1. 包括文件](ecpg-preproc.html#ECPG-INCLUDE)
[36.9.2. define和undef指令](ecpg-preproc.html#ECPG-DEFINE)
[36.9.3. ifdef、ifndef、elif、else和endif指令](ecpg-preproc.html#ECPG-IFDEF)
可以使用几个预处理器指令来修改`ecpg`预处理器解析并处理文件。
### 36.9.1.包括文件
要在嵌入式SQL程序中包含外部文件,请使用:
```
EXEC SQL INCLUDE filename;
EXEC SQL INCLUDE <filename>;
EXEC SQL INCLUDE "filename";
```
嵌入式SQL预处理器将查找名为`*`文件名`*h`,对其进行预处理,并将其包含在生成的C输出中。因此,可以正确处理包含文件中的嵌入式SQL语句。
这个`ecpg`预处理器将按以下顺序在多个目录中搜索文件:
- 当前目录
- `/usr/本地/包括`
- PostgreSQL包含目录,在构建时定义(例如。,`/usr/local/pgsql/include`)
- `/usr/包括`
但是什么时候`EXEC SQL INCLUDE“*`文件名`*"`则只搜索当前目录。
在每个目录中,预处理器将首先查找给定的文件名,如果找不到,将追加`H`添加到文件名,然后重试(除非指定的文件名已具有该后缀)。
注意`EXEC SQL包括`是*不*一样:
```
#include <filename.h>
```
因为该文件不受SQL命令预处理的约束。当然,您可以继续使用C`#包括`指令以包含其他头文件。
### 笔记
include文件名区分大小写,尽管`EXEC SQL包括`命令遵循正常的SQL区分大小写规则。
### 36.9.2.define和undef指令
与指令类似`#定义`从C语言中可以看出,嵌入式SQL有一个类似的概念:
```
EXEC SQL DEFINE name;
EXEC SQL DEFINE name value;
```
所以你可以定义一个名字:
```
EXEC SQL DEFINE HAVE_FEATURE;
```
你也可以定义常数:
```
EXEC SQL DEFINE MYNUMBER 12;
EXEC SQL DEFINE MYSTRING 'abc';
```
使用`未定义`要删除以前的定义,请执行以下操作:
```
EXEC SQL UNDEF MYNUMBER;
```
当然,您可以继续使用C版本`#定义``#未定义`在嵌入式SQL程序中。不同之处在于对定义的值进行评估的地方。如果你使用`EXEC SQL定义`然后`ecpg`预处理器评估定义并替换值。例如,如果你写:
```
EXEC SQL DEFINE MYNUMBER 12;
...
EXEC SQL UPDATE Tbl SET col = MYNUMBER;
```
然后`ecpg`将已经进行替换,并且您的C编译器将永远不会看到任何名称或标识符`我的号码`.请注意,您不能使用`#定义`对于将在嵌入式SQL查询中使用的常量,因为在这种情况下,嵌入式SQL预编译器无法看到此声明。
### 36.9.3.ifdef、ifndef、elif、else和endif指令
可以使用以下指令有条件地编译代码段:
`execsqlifdef*`名称`*;`
检查*`名称`*如果需要,则处理后续行*`名称`*已通过定义`EXEC SQL定义*`名称`*`.
`EXEC SQL ifndef*`名称`*;`
检查*`名称`*如果需要,则处理后续行*`名称`**不*已通过定义`EXEC SQL定义*`名称`*`.
`execsqlelif*`名称`*;`
`execsqlifdef*`名称`*``EXEC SQL ifndef*`名称`*`指令。任何数量的`否则如果`部分可以出现。在一个`否则如果`将被处理,如果*`名称`*已经定义了*和*之前没有相同的章节`条件编译`/`如果未定义`...`恩迪夫`构造已被处理。
`EXEC SQL else;`
开始一个可选的、最终的可选部分`execsqlifdef*`名称`*``EXEC SQL ifndef*`名称`*`指令。如果没有相同的前一部分,将处理后续行`条件编译`/`如果未定义`...`恩迪夫`构造已被处理。
`EXEC SQL endif;`
结束`条件编译`/`如果未定义`...`恩迪夫`建筑后续行正常处理。
`条件编译`/`如果未定义`...`恩迪夫`构造可以嵌套,最深可达127层。
本例将编译三个示例中的一个`设定时区`命令:
```
EXEC SQL ifdef TZVAR;
EXEC SQL SET TIMEZONE TO TZVAR;
EXEC SQL elif TZNAME;
EXEC SQL SET TIMEZONE TO TZNAME;
EXEC SQL else;
EXEC SQL SET TIMEZONE TO 'GMT';
EXEC SQL endif;
```
## 19.12.在Windows上注册事件日志
[](<>)
要在操作系统中注册Windows事件日志库,请发出以下命令:
```
regsvr32 pgsql_library_directory/pgevent.dll
```
这将在名为的默认事件源下创建事件查看器使用的注册表项`PostgreSQL`.
指定不同的事件源名称(请参见[事件\_来源](runtime-config-logging.html#GUC-EVENT-SOURCE)),使用`/n``/我`选项:
```
regsvr32 /n /i:event_source_name pgsql_library_directory/pgevent.dll
```
要从操作系统中注销事件日志库,请发出以下命令:
```
regsvr32 /u [/i:event_source_name] pgsql_library_directory/pgevent.dll
```
### 笔记
要在数据库服务器中启用事件日志记录,请修改[日志\_目的地](runtime-config-logging.html#GUC-LOG-DESTINATION)包括`事件记录`在里面`postgresql。形态`.
## 14.3.用显式方法控制计划员`参加`条款
[](<>)
通过使用显式`参加`语法。要了解这一点的重要性,我们首先需要一些背景知识。
在简单的联接查询中,例如:
```
SELECT * FROM a, b, c WHERE a.id = b.id AND b.ref = c.id;
```
计划者可以按任意顺序加入给定的表。例如,它可以使用`哪里`条件`a、 id=b.id`,然后使用另一个`哪里`条件或者它可以将B连接到C,然后将A连接到该结果。或者它可以把A和C连接起来,然后把它们和B连接起来——但这将是低效的,因为A和C的完全笛卡尔积必须形成,而在这个过程中没有适用的条件`哪里`子句以允许优化联接。(PostgreSQL executor中的所有连接都发生在两个输入表之间,因此有必要以其中一种方式建立结果。)重要的一点是,这些不同的连接可能性给出了语义上等价的结果,但可能会有巨大不同的执行成本。因此,计划者将对所有这些问题进行研究,试图找到最有效的查询计划。
当一个查询只涉及两个或三个表时,不需要担心太多的联接顺序。但是,随着表的数量增加,可能的连接顺序的数量呈指数增长。除了十个左右的输入表之外,对所有可能的表进行彻底的搜索已经不现实了,即使是六个或七个表,规划也可能需要很长时间。当输入表太多时,PostgreSQL planner将从穷举搜索切换到*遗传的*通过有限的可能性进行概率搜索。(切换阈值由[盖库\_门槛](runtime-config-query.html#GUC-GEQO-THRESHOLD)运行时参数。)基因搜索花费的时间更少,但不一定能找到最好的方案。
当查询涉及外部联接时,planner的自由度比普通(内部)联接要小。例如,考虑:
```
SELECT * FROM a LEFT JOIN (b JOIN c ON (b.ref = c.id)) ON (a.id = b.id);
```
虽然这个查询的限制表面上与前一个示例类似,但语义不同,因为在B和C的联接中,a的每一行都必须发出一行,而B和C的联接中没有匹配的行。因此,规划器在这里没有联接顺序的选择:它必须将B联接到C,然后将a联接到该结果。因此,与上一个查询相比,此查询计划所需的时间更少。在其他情况下,计划者可能能够确定多个联接顺序是安全的。例如,假设:
```
SELECT * FROM a LEFT JOIN b ON (a.bid = b.id) LEFT JOIN c ON (a.cid = c.id);
```
先将A加入B或C是有效的。目前只有`完全连接`完全约束联接顺序。大多数实际案例涉及`左连接``右键连接`可以在某种程度上重新安排。
显式内部联接语法(`内部连接`, `交叉连接`,还是朴素`参加`)语义上与在中列出输入关系相同`从…起`,因此它不约束联接顺序。
尽管大多数`参加`不要完全约束联接顺序,可以指示PostgreSQL查询计划器处理所有`参加`子句作为约束联接顺序的条件。例如,这三个查询在逻辑上是等价的:
```
SELECT * FROM a, b, c WHERE a.id = b.id AND b.ref = c.id;
SELECT * FROM a CROSS JOIN b CROSS JOIN c WHERE a.id = b.id AND b.ref = c.id;
SELECT * FROM a JOIN (b JOIN c ON (b.ref = c.id)) ON (a.id = b.id);
```
但如果我们告诉规划者尊重`参加`第二种和第三种方法比第一种方法花费的时间更少。这种影响不值得担心,因为只有三个表,但它可以挽救许多表。
强制规划者遵循explicit制定的联接顺序`参加`s、 设定[参加\_崩溃\_限度](runtime-config-query.html#GUC-JOIN-COLLAPSE-LIMIT)将运行时参数设置为1。(以下讨论了其他可能的值。)
为了缩短搜索时间,不需要完全约束联接顺序,因为可以使用它`参加`在平面中的项目中的运算符`从…起`列表例如,考虑:
```
SELECT * FROM a CROSS JOIN b, c, d, e WHERE ...;
```
具有`加入_崩溃_极限`=1时,这会强制计划程序在将A连接到B之前将其连接到其他表,但不会以其他方式限制其选择。在本例中,可能的联接顺序的数量减少了5倍。
以这种方式约束计划者的搜索对于减少计划时间和引导计划者选择好的查询计划都是一种有用的技术。如果计划员默认选择了一个错误的连接顺序,您可以通过`参加`语法——假设你知道更好的顺序,也就是说。建议进行实验。
影响计划时间的一个密切相关的问题是将子查询分解为父查询。例如,考虑:
```
SELECT *
FROM x, y,
(SELECT * FROM a, b, c WHERE something) AS ss
WHERE somethingelse;
```
这种情况可能是因为使用了包含连接的视图;景色很美`选择`规则将被插入到视图引用的位置,生成一个类似于上述的查询。通常,计划者会尝试将子查询折叠到父查询中,从而产生:
```
SELECT * FROM x, y, a, b, c WHERE something AND somethingelse;
```
这通常会产生比单独规划子查询更好的计划。(例如,外部`哪里`条件可能是,将X连接到第一行可以消除A的许多行,从而避免形成子查询的完整逻辑输出。)但与此同时,我们增加了计划时间;在这里,我们有一个五路连接问题来代替两个单独的三路连接问题。由于可能性的数量呈指数级增长,这就产生了很大的不同。规划者试图避免陷入巨大的连接搜索问题,如果子查询超过`从_崩溃_极限` `从…起`项将导致父查询。您可以通过向上或向下调整此运行时参数来权衡计划时间和计划质量。
[从…起\_崩溃\_限度](runtime-config-query.html#GUC-FROM-COLLAPSE-LIMIT)[参加\_崩溃\_限度](runtime-config-query.html#GUC-JOIN-COLLAPSE-LIMIT)它们的名称相似,因为它们做的事情几乎相同:一个控制规划器何时“展平”子查询,另一个控制规划器何时展平显式连接。通常你会`加入_崩溃_极限`相当于`从_崩溃_极限`(这样显式连接和子查询的作用类似)或`加入_崩溃_极限`到1(如果希望通过显式联接控制联接顺序)。但是,如果您试图微调计划时间和运行时间之间的权衡,则可能会对它们进行不同的设置。
## 13.3.显式锁定
[13.3.1. 桌面锁](explicit-locking.html#LOCKING-TABLES)
[13.3.2. 行级锁](explicit-locking.html#LOCKING-ROWS)
[13.3.3. 页面级锁](explicit-locking.html#LOCKING-PAGES)
[13.3.4. 僵局](explicit-locking.html#LOCKING-DEADLOCKS)
[13.3.5. 顾问锁](explicit-locking.html#ADVISORY-LOCKS)
[](<>)
PostgreSQL提供了各种锁模式来控制对表中数据的并发访问。在MVCC不能提供所需行为的情况下,这些模式可用于应用程序控制的锁定。此外,大多数PostgreSQL命令会自动获取适当模式的锁,以确保在命令执行时不会以不兼容的方式删除或修改引用的表。(例如,`截断`无法安全地与同一表上的其他操作同时执行,因此它会获得`访问独占`锁定桌子以强制执行。)
要检查数据库服务器中当前未完成的锁的列表,请使用[`pg_锁`](view-pg-locks.html)系统视图。有关监控锁管理器子系统状态的更多信息,请参阅[第28章](monitoring.html).
### 13.3.1.桌面锁
[](<>)
下面的列表显示了可用的锁定模式以及PostgreSQL自动使用它们的上下文。您还可以使用命令显式获取这些锁中的任何一个[](sql-lock.html).记住,所有这些锁模式都是表级锁,即使名称中包含单词“row”;锁定模式的名称是历史记录。在某种程度上,这些名称反映了每个锁模式的典型用法——但语义都是相同的。一种锁模式和另一种锁模式之间唯一的真正区别是它们之间冲突的锁模式集(请参见[表13.2](explicit-locking.html#TABLE-LOCK-COMPATIBILITY)).两个事务不能同时在同一个表上持有冲突模式的锁。(然而,交易从不与自身发生冲突。例如,它可能获得`访问独占`锁定并稍后获取`访问共享`锁在同一张桌子上。)非冲突锁模式可以由多个事务同时持有。请特别注意,某些锁定模式是自冲突的(例如`访问独占`锁一次不能由多个事务持有),而其他事务不会自相矛盾(例如`访问共享`锁可以由多个事务持有)。
**表级锁定模式**
`访问共享`
`访问独占`仅限锁定模式。
这个`选择`命令在引用的表上获取此模式的锁。一般来说,任何查询*读到*一个表,如果不修改它,将获得此锁定模式。
`行共享`
`独家``访问独占`锁定模式。
这个`选择更新``选择共享`命令在目标表上获取此模式的锁(除了`访问共享`锁定已引用但未选中的任何其他表`更新/分享`).
`排他`
`共有`, `共享行独占`, `独家``访问独占`锁定模式。
命令`使现代化`, `删去``插入`在目标表上获取此锁定模式(除了`访问共享`锁定任何其他引用的表)。通常情况下,该锁定模式将由以下命令获取:*修改数据*在桌子上。
`共享更新独占`
`共享更新独占`, `共有`, `共享行独占`, `独家``访问独占`锁定模式。此模式保护表不受并发架构更改和`真空`跑。
获得`真空`(没有`满的`), `分析`, `同时创建索引`, `创建统计数据`, `评论`, `同时重新编制索引`,而且是肯定的[`改变索引`](sql-alterindex.html)[`改变桌子`](sql-altertable.html)变体(有关详细信息,请参阅这些命令的文档)。
`共有`
`排他`, `共享更新独占`, `共享行独占`, `独家``访问独占`锁定模式。此模式保护表不受并发数据更改的影响。
获得`创建索引`(没有`同时`).
`共享行独占`
`排他`, `共享更新独占`, `共有`, `共享行独占`, `独家``访问独占`锁定模式。此模式保护表不受并发数据更改的影响,并且是自排他的,因此一次只能有一个会话保存它。
获得`创建触发器`还有一些形式的[`改变桌子`](sql-altertable.html).
`独家`
`行共享`, `排他`, `共享更新独占`, `共有`, `共享行独占`, `独家``访问独占`锁定模式。此模式只允许并发`访问共享`锁,也就是说,只有从表中读取数据才能与持有该锁模式的事务并行进行。
获得`同时刷新物化视图`.
`访问独占`
与所有模式的锁冲突(`访问共享`, `行共享`, `排他`, `共享更新独占`, `共有`, `共享行独占`, `独家``访问独占`).此模式保证持有人是以任何方式访问表的唯一交易。
被政府收购`升降台`, `截断`, `重新索引`, `簇`, `真空满``刷新物化视图`(没有`同时`)命令。多种形式的`改变索引``改变桌子`也可以在这个级别获得一个锁。这也是默认的锁定模式`锁桌`不显式指定模式的语句。
### 提示
只有一个`访问独占`锁块a`选择`(没有`更新/分享`)声明。
一旦获得,锁通常会一直保持到交易结束。但是,如果在建立保存点后获得了锁,则如果保存点回滚到,锁将立即释放。这符合以下原则:`回降`取消保存点之后命令的所有效果。PL/pgSQL异常块中获取的锁也是如此:从该块中的错误转义将释放在该块中获取的锁。
**表13.2。冲突锁模式**
| 请求的锁定模式 | 现有锁定模式 | | | | | | | |
| ------- | :----: | --- | --- | --- | --- | --- | --- | --- |
| `访问共享` | `行共享` | `排不包括。` | `共享更新不包括。` | `共有` | `共享行不包括。` | `不包括。` | `访问不包括。` | |
| `访问共享` | | | | | | | | 十、 |
| `行共享` | | | | | | | 十、 | 十、 |
| `排不包括。` | | | | | 十、 | 十、 | 十、 | 十、 |
| `共享更新不包括。` | | | | 十、 | 十、 | 十、 | 十、 | 十、 |
| `共有` | | | 十、 | 十、 | | 十、 | 十、 | 十、 |
| `共享行不包括。` | | | 十、 | 十、 | 十、 | 十、 | 十、 | 十、 |
| `不包括。` | | 十、 | 十、 | 十、 | 十、 | X | X | X |
| `ACCESS EXCL.` | X | X | X | X | X | X | X | X |
### 13.3.2. Row-Level Locks
In addition to table-level locks, there are row-level locks, which are listed as below with the contexts in which they are used automatically by PostgreSQL. See[Table 13.3](explicit-locking.html#ROW-LOCK-COMPATIBILITY)for a complete table of row-level lock conflicts. Note that a transaction can hold conflicting locks on the same row, even in different subtransactions; but other than that, two transactions can never hold conflicting locks on the same row. Row-level locks do not affect data querying; they block only*writers and lockers*to the same row. Row-level locks are released at transaction end or during savepoint rollback, just like table-level locks.
**Row-Level Lock Modes**
`FOR UPDATE`
`FOR UPDATE`causes the rows retrieved by the`SELECT`statement to be locked as though for update. This prevents them from being locked, modified or deleted by other transactions until the current transaction ends. That is, other transactions that attempt`UPDATE`,`DELETE`,`SELECT FOR UPDATE`, `选择无密钥更新`, `选择共享``选择密钥共享`在当前事务结束之前,这些行中的任何一行都将被阻止;相反地`选择更新`将等待在同一行上运行任何这些命令的并发事务,然后锁定并返回更新的行(如果行已删除,则不返回行)。在一分钟之内`可重复读取``可序列化`但是,如果要锁定的行在事务启动后发生了更改,则会抛出一个错误。有关进一步讨论,请参阅[第13.4节](applevel-consistency.html).
这个`更新`锁定模式也可由任何`删去`一排,还有一个`使现代化`这会修改某些列的值。当前,考虑用于`使现代化`case是那些具有唯一的索引,可以在外键中使用的索引(因此不考虑部分索引和表达式索引),但这在将来可能会发生变化。
`无需密钥更新`
行为类似于`更新`,但获取的锁较弱:此锁不会阻止`选择密钥共享`试图在同一行上获取锁的命令。该锁定模式也可由任何用户获取`使现代化`这并不意味着`更新`
`分享`
行为类似于`无需密钥更新`,但它会在每个检索到的行上获取共享锁,而不是独占锁。共享锁会阻止其他事务执行`使现代化`, `删去`, `选择更新``选择无密钥更新`在这些行上,但这并不阻止它们执行`选择共享``选择密钥共享`.
`关键份额`
行为类似于`分享`,除了锁较弱外:`选择更新`被阻止了,但没有`选择无密钥更新`.密钥共享锁阻止其他事务执行`删去`或任何`使现代化`这会更改键值,但不会更改其他键值`使现代化`它也不能阻止`选择无密钥更新`, `选择共享``选择密钥共享`.
PostgreSQL不记得有关内存中修改行的任何信息,因此一次锁定的行数没有限制。但是,锁定一行可能会导致磁盘写入,例如:。,`选择更新`修改选定行以将其标记为锁定,因此将导致磁盘写入。
**表13.3。行级锁冲突**
| 请求的锁定模式 | 当前锁定模式 | | | |
| ------- | ------ | --- | --- | --- |
| 关键份额 | 分享 | 无需密钥更新 | 更新 | |
| 关键份额 | | | | 十、 |
| 分享 | | | 十、 | 十、 |
| 无需密钥更新 | | 十、 | 十、 | 十、 |
| 更新 | 十、 | 十、 | 十、 | 十、 |
### 13.3.3.页面级锁
除了表锁和行锁之外,页级共享/排他锁还用于控制对共享缓冲池中表页的读/写访问。这些锁在获取或更新行后立即释放。应用程序开发人员通常不需要关心页面级锁,但为了完整性,这里提到了它们。
### 13.3.4.僵局
[](<>)
使用显式锁定可以增加*僵局*,其中两个(或更多)事务各自持有对方想要的锁。例如,如果事务1获取了表A上的独占锁,然后尝试获取表B上的独占锁,而事务2已经独占锁定了表B,现在需要表A上的独占锁,那么两个事务都不能继续。PostgreSQL会自动检测死锁情况,并通过中止其中一个相关事务来解决死锁,允许其他事务完成。(准确地说,哪一笔交易将被中止很难预测,也不应该依赖。)
请注意,死锁也可能是行级锁的结果(因此,即使不使用显式锁,死锁也可能发生)。考虑两个并发事务修改一个表的情况。第一个事务执行:
```
UPDATE accounts SET balance = balance + 100.00 WHERE acctnum = 11111;
```
这将在具有指定帐号的行上获取行级锁。然后,执行第二个事务:
```
UPDATE accounts SET balance = balance + 100.00 WHERE acctnum = 22222;
UPDATE accounts SET balance = balance - 100.00 WHERE acctnum = 11111;
```
第一个`更新`语句成功获取指定行的行级别锁,因此成功更新该行。然而,第二个`更新`语句发现它试图更新的行已经被锁定,因此它等待获取锁的事务完成。事务二现在正在等待事务1完成,然后再继续执行。现在,事务一执行:
```
UPDATE accounts SET balance = balance - 100.00 WHERE acctnum = 22222;
```
事务一试图在指定的行上获取行级别的锁,但不能:事务二已经持有这样的锁。所以它等待事务2完成。因此,事务一在事务2上被阻塞,事务二在事务一上被阻止:死锁条件。PostgreSQL将检测到这种情况并中止其中一个事务。
对于死锁的最好防御通常是确保所有使用数据库的应用程序都以一致的顺序获取多个对象上的锁,从而避免死锁。在上面的示例中,如果两个事务都以相同的顺序更新了行,则不会发生死锁。还应该确保在事务中获取的对象上获得的第一个锁是该对象所需的最严格的模式。如果事先验证这一点不可行,那么可以通过重试由于死锁而中止的事务来实时处理死锁。
只要未检测到死锁情况,寻求表级或行级锁的事务将无限期地等待释放冲突的锁。这意味着应用程序不应该长时间(例如,在等待用户输入的同时)保持事务打开。
### 13.3.5.咨询锁
[](<>)[](<>)
PostgreSQL提供了一种创建具有应用程序定义含义的锁的方法。这些被称为*咨询锁*,因为系统没有强制使用它们——正确使用它们取决于应用程序。对于MVCC模型来说,咨询锁对于锁定策略非常有用。例如,咨询锁的一个常用方法是模拟所谓“平面文件”数据管理系统典型的悲观锁定策略。虽然存储在表中的标志可以用于相同的目的,但是咨询锁的速度更快,避免了表bloat,并且在会话结束时服务器会自动清理。
在PostgreSQL中获取咨询锁有两种方法:会话级或事务级。一旦在会话级别获得,咨询锁将一直保持到显式释放或会话结束为止。与标准锁请求不同,会话级咨询锁请求不遵守事务语义:在回滚之后,在随后回滚的事务期间获取的锁仍然会保持不变,同样,即使调用事务在以后失败,解锁也会有效。锁可以通过其拥有的进程多次获得;对于每个已完成的锁请求,在实际释放锁之前,必须有相应的解锁请求。另一方面,事务级锁请求的行为更像常规的锁请求:它们在事务结束时自动释放,并且没有显式的解锁操作。对于短期使用咨询锁,这种行为通常比会话级行为更方便。对于相同的咨询锁标识符,会话级别和事务级锁请求将以预期的方式相互阻止。如果会话已经持有给定的咨询锁,则即使其他会话正在等待锁,它的其他请求也将始终成功;无论现有锁保持和新请求处于会话级别还是事务级别,此语句都是真的。
与PostgreSQL中的所有锁一样,任何会话当前持有的一个完整的咨询锁列表可以在[`pg_锁`](view-pg-locks.html)系统视图。
建议锁和常规锁都存储在共享内存池中,其大小由配置变量定义[最大值\_锁\_每\_交易](runtime-config-locks.html#GUC-MAX-LOCKS-PER-TRANSACTION)[最大值\_连接](runtime-config-connection.html#GUC-MAX-CONNECTIONS)。必须注意不要耗尽此内存,否则服务器将无法授予任何锁。这对服务器可授予的建议锁的数量施加了上限,通常为数十到几十万,具体取决于服务器的配置方式。
在某些情况下,使用建议锁定方法,尤其是在涉及显式排序和`限度`子句中,由于SQL表达式的求值顺序,必须小心控制获取的锁。例如:
```
SELECT pg_advisory_lock(id) FROM foo WHERE id = 12345; -- ok
SELECT pg_advisory_lock(id) FROM foo WHERE id > 12345 LIMIT 100; -- danger!
SELECT pg_advisory_lock(q.id) FROM
(
SELECT id FROM foo WHERE id > 12345 LIMIT 100
) q; -- ok
```
在上面的查询中,第二种形式是危险的,因为`限度`不保证在执行锁定功能之前应用。这可能会导致获取一些应用程序不期望的锁,因此无法释放(直到会话结束)。从应用程序的角度来看,这样的锁将是悬挂的,尽管在应用程序中仍然可以看到`pg_锁`.
中介绍了用于操作建议锁的功能[第9.27.10节](functions-admin.html#FUNCTIONS-ADVISORY-LOCKS).
## H.2。管理工具
[](<>)
PostgreSQL有几种可用的管理工具。最受欢迎的是[pgAdmin](https://www.pgadmin.org/),也有几种商用的。
此差异已折叠。
## 9.19.数组函数和运算符
[表9.51](functions-array.html#ARRAY-OPERATORS-TABLE)显示可用于数组类型的专用运算符。除此之外,中还显示了常用的比较运算符[表9.1](functions-comparison.html#FUNCTIONS-COMPARISON-OP-TABLE)可用于阵列。比较运算符使用元素数据类型的默认B树比较函数逐个元素比较数组内容,并根据第一个差异进行排序。在多维数组中,元素按行的主要顺序访问(最后一个下标变化最快)。如果两个数组的内容相等,但维度不同,那么维度信息中的第一个差异将决定排序顺序。
**表9.51。数组运算符**
| 操作人员<br/><br/>描述<br/><br/>例子 |
| ---------------------------- |
| `任意数组` `@>` `任意数组``布尔值`<br/><br/>第一个数组是否包含第二个数组,也就是说,第二个数组中出现的每个元素是否等于第一个数组中的某个元素?(复制品没有经过特殊处理,因此`数组[1]``数组[1,1]`每个都被认为包含另一个。)<br/><br/>`数组[1,4,3]@>数组[3,1,3]``t` |
| `任意数组` `<@` `任意数组``布尔值`<br/><br/>第一个数组是否包含第二个数组?<br/><br/>`ARRAY[2,2,7] <@ ARRAY[1,7,4,2,6]``t` |
| `anyarray` `&&` `anyarray``boolean`<br/><br/>Do the arrays overlap, that is, have any elements in common?<br/><br/>`ARRAY[1,4,3] && ARRAY[2,1]``t` |
| `anycompatiblearray` `||` `anycompatiblearray``anycompatiblearray`<br/><br/>Concatenates the two arrays. Concatenating a null or empty array is a no-op; otherwise the arrays must have the same number of dimensions (as illustrated by the first example) or differ in number of dimensions by one (as illustrated by the second). If the arrays are not of identical element types, they will be coerced to a common type (see[Section 10.5](typeconv-union-case.html)).<br/><br/>`ARRAY[1,2,3] || ARRAY[4,5,6,7]``{1,2,3,4,5,6,7}`<br/><br/>`ARRAY[1,2,3] || ARRAY[[4,5,6],[7,8,9.9]]`→ {`{1,2,3},{4,5,6},{7,8,9.9}`} |
| `anycompatible` `||` `anycompatiblearray``anycompatiblearray`<br/><br/>Concatenates an element onto the front of an array (which must be empty or one-dimensional).<br/><br/>`3 || ARRAY[4,5,6]``{3,4,5,6}` |
| `anycompatiblearray` `||` `anycompatible``anycompatiblearray`<br/><br/>Concatenates an element onto the end of an array (which must be empty or one-dimensional).<br/><br/>`ARRAY[4,5,6] || 7``{4,5,6,7}` |
See[Section 8.15](arrays.html)for more details about array operator behavior. See[Section 11.2](indexes-types.html)for more details about which operators support indexed operations.
[Table 9.52](functions-array.html#ARRAY-FUNCTIONS-TABLE)shows the functions available for use with array types. See[Section 8.15](arrays.html)for more information and examples of the use of these functions.
**Table 9.52. Array Functions**
| Function<br/><br/>描述<br/><br/>例子 | | | | |
| -------------------------------- | --- | --- | --- | --- |
| [](<>) `数组_追加` ( `随便什么`, `任何兼容的` ) → `随便什么`<br/><br/>将元素追加到数组的末尾(与`随便什么` `||` `任何兼容的`接线员)。<br/><br/>`数组_追加(数组[1,2],3)``{1,2,3}` | | | | |
| [](<>) `猫咪` ( `随便什么`, `随便什么` ) → `随便什么`<br/><br/>连接两个数组(与`随便什么` `||` `随便什么`接线员)。<br/><br/>`数组_cat(数组[1,2,3],数组[4,5])``{1,2,3,4,5}` | | | | |
| [](<>) `阵列亮度` ( `任意数组` ) → `文本`<br/><br/>返回数组维度的文本表示形式。<br/><br/>`数组_dims(数组[[1,2,3],[4,5,6])``[1:2][1:3]` | | | | |
| [](<>) `数组填充` ( `任何元素`, `整数[]` \[, `整数[]` ] ) → `任意数组`<br/><br/>返回一个由给定值的副本填充的数组,其维数为第二个参数指定的长度。可选的第三个参数为每个维度提供下限值(默认为all)`1.`).<br/><br/>`数组填充(11,数组[2,3])``{{11,11,11},{11,11,11}}`<br/><br/>`数组填充(7,数组[3],数组[2])``[2:4]={7,7,7}` | | | | |
| [](<>) `数组长度` ( `任意数组`, `整数` ) → `整数`<br/><br/>返回请求的数组维度的长度。<br/><br/>`数组长度(数组[1,2,3],1)``3.` | | | | |
| [](<>) `数组_较低` ( `任意数组`, `整数` ) → `整数`<br/><br/>返回请求的数组维度的下限。<br/><br/>`数组_lower('[0:2]={1,2,3}'::整数[],1)``0` | | | | |
| [](<>) `阵列ndims` ( `任意数组` ) → `整数`<br/><br/>返回数组的维数。<br/><br/>`数组_ndims(数组[[1,2,3],[4,5,6])``2.` | | | | |
| [](<>) `阵列位置` ( `随便什么`, `任何兼容的` [, `整数` ] ) → `整数`<br/><br/>返回数组中第二个参数第一次出现的下标,或`无效的`如果它不存在。如果给出了第三个参数,搜索将从该下标开始。数组必须是一维的。比较是使用`与…没有区别`语义,因此可以搜索`无效的`.<br/><br/>`数组位置(数组['sun','mon','tue','wed','thu','fri','sat','mon')``2.` | | | | |
| [](<>) `阵列位置` ( `随便什么`, `任何兼容的` ) → `整数[]`<br/><br/>返回作为第一个参数给定的数组中第二个参数的所有匹配项的下标数组。数组必须是一维的。比较是使用`与…没有区别`语义,因此可以搜索`无效的`. `无效的`仅当数组为`无效的`; 如果在数组中找不到该值,则返回一个空数组。<br/><br/>`数组位置(数组['A','A','B','A'],'A')``{1,2,4}` | | | | |
| [](<>) `数组_前置` ( `任何兼容的`, `随便什么` ) → `随便什么`<br/><br/>将元素前置到数组的开头(与`任何兼容的` `||` `随便什么`接线员)。<br/><br/>`数组_前置(1,数组[2,3])``{1,2,3}` | | | | |
| [](<>) `数组_移除` ( `随便什么`, `任何兼容的` ) → `随便什么`<br/><br/>从数组中删除与给定值相等的所有元素。数组必须是一维的。比较是使用`与…没有区别`语义,因此可以删除`无效的`s<br/><br/>`数组_移除(数组[1,2,3,2],2)``{1,3}` | | | | |
| [](<>) `数组_替换` ( `随便什么`, `任何兼容的`, `任何兼容的` ) → `随便什么`<br/><br/>用第三个参数替换等于第二个参数的每个数组元素。<br/><br/>`数组_替换(数组[1,2,5,4],5,3)``{1,2,3,4}` | | | | |
| [](<>) `数组到字符串` ( *`大堆`* `任意数组`, *`定界符`* `文本` [, *`空字符串_ `*文本` `] ) → `文本`<br/><br/>将每个数组元素转换为其文本表示形式,并将由*`定界符`*一串如果*`空字符串`*是给予的,不是`无效的`然后`无效的`数组条目由该字符串表示;否则,它们将被忽略。<br/><br/>`数组_到_字符串(数组[1,2,3,NULL,5],',','*')``1,2,3,*,5` | | | | |
| [](<>) `上排` ( `任意数组`, `整数` ) → `整数`<br/><br/>返回请求的数组维度的上限。<br/><br/>`数组_upper(数组[1,8,3,7],1)``4.` | | | | |
| [](<>) `基数` ( `任意数组` ) → `整数`<br/><br/>返回数组中的元素总数,如果数组为空,则返回0。<br/><br/>`基数(数组[[1,2],[3,4])``4.` | | | | |
| [](<>) `trim_阵列` ( *`大堆`* `任意数组`, *`n`* `整数` ) → `任意数组`<br/><br/>通过删除最后一个数组来修剪数组*`n`*元素。如果数组是多维的,则只修剪第一个维度。<br/><br/>`trim_数组(数组[1,2,3,4,5,6],2)``{1,2,3,4}` | | | | |
| [](<>) `不安` ( `任意数组` ) → `任意元素集`<br/><br/>将数组展开为一组行。阵列的元素按存储顺序读取。<br/><br/>`unnest(数组[1,2])```<br/><br/>`1<br/>2<br/><br/>`unest(数组['foo','bar',['baz','qux'])→``<br/><br/>`<br/>foo<br/>bar<br/>baz<br/>qux<br/><br/>` | | | | |
| `不安` ( `任意数组`, `任意数组` [, ... ] ) → `任意元素的集合,任意元素[,…]`<br/><br/>将多个数组(可能具有不同的数据类型)扩展为一组行。如果数组的长度不尽相同,则较短的数组将填充`无效的`s、 此表单只允许在查询的FROM子句中使用;看见[第7.2.1.4节](queries-table-expressions.html#QUERIES-TABLEFUNCTIONS).<br/><br/>`从unnest(数组[1,2],数组['foo','bar','baz'])中选择*作为x(a,b)```<br/><br/>\```<br/>A. | b<br/>---+-----<br/>1. | 福<br/>2. | 酒吧<br/> | 巴兹<br/><br/>\``` |
### 笔记
有两种不同的行为`字符串到数组`来自PostgreSQL 9.1之前的版本。首先,它将返回一个空(零元素)数组,而不是`无效的`当输入字符串长度为零时。第二,如果分隔符字符串是`无效的`,该函数将输入拆分为单个字符,而不是返回`无效的`和以前一样。
另见[第9.21节](functions-aggregate.html)关于聚合函数`数组_agg`用于阵列。
## 9.11.几何函数与算子
几何类型`指向`,`盒`,`lseg`,`线`,`路径`,`多边形``圆圈`拥有大量本机支持函数和运算符,如中所示[表9.35](functions-geometry.html#FUNCTIONS-GEOMETRY-OP-TABLE),[表9.36](functions-geometry.html#FUNCTIONS-GEOMETRY-FUNC-TABLE)[表9.37](functions-geometry.html#FUNCTIONS-GEOMETRY-CONV-TABLE).
**表9.35。几何算子**
| 操作人员<br/><br/>描述<br/><br/>例子 |
| ---------------------------- |
| *`几何_型`* `+` `指向``*`几何\_`*`<br/><br/>添加第二个的坐标`指向`到第一个论点的每一点,从而进行翻译。适用于`指向`, `盒`, `路径`, `圆圈`.<br/><br/>`方框'(1,1),(0,0)'+点'(2,0)'``(3,1),(2,0)` |
| `路径` `+` `路径``路径`<br/><br/>连接两个打开的路径(如果任一路径关闭,则返回NULL)。<br/><br/>`路径“[(0,0),(1,1)]”+路径“[(2,2),(3,3),(4,4)]”``[(0,0),(1,1),(2,2),(3,3),(4,4)]` |
| *`几何_型`* `-` `指向``*`几何\_`*`<br/><br/>减去第二个坐标`指向`从第一个论点的每一点出发,进行翻译。适用于`指向`, `盒`, `路径`, `圆圈`.<br/><br/>`方框'(1,1),(0,0)'-点'(2,0)'``(-1,1),(-2,0)` |
| *`几何_型`* `*` `指向``*`几何\_`*`<br/><br/>将第一个参数的每个点乘以第二个参数`指向`(将点视为由实部和虚部表示的复数,并执行标准复数乘法)。如果一个人解释第二个`指向`作为向量,这相当于按向量长度缩放对象的大小和与原点的距离,并按向量与原点的角度逆时针旋转对象*`十、`*轴适用于`指向`, `盒`,[<sup class="footnote" id="FUNCTIONS-GEOMETRY-ROTATION-FN">\[a\]</sup>](#ftn.FUNCTIONS-GEOMETRY-ROTATION-FN) `路径`, `圆圈`.<br/><br/>`路径“((0,0)、(1,0)、(1,1))”*点“(3.0,0)”``((0,0),(3,0),(3,3))`<br/><br/>`路径“((0,0)、(1,0)、(1,1))”*点(cosd(45),sind(45))``((0,0),​(0.7071067811865475,0.7071067811865475),​(0,1.414213562373095))` |
| *`几何_型`* `/` `指向``*`几何\_`*`<br/><br/>将第一个论点的每一点除以第二个论点`指向`(将点视为由实部和虚部表示的复数,并执行标准复数除法)。如果一个人解释第二个`指向`作为向量,这相当于将对象的大小和与原点的距离向下缩放向量的长度,并将其围绕原点顺时针旋转向量与原点的角度*`十、`*轴适用于`指向`, `盒`,[<sup class="footnoteref">\[a\]</sup>](functions-geometry.html#ftn.FUNCTIONS-GEOMETRY-ROTATION-FN) `路径`, `圆圈`.<br/><br/>`路径“((0,0),(1,0),(1,1))”/点“(2.0,0)”``((0,0),(0.5,0),(0.5,0.5))`<br/><br/>`路径“((0,0)、(1,0)、(1,1))”/点(cosd(45),sind(45))``((0,0),​(0.7071067811865476,-0.7071067811865476),​(1.4142135623730951,0))` |
| `@-@` *`几何_型`*`双精度`<br/><br/>计算总长度。适用于`lseg`, `路径`.<br/><br/>`@-@路径“[(0,0)、(1,0)、(1,1)]”``2.` |
| `@@` *`几何_型`*`指向`<br/><br/>计算中心点。适用于`盒`, `lseg`, `多边形`, `圆圈`.<br/><br/>`@@框'(2,2),(0,0)'``(1,1)` |
| `#` *`几何_型`*`整数`<br/><br/>返回点数。适用于`路径`, `多边形`.<br/><br/>`#路径“((1,0),(0,1),(-1,0))”``3.` |
| *`几何_型`* `#` *`几何_型`*`指向`<br/><br/>计算交点,如果没有交点,则为NULL。适用于`lseg`, `线`.<br/><br/>`lseg'[(0,0),(1,1)]“#lseg'[(1,0),(0,1)]”``(0.5,0.5)` |
| `盒` `#` `盒``盒`<br/><br/>计算两个框的交点,如果没有,则为NULL。<br/><br/>`盒子(2,2),(-1,-1)#盒子(1,1),(-2,-2)'``(1,1),(-1,-1)` |
| *`几何_型`* `##` *`几何_型`*`指向`<br/><br/>计算第二个对象上距离第一个对象最近的点。适用于以下几对类型:(`指向`, `盒`), (`指向`, `lseg`), (`观点`,`线`), (`lseg`,`盒子`), (`lseg`,`lseg`), (`线`,`lseg`)。<br/><br/>`point '(0,0)' ## lseg '[(2,0),(0,2)]'``(1,1)` |
| *`几何类型`* `<->` *`几何类型`*`双精度`<br/><br/>计算对象之间的距离。适用于所有几何类型,除了`多边形`, 对于所有的组合`观点`使用另一种几何类型,对于这些额外的类型对:(`盒子`,`lseg`), (`lseg`,`线`), (`多边形`,`圆圈`) (以及换向器案例)。<br/><br/>`圆'<(0,0),1>' <-> 圆'<(5,0),1>'``3` |
| *`几何类型`* `@>` *`几何类型`*`布尔值`<br/><br/>第一个对象是否包含第二个?可用于这些类型对:(`盒子`,`观点`), (`盒子`,`盒子`), (`小路`,`观点`), (`多边形`,`观点`), (`多边形`,`多边形`), (`圆圈`,`观点`), (`圆圈`,`圆圈`)。<br/><br/>`圆'<(0,0),2>'@>点'(1,1)'``吨` |
| *`几何类型`* `<@` *`几何类型`*`布尔值`<br/><br/>第一个对象是包含在第二个对象中还是包含在第二个对象中?可用于这些类型对:(`观点`,`盒子`), (`观点`, `lseg`), (`观点`, `线`), (`观点`, `小路`), (`观点`, `多边形`), (`观点`, `圆圈`), (`盒子`, `盒子`), (`lseg`, `盒子`), (`lseg`,`线`), (`多边形`,`多边形`), (`圆圈`,`圆圈`)。<br/><br/>`点 '(1,1)' <@ 圆圈 '<(0,0),2>'``吨` |
| *`几何类型`* `&&` *`几何类型`*`布尔值`<br/><br/>这些对象是否重叠?(有一个共同点使这一点成为现实。)适用于`盒子`,`多边形`,`圆圈`.<br/><br/>`框'(1,1),(0,0)' && 框'(2,2),(0,0)'``吨` |
| *`几何类型`* `<<` *`几何类型`*`布尔值`<br/><br/>第一个对象严格在第二个对象的左边吗?可以用来`观点`,`盒子`,`多边形`,`圆圈`.<br/><br/>`圆'<(0,0),1>' << 圆'<(5,0),1>'``吨` |
| *`几何类型`* `>>` *`几何类型`*`布尔值`<br/><br/>第一个对象是否严格正确于第二个对象?可以用来`观点`,`盒子`,`多边形`,`圆圈`.<br/><br/>`圆'<(5,0),1>' >> 圆'<(0,0),1>'``吨` |
| *`几何类型`* `&<` *`几何类型`*`布尔值`<br/><br/>第一个对象不会延伸到第二个对象的右侧吗?可以用来`盒子`,`多边形`,`圆圈`.<br/><br/>`框'(1,1),(0,0)' &< 框'(2,2),(0,0)'``吨` |
| *`几何类型`* `&>` *`几何类型`*`布尔值`<br/><br/>第一个对象不会延伸到第二个对象的左侧吗?可以用来`盒子`,`多边形`,`圆圈`.<br/><br/>`框'(3,3),(0,0)&>框'(2,2),(0,0)'``t` |
| *`几何_型`* `<<|` *`几何_型`*`布尔值`<br/><br/>第一个物体严格低于第二个吗?适用于`指向`,`盒`,`多边形`,`圆圈`.<br/><br/>`方框(3,3)、(0,0)<<方框(5,5)、(3,4)'``t` |
| *`几何_型`* `|>>` *`几何_型`*`布尔值`<br/><br/>第一个物体严格高于第二个吗?适用于`指向`,`盒`, `多边形`, `圆圈`.<br/><br/>`盒子'(5,5),(3,4)|>>盒子'(3,3),(0,0)'``t` |
| *`几何_型`* `&<|` *`几何_型`*`布尔值`<br/><br/>第一个物体不延伸到第二个物体之上吗?适用于`盒`, `多边形`, `圆圈`.<br/><br/>`盒子'(1,1),(0,0)&<|盒子'(2,2),(0,0)'``t` |
| *`几何_型`* `|&>` *`几何_型`*`布尔值`<br/><br/>第一个物体不延伸到第二个物体以下吗?适用于`盒`, `多边形`, `圆圈`.<br/><br/>`框'(3,3),(0,0)|和>框'(2,2),(0,0)'``t` |
| `盒` `<^` `盒``布尔值`<br/><br/>第一个物体是否低于第二个(允许边缘接触)?<br/><br/>`方框“((1,1)、(0,0))”<^box“((2,2)、(1,1))”``t` |
| `盒` `>^` `盒``布尔值`<br/><br/>第一个物体是否在第二个物体之上(允许边缘接触)?<br/><br/>`框“((2,2)、(1,1))”>^box“((1,1)、(0,0))”``t` |
| *`几何_型`* `?#` *`几何_型`*`布尔值`<br/><br/>这些物体相交吗?适用于以下几对类型:(`盒`, `盒`), (`lseg`, `盒`), (`lseg`, `lseg`), (`lseg`, `线`), (`线`, `盒`), (`线`, `线`), (`路径`, `路径`).<br/><br/>`lseg'[(-1,0),(1,0)]?#方框'(2,2),(-2,-2)'``t` |
| `?-` `线``布尔值`<br/><br/>`?-` `lseg``布尔值`<br/><br/>这条线是水平的吗?<br/><br/>`?- lseg'[(-1,0),(1,0)]'``t` |
| `指向` `?-` `指向``布尔值`<br/><br/>点是否水平对齐(即y坐标相同)?<br/><br/>`(1,0)点?-点'(0,0)'``t` |
| `?|` `线``布尔值`<br/><br/>`?|` `lseg``布尔值`<br/><br/>这条线是垂直的吗?<br/><br/>`?| lseg'[(-1,0),(1,0)]'``f` |
| `指向` `?|` `指向``布尔值`<br/><br/>点是否垂直对齐(即具有相同的x坐标)?<br/><br/>`(0,1)点?|点'(0,0)'``t` |
| `线` `?-|` `线``布尔值`<br/><br/>`lseg` `?-|` `lseg``布尔值`<br/><br/>直线垂直吗?<br/><br/>`lseg'[(0,0),(0,1)]'?-|lseg'[(0,0),(1,0)]'``t` |
| `线` `?||` `线``布尔值`<br/><br/>`lseg` `?||` `lseg``布尔值`<br/><br/>直线平行吗?<br/><br/>`lseg'[(-1,0),(1,0)]?||lseg'[(-1,2),(1,2)]'``t` |
| *`几何_型`* `~=` *`几何_型`*`布尔值`<br/><br/>这些物体是一样的吗?适用于`指向`, `盒`, `多边形`, `圆圈`.<br/><br/>`多边形“((0,0),(1,1))”~=多边形“((1,1),(0,0))”``t` |
| [<sup class="para">\[a\] </sup>](#FUNCTIONS-GEOMETRY-ROTATION-FN)使用这些操作符“旋转”长方体只会移动其角点:长方体的边仍被认为与轴平行。因此,不会像真正的旋转那样保留长方体的大小。 |
### 小心
请注意,“与”运算符,`~=`,代表了社会平等的通常观念`指向`, `盒`, `多边形``圆圈`类型。一些几何类型也有一个`=`接线员,但是`=`比较平等*地区*只有其他标量比较运算符(`<=`以此类推),在这些类型可用的情况下,同样地比较区域。
### 笔记
在PostgreSQL 14之前,这一点严格低于/高于比较运算符`指向` `<<|` `指向``指向` `|>>` `指向`分别被称为`<^``>^`。这些名称仍然可用,但已被弃用,最终将被删除。
**表9.36。几何函数**
| 作用<br/><br/>描述<br/><br/>例子 |
| -------------------------- |
| [](<>) `地区` ( *`几何_型`* ) → `双精度`<br/><br/>计算面积。适用于`盒`, `路径`, `圆圈`A.`路径`输入必须关闭,否则返回NULL。此外,如果`路径`是自交的,结果可能毫无意义。<br/><br/>`面积(方框(2,2)、(0,0)’)``4.` |
| [](<>) `居中` ( *`几何_型`* ) → `指向`<br/><br/>计算中心点。适用于`盒`, `圆圈`.<br/><br/>`中心(1,2)、(0,0)框)``(0.5,1)` |
| [](<>) `斜线的` ( `盒` ) → `lseg`<br/><br/>将长方体的对角线提取为线段(与`lseg(盒子)`).<br/><br/>`对角线(方框’(1,2),(0,0)’)``[(1,2),(0,0)]` |
| [](<>) `直径` ( `圆圈` ) → `双精度`<br/><br/>计算圆的直径。<br/><br/>`直径(圆圈“<(0,0),2>”)``4.` |
| [](<>) `身高` ( `盒` ) → `双精度`<br/><br/>计算长方体的垂直大小。<br/><br/>`高度(1,2)、(0,0)框)``2.` |
| [](<>) `是封闭的` ( `路径` ) → `布尔值`<br/><br/>这条路封闭了吗?<br/><br/>`isclosed(路径“((0,0)、(1,1)、(2,0))”)``t` |
| [](<>) `伊索彭` ( `路径` ) → `布尔值`<br/><br/>这条路通吗?<br/><br/>`等参线(路径“[(0,0),(1,1),(2,0)]”``t` |
| [](<>) `长` ( *`几何_型`* ) → `双精度`<br/><br/>计算总长度。适用于`lseg`, `路径`.<br/><br/>`长度(路径“(-1,0),(1,0))”``4.` |
| [](<>) `n点` ( *`几何_型`* ) → `整数`<br/><br/>返回点数。适用于`路径`, `多边形`.<br/><br/>`n点(路径“[(0,0)、(1,1)、(2,0)]”``3.` |
| [](<>) `pclose` ( `路径` ) → `路径`<br/><br/>将路径转换为封闭形式。<br/><br/>`pclose(路径“[(0,0)、(1,1)、(2,0)]”``((0,0),(1,1),(2,0))` |
| [](<>) `波本` ( `路径` ) → `路径`<br/><br/>将路径转换为开放形式。<br/><br/>`popen(路径“((0,0)、(1,1)、(2,0))”)``[(0,0),(1,1),(2,0)]` |
| [](<>) `半径` ( `圆圈` ) → `双精度`<br/><br/>计算圆的半径。<br/><br/>`半径(圆“<(0,0),2>”)``2.` |
| [](<>) `斜坡` ( `指向`, `指向` ) → `双精度`<br/><br/>计算通过两点绘制的直线的坡度。<br/><br/>`坡度(点“(0,0)”,点“(2,1)”)``0.5` |
| [](<>) `宽度` ( `盒` ) → `双精度`<br/><br/>计算长方体的水平大小。<br/><br/>`宽度(框’(1,2),(0,0)’)``1.` |
**表9.37。几何类型转换函数**
| 作用<br/><br/>描述<br/><br/>例子 |
| -------------------------- |
| [](<>) `盒` ( `圆圈` ) → `盒`<br/><br/>计算圆内的内接框。<br/><br/>`框(圈“<(0,0),2>”)``(1.414213562373095,1.414213562373095),​(-1.414213562373095,-1.414213562373095)` |
| `盒` ( `指向` ) → `盒`<br/><br/>将点转换为空框。<br/><br/>`方框(1,0点)``(1,0),(1,0)` |
| `盒` ( `指向`, `指向` ) → `盒`<br/><br/>将任意两个角点转换为长方体。<br/><br/>`方框(点“(0,1)”,点“(1,0)”)``(1,1),(0,0)` |
| `盒` ( `多边形` ) → `盒`<br/><br/>计算多边形的边界框。<br/><br/>`长方体(多边形'((0,0),(1,1),(2,0)))``(2,1),(0,0)` |
| [](<>) `装订盒` ( `盒`, `盒` ) → `盒`<br/><br/>计算两个框的边界框。<br/><br/>`装订盒(盒’(1,1),(0,0)’,盒’(4,4),(3,3)’)``(4,4),(0,0)` |
| [](<>) `圆圈` ( `盒` ) → `圆圈`<br/><br/>计算包围盒的最小圆。<br/><br/>`圆圈(方框’(1,1)、(0,0)’)``<(0.5,0.5),0.7071067811865476>` |
| `圆圈` ( `指向`, `双精度` ) → `圆圈`<br/><br/>从圆心和半径构建圆。<br/><br/>`圆(点“(0,0)”,2.0)``<(0,0),2>` |
| `圆圈` ( `多边形` ) → `圆圈`<br/><br/>将多边形转换为圆。圆心是多边形点位置的平均值,半径是多边形点与圆心的平均距离。<br/><br/>`圆(多边形“((0,0)、(1,3)、(2,0))”)``<(1,1),1.6094757082487299>` |
| [](<>) `线` ( `指向`, `指向` ) → `线`<br/><br/>将两点转换为穿过它们的直线。<br/><br/>`直线(点'-1,0',点'-1,0')``{0,-1,0}` |
| [](<>) `lseg` ( `盒` ) → `lseg`<br/><br/>将长方体的对角线提取为线段。<br/><br/>`lseg(框(1,0),(-1,0)``[(1,0),(-1,0)]` |
| `lseg` ( `指向`, `指向` ) → `lseg`<br/><br/>从两个端点构造线段。<br/><br/>`lseg(点'-1,0',点'-1,0')``[(-1,0),(1,0)]` |
| [](<>) `路径` ( `多边形` ) → `路径`<br/><br/>将多边形转换为具有相同点列表的闭合路径。<br/><br/>`路径(多边形“((0,0)、(1,1)、(2,0))”)``((0,0),(1,1),(2,0))` |
| [](<>) `指向` ( `双精度`, `双精度` ) → `指向`<br/><br/>从其坐标构造点。<br/><br/>`第(23.4,-44.5)点``(23.4,-44.5)` |
| `指向` ( `盒` ) → `指向`<br/><br/>计算框的中心。<br/><br/>`点(框'(1,0),(-1,0)')``(0,0)` |
| `观点` ( `圆圈` ) → `观点`<br/><br/>计算圆心。<br/><br/>`点(圆圈'<(0,0),2>')``(0,0)` |
| `观点` ( `lseg` ) → `观点`<br/><br/>计算线段的中心。<br/><br/>`点(lseg'[(-1,0),(1,0)]')``(0,0)` |
| `观点` ( `多边形` ) → `观点`<br/><br/>计算多边形的中心(多边形点位置的平均值)。<br/><br/>`点(多边形'((0,0),(1,1),(2,0))')``(1,0.3333333333333333)` |
| [](<>) `多边形`(`盒`) →`多边形`<br/><br/>将长方体转换为4点多边形。<br/><br/>`多边形(框'(1,1),(0,0)')``((0,0),(0,1),(1,1),(1,0))` |
| `多边形`(`圆圈`) →`多边形`<br/><br/>将圆转换为12点多边形。<br/><br/>`多边形(圆“<(0,0),2>”)``((-2,0),​(-1.7320508075688774,0.9999999999999999),​(-1.0000000000000002,1.7320508075688772),​(-1.2246063538223773e-16,2),​(0.9999999999999996,1.7320508075688774),​(1.732050807568877,1.0000000000000007),​(2,2.4492127076447545e-16),​(1.7320508075688776,-0.9999999999999994),​(1.0000000000000009,-1.7320508075688767),​(3.673819061467132e-16,-2),​(-0.9999999999999987,-1.732050807568878),​(-1.7320508075688767,-1.0000000000000009))` |
| `多边形`(`整数`,`圆圈`) →`多边形`<br/><br/>将圆转换为*`n`*-点多边形。<br/><br/>`多边形(4,圆“<(3,0),1>”)``((2,0),​(3,1),​(4,1.2246063538223773e-16),​(3,-1))` |
| `多边形` ( `路径` ) → `多边形`<br/><br/>将闭合路径转换为具有相同点列表的多边形。<br/><br/>`多边形(路径“((0,0)、(1,1)、(2,0))”)``((0,0),(1,1),(2,0))` |
可以访问a的两个部件号`指向`就像点是一个索引为0和1的数组。例如,如果`t、 p`是一个`指向`那么专栏呢`从t中选择p[0]`检索X坐标并`更新t集p[1]=。。。`更改Y坐标。同样,类型为`盒``lseg`可以被视为两个数组`指向`价值观
此差异已折叠。
## 9.1.逻辑运算符
[](<>)[](<>)
常见的逻辑运算符有:[](<>) [](<>) [](<>) [](<>) [](<>) [](<>)
```
boolean AND boolean → boolean
boolean OR boolean → boolean
NOT boolean → boolean
```
SQL使用真、假和假三值逻辑系统`无效的`,表示“未知”。观察以下真值表:
| *`A.`* | *`b`* | *`A.`**`b`* | *`A.`**`b`* |
| ------ | ----- | ------------ | ------------ |
| 符合事实的 | 符合事实的 | 符合事实的 | 符合事实的 |
| 符合事实的 | 错误的 | 错误的 | 符合事实的 |
| 符合事实的 | 无效的 | 无效的 | 符合事实的 |
| 错误的 | 错误的 | FALSE | FALSE |
| FALSE | NULL | FALSE | NULL |
| NULL | NULL | NULL | NULL |
| *`a`* | NOT*`a`* |
| ----- | -------- |
| TRUE | FALSE |
| FALSE | TRUE |
| NULL | NULL |
The operators`AND`and`OR`are commutative, that is, you can switch the left and right operands without affecting the result. (However, it is not guaranteed that the left operand is evaluated before the right operand. See[Section 4.2.14](sql-expressions.html#SYNTAX-EXPRESS-EVAL)for more information about the order of evaluation of subexpressions.)
## 9.12.网络地址功能和运营商
IP网络地址类型,`苹果酒``内特`,支持中所示的常用比较运算符[表9.1](functions-comparison.html#FUNCTIONS-COMPARISON-OP-TABLE)以及中所示的专用运算符和函数[表9.38](functions-net.html#CIDR-INET-OPERATORS-TABLE)[表9.39](functions-net.html#CIDR-INET-FUNCTIONS-TABLE).
任何`苹果酒`价值可以被赋予`内特`含蓄地因此,如下所示的操作人员和功能在`内特`也在努力`苹果酒`价值观(如果有单独的功能`内特``苹果酒`,这是因为这两种情况下的行为应该不同。)此外,它还被允许进行投票`内特`重视`苹果酒`。完成此操作后,网络掩码右侧的任何位都会自动归零,以创建有效的`苹果酒`价值
**表9.38。IP地址操作员**
| 操作人员<br/><br/>描述<br/><br/>例子 |
| ---------------------------- |
| `内特` `<<` `内特``布尔值`<br/><br/>子网是否严格由子网控制?这个操作符和接下来的四个操作符测试子网是否包含在内。他们只考虑两个地址的网络部分(忽略网络掩码右边的任何位),并确定一个网络是否与另一个网络相同或子网。<br/><br/>`inet'192.168.1.5'<<inet'192.168.1/24'``t`<br/><br/>`inet'192.168.0.5'<<inet'192.168.1/24'``f`<br/><br/>`inet'192.168.1/24'<<inet'192.168.1/24'``f` |
| `内特` `<<=` `内特``布尔值`<br/><br/>子网是否由子网包含或等于子网?<br/><br/>`inet '192.168.1/24' <<= inet '192.168.1/24'``吨` |
| `网络` `>>` `网络``布尔值`<br/><br/>子网是否严格包含子网?<br/><br/>`inet '192.168.1/24' >> inet '192.168.1.5'``吨` |
| `网络` `>>=` `网络``布尔值`<br/><br/>子网是否包含或等于子网?<br/><br/>`inet '192.168.1/24' >>= inet '192.168.1/24'``吨` |
| `网络` `&&` `网络``布尔值`<br/><br/>任一子网是否包含或等于另一个子网?<br/><br/>`inet '192.168.1/24' && inet '192.168.1.80/28'``吨`<br/><br/>`inet '192.168.1/24' && inet '192.168.2.0/28'``f` |
| `~` `网络``网络`<br/><br/>按位计算 NOT。<br/><br/>`〜净'192.168.1.6'``63.87.254.249` |
| `网络` `&` `网络``网络`<br/><br/>计算按位与。<br/><br/>`inet '192.168.1.6' & inet '0.0.0.255'``0.0.0.6` |
| `网络` `|` `网络``网络`<br/><br/>计算按位或。<br/><br/>`inet '192.168.1.6' | inet '0.0.0.255'``192.168.1.255` |
| `inet` `+` `bigint``inet`<br/><br/>Adds an offset to an address.<br/><br/>`inet '192.168.1.6' + 25``192.168.1.31` |
| `bigint` `+` `inet``inet`<br/><br/>Adds an offset to an address.<br/><br/>`200 + inet '::ffff:fff0:1'``::ffff:255.240.0.201` |
| `inet` `-` `bigint``inet`<br/><br/>Subtracts an offset from an address.<br/><br/>`inet '192.168.1.43' - 36``192.168.1.7` |
| `内特` `-` `内特``比基特`<br/><br/>计算两个地址的差。<br/><br/>`inet'192.168.1.43'-inet'192.168.1.19'``24`<br/><br/>`inet'::1'-inet'::ffff:1'``-4294901760` |
**表9.39。IP地址功能**
| 作用<br/><br/>描述<br/><br/>例子 |
| -------------------------- |
| [](<>) `阿伯雷夫`(`内特`) →`文本`<br/><br/>将缩写显示格式创建为文本。(结果与`内特`输出函数产生;它仅在与显式强制转换的结果进行比较时被“缩写”`文本`,由于历史原因,它永远不会抑制网络掩码部分。)<br/><br/>`abbrev(inet '10.1.0.0/32')``10.1.0.0` |
| `abbrev`(`cidr`) →`text`<br/><br/>Creates an abbreviated display format as text. (The abbreviation consists of dropping all-zero octets to the right of the netmask; more examples are in[Table 8.22](datatype-net-types.html#DATATYPE-NET-CIDR-TABLE).)<br/><br/>`abbrev(cidr '10.1.0.0/16')``10.1/16` |
| [](<>) `broadcast`(`inet`) →`inet`<br/><br/>Computes the broadcast address for the address's network.<br/><br/>`broadcast(inet '192.168.1.5/24')``192.168.1.255/24` |
| [](<>) `family`(`inet`) →`integer`<br/><br/>返回地址的族:`4.`对于IPv4,`6.`对于IPv6。<br/><br/>`家庭(inet':1')``6.` |
| [](<>) `主办` ( `内特` ) → `文本`<br/><br/>以文本形式返回IP地址,忽略网络掩码。<br/><br/>`主机(inet'192.168.1.0/24')``192.168.1.0` |
| [](<>) `人质面具` ( `内特` ) → `内特`<br/><br/>计算地址网络的主机掩码。<br/><br/>`主机掩码(inet'192.168.23.20/30')``0.0.0.3` |
| [](<>) `inet_合并` ( `内特`, `内特` ) → `苹果酒`<br/><br/>计算包含两个给定网络的最小网络。<br/><br/>`inet_merge(inet'192.168.1.5/24',inet'192.168.2.5/24')``192.168.0.0/22` |
| [](<>) `同一个家庭` ( `内特`, `内特` ) → `布尔值`<br/><br/>测试地址是否属于同一IP系列。<br/><br/>`inet_同一系列(inet'192.168.1.5/24',inet':1')``f` |
| [](<>) `蒙面人` ( `内特` ) → `整数`<br/><br/>以位为单位返回网络掩码长度。<br/><br/>`masklen(inet'192.168.1.5/24')``24` |
| [](<>) `网络掩码` ( `内特` ) → `内特`<br/><br/>计算地址网络的网络掩码。<br/><br/>`网络掩码(inet'192.168.1.5/24')``255.255.255.0` |
| [](<>) `网络` ( `内特` ) → `苹果酒`<br/><br/>返回地址的网络部分,将网络掩码右侧的内容置零。(这相当于将值转换为`苹果酒`.)<br/><br/>`网络(inet'192.168.1.5/24')``192.168.1.0/24` |
| [](<>) `戴上面具` ( `内特`, `整数` ) → `内特`<br/><br/>设置网络掩码的长度`内特`价值地址部分不变。<br/><br/>`梅斯克伦(inet'192.168.1.5/24',16)``192.168.1.5/16` |
| `戴上面具` ( `苹果酒`, `整数` ) → `苹果酒`<br/><br/>设置网络掩码的长度`苹果酒`价值新网络掩码右侧的地址位设置为零。<br/><br/>`梅斯克伦(cidr'192.168.1.0/24',16)``192.168.0.0/16` |
| [](<>) `文本` ( `内特` ) → `文本`<br/><br/>以文本形式返回未修改的IP地址和网络掩码长度。(这与显式强制转换的结果相同。)`文本`.)<br/><br/>`文本(inet'192.168.1.5')``192.168.1.5/32` |
### 提示
这个`阿伯雷夫`, `主办``文本`这些功能主要用于为IP地址提供可选的显示格式。
MAC地址类型,`马卡德尔``macaddr8`,支持中所示的常用比较运算符[表9.1](functions-comparison.html#FUNCTIONS-COMPARISON-OP-TABLE)以及中显示的特殊功能[表9.40](functions-net.html#MACADDR-FUNCTIONS-TABLE).此外,它们还支持按位逻辑运算符`~`, `&``|`(不是,和或),正如上面显示的IP地址。
**表9.40。MAC地址函数**
| 作用<br/><br/>描述<br/><br/>例子 |
| -------------------------- |
| [](<>) `特鲁克` ( `马卡德尔` ) → `马卡德尔`<br/><br/>将地址的最后3个字节设置为零。剩余的前缀可以与特定制造商关联(使用PostgreSQL中未包含的数据)。<br/><br/>`trunc(macaddr'12:34:56:78:90:ab')``12:34:56:00:00:00` |
| `特鲁克` ( `macaddr8` ) → `macaddr8`<br/><br/>将地址的最后5个字节设置为零。剩余的前缀可以与特定制造商关联(使用PostgreSQL中未包含的数据)。<br/><br/>`trunc(macaddr8'12:34:56:78:90:ab:cd:ef')``12:34:56:00:00:00:00:00` |
| [](<>) `macaddr8_set7bit` ( `macaddr8` ) → `macaddr8`<br/><br/>将地址的第7位设置为1,创建被称为修改的EUI-64,以包含在IPv6地址中。<br/><br/>`macaddr8_set7bit(macaddr8'00:34:56:ab:cd:ef')``02:34:56:ff:fe:ab:cd:ef` |
## 9.23.子查询表达式
[9.23.1.`存在`](functions-subquery.html#FUNCTIONS-SUBQUERY-EXISTS)
[9.23.2.`在里面`](functions-subquery.html#FUNCTIONS-SUBQUERY-IN)
[9.23.3.`不在`](functions-subquery.html#FUNCTIONS-SUBQUERY-NOTIN)
[9.23.4.`任何`/`一些`](functions-subquery.html#FUNCTIONS-SUBQUERY-ANY-SOME)
[9.23.5.`全部的`](functions-subquery.html#FUNCTIONS-SUBQUERY-ALL)
[9.23.6. 单行比较](functions-subquery.html#id-1.5.8.29.15)
[](<>)[](<>)[](<>)[](<>)[](<>)[](<>)[](<>)
本节介绍PostgreSQL中可用的与SQL兼容的子查询表达式。本节中记录的所有表达式形式都返回布尔(真/假)结果。
### 9.23.1.`存在`
```
EXISTS (subquery)
```
的论点`存在`这是一种武断的行为`选择`声明,或*子查询*.对子查询进行求值,以确定它是否返回任何行。如果它返回至少一行,则`存在`是“真的”;如果子查询不返回任何行,则`存在`是“假”。
子查询可以引用周围查询中的变量,这些变量将在子查询的任何一次计算中充当常量。
子查询通常只执行足够长的时间,以确定是否至少返回一行,而不是一直执行到完成。编写具有副作用(例如调用序列函数)的子查询是不明智的;副作用是否发生可能无法预测。
由于结果只取决于是否返回任何行,而不取决于这些行的内容,因此子查询的输出列表通常并不重要。一种常见的编码约定是编写所有`存在`表格中的测试`存在(选择1,其中…)`。但是,此规则也有例外,例如使用`横断`.
这个简单的例子就像一个内部连接`可乐2`,但它最多为每一行生成一个输出行`表1`行,即使有多个匹配`表2`排:
```
SELECT col1
FROM tab1
WHERE EXISTS (SELECT 1 FROM tab2 WHERE col2 = tab1.col2);
```
### 9.23.2. `在里面`
```
expression IN (subquery)
```
右边是一个带括号的子查询,它必须只返回一列。对左侧表达式求值,并与子查询结果的每一行进行比较。结果`在里面`如果找到任何相等的子查询行,则为“true”。如果没有找到相等的行(包括子查询不返回行的情况),则结果为“false”。
请注意,如果左侧表达式产生null,或者如果没有相等的右侧值,并且至少有一行右侧表达式产生null,则`在里面`构造将为null,而不是false。这符合SQL关于空值布尔组合的常规规则。
就像`存在`,假设子查询将被完全计算是不明智的。
```
row_constructor IN (subquery)
```
这张照片的左边`在里面`是行构造函数,如中所述[第4.2.13节](sql-expressions.html#SQL-SYNTAX-ROW-CONSTRUCTORS).右侧是一个带括号的子查询,它返回的列数必须与左侧行中的表达式数完全相同。左侧表达式将按行计算并与子查询结果的每一行进行比较。结果`在里面`如果找到任何相等的子查询行,则为“true”。如果没有找到相等的行(包括子查询不返回行的情况),则结果为“false”。
通常,行中的空值是按照SQL布尔表达式的常规规则组合的。如果两行的所有对应成员都非空且相等,则认为这两行相等;如果任何对应的成员非空且不相等,则行不相等;否则,该行比较的结果未知(null)。如果所有每行结果都不相等或为空,且至少有一个为空,则`在里面`是空的。
### 9.23.3. `不在`
```
expression NOT IN (subquery)
```
右边是一个带括号的子查询,它必须只返回一列。对左侧表达式求值,并与子查询结果的每一行进行比较。结果`不在`如果只找到不相等的子查询行(包括子查询不返回行的情况),则为“true”。如果找到任何相等的行,则结果为“false”。
请注意,如果左侧表达式产生null,或者如果没有相等的右侧值,并且至少有一行右侧表达式产生null,则`不在`构造将为null,而不是true。这符合SQL关于空值布尔组合的常规规则。
就像`存在`,假设子查询将被完全计算是不明智的。
```
row_constructor NOT IN (subquery)
```
这张照片的左边`不在`是行构造函数,如中所述[第4.2.13节](sql-expressions.html#SQL-SYNTAX-ROW-CONSTRUCTORS).右侧是一个带括号的子查询,它返回的列数必须与左侧行中的表达式数完全相同。左侧表达式将按行计算并与子查询结果的每一行进行比较。结果`不在`如果只找到不相等的子查询行(包括子查询不返回行的情况),则为“true”。如果找到任何相等的行,则结果为“false”。
通常,行中的空值是按照SQL布尔表达式的常规规则组合的。如果两行的所有对应成员都非空且相等,则认为这两行相等;如果任何对应的成员非空且不相等,则行不相等;否则,该行比较的结果未知(null)。如果所有每行结果都不相等或为空,且至少有一个为空,则`不在`是空的。
### 9.23.4. `任何`/`一些`
```
expression operator ANY (subquery)
expression operator SOME (subquery)
```
右边是一个带括号的子查询,它必须只返回一列。使用给定的表达式计算左侧表达式,并与子查询结果的每一行进行比较*`操作人员`*,它必须产生一个布尔结果。结果`任何`如果得到任何真实结果,则为“真”。如果没有找到真正的结果(包括子查询不返回任何行的情况),则结果为“false”。
`一些`是的同义词`任何`. `在里面`相当于`=任何`.
请注意,如果没有成功,并且至少有一行右边的运算符结果为null,则`任何`构造将为null,而不是false。这符合SQL关于空值布尔组合的常规规则。
就像`存在`,假设子查询将被完全计算是不明智的。
```
row_constructor operator ANY (subquery)
row_constructor operator SOME (subquery)
```
这张照片的左边`任何`是行构造函数,如中所述[第4.2.13节](sql-expressions.html#SQL-SYNTAX-ROW-CONSTRUCTORS).右侧是一个带括号的子查询,它返回的列数必须与左侧行中的表达式数完全相同。使用给定的表达式,按行计算左侧表达式,并将其与子查询结果的每一行进行比较*`操作人员`*.结果`任何`如果对任何子查询行的比较返回true,则为“true”。如果每个子查询行的比较结果都返回false(包括子查询不返回行的情况),则结果为“false”。如果与子查询行的比较没有返回true,并且至少有一个比较返回NULL,则结果为NULL。
看见[第9.24.5节](functions-comparisons.html#ROW-WISE-COMPARISON)有关行构造函数比较的含义的详细信息。
### 9.23.5. `全部的`
```
expression operator ALL (subquery)
```
右边是一个带括号的子查询,它必须只返回一列。使用给定的表达式计算左侧表达式,并与子查询结果的每一行进行比较*`操作人员`*,它必须产生一个布尔结果。结果`全部的`如果所有行都返回true(包括子查询不返回行的情况),则为“true”。如果发现任何错误结果,则结果为“错误”。如果与子查询行的比较没有返回false,并且至少有一个比较返回NULL,则结果为NULL。
`不在`相当于`<>全部`.
就像`存在`,假设子查询将被完全计算是不明智的。
```
row_constructor operator ALL (subquery)
```
这张照片的左边`全部的`是行构造函数,如中所述[第4.2.13节](sql-expressions.html#SQL-SYNTAX-ROW-CONSTRUCTORS).右侧是一个带括号的子查询,它返回的列数必须与左侧行中的表达式数完全相同。使用给定的表达式,按行计算左侧表达式,并将其与子查询结果的每一行进行比较*`操作人员`*.结果`全部的`如果对所有子查询行(包括子查询不返回行的情况)进行比较,则为“true”。如果对任何子查询行的比较返回false,则结果为“false”。如果与子查询行的比较没有返回false,并且至少有一个比较返回NULL,则结果为NULL。
看见[第9.24.5节](functions-comparisons.html#ROW-WISE-COMPARISON)有关行构造函数比较的含义的详细信息。
### 9.23.6.单行比较
[](<>)
```
row_constructor operator (subquery)
```
左侧是行构造函数,如中所述[第4.2.13节](sql-expressions.html#SQL-SYNTAX-ROW-CONSTRUCTORS).右侧是一个带括号的子查询,它返回的列数必须与左侧行中的表达式数完全相同。此外,子查询不能返回多行。(如果返回零行,则结果为空。)左侧将按行计算并与单个子查询结果行进行比较。
看见[第9.24.5节](functions-comparisons.html#ROW-WISE-COMPARISON)有关行构造函数比较的含义的详细信息。
## 9.13.文本搜索函数和运算符
[](<>)[](<>)
[表9.41](functions-textsearch.html#TEXTSEARCH-OPERATORS-TABLE),[表9.42](functions-textsearch.html#TEXTSEARCH-FUNCTIONS-TABLE)[表9.43](functions-textsearch.html#TEXTSEARCH-FUNCTIONS-DEBUG-TABLE)总结全文搜索提供的函数和运算符。看见[第12章](textsearch.html)有关PostgreSQL文本搜索功能的详细说明。
**表9.41。文本搜索操作员**
| 操作人员<br/><br/>描述<br/><br/>例子 |
| ---------------------------- |
| `tsvector` `@@` `tsquery``布尔值`<br/><br/>`tsquery` `@@` `tsvector``布尔值`<br/><br/>`tsvector`火柴`tsquery`? (参数可以按任意顺序给出。)<br/><br/>`to_tsvector(“肥猫吃老鼠”)@@to_tsquery(“猫和老鼠”)``t` |
| `文本` `@@` `tsquery``布尔值`<br/><br/>在隐式调用`to_tsvector()`火柴`tsquery`?<br/><br/>`“肥猫吃老鼠”@@to_tsquery(“猫和老鼠”)``t` |
| `tsvector` `@@@` `tsquery``布尔值`<br/><br/>`tsquery` `@@@` `tsvector` → `布尔值`<br/><br/>这是一个不推荐使用的同义词`@@`.<br/><br/>`to_tsvector(“肥猫吃老鼠”)@@@to_tsquery(“猫和老鼠”)``t` |
| `tsvector` `||` `tsvector``tsvector`<br/><br/>Concatenates two`tsvector`s. If both inputs contain lexeme positions, the second input's positions are adjusted accordingly.<br/><br/>`'a:1 b:2'::tsvector || 'c:1 d:2 b:3'::tsvector``'a':1 'b':2,5 'c':3 'd':4` |
| `tsquery` `&&` `tsquery``tsquery`<br/><br/>ANDs two`tsquery`s together, producing a query that matches documents that match both input queries.<br/><br/>`'fat | rat'::tsquery && 'cat'::tsquery``( 'fat' | 'rat' ) & 'cat'` |
| `tsquery` `||` `tsquery``tsquery`<br/><br/>ORs two`tsquery`s together, producing a query that matches documents that match either input query.<br/><br/>`'fat | rat'::tsquery || 'cat'::tsquery``'fat' | 'rat' | 'cat'` |
| `!!` `tsquery``tsquery`<br/><br/>Negates a`tsquery`, producing a query that matches documents that do not match the input query.<br/><br/>`!! 'cat'::tsquery``!'cat'` |
| `tsquery` `<->` `tsquery``tsquery`<br/><br/>Constructs a phrase query, which matches if the two input queries match at successive lexemes.<br/><br/>`to_tsquery('fat') <-> to_tsquery('rat')``'fat' <-> 'rat'` |
| `tsquery` `@>` `tsquery``boolean`<br/><br/>Does first`tsquery`contain the second? (This considers only whether all the lexemes appearing in one query appear in the other, ignoring the combining operators.)<br/><br/>`'cat'::tsquery @> 'cat & rat'::tsquery``f` |
| `tsquery` `<@` `tsquery``boolean`<br/><br/>Is first`tsquery`contained in the second? (This considers only whether all the lexemes appearing in one query appear in the other, ignoring the combining operators.)<br/><br/>`'cat'::tsquery <@ 'cat & rat'::tsquery``t`<br/><br/>`'cat'::tsquery <@ '!cat & rat'::tsquery``t` |
In addition to these specialized operators, the usual comparison operators shown in[Table 9.1](functions-comparison.html#FUNCTIONS-COMPARISON-OP-TABLE)are available for types`tsvector`and`tsquery`. These are not very useful for text searching but allow, for example, unique indexes to be built on columns of these types.
**Table 9.42. Text Search Functions**
| Function<br/><br/>Description<br/><br/>Example(s) | | | | | | | | |
| ------------------------------------------------- | --- | --- | --- | --- | --- | --- | --- | --- |
| [](<>) `array_to_tsvector`(`文本[]` ) → `tsvector`<br/><br/>将词素数组转换为`tsvector`.给定的字符串按原样使用,无需进一步处理。<br/><br/>`数组_to_tsvector(“{fat,cat,rat}”)::text[]``“猫”“胖”“老鼠”` | | | | | | | | |
| [](<>) `获取当前配置` ( ) → `regconfig`<br/><br/>返回当前默认文本搜索配置(由设置)的OID[违约\_文本\_搜索\_配置](runtime-config-client.html#GUC-DEFAULT-TEXT-SEARCH-CONFIG)).<br/><br/>`获取当前配置``英语` | | | | | | | | |
| [](<>) `长` ( `tsvector` ) → `整数`<br/><br/>返回列表中的词素数`tsvector`.<br/><br/>`长度('脂肪:2,4猫:3大鼠:5A'::tsvector)``3.` | | | | | | | | |
| [](<>) `纽诺德` ( `tsquery` ) → `整数`<br/><br/>返回列表中词素加运算符的数目`tsquery`.<br/><br/>`numnode(“(脂肪和老鼠)|猫”::tsquery)``5.` | | | | | | | | |
| [](<>) `普莱托·尤茨基` ( [ *`配置`* `regconfig`, ] *`查询`* `文本` ) → `tsquery`<br/><br/>将文本转换为`tsquery`,根据指定或默认配置规范化单词。忽略字符串中的任何标点符号(它不确定查询运算符)。结果查询匹配文本中包含所有非停止词的文档。<br/><br/>`普兰托·尤茨基(‘英语’、‘胖老鼠’)``“胖子”和“老鼠”` | | | | | | | | |
| [](<>) `短语to_tsquery` ( [ *`配置`* `regconfig`, ] *`查询`* `文本` ) → `tsquery`<br/><br/>将文本转换为`tsquery`,根据指定或默认配置规范化单词。忽略字符串中的任何标点符号(它不确定查询运算符)。结果查询匹配包含文本中所有非停止词的短语。<br/><br/>`短语to_tsquery(“英语”,“肥鼠”)``“肥胖”<->“老鼠”`<br/><br/>`短语to_tsquery(‘英语’、‘猫和老鼠’)``“猫”<2>“老鼠”` | | | | | | | | |
| [](<>) `网络搜索` ( [ *`配置`* `regconfig`, ] *`查询`* `文本` ) → `tsquery`<br/><br/>将文本转换为`tsquery`,根据指定或默认配置规范化单词。引用的单词序列被转换为短语测试。“or”一词被理解为产生or运算符,破折号产生NOT运算符;其他标点符号被忽略。这近似于一些常见的web搜索工具的行为。<br/><br/>`websearch_to_tsquery('english'、'fat rat'或cat dog')``“胖”<->“老鼠”|“猫”和“狗”` | | | | | | | | |
| [](<>) `栎树` ( `tsquery` ) → `文本`<br/><br/>生成可转位部分的表示形式`tsquery`.结果是空的或只是`T`指示不可索引的查询。<br/><br/>`querytree('foo&!bar':tsquery)``“福”` | | | | | | | | |
| [](<>) `设定重量` ( *`矢量`* `tsvector`, *`重量`* `“char”` ) → `tsvector`<br/><br/>分配指定的*`重量`*每个元素的*`矢量`*.<br/><br/>`设定体重('脂肪:2,4猫:3大鼠:5B'::tsvector'A')``“猫”:3A“脂肪”:2A,4A“老鼠”:5A` | | | | | | | | |
| [](<>) `设定重量` ( *`矢量`* `tsvector`, *`重量`* `“char”`, *`词位`* `文本[]` ) → `tsvector`<br/><br/>分配指定的*`重量`**`矢量`*列在*`词位`*.<br/><br/>`设定体重('脂肪:2,4猫:3鼠:5,6B'::tsvector'A','{cat,rat}')``“猫”:3A“脂肪”:2,4“老鼠”:5A、6A` | | | | | | | | |
| [](<>) `带` ( `tsvector` ) → `tsvector`<br/><br/>从中删除位置和权重`tsvector`.<br/><br/>`条状('脂肪:2,4猫:3鼠:5A'::tsvector)``“猫”“胖”“老鼠”` | | | | | | | | |
| [](<>) `质疑` ( [ *`配置`* `regconfig`, ] *`查询`* `文本` ) → `tsquery`<br/><br/>将文本转换为`tsquery`,根据指定或默认配置规范化单词。这些单词必须用有效的字母组合`tsquery`接线员。<br/><br/>`to_tsquery('english'、'The&Fat&Rats')``“胖子”和“老鼠”` | | | | | | | | |
| [](<>) `到_tsvector` ( [ *`配置`* `regconfig`, ] *`文件`* `文本` ) → `tsvector`<br/><br/>将文本转换为`tsvector`,根据指定或默认配置规范化单词。结果中包含位置信息。<br/><br/>`to_tsvector(“英语”,“肥鼠”)``“肥胖”:2“老鼠”:3` | | | | | | | | |
| `到_tsvector` ( [ *`配置`* `regconfig`, ] *`文件`* `json` ) → `tsvector`<br/><br/>`到_tsvector` ( [ *`配置`* `regconfig`, ] *`文件`* `jsonb` ) → `tsvector`<br/><br/>将JSON文档中的每个字符串值转换为`tsvector`,根据指定或默认配置规范化单词。然后将结果连接到文档中以生成输出。位置信息的生成就像每对字符串值之间存在一个停止字一样。(注意,当输入为空时,JSON对象字段的“文档顺序”取决于实现。)`jsonb`; 观察示例中的差异。)<br/><br/>`to_tsvector('english','{“aa”:“肥鼠”,“b”:“狗”}'::json)``“狗”:5“脂肪”:2“老鼠”:3`<br/><br/>`to_tsvector('english','{“aa”:“肥鼠”,“b”:“狗”}'::jsonb)``“狗”:1“脂肪”:4“老鼠”:5` | | | | | | | | |
| [](<>) `json_to_tsvector` ( [ *`配置`* `regconfig`, ] *`文件`* `json`, *`滤器`* `jsonb` ) → `tsvector`<br/><br/>[](<>) `jsonb_to_tsvector` ( [ *`配置`* `regconfig`, ] *`文件`* `jsonb`, *`滤器`* `jsonb` ) → `tsvector`<br/><br/>选择JSON文档中由*`滤器`*把每一个都变成一个`tsvector`,根据指定或默认配置规范化单词。然后将结果连接到文档中以生成输出。位置信息的生成就像每对选定项目之间存在一个停止字一样。(注意,当输入为空时,JSON对象字段的“文档顺序”取决于实现。)`jsonb`)The*`滤器`*一定是个`jsonb`包含零个或多个以下关键字的数组:`“字符串”`(包括所有字符串值),`“数字”`(包括所有数值),`“布尔”`(包括所有布尔值),`“钥匙”`(包括所有钥匙),或`“全部”`(包括上述所有内容)。作为特例*`滤器`*也可以是这些关键字之一的简单JSON值。<br/><br/>`json_to_tsvector('english','{a:'The Fat Rats',b:'123}'::json,[“string”,“numeric”])``“123”:5“脂肪”:2“老鼠”:3`<br/><br/>`json_to_tsvector('english','{cat:“肥鼠”,“狗”:123}'::json,'all')``“123”:9“猫”:1“狗”:7“肥”:4“鼠”:5` | | | | | | | | |
| [](<>) `删除` ( *`矢量`* `tsvector`, *`词素`* `文本` ) → `tsvector`<br/><br/>删除给定事件的任何出现*`词素`**`矢量`*.<br/><br/>`ts_delete('fat:2,4 cat:3 rat:5A'::tsvector'fat')``“猫”:3“老鼠”:5A` | | | | | | | | |
| `删除` ( *`矢量`* `tsvector`, *`词位`* `文本[]` ) → `tsvector`<br/><br/>删除中出现的所有词素*`词位`**`矢量`*.<br/><br/>`ts_delete('fat:2,4 cat:3 rat:5A'::tsvector,数组['fat','rat']))``“猫”:3` | | | | | | | | |
| [](<>) `ts_过滤器` ( *`矢量`* `tsvector`, *`砝码`* `“char”[]` ) → `tsvector`<br/><br/>仅选择具有给定属性的元素*`砝码`**`矢量`*.<br/><br/>`ts_过滤器('fat:2,4 cat:3b,7c rat:5A'::tsvector,{a,b}')``“猫”:3B“老鼠”:5A` | | | | | | | | |
| [](<>) `标题` ( [ *`配置`* `regconfig`, ] *`文件`* `文本`, *`查询`* `tsquery` [, *`选项`* `文本` ] ) → `文本`<br/><br/>以缩写形式显示*`查询`*在*`文件`*,必须是原始文本,而不是`tsvector`.在匹配到查询之前,文档中的单词将根据指定或默认配置进行规范化。中讨论了此函数的使用[第12.3.4节](textsearch-controls.html#TEXTSEARCH-HEADLINE),它还描述了可用的*`选项`*.<br/><br/>`标题(‘肥猫吃老鼠’,‘猫’)``肥猫吃掉了老鼠。` | | | | | | | | |
| `标题` ( [ *`配置`* `regconfig`, ] *`文件`* `json`, *`查询`* `tsquery` [, *`选项`* `文本` ] ) → `文本`<br/><br/>`标题` ( [ *`配置`* `regconfig`, ] *`文件`* `jsonb`, *`查询`* `tsquery` [, *`选项`* `文本` ] ) → `文本`<br/><br/>以缩写形式显示与*`查询`*出现在JSON中的字符串值中*`文件`*看见[第12.3.4节](textsearch-controls.html#TEXTSEARCH-HEADLINE)更多细节。<br/><br/>`ts_标题(“{”cat:“倾盆大雨的猫和狗“}”)::jsonb,'cat')``{“猫”:“猫和狗”}` | | | | | | | | |
| [](<>) `T_秩` ( \[ *`砝码`* `真实的`, ] *`矢量`* `tsvector`, *`查询`* `tsquery` [, *`规范化`* `整数` ] ) → `真实的`<br/><br/>计算一个分数,显示*`矢量`*匹配*`查询`*看见[第12.3.3节](textsearch-controls.html#TEXTSEARCH-RANKING)详细信息。<br/><br/>`T_rank(to_tsvector(“雨中的猫和狗”),“猫”)``0.06079271` | | | | | | | | |
| [](<>) `T_rank_cd` ( \[ *`砝码`* `真实的`, ] *`矢量`* `tsvector`, *`查询`* `tsquery` [, *`规范化`* `整数` ] ) → `真实的`<br/><br/>计算一个分数,显示*`矢量`*匹配*`查询`*,使用覆盖密度算法。看见[第12.3.3节](textsearch-controls.html#TEXTSEARCH-RANKING)详细信息。<br/><br/>`ts_rank_cd(to_tsvector(‘雨中的猫和狗’),‘猫’)``0.1` | | | | | | | | |
| [](<>) `重写` ( *`查询`* `tsquery`, *`目标`* `tsquery`, *`代替`* `tsquery` ) → `tsquery`<br/><br/>替换出现的*`目标`*具有*`代替`**`查询`*看见[第12.4.2.1节](textsearch-features.html#TEXTSEARCH-QUERY-REWRITING)详细信息。<br/><br/>`t|u rewrite('a&b'::tsquery,'a'::tsquery,'foo | bar'::tsquery)``“b”和(“foo”|“bar”)` | | | | | | | | |
| `重写` ( *`查询`* `tsquery`, *`选择`* `文本` ) → `tsquery`<br/><br/>替换部分*`查询`*根据通过执行`选择`命令看见[第12.4.2.1节](textsearch-features.html#TEXTSEARCH-QUERY-REWRITING)详细信息。<br/><br/>`选择t_rewrite('a&b'::tsquery,'SELECT t,s FROM alias')``“b”和(“foo”|“bar”)` | | | | | | | | |
| [](<>) `Tsu_短语` ( *`问题1`* `tsquery`, *`问题2`* `tsquery` ) → `tsquery`<br/><br/>构造一个短语查询,用于搜索*`问题1`**`问题2`*在连续的词素中(与`<->`接线员)。<br/><br/>`短语(to_tsquery('fat')、to_tsquery('cat'))``“胖”<->“猫”` | | | | | | | | |
| `Tsu_短语` ( *`问题1`* `tsquery`, *`问题2`* `tsquery`, *`距离`* `整数` ) → `tsquery`<br/><br/>构造一个短语查询,用于搜索*`问题1`**`问题2`*这种情况确实发生了*`距离`*词素分离。<br/><br/>`短语(to_tsquery('fat')、to_tsquery('cat')、10)``“肥猫”` | | | | | | | | |
| [](<>) `TSU-to-U阵列` ( `tsvector` ) → `文本[]`<br/><br/>皈依`tsvector`到一系列词汇表。<br/><br/>`tsvector_to_数组('fat:2,4 cat:3 rat:5A'::tsvector)``{猫、肥、鼠}` | | | | | | | | |
| [](<>) `不安` ( `tsvector` ) → `一套记录` ( *`词素`* `文本`, *`位置`* `smallint[]`, *`砝码`* `文本` )<br/><br/>扩展`tsvector`分成一组行,每个词素一行。<br/><br/>`从unnest中选择*('cat:3脂肪:2,4大鼠:5A'::tsvector)```<br/><br/>\```<br/>词素 | 位置 | 砝码<br/>--------+-----------+---------<br/>猫 | {3} | {D}<br/>脂肪 | {2,4} | {D,D}<br/>老鼠 | {5} | {A}<br/><br/>\``` |
### 笔记
所有接受可选文本的文本搜索功能`regconfig`参数将使用[违约\_文本\_搜索\_配置](runtime-config-client.html#GUC-DEFAULT-TEXT-SEARCH-CONFIG)当这个论点被省略时。
中的功能[表9.43](functions-textsearch.html#TEXTSEARCH-FUNCTIONS-DEBUG-TABLE)单独列出,因为它们通常不用于日常文本搜索操作。它们主要有助于开发和调试新的文本搜索配置。
**表9.43。文本搜索调试功能**
| 作用<br/><br/>描述<br/><br/>例子 |
| -------------------------- |
| [](<>) `调试` ( [ *`配置`* `regconfig`, ] *`文件`* `文本` ) → `一套记录` ( *`别名`* `文本`,*`描述`* `文本`,*`令牌`* `文本`,*`字典`* `字典[]`,*`字典`* `规范的`,*`词位`* `文本[]`)<br/><br/>从*`文档`*根据指定的或默认的文本搜索配置,并返回有关如何处理每个令牌的信息。看[第 12.8.1 节](textsearch-debugging.html#TEXTSEARCH-CONFIGURATION-TESTING)详情。<br/><br/>`ts_debug('english', '最亮的超新星')``(asciiword,"Word, all ASCII",The,{english_stem},english_stem,{}) ...` |
| [](<>) `ts_lexize`(*`听写`* `规范的`,*`令牌`* `文本`) →`文本[]`<br/><br/>如果字典已知输入标记,则返回替换词位数组;如果字典已知标记但它是停用词,则返回空数组;如果不是已知词,则返回 NULL。看[第 12.8.3 节](textsearch-debugging.html#TEXTSEARCH-DICTIONARY-TESTING)详情。<br/><br/>`ts_lexize('english_stem', '星星')``{星星}` |
| [](<>) `ts_parse`(*`解析器名称`* `文本`,*`文档`* `文本`) →`记录集`(*`小孩子`* `整数`,*`令牌`* `文本`)<br/><br/>*`文档`*使用命名解析器。看[第 12.8.2 节](textsearch-debugging.html#TEXTSEARCH-PARSER-TESTING)详情。<br/><br/>`ts_parse('default', 'foo - bar')``(1,富) ...` |
| `ts_parse`(*`parser_oid`* `样的`,*`文档`* `文本`) →`记录集`(*`小孩子`* `整数`,*`令牌`* `文本`)<br/><br/>*`文档`*使用由 OID 指定的解析器。看[第 12.8.2 节](textsearch-debugging.html#TEXTSEARCH-PARSER-TESTING)详情。<br/><br/>`ts_parse(3722, 'foo - bar')``(1,富) ...` |
| [](<>) `ts_token_type`(*`解析器名称`* `文本`) →`记录集`(*`小孩子`* `整数`,*`别名`* `文本`,*`描述`* `文本`)<br/><br/>返回一个表,该表描述了命名解析器可以识别的每种类型的标记。看[第 12.8.2 节](textsearch-debugging.html#TEXTSEARCH-PARSER-TESTING)详情。<br/><br/>`ts_token_type('默认')``(1,asciiword,"Word, all ASCII") ...` |
| `ts_token_type`(*`parser_oid`* `样的`) →`记录集`(*`小孩子`* `整数`,*`别名`* `文本`,*`描述`* `文本`)<br/><br/>返回一个表,该表描述了由 OID 指定的解析器可以识别的每种类型的标记。看[第 12.8.2 节](textsearch-debugging.html#TEXTSEARCH-PARSER-TESTING)详情。<br/><br/>`ts_token_type(3722)``(1,asciiword,"Word, all ASCII") ...` |
| [](<>) `ts_stat`(*`查询`* `文本` [,权重*` `*文本` `]) →`记录集`(*`单词`* `文本`,*`ndoc`* `整数`,*`入门`* `整数`)<br/><br/>执行*`查询`*,它必须返回一个`向量`列,并返回有关数据中包含的每个不同词位的统计信息。看[第 12.4.4 节](textsearch-features.html#TEXTSEARCH-STATISTICS)详情。<br/><br/>`ts_stat('从 apod 中选择向量')``(foo,10,15) ...` |
此差异已折叠。
## F.15。模糊格式
[F.15.1。Soundex](fuzzystrmatch.html#id-1.11.7.24.6)[F.15.2。莱文斯坦](fuzzystrmatch.html#id-1.11.7.24.7)[F.15.3。变音](fuzzystrmatch.html#id-1.11.7.24.8)[F.15.4。双变音](fuzzystrmatch.html#id-1.11.7.24.9)
[](<>)
这个`模糊格式`模块提供了几个函数来确定字符串之间的相似性和距离。
### 小心
目前`soundex`,`变音`,`数字电话``dmetaphone_alt`函数不能很好地与多字节编码(如UTF-8)配合使用。
该模块被认为是“受信任的”,也就是说,它可以由拥有`创造`当前数据库的权限。
### F.15.1。Soundex
Soundex系统是一种通过将相似的发音名称转换为相同代码来匹配它们的方法。它最初在1880年、1900年和1910年的美国人口普查中使用。请注意,Soundex对于非英语名称不是很有用。
这个`模糊格式`模块提供两个使用Soundex代码的功能:
[](<>)[](<>)
```
soundex(text) returns text
difference(text, text) returns int
```
这个`soundex`函数将字符串转换为其Soundex代码。这个`差别`函数将两个字符串转换为它们的Soundex代码,然后报告匹配代码位置的数量。由于Soundex代码有四个字符,因此结果的范围从零到四,零表示不匹配,四表示完全匹配。(因此,该函数被错误命名为-`相似性`这是一个更好的名字。)
以下是一些用法示例:
```
SELECT soundex('hello world!');
SELECT soundex('Anne'), soundex('Ann'), difference('Anne', 'Ann');
SELECT soundex('Anne'), soundex('Andrew'), difference('Anne', 'Andrew');
SELECT soundex('Anne'), soundex('Margaret'), difference('Anne', 'Margaret');
CREATE TABLE s (nm text);
INSERT INTO s VALUES ('john');
INSERT INTO s VALUES ('joan');
INSERT INTO s VALUES ('wobbly');
INSERT INTO s VALUES ('jack');
SELECT * FROM s WHERE soundex(nm) = soundex('john');
SELECT * FROM s WHERE difference(s.nm, 'john') > 2;
```
### F.15.2。莱文施坦
此函数用于计算两个字符串之间的Levenshtein距离:
[](<>)[](<>)
```
levenshtein(text source, text target, int ins_cost, int del_cost, int sub_cost) returns int
levenshtein(text source, text target) returns int
levenshtein_less_equal(text source, text target, int ins_cost, int del_cost, int sub_cost, int max_d) returns int
levenshtein_less_equal(text source, text target, int max_d) returns int
```
二者都`来源``目标`可以是任何非空字符串,最多255个字符。成本参数分别指定字符插入、删除或替换的费用。您可以省略成本参数,就像在函数的第二个版本中一样;在这种情况下,它们都默认为1。
`levenshtein_less_equal`是Levenshtein函数的一个加速版本,仅适用于感兴趣的小距离。如果实际距离小于或等于`麦克斯`然后`levenshtein_less_equal`返回正确的距离;否则,它将返回大于`麦克斯`如果`麦克斯`如果是负面的,那么行为与`莱文施坦`.
例如:
```
test=# SELECT levenshtein('GUMBO', 'GAMBOL');
levenshtein
### F.15.3. Metaphone
Metaphone, like Soundex, is based on the idea of constructing a representative code for an input string. Two strings are then deemed similar if they have the same codes.
This function calculates the metaphone code of an input string:
[]()
```
变音(文本源,int max_output_length)返回文本
```
`source` has to be a non-null string with a maximum of 255 characters. `max_output_length` sets the maximum length of the output metaphone code; if longer, the output is truncated to this length.
Example:
```
测试=#选择变音('GUMBO',4);变音
### F.15.4。双变音
双变音系统为给定的输入字符串计算两个“听起来像”的字符串——“主”和“备用”。在大多数情况下,它们是相同的,但对于非英语名称,它们可能会有点不同,这取决于发音。这些函数计算主代码和备用代码:
[](<>)[](<>)
```
dmetaphone(text source) returns text
dmetaphone_alt(text source) returns text
```
输入字符串没有长度限制。
例子:
```
test=# SELECT dmetaphone('gumbo');
dmetaphone
```
## 60.4.进一步阅读
以下资源包含有关遗传算法的其他信息:
- [《搭便车者进化计算指南》](http://www.faqs.org/faqs/ai-faq/genetic/part1/),(常见问题解答<news://comp.ai.genetic>)
- [进化计算及其在艺术设计中的应用](https://www.red3d.com/cwr/evolve.html)克雷格·雷诺兹著
- [\[elma04\]](biblio.html#ELMA04)
- [\[方\]](biblio.html#FONG)
## 60.1.查询处理是一个复杂的优化问题
在所有关系运算符中,最难处理和优化的是*参加*。可能的查询计划数随查询中的联接数呈指数增长。进一步的优化工作是由各种*联接方法*(例如,PostgreSQL中的嵌套循环、散列联接、合并联接)来处理单个联接和各种*索引*(例如,PostgreSQL中的B树、哈希、GiST和GIN)作为关系的访问路径。
普通的PostgreSQL查询优化器执行*近乎穷尽的搜索*在替代战略的空间上。该算法首先在IBM的System R数据库中引入,生成一个接近最优的联接顺序,但当查询中的联接数量增加时,可能会占用大量的时间和内存空间。这使得普通的PostgreSQL查询优化器不适合连接大量表的查询。
在德国弗赖贝格的矿业和技术大学自动控制研究所遇到了一些问题,当它想使用PostgreSQL作为一个基于决策支持知识的系统维护电网的后端时。DBMS需要为基于知识的系统的推理机处理大型连接查询。使用普通查询优化器进行的这些查询中的连接数不可行。
下面我们将介绍*遗传算法*以对涉及大量联接的查询有效的方式解决联接排序问题。
## 60.2.遗传算法
遗传算法(GA)是一种通过随机搜索操作的启发式优化方法。优化问题的可能解集被视为*人口*属于*个人*.个人对环境的适应程度由其*健身*.
搜索空间中个体的坐标由*染色体*,本质上是一组字符串。A.*基因*是染色体的一个分段,它编码被优化的单个参数的值。基因的典型编码可能是*二进制的**整数*.
通过模拟进化操作*重组*,*突变**选择*新一代的搜索点显示出比他们的祖先更高的平均适合度。[图60.1](geqo-intro2.html#GEQO-FIGURE)说明了这些步骤。
**图60.1。遗传算法的结构**
根据公司的说法。人工智能。遗传常见问题解答遗传算法不是对问题解决方案的纯随机搜索,这一点无论怎样强调都不过分。遗传算法使用随机过程,但结果明显是非随机的(优于随机)。
## 60.3.PostgreSQL中的遗传查询优化(GEQO)
[60.3.1. 使用GEQO生成可能的计划](geqo-pg-intro.html#id-1.10.12.5.6)
[60.3.2. PostgreSQL GEQO的未来实施任务](geqo-pg-intro.html#GEQO-FUTURE)
GEQO模块处理查询优化问题时,就像处理著名的旅行商问题(TSP)一样。可能的查询计划被编码为整数字符串。每个字符串表示从一个查询关系到下一个查询关系的连接顺序。例如,连接树
```
/\
/\ 2
/\ 3
4 1
```
由整数字符串“4-1-3-2”编码,这意味着首先连接关系“4”和“1”,然后是“3”,然后是“2”,其中1、2、3、4是PostgreSQL优化器中的关系ID。
PostgreSQL中GEQO实现的具体特征如下:
- a的用法*稳态*GA(替换群体中最不合适的个体,而不是整代替换)允许快速收敛到改进的查询计划。这对于在合理的时间内处理查询至关重要;
- 使用*边缘复合交叉*特别适用于通过遗传算法求解TSP时保持较低的边缘损失;
- 不推荐使用突变作为遗传算子,因此不需要修复机制来生成合法的TSP旅行。
GEQO模块的部分内容改编自D.Whitley的Genitor算法。
GEQO模块允许PostgreSQL查询优化器通过非穷举搜索有效地支持大型连接查询。
### 60.3.1.使用GEQO生成可能的计划
GEQO规划流程使用标准规划器代码生成扫描个人关系的计划。然后使用遗传方法制定加入计划。如上所示,每个候选连接计划由一个连接基本关系的序列表示。在初始阶段,GEQO代码只是随机生成一些可能的连接序列。对于考虑的每个连接序列,将调用标准planner代码来估计使用该连接序列执行查询的成本。(对于连接序列的每个步骤,都会考虑所有三种可能的连接策略;并且所有最初确定的关系扫描计划都可用。估计成本是这些可能性中最便宜的。)估计成本较低的连接序列被认为比成本较高的连接序列“更适合”。遗传算法丢弃最不合适的候选。然后,通过组合更合适的候选基因来生成新的候选基因——也就是说,通过使用已知低成本连接序列的随机选择部分来创建新序列以供考虑。重复该过程,直到考虑到预设数量的连接序列;然后使用搜索过程中任何时候找到的最佳计划生成完成的计划。
这一过程本质上是不确定的,因为在最初的群体选择和随后的最佳候选者“突变”过程中都会进行随机选择。为了避免所选计划发生意外变化,每次运行GEQO算法时,都会用当前值重新启动随机数生成器[盖库\_种子](runtime-config-query.html#GUC-GEQO-SEED)参数设置。只要`蛤蟆籽`如果其他GEQO参数保持不变,那么将为给定的查询生成相同的计划(以及其他计划器输入,如统计数据)。要尝试不同的搜索路径,请尝试更改`蛤蟆籽`.
### 60.3.2.PostgreSQL GEQO的未来实施任务
改进遗传算法参数设置仍需努力。存档`src/backend/optimizer/geqo/geqo_main。C`例行公事`给我泳池大小``给我多少代`,我们必须为参数设置找到折衷方案,以满足两个相互竞争的要求:
- 查询计划的最优性
- 计算时间
在当前的实现中,通过从头开始运行standard planner的连接选择和成本估算代码来估计每个候选连接序列的适合度。由于不同的候选者使用相似的连接子序列,大量工作将被重复。通过保留子联接的成本估算,这可以大大加快速度。问题是要避免在保持这种状态时花费不合理的内存量。
在更基本的层面上,目前尚不清楚使用为TSP设计的GA算法来解决查询优化是否合适。在TSP的情况下,与任何子字符串(部分遍历)相关的成本独立于遍历的其余部分,但对于查询优化来说,这肯定不是真的。因此,边缘重组交叉是否是最有效的变异过程值得怀疑。
## 67.2.内置运算符类
PostgreSQL核心发行版包括中所示的GIN运算符类[表67.1](gin-builtin-opclasses.html#GIN-BUILTIN-OPCLASSES-TABLE)(中介绍的一些可选模块)[附录F](contrib.html)提供额外的轧棉机操作员课程。)
**表67.1。内置的GIN操作符类**
| 名称 | 可转位算子 |
| --- | ----- |
| `阵列运算` | `&&(任意数组,任意数组)` |
| `@>(任意数组,任意数组)` | |
| `<@(任意数组,任意数组)` | |
| `=(任意数组,任意数组)` | |
| `jsonb_ops` | `@>(jsonb,jsonb)` |
| `@? (jsonb,jsonpath)` | |
| `@@(jsonb,jsonpath)` | |
| `? (jsonb,文本)` | |
| `?|(jsonb,文本[])` | |
| `&nbsp;(jsonb,文本[])` | |
| `jsonb_路径_操作` | `@>(jsonb,jsonb)` |
| `@?(jsonb,jsonpath)` | |
| `@@(jsonb,jsonpath)` | |
| `Tsu ops` | `@@(tsvector,tsquery)` |
| `@@(tsvector,tsquery)` | |
类型的两个运算符类的`jsonb`(笑声)`jsonb_ops`是默认值。`jsonb_路径_操作`只支持少数运营商,但为这些运营商提供了更好的性能。湖[第8.14.4节](datatype-json.html#JSON-INDEXING)详细信息。
## 67.4.实施
[67.4.1. 快速更新技术](gin-implementation.html#GIN-FAST-UPDATE)
[67.4.2. 部分匹配算法](gin-implementation.html#GIN-PARTIAL-MATCH)
在内部,GIN索引包含在键上构造的B树索引,其中每个键都是一个或多个索引项(例如,数组的一个成员)的元素,叶页中的每个元组都包含指向堆指针的B树的指针(“发布树”),或者一个简单的堆指针列表(“发布列表”),当列表足够小,可以与键值一起放入一个索引元组时。[图67.1](gin-implementation.html#GIN-INTERNALS-FIGURE)说明了GIN索引的这些组件。
从PostgreSQL 9.1开始,索引中可以包含空键值。此外,占位符null也包含在索引中,用于索引为null或不包含键的索引项`提取值`。这允许搜索应该查找空项目的内容。
多列GIN索引是通过在复合值(列号、键值)上构建单个B树来实现的。不同列的键值可以是不同的类型。
**图67.1。杜松子酒**
### 67.4.1.快速更新技术
由于反向索引的本质,更新GIN索引的速度往往很慢:插入或更新一个堆行可能会导致多次插入索引(从索引项中提取的每个键对应一个)。GIN可以通过将新元组插入到一个临时的、未排序的待处理项列表中来推迟大部分工作。当表格被抽真空或自动分析时,或者`杜松子酒清洁待处理清单`函数,或者如果挂起列表大于[杜松子酒\_悬而未决的\_列表\_限度](runtime-config-client.html#GUC-GIN-PENDING-LIST-LIMIT),使用初始索引创建期间使用的相同批量插入技术将条目移动到主GIN数据结构。这大大提高了GIN索引的更新速度,甚至计算了额外的真空开销。此外,开销工作可以通过后台进程而不是前台查询处理来完成。
这种方法的主要缺点是,除了搜索常规索引外,搜索还必须扫描待处理项列表,因此大量待处理项列表将显著降低搜索速度。另一个缺点是,虽然大多数更新都很快,但导致挂起列表变得“太大”的更新会导致立即的清理周期,因此比其他更新慢得多。正确使用自动真空可以最大限度地减少这两个问题。
如果一致的响应时间比更新速度更重要,可以通过关闭`快速更新`GIN索引的存储参数。看见[创建索引](sql-createindex.html)详细信息。
### 67.4.2.部分匹配算法
GIN可以支持“部分匹配”查询,在这种查询中,查询不会确定一个或多个键的精确匹配,但可能的匹配属于合理狭窄的键值范围(在`比较`支持方法)。这个`提取查询`方法,而不是返回要精确匹配的键值,而是返回一个键值,该键值是要搜索的范围的下限,并设置`P匹配`这是真的。然后使用`比较部分`方法`比较部分`对于匹配的索引键,必须返回零;对于仍在要搜索的范围内的非匹配项,必须返回小于零;如果索引键超出了可以匹配的范围,则必须返回大于零。
## 67.6.局限性
GIN假设可转位运算符是严格的。这意味着`提取值`不会对空项值调用(而是自动创建占位符索引项),并且`提取查询`也不会对空查询值调用(相反,该查询被假定为不可满足)。但是请注意,支持包含在非null复合项或查询值中的null键值。
## 65.2.内置运算符类
PostgreSQL核心发行版包括中所示的GiST运算符类[表65.1](gist-builtin-opclasses.html#GIST-BUILTIN-OPCLASSES-TABLE)(中介绍的一些可选模块)[附录F](contrib.html)提供其他GiST运算符类。)
**表65.1。内置GiST运算符类**
| 名称 | 可转位算子 | 排序运算符 |
| --- | ----- | ----- |
| `箱子操作` | `<<(盒子,盒子)` | `<->(框、点)` |
| `&<(盒子,盒子)` | | |
| `&&(盒子,盒子)` | | |
| `&>(盒子,盒子)` | | |
| `>>(盒子,盒子)` | | |
| `~=(盒子,盒子)` | | |
| `@>(盒子,盒子)` | | |
| `<@(盒子,盒子)` | | |
| `&<|(盒子,盒子)` | | |
| `<<|(盒子,盒子)` | | |
| `|>>(盒子,盒子)` | | |
| `|&>(盒子,盒子)` | | |
| `(盒子,盒子)` | | |
| `@(盒子,盒子)` | | |
| `圆圈行动` | `<<(圆圈,圆圈)` | `<->(圆,点)` |
| `&<(圆圈,圆圈)` | | |
| `&>(圈,圈)` | | |
| `>>(圈,圈)` | | |
| `<@(圆圈,圆圈)` | | |
| `@>(圈,圈)` | | |
| `~=(圆圈,圆圈)` | | |
| `&&(圈,圈)` | | |
| `|>>(圈,圈)` | | |
| `<<|(圆圈,圆圈)` | | |
| `&<|(圆圈,圆圈)` | | |
| `|&>(圈,圈)` | | |
| `@(圈,圈)` | | |
| `(圆圈,圆圈)` | | |
| `内特奥普酒店` | `<(inet,inet)` | |
| `<<=(inet,inet)` | | |
| `>>(inet,inet)` | | |
| `>>=(inet,inet)` | | |
| `=(inet,inet)` | | |
| `<>(inet,inet)` | | |
| `<(inet,inet)` | | |
| `<=(inet,inet)` | | |
| `>(inet,inet)` | | |
| `>=(inet,inet)` | | |
| `&&(inet,inet)` | | |
| `multirange_ops` | `= (anymultirange, anymultirange)` | |
| `&& (anymultirange, anymultirange)` | | |
| `&& (anymultirange, anyrange)` | | |
| `@> (anymultirange, anyelement)` | | |
| `@> (anymultirange, anymultirange)` | | |
| `@> (anymultirange, anyrange)` | | |
| `<@ (anymultirange, anymultirange)` | | |
| `<@ (anymultirange, anyrange)` | | |
| `<< (anymultirange, anymultirange)` | | |
| `<< (anymultirange, anyrange)` | | |
| `>> (anymultirange, anymultirange)` | | |
| `>> (anymultirange, anyrange)` | | |
| `&< (anymultirange, anymultirange)` | | |
| `&< (anymultirange, anyrange)` | | |
| `&> (anymultirange, anymultirange)` | | |
| `&> (anymultirange, anyrange)` | | |
| `-|- (anymultirange, anymultirange)` | | |
| `-|- (anymultirange, anyrange)` | | |
| `point_ops` | `|>> (point, point)` | `<-> (point, point)` |
| `<< (point, point)` | | |
| `>> (point, point)` | | |
| `<<| (point, point)` | | |
| `~= (point, point)` | | |
| `<@ (point, box)` | | |
| `<@(点、多边形)` | | |
| `<@(点、圆)` | | |
| `保利奥普斯酒店` | `<<(多边形,多边形)` | `<->(多边形,点)` |
| `&<(多边形,多边形)` | | |
| `&>(多边形,多边形)` | | |
| `>>(多边形,多边形)` | | |
| `<@(多边形,多边形)` | | |
| `@>(多边形,多边形)` | | |
| `~=(多边形,多边形)` | | |
| `&&(多边形,多边形)` | | |
| `<<|(多边形,多边形)` | | |
| `&<|(多边形,多边形)` | | |
| `|&>(多边形,多边形)` | | |
| `|>>(多边形,多边形)` | | |
| `@(多边形,多边形)` | | |
| `(多边形,多边形)` | | |
| `射程行动` | `=(任意范围,任意范围)` | |
| `&&(任意范围,任意范围)` | | |
| `&&(任意范围,任意多范围)` | | |
| `@>(任意范围,任意元素)` | | |
| `@>(任意范围,任意范围)` | | |
| `@>(任意范围,任意多范围)` | | |
| `<@(任意范围,任意范围)` | | |
| `<@(任意范围,任意多范围)` | | |
| `<<(鹿角,鹿角)` | | |
| `<<(鹿角,鹿角)` | | |
| `>>(鹿角,鹿角)` | | |
| `>>(鹿角,鹿角)` | | |
| `&<(鹿角,鹿角)` | | |
| `&<(鹿角,鹿角)` | | |
| `&>(鹿角,鹿角)` | | |
| `&>(鹿角,鹿角)` | | |
| `-|-(鹿角,鹿角)` | | |
| `-|-(鹿角,鹿角)` | | |
| `Tsu_ops` | `<@(tsquery,tsquery)` | |
| `@>(tsquery,tsquery)` | | |
| `Tsu ops` | `@@(tsvector,tsquery)` | |
出于历史原因`内特奥普酒店`运算符类不是类型的默认类`内特``苹果酒`.要使用它,请在`创建索引`例如
```
CREATE INDEX ON my_table USING GIST (my_inet_column inet_ops);
```
此差异已折叠。
## 37.23。`域`
风景`域`包含当前数据库中定义的所有域。仅显示当前用户有权访问的那些域(通过成为所有者或具有某些特权)。
**表 37.21。`域`列**
| 列类型<br/><br/>描述 |
| --------------- |
| `域目录` `sql_identifier`<br/><br/>包含域的数据库的名称(始终为当前数据库) |
| `域模式` `sql_identifier`<br/><br/>包含域的架构的名称 |
| `域名` `sql_identifier`<br/><br/>域名 |
| `数据类型` `字符数据`<br/><br/>域的数据类型,如果它是内置类型,或者`大批`如果它是某个数组(在这种情况下,请参阅视图`元素类型`), 别的`用户自定义`(在这种情况下,类型在`udt_name`和相关的列)。 |
| `character_maximum_length` `基数`<br/><br/>如果域有字符或位串类型,则声明最大长度;对于所有其他数据类型,或者如果没有声明最大长度,则为 null。 |
| `character_octet_length` `基数`<br/><br/>如果域具有字符类型,则以八位字节(字节)为单位的数据的最大可能长度;所有其他数据类型为 null。最大八位字节长度取决于声明的字符最大长度(见上文)和服务器编码。 |
| `字符集目录` `sql_identifier`<br/><br/>适用于 PostgreSQL 中不可用的功能 |
| `character_set_schema` `sql_identifier`<br/><br/>适用于 PostgreSQL 中不可用的功能 |
| `字符集名称` `sql_identifier`<br/><br/>适用于 PostgreSQL 中不可用的功能 |
| `collat​​ion_catalog` `sql_identifier`<br/><br/>包含域排序规则的数据库名称(始终为当前数据库),如果默认为 null 或域的数据类型不可排序 |
| `collat​​ion_schema` `sql_identifier`<br/><br/>包含域排序规则的架构名称,默认为 null 或域的数据类型不可排序 |
| `collat​​ion_name` `sql_identifier`<br/><br/>域的排序规则的名称,默认为空或域的数据类型不可排序 |
| `数字精度` `基数`<br/><br/>如果域具有数字类型,则此列包含此域的类型的(声明的或隐含的)精度。精度表示有效位数。它可以用十进制(以 10 为底)或二进制(以 2 为底)表示,如列中所述`numeric_precision_radix`.对于所有其他数据类型,此列为空。 |
| `numeric_precision_radix` `基数`<br/><br/>如果域具有数字类型,则此列将指示列中的值的基数`数字精度``数字比例尺`都表达出来了。该值为2或10。对于所有其他数据类型,此列为空。 |
| `数字比例尺` `基数`<br/><br/>如果域具有精确的数字类型,则此列包含该域类型的(声明的或隐式的)刻度。刻度表示小数点右侧的有效位数。根据列中的规定,它可以用十进制(以10为基数)或二进制(以2为基数)表示`数字精度基数`。对于所有其他数据类型,此列为空。 |
| `日期时间精度` `基数`<br/><br/>如果`数据类型`标识日期、时间、时间戳或间隔类型,此列包含此域类型的(声明的或隐式的)小数秒精度,即秒值小数点后保留的小数位数。对于所有其他数据类型,此列为空。 |
| `区间型` `字符数据`<br/><br/>如果`数据类型`标识间隔类型,此列包含该域的间隔包括哪些字段的规范,例如。,`年复一年`,`日复一日`,等等。如果未指定字段限制(即间隔接受所有字段),并且对于所有其他数据类型,此字段为空。 |
| `区间精度` `基数`<br/><br/>适用于PostgreSQL中不可用的功能(请参阅`日期时间精度`对于间隔类型域的小数秒精度) |
| `域默认值` `字符数据`<br/><br/>域的默认表达式 |
| `udt_目录` `sql_标识符`<br/><br/>定义域数据类型的数据库的名称(始终为当前数据库) |
| `udt_模式` `sql_标识符`<br/><br/>定义域数据类型的架构的名称 |
| `udt_名称` `sql_标识符`<br/><br/>域数据类型的名称 |
| `目录范围` `sql_标识符`<br/><br/>适用于PostgreSQL中不可用的功能 |
| `范围和模式` `sql_标识符`<br/><br/>适用于PostgreSQL中不可用的功能 |
| `范围名称` `sql_标识符`<br/><br/>适用于PostgreSQL中不可用的功能 |
| `最大基数` `基数`<br/><br/>总是空的,因为数组在PostgreSQL中总是有无限的最大基数 |
| `dtd_标识符` `sql_标识符`<br/><br/>域的数据类型描述符的标识符,在与该域有关的数据类型描述符中是唯一的(这很简单,因为一个域只包含一个数据类型描述符)。这主要用于与此类标识符的其他实例连接。(未定义标识符的具体格式,也不保证在未来版本中保持不变。) |
## 17.5.安装后设置
[17.5.1. 共享库](install-post.html#INSTALL-POST-SHLIBS)
[17.5.2. 环境变量](install-post.html#id-1.6.4.9.3)
### 17.5.1.共享库
[](<>)
在某些具有共享库的系统上,您需要告诉系统如何查找新安装的共享库。它所在的系统*不*必要的软件包括FreeBSD、HP-UX、Linux、NetBSD、OpenBSD和Solaris。
设置共享库搜索路径的方法因平台而异,但最广泛使用的方法是设置环境变量`图书馆路`就像这样:在伯恩贝壳里(`嘘`,`ksh`,`猛击`,`zsh`):
```
LD_LIBRARY_PATH=/usr/local/pgsql/lib
export LD_LIBRARY_PATH
```
或者在`csh``tcsh`:
```
setenv LD_LIBRARY_PATH /usr/local/pgsql/lib
```
代替`/usr/local/pgsql/lib`无论你设定了什么`--利伯迪尔`加入[第一步](install-procedure.html#CONFIGURE)。您应该将这些命令放入shell启动文件中,例如`/等/简介``~/.bash_简介`。有关此方法的注意事项,请访问[http://xahlee.info/UnixResource\_迪尔/\_/ldpath。html](http://xahlee.info/UnixResource_dir/_/ldpath.html).
在某些系统上,最好设置环境变量`LD_RUN_PATH` *之前*建筑物
在Cygwin上,将库目录放入`路径`或者移动`.dll`将文件放入`箱子`目录
如果有疑问,请参阅系统的手册页(可能是`劳埃德。所以``rld`).如果您稍后收到如下消息:
```
psql: error in loading shared libraries
libpq.so.2.1: cannot open shared object file: No such file or directory
```
那么这一步是必要的。那就好好照顾它吧。
[](<>)如果您在Linux上,并且具有root访问权限,则可以运行:
```
/sbin/ldconfig /usr/local/pgsql/lib
```
(或等效目录),使运行时链接器能够更快地找到共享库。请参阅第页的手册`ldconfig`了解更多信息。在FreeBSD、NetBSD和OpenBSD上,命令是:
```
/sbin/ldconfig -m /usr/local/pgsql/lib
```
相反目前还不知道其他系统是否有类似的命令。
### 17.5.2.环境变量
[](<>)
如果你安装到`/usr/local/pgsql`或者默认情况下未搜索程序的其他位置,您应该添加`/usr/local/pgsql/bin`(或者你设定的任何东西)`--宾迪尔`加入[第一步](install-procedure.html#CONFIGURE))进入你的`路径`.严格来说,这是没有必要的,但它将使PostgreSQL的使用更加方便。
为此,请将以下内容添加到shell启动文件中,例如`~/.bash_简介`(或`/等/简介`,如果希望它影响所有用户):
```
PATH=/usr/local/pgsql/bin:$PATH
export PATH
```
如果你正在使用`csh``tcsh`,然后使用以下命令:
```
set path = ( /usr/local/pgsql/bin $path )
```
[](<>)为了使系统能够找到man文档,除非安装到默认搜索的位置,否则需要在shell启动文件中添加以下行:
```
MANPATH=/usr/local/pgsql/share/man:$MANPATH
export MANPATH
```
环境变量`PGHOST``PGPORT`为客户端应用程序指定数据库服务器的主机和端口,覆盖默认编译的。如果要远程运行客户端应用程序,那么如果每个计划使用数据库集的用户`PGHOST`。不过,这不是必需的;这些设置可以通过命令行选项与大多数客户端程序通信。
此差异已折叠。
## F.19。不是吗
[F.19.1。数据类型](isn.html#id-1.11.7.28.5)[F.19.2。铸造](isn.html#id-1.11.7.28.6)[F.19.3。函数和运算符](isn.html#id-1.11.7.28.7)[F.19.4。例子](isn.html#id-1.11.7.28.8)[F.19.5。参考文献](isn.html#id-1.11.7.28.9)[F.19.6。著者](isn.html#id-1.11.7.28.10)
[](<>)
这个`不是吗`模块为以下国际产品编号标准提供数据类型:EAN13、UPC、ISBN(图书)、ISMN(音乐)和ISSN(系列)。根据前缀的硬编码列表,在输入时验证数字;此前缀列表还用于在输出时对数字进行连字符。由于新前缀会不时被分配,前缀列表可能已经过时。希望该模块的未来版本将从一个或多个用户可以根据需要轻松更新的表中获取前缀列表;然而,目前只能通过修改源代码和重新编译来更新列表。或者,该模块的未来版本可能会放弃前缀验证和断字支持。
该模块被认为是“受信任的”,也就是说,它可以由拥有`创造`当前数据库的权限。
### F.19.1。数据类型
[表F.11](isn.html#ISN-DATATYPES)显示由提供的数据类型`不是吗`单元
**表F.11。`不是吗`数据类型**
| 数据类型 | 描述 |
| ---- | --- |
| `EAN13` | 欧洲商品编号,始终以EAN13显示格式显示 |
| `ISBN13` | 以新的EAN13显示格式显示的国际标准书号 |
| `ISMN13` | 以新的EAN13显示格式显示的国际标准音乐号码 |
| `ISSN13` | 以新的EAN13显示格式显示的国际标准序列号 |
| `ISBN` | 以旧的短显示格式显示的国际标准书号 |
| `ISMN` | 以旧的短显示格式显示的国际标准音乐号码 |
| `伊森` | 以旧的短显示格式显示的国际标准序列号 |
| `UPC` | 通用产品代码 |
注意:
1. ISBN13、ISMN13、ISSN13号都是EAN13号。
2. EAN13数字并不总是ISBN13、ISMN13或ISSN13(有些是)。
3. 一些ISBN13数字可以显示为ISBN。
4. 一些ISMN13数字可以显示为ISMN。
5. 一些ISSN13数字可以显示为ISSN。
6. UPC编号是EAN13编号的一个子集(基本上是没有第一个编号的EAN13)`0`数字)。
7. 所有UPC、ISBN、ISMN和ISSN编号都可以表示为EAN13编号。
在内部,所有这些类型都使用相同的表示(64位整数),并且都可以互换。提供了多种类型来控制显示格式,并允许更严格的输入有效性检查,该输入应表示一种特定类型的数字。
这个`ISBN`, `ISMN`和`伊森`只要可能,类型将显示数字的短版本(ISxN 10),对于不适合短版本的数字,类型将显示ISxN 13格式。这个`EAN13`, `ISBN13`, `ISMN13`和`ISSN13`类型将始终显示ISxN(EAN13)的长版本。
### F.19.2。铸造
这个`不是吗`模块提供以下类型转换对:
- ISBN13\\\<=> EAN13
- ISMN13\\\<=> EAN13
- ISSN13\\\<=> EAN13
- ISBN\\\<=> EAN13
- ISMN \\\<=>EAN13
- ISSN \\\<=>EAN13
- UPC \\\<=>EAN13
- ISBN \\\<=>ISBN13
- ISMN \\\<=>ISMN13
- ISSN \\\<=>ISSN13
When casting from`EAN13`to another type, there is a run-time check that the value is within the domain of the other type, and an error is thrown if not. The other casts are simply relabelings that will always succeed.
### F.19.3. Functions and Operators
The`isn`module provides the standard comparison operators, plus B-tree and hash indexing support for all these data types. In addition there are several specialized functions; shown in[Table F.12](isn.html#ISN-FUNCTIONS). In this table,`不是吗`指模块的任何一种数据类型。
**表F.12。 `不是吗`功能**
| 作用<br/><br/>描述 |
| -------------- |
| [](<>) `你不软弱吗` ( `布尔值` ) → `布尔值`<br/><br/>设置弱输入模式,并返回新设置。 |
| `你不软弱吗` () → `布尔值`<br/><br/>返回弱模式的当前状态。 |
| [](<>) `使你有效` ( `不是吗` ) → `不是吗`<br/><br/>验证无效数字(清除无效标志)。 |
| [](<>) `_有效吗` ( `不是吗` ) → `布尔值`<br/><br/>检查是否存在无效标志。 |
*虚弱的*模式用于将无效数据插入表中。无效表示校验位错误,而不是缺少数字。
为什么要使用弱模式?嗯,可能是因为你收集了大量的ISBN号,而且其中有太多的ISBN号,出于奇怪的原因,一些ISBN号的校验位是错误的(可能是从打印的列表中扫描的数字,OCR得到的数字是错误的,可能是手动捕获的数字……谁知道呢)。不管怎么说,关键是你可能想收拾残局,但你仍然希望能够在数据库中拥有所有的数字,并且可能使用外部工具来定位数据库中的无效数字,这样你就可以更容易地验证信息和验证它;例如,你需要选择表中所有的无效数字。
当使用弱模式在表格中插入无效数字时,数字将与更正的校验位一起插入,但它将以感叹号显示(`!`)例如,在最后`0-11-000322-5!`。此无效标记可通过`_有效吗`函数并用`使你有效`作用
您还可以通过添加`!`数字末尾的字符。
另一个特点是,在输入过程中,您可以编写`?`替换校验位,并自动插入正确的校验位。
### F.19.4。例子
```
--Using the types directly:
SELECT isbn('978-0-393-04002-9');
SELECT isbn13('0901690546');
SELECT issn('1436-4522');
--Casting types:
-- note that you can only cast from ean13 to another type when the
-- number would be valid in the realm of the target type;
-- thus, the following will NOT work: select isbn(ean13('0220356483481'));
-- but these will:
SELECT upc(ean13('0220356483481'));
SELECT ean13(upc('220356483481'));
--Create a table with a single column to hold ISBN numbers:
CREATE TABLE test (id isbn);
INSERT INTO test VALUES('9780393040029');
--Automatically calculate check digits (observe the '?'):
INSERT INTO test VALUES('220500896?');
INSERT INTO test VALUES('978055215372?');
SELECT issn('3251231?');
SELECT ismn('979047213542?');
--Using the weak mode:
SELECT isn_weak(true);
INSERT INTO test VALUES('978-0-11-000533-4');
INSERT INTO test VALUES('9780141219307');
INSERT INTO test VALUES('2-205-00876-X');
SELECT isn_weak(false);
SELECT id FROM test WHERE NOT is_valid(id);
UPDATE test SET id = make_valid(id) WHERE id = '2-205-00876-X!';
SELECT * FROM test;
SELECT isbn13(id) FROM test;
```
### F.19.5。参考书目
实施本模块的信息来自多个网站,包括:
- <https://www.isbn-international.org/>
- <https://www.issn.org/>
- <https://www.ismn-international.org/>
- <https://www.wikipedia.org/>
用于连字号的前缀也来自:
- <https://www.gs1.org/standards/id-keys>
- [https://en.wikipedia.org/wiki/List\_属于\_ISBN\_标识符\_组](https://en.wikipedia.org/wiki/List_of_ISBN_identifier_groups)
- <https://www.isbn-international.org/content/isbn-users-manual>
- [https://en.wikipedia.org/wiki/International\_标准\_音乐\_数字](https://en.wikipedia.org/wiki/International_Standard_Music_Number)
- <https://www.ismn-international.org/ranges.html>
在创建算法的过程中非常小心,并根据ISBN、ISMN、ISSN用户手册中建议的算法进行了仔细验证。
### F.19.6。作者
German Méndez Bravo(克朗),2004-2006年
本模块的灵感来自加勒特·A·沃尔曼的`国际标准书号`密码
## 34.4.异步命令处理
[](<>)
这个[`PQexec`](libpq-exec.html#LIBPQ-PQEXEC)该函数足以在正常的同步应用程序中提交命令。然而,它有一些对某些用户很重要的缺陷:
- [`PQexec`](libpq-exec.html#LIBPQ-PQEXEC)等待命令完成。应用程序可能还有其他工作要做(比如维护用户界面),在这种情况下,它不想阻止等待响应。
- 由于客户端应用程序在等待结果时暂停执行,因此应用程序很难决定是否要尝试取消正在执行的命令。(这可以通过信号处理器完成,但不能通过其他方式完成。)
- [`PQexec`](libpq-exec.html#LIBPQ-PQEXEC)只能返回一个`PGresult`结构如果提交的命令字符串包含多个SQL命令,则除最后一个命令外`PGresult`被丢弃[`PQexec`](libpq-exec.html#LIBPQ-PQEXEC).
- [`PQexec`](libpq-exec.html#LIBPQ-PQEXEC)始终收集命令的整个结果,并将其缓冲在单个`PGresult`。虽然这简化了应用程序的错误处理逻辑,但对于包含多行的结果来说可能不切实际。
不喜欢这些限制的应用程序可以使用[`PQexec`](libpq-exec.html#LIBPQ-PQEXEC)它由以下部分构成:[`PQsendQuery`](libpq-async.html#LIBPQ-PQSENDQUERY)和[`PQgetResult`](libpq-async.html#LIBPQ-PQGETRESULT).还有[`PQsendQueryParams`](libpq-async.html#LIBPQ-PQSENDQUERYPARAMS),[`PQsendPrepare`](libpq-async.html#LIBPQ-PQSENDPREPARE),[`PQsendQueryPrepared`](libpq-async.html#LIBPQ-PQSENDQUERYPREPARED),[`PQsendDescribePrepared`](libpq-async.html#LIBPQ-PQSENDDESCRIBEPREPARED), 和[`PQsendDescribePortal`](libpq-async.html#LIBPQ-PQSENDDESCRIBEPORTAL), 它可以与[`PQgetResult`](libpq-async.html#LIBPQ-PQGETRESULT)复制的功能[`PQexec 参数`](libpq-exec.html#LIBPQ-PQEXECPARAMS),[`PQprepare`](libpq-exec.html#LIBPQ-PQPREPARE),[`PQexec 准备`](libpq-exec.html#LIBPQ-PQEXECPREPARED),[`PQdescribePrepared`](libpq-exec.html#LIBPQ-PQDESCRIBEPREPARED), 和[`PQdescribePortal`](libpq-exec.html#LIBPQ-PQDESCRIBEPORTAL)分别。
`PQsendQuery`[](<>)
向服务器提交命令而不等待结果。如果命令成功发送则返回 1,否则返回 0(在这种情况下,使用[`PQerrorMessage`](libpq-status.html#LIBPQ-PQERRORMESSAGE)以获取有关故障的更多信息)。
```
int PQsendQuery(PGconn *conn, const char *command);
```
调用成功后[`PQsendQuery`](libpq-async.html#LIBPQ-PQSENDQUERY), 称呼[`PQgetResult`](libpq-async.html#LIBPQ-PQGETRESULT)一次或多次获得结果。[`PQsendQuery`](libpq-async.html#LIBPQ-PQSENDQUERY)不能再次调用(在同一连接上),直到[`PQgetResult`](libpq-async.html#LIBPQ-PQGETRESULT)返回了一个空指针,表示命令执行完毕。
在管道模式下,不允许包含多个 SQL 命令的命令字符串。
`PQsendQueryParams`[](<>)
向服务器提交命令和单独的参数,而不等待结果。
```
int PQsendQueryParams(PGconn *conn,
const char *command,
int nParams,
const Oid *paramTypes,
const char * const *paramValues,
const int *paramLengths,
const int *paramFormats,
int resultFormat);
```
这相当于[`PQsendQuery`](libpq-async.html#LIBPQ-PQSENDQUERY)除了查询参数可以与查询字符串分开指定。该函数的参数的处理方式与[`PQexec 参数`](libpq-exec.html#LIBPQ-PQEXECPARAMS).喜欢[`PQexec 参数`](libpq-exec.html#LIBPQ-PQEXECPARAMS),它只允许查询字符串中有一个命令。
`PQsendPrepare`[](<>)
发送请求以使用给定参数创建准备好的语句,而无需等待完成。
```
int PQsendPrepare(PGconn *conn,
const char *stmtName,
const char *query,
int nParams,
const Oid *paramTypes);
```
这是一个异步版本[`PQprepare`](libpq-exec.html#LIBPQ-PQPREPARE):如果能够发送请求,则返回 1,否则返回 0。调用成功后,调用[`PQgetResult`](libpq-async.html#LIBPQ-PQGETRESULT)判断服务器是否成功创建了prepared statement。该函数的参数的处理方式与[`PQprepare`](libpq-exec.html#LIBPQ-PQPREPARE).
`PQsendQueryPrepared`[](<>)
发送请求以执行具有给定参数的准备好的语句,而无需等待结果。
```
int PQsendQueryPrepared(PGconn *conn,
const char *stmtName,
int nParams,
const char * const *paramValues,
const int *paramLengths,
const int *paramFormats,
int resultFormat);
```
这类似于[`PQsendQueryParams`](libpq-async.html#LIBPQ-PQSENDQUERYPARAMS),但要执行的命令是通过命名先前准备的语句来指定的,而不是给出查询字符串。该函数的参数的处理方式与[`PQexec 准备`](libpq-exec.html#LIBPQ-PQEXECPREPARED).
`PQsendDescribePrepared`[](<>)
提交请求以获取有关指定预准备语句的信息,而无需等待完成。
```
int PQsendDescribePrepared(PGconn *conn, const char *stmtName);
```
这是一个异步版本[`PQdescribePrepared`](libpq-exec.html#LIBPQ-PQDESCRIBEPREPARED):如果能够发送请求,则返回 1,否则返回 0。调用成功后,调用[`PQgetResult`](libpq-async.html#LIBPQ-PQGETRESULT)来获得结果。该函数的参数的处理方式与[`PQdescribePrepared`](libpq-exec.html#LIBPQ-PQDESCRIBEPREPARED).
`PQsendDescribePortal`[](<>)
提交请求以获取有关指定门户的信息,而无需等待完成。
```
int PQsendDescribePortal(PGconn *conn, const char *portalName);
```
这是一个异步版本[`PQdescribePortal`](libpq-exec.html#LIBPQ-PQDESCRIBEPORTAL):如果能够发送请求,则返回 1,否则返回 0。调用成功后,调用[`PQgetResult`](libpq-async.html#LIBPQ-PQGETRESULT)来获得结果。该函数的参数的处理方式与[`PQdescribePortal`](libpq-exec.html#LIBPQ-PQDESCRIBEPORTAL).
`PQgetResult`[](<>)
等待前一个结果的下一个结果[`PQsendQuery`](libpq-async.html#LIBPQ-PQSENDQUERY),[`PQsendQueryParams`](libpq-async.html#LIBPQ-PQSENDQUERYPARAMS),[`PQsendPrepare`](libpq-async.html#LIBPQ-PQSENDPREPARE),[`PQsendQueryPrepared`](libpq-async.html#LIBPQ-PQSENDQUERYPREPARED),[`PQsendDescribePrepared`](libpq-async.html#LIBPQ-PQSENDDESCRIBEPREPARED),[`PQsendDescribePortal`](libpq-async.html#LIBPQ-PQSENDDESCRIBEPORTAL), 或者[`PQpipelineSync`](libpq-pipeline-mode.html#LIBPQ-PQPIPELINESYNC)调用,并返回它。命令完成时返回一个空指针,不会再有结果。
```
PGresult *PQgetResult(PGconn *conn);
```
[`PQgetResult`](libpq-async.html#LIBPQ-PQGETRESULT)必须重复调用,直到它返回一个空指针,表示命令完成。(如果在没有命令处于活动状态时调用,[`PQgetResult`](libpq-async.html#LIBPQ-PQGETRESULT)将立即返回一个空指针。)每个非空结果来自[`PQgetResult`](libpq-async.html#LIBPQ-PQGETRESULT)应该使用相同的处理`PG结果`前面描述的访问器函数。不要忘记释放每个结果对象[`PQclear`](libpq-exec.html#LIBPQ-PQCLEAR)完成后。注意[`PQgetResult`](libpq-async.html#LIBPQ-PQGETRESULT)仅当命令处于活动状态且必要的响应数据尚未被读取时才会阻塞[`PQconsume输入` ](libpq-async.html#LIBPQ-PQCONSUMEINPUT).
在流水线模式下,`PQgetResult`除非发生错误,否则将正常返回;对于在导致错误的查询之后发送的任何后续查询,直到(并且不包括)下一个同步点,类型的特殊结果`PGRES_PIPELINE_ABORTED`将被返回,并在其后返回一个空指针。当达到管道同步点时,类型为`PGRES_PIPELINE_SYNC`将被退回。紧跟在同步点之后的下一个查询的结果(即同步点之后不返回空指针)。
### 笔记
即使当[`PQresult状态`](libpq-exec.html#LIBPQ-PQRESULTSTATUS)表示致命错误,[`PQgetResult`](libpq-async.html#LIBPQ-PQGETRESULT)应该调用直到它返回一个空指针,以允许 libpq 完全处理错误信息。
使用[`PQsendQuery`](libpq-async.html#LIBPQ-PQSENDQUERY)[`PQgetResult`](libpq-async.html#LIBPQ-PQGETRESULT)解决其中之一[`执行程序`](libpq-exec.html#LIBPQ-PQEXEC)的问题:如果一个命令字符串包含多个SQL命令,则可以单独获取这些命令的结果。(顺便说一下,这允许一种简单形式的重叠处理:客户端可以处理一个命令的结果,而服务器仍在处理同一命令字符串中的后续查询。)
另一个经常需要的功能,可以通过[`PQsendQuery`](libpq-async.html#LIBPQ-PQSENDQUERY)[`PQgetResult`](libpq-async.html#LIBPQ-PQGETRESULT)一次检索大查询结果一行。这在[第 34.6 节](libpq-single-row-mode.html).
本身,调用[`PQgetResult`](libpq-async.html#LIBPQ-PQGETRESULT)仍然会导致客户端阻塞,直到服务器完成下一个 SQL 命令。这可以通过正确使用另外两个功能来避免:
`PQconsume输入`[](<>)
如果可以从服务器获得输入,则使用它。
```
int PQconsumeInput(PGconn *conn);
```
[`PQconsume输入` ](libpq-async.html#LIBPQ-PQCONSUMEINPUT)通常返回 1 表示“没有错误”,但如果出现某种故障则返回 0(在这种情况下[`PQerrorMessage`](libpq-status.html#LIBPQ-PQERRORMESSAGE)可以咨询)。请注意,结果并未说明是否实际收集了任何输入数据。打电话后[`PQconsume输入` ](libpq-async.html#LIBPQ-PQCONSUMEINPUT),应用程序可以检查[`PQis忙碌`](libpq-async.html#LIBPQ-PQISBUSY)和/或`PQ 通知`看看他们的状态是否发生了变化。
[`PQconsume输入` ](libpq-async.html#LIBPQ-PQCONSUMEINPUT)即使应用程序还没有准备好处理结果或通知,也可以调用。该函数将读取可用数据并将其保存在缓冲区中,从而导致`选择()`阅读就绪指示离开。该应用程序因此可以使用[`PQconsume输入` ](libpq-async.html#LIBPQ-PQCONSUMEINPUT)清除`选择()`立即状况,然后在闲暇时检查结果。
`PQis忙碌`[](<>)
如果命令忙,则返回 1,即[`PQgetResult`](libpq-async.html#LIBPQ-PQGETRESULT)会阻塞等待输入。返回 0 表示[`PQgetResult`](libpq-async.html#LIBPQ-PQGETRESULT)可以在保证不阻塞的情况下调用。
```
int PQisBusy(PGconn *conn);
```
[`PQis忙碌`](libpq-async.html#LIBPQ-PQISBUSY)本身不会尝试从服务器读取数据;所以[`PQconsume输入` ](libpq-async.html#LIBPQ-PQCONSUMEINPUT)必须先调用,否则忙碌状态永远不会结束。
使用这些函数的典型应用程序将有一个主循环,它使用`选择()`要么`轮询()`等待它必须响应的所有条件。条件之一将从服务器输入,根据`选择()`表示文件描述符上的可读数据[`PQsocket`](libpq-status.html#LIBPQ-PQSOCKET).当主循环检测到输入就绪时,它应该调用[`PQconsume输入` ](libpq-async.html#LIBPQ-PQCONSUMEINPUT)读取输入。然后它可以调用[`PQis忙碌`](libpq-async.html#LIBPQ-PQISBUSY), 其次是[`PQgetResult`](libpq-async.html#LIBPQ-PQGETRESULT)如果[`PQis忙碌`](libpq-async.html#LIBPQ-PQISBUSY)返回假 (0)。它也可以调用`PQ 通知`检测`通知`消息(见[第 34.9 节](libpq-notify.html))。
使用的客户端[`PQsendQuery`](libpq-async.html#LIBPQ-PQSENDQUERY)/[`PQgetResult`](libpq-async.html#LIBPQ-PQGETRESULT)还可以尝试取消服务器仍在处理的命令;看[第 34.7 节](libpq-cancel.html).但不管[`取消`](libpq-cancel.html#LIBPQ-PQCANCEL),应用程序必须使用[`PQgetResult`](libpq-async.html#LIBPQ-PQGETRESULT)。成功取消只会导致命令提前终止。
通过使用上述功能,可以避免在等待来自数据库服务器的输入时发生阻塞。但是,应用程序仍有可能阻止等待向服务器发送输出。这种情况相对少见,但如果发送很长的SQL命令或数据值,就会发生这种情况。(如果应用程序通过`抄送`(然而)为了防止这种可能性并实现完全无阻塞的数据库操作,可以使用以下附加功能。
`PQsetnonblocking`[](<>)
设置连接的非阻塞状态。
```
int PQsetnonblocking(PGconn *conn, int arg);
```
如果需要,将连接状态设置为非阻塞*`阿格`*是1,如果*`阿格`*是0。如果正常,则返回0;如果错误,则返回1。
在非阻塞状态下,调用[`PQsendQuery`](libpq-async.html#LIBPQ-PQSENDQUERY),[`PQputline`](libpq-copy.html#LIBPQ-PQPUTLINE),[`PQputnbytes`](libpq-copy.html#LIBPQ-PQPUTNBYTES),[`PQputCopyData`](libpq-copy.html#LIBPQ-PQPUTCOPYDATA)[`PQendcopy`](libpq-copy.html#LIBPQ-PQENDCOPY)如果需要再次调用,则不会阻止,而是返回错误。
注意[`PQexec`](libpq-exec.html#LIBPQ-PQEXEC)不支持非阻塞模式;如果它被调用,它将以阻塞方式运行。
`PQIS非阻塞`[](<>)
返回数据库连接的阻塞状态。
```
int PQisnonblocking(const PGconn *conn);
```
如果连接设置为非阻塞模式,则返回1;如果连接设置为阻塞模式,则返回0。
`PQflush`[](<>)
尝试将任何排队的输出数据刷新到服务器。如果成功(或如果发送队列为空),则返回0;如果由于某种原因失败,则返回-1;如果无法发送发送队列中的所有数据,则返回1(这种情况仅在连接未阻塞时发生)。
```
int PQflush(PGconn *conn);
```
在非阻塞连接上发送任何命令或数据后,调用[`PQflush`](libpq-async.html#LIBPQ-PQFLUSH).如果返回1,则等待套接字变为读写就绪。如果已准备好写入,请致电[`PQflush`](libpq-async.html#LIBPQ-PQFLUSH)再一次如果它已准备就绪,请致电[`pqconsumer输入` ](libpq-async.html#LIBPQ-PQCONSUMEINPUT),然后打电话[`PQflush`](libpq-async.html#LIBPQ-PQFLUSH)再一次重复直到[`PQflush`](libpq-async.html#LIBPQ-PQFLUSH)返回0。(有必要检查read ready(读取准备就绪)并使用[`pqconsumer输入` ](libpq-async.html#LIBPQ-PQCONSUMEINPUT),因为服务器可以阻止向我们发送数据,例如通知消息,并且在我们读取数据之前不会读取我们的数据。)一旦[`PQflush`](libpq-async.html#LIBPQ-PQFLUSH)返回0,等待套接字读取就绪,然后如上所述读取响应。
## 34.21.构建libpq程序
[](<>)
要使用libpq构建(即编译和链接)程序,您需要执行以下所有操作:
- 包括`libpq-fe。H`头文件:
```
#include <libpq-fe.h>
```
如果您未能做到这一点,那么您通常会从编译器中收到类似以下内容的错误消息:
```
foo.c: In function `main':
foo.c:34: `PGconn' undeclared (first use in this function)
foo.c:35: `PGresult' undeclared (first use in this function)
foo.c:54: `CONNECTION_BAD' undeclared (first use in this function)
foo.c:68: `PGRES_COMMAND_OK' undeclared (first use in this function)
foo.c:95: `PGRES_TUPLES_OK' undeclared (first use in this function)
```
- 通过提供`-我*`目录`*`选项添加到编译器中。(在某些情况下,编译器会在默认情况下查看相关目录,因此您可以忽略此选项。)例如,compile命令行可能如下所示:
```
cc -c -I/usr/local/pgsql/include testprog.c
```
如果您使用的是makefiles,那么将该选项添加到`CPPFLAGS`变量:
```
CPPFLAGS += -I/usr/local/pgsql/include
```
如果你的程序有可能被其他用户编译,那么你不应该像这样硬编码目录位置。相反,您可以运行该实用程序`pg_配置`[](<>)要了解头文件在本地系统上的位置,请执行以下操作:
```
$ pg_config --includedir
/usr/local/include
```
如果你有`包装配置`[](<>)安装后,您可以改为运行:
```
$ pkg-config --cflags libpq
-I/usr/local/include
```
请注意,这已经包括`-我`在小路前面。
未能为编译器指定正确的选项将导致错误消息,例如:
```
testlibpq.c:8:22: libpq-fe.h: No such file or directory
```
- 链接最终程序时,请指定选项`-lpq`这样libpq库和选项`-L*`目录`*`将编译器指向libpq库所在的目录。(同样,默认情况下,编译器将搜索一些目录。)为了实现最大的可移植性,请将`-L`选择权`-lpq`选项例如:
```
cc -o testprog testprog1.o testprog2.o -L/usr/local/pgsql/lib -lpq
```
您可以使用`pg_配置`也:
```
$ pg_config --libdir
/usr/local/pgsql/lib
```
或者再次使用`包装配置`:
```
$ pkg-config --libs libpq
-L/usr/local/pgsql/lib -lpq
```
再次注意,这将打印完整选项,而不仅仅是路径。
指向此区域问题的错误消息可能如下所示:
```
testlibpq.o: In function `main':
testlibpq.o(.text+0x60): undefined reference to `PQsetdbLogin'
testlibpq.o(.text+0x71): undefined reference to `PQstatus'
testlibpq.o(.text+0xa4): undefined reference to `PQerrorMessage'
```
这意味着你忘了`-lpq`.
```
/usr/bin/ld: cannot find -lpq
```
这意味着你忘了`-L`选项或未指定正确的目录。
此差异已折叠。
## 34.10. Functions Associated with the`COPY`Command
[34.10.1. Functions for Sending`COPY`Data](libpq-copy.html#LIBPQ-COPY-SEND)
[34.10.2. Functions for Receiving`COPY`Data](libpq-copy.html#LIBPQ-COPY-RECEIVE)
[34.10.3. Obsolete Functions for`COPY`](libpq-copy.html#LIBPQ-COPY-DEPRECATED)
[](<>)
The`COPY`command in PostgreSQL has options to read from or write to the network connection used by libpq. The functions described in this section allow applications to take advantage of this capability by supplying or consuming copied data.
The overall process is that the application first issues the SQL`COPY`command via[`PQexec`](libpq-exec.html#LIBPQ-PQEXEC)or one of the equivalent functions. The response to this (if there is no error in the command) will be a`PGresult`object bearing a status code of`PGRES_COPY_OUT`or`PGRES_COPY_IN`(depending on the specified copy direction). The application should then use the functions of this section to receive or transmit data rows. When the data transfer is complete, another`PGresult`object is returned to indicate success or failure of the transfer. Its status will be`PGRES_COMMAND_OK`for success or`PGRES_FATAL_ERROR`如果遇到一些问题。此时可以通过以下方式发出进一步的 SQL 命令[`执行程序`](libpq-exec.html#LIBPQ-PQEXEC).(不能使用同一连接执行其他 SQL 命令,而`复制`操作正在进行中。)
如果一个`复制`命令是通过发出的[`执行程序`](libpq-exec.html#LIBPQ-PQEXEC)在可能包含其他命令的字符串中,应用程序必须继续通过以下方式获取结果[`PQgetResult`](libpq-async.html#LIBPQ-PQGETRESULT)完成后`复制`顺序。只有当[`PQgetResult`](libpq-async.html#LIBPQ-PQGETRESULT)返回`空值`是否确定[`执行程序`](libpq-exec.html#LIBPQ-PQEXEC)命令字符串已完成,可以安全地发出更多命令。
本节的功能只有在获得结果状态后才能执行`PGRES_COPY_OUT`要么`PGRES_COPY_IN`[`执行程序`](libpq-exec.html#LIBPQ-PQEXEC)要么[`PQgetResult`](libpq-async.html#LIBPQ-PQGETRESULT).
一种`PGresult`object bearing one of these status values carries some additional data about the`COPY`operation that is starting. This additional data is available using functions that are also used in connection with query results:
`PQnfields`[](<>)
Returns the number of columns (fields) to be copied.
`PQbinaryTuples`[](<>)
0 indicates the overall copy format is textual (rows separated by newlines, columns separated by separator characters, etc). 1 indicates the overall copy format is binary. See[COPY](sql-copy.html)for more information.
`PQfformat`[](<>)
Returns the format code (0 for text, 1 for binary) associated with each column of the copy operation. The per-column format codes will always be zero when the overall copy format is textual, but the binary format can support both text and binary columns. (However, as of the current implementation of`COPY`, only binary columns appear in a binary copy; so the per-column formats always match the overall format at present.)
### 34.10.1. Functions for Sending`COPY`Data
These functions are used to send data during`COPY FROM STDIN`. They will fail if called when the connection is not in`COPY_IN`state.
`PQputCopyData`[](<>)
Sends data to the server during`COPY_IN`state.
```
int PQputCopyData(PGconn *conn,
const char *buffer,
int nbytes);
```
Transmits the`COPY`data in the specified*`buffer`*, 长度*`nbytes`*, 到服务器。如果数据已排队,则结果为 1,如果由于缓冲区已满而未排队,则结果为 0(这只会在非阻塞模式下发生),如果发生错误,则结果为 -1。(采用[`PQerrorMessage`](libpq-status.html#LIBPQ-PQERRORMESSAGE)如果返回值为 -1,则检索详细信息。如果值为零,请等待写入就绪,然后重试。)
该应用程序可以划分`复制`数据流到任何方便大小的缓冲区加载中。缓冲区加载边界在发送时没有语义意义。数据流的内容必须与预期的数据格式相匹配`复制`命令;看[复制](sql-copy.html)详情。
`PQputCopyEnd`[](<>)
在期间向服务器发送数据结束指示`COPY_IN`状态。
```
int PQputCopyEnd(PGconn *conn,
const char *errormsg);
```
结束`COPY_IN`如果操作成功*`错误消息`*`空值`.如果*`错误消息`*不是`空值`然后`复制`被迫失败,字符串指向*`错误消息`*用作错误消息。(但是,我们不应该假设这个确切的错误消息会从服务器返回,因为服务器可能已经失败了。)`复制`因为它自己的原因。)
如果发送了终止消息,则结果为1;或者在非阻塞模式下,这可能仅表明终止消息已成功排队。(在非阻塞模式下,为了确保数据已经发送,接下来应该等待write ready并调用[`PQflush`](libpq-async.html#LIBPQ-PQFLUSH),重复,直到返回零。)零表示由于缓冲区已满,函数无法对终止消息排队;这只会在非阻塞模式下发生。(在这种情况下,请等待write ready并尝试[`PQputCopyEnd`](libpq-copy.html#LIBPQ-PQPUTCOPYEND)再打一次。)如果出现硬错误,则返回-1;你可以用[`PQerrorMessage`](libpq-status.html#LIBPQ-PQERRORMESSAGE)检索详细信息。
成功呼叫后[`PQputCopyEnd`](libpq-copy.html#LIBPQ-PQPUTCOPYEND)呼叫[`PQgetResult`](libpq-async.html#LIBPQ-PQGETRESULT)以获取`复制`命令人们可以等待这个结果以通常的方式出现。然后恢复正常操作。
### 34.10.2.接收功能`复制`数据
这些函数用于在运行期间接收数据`复制到标准输出`。如果在连接不在时调用,它们将失败`抄写`状态
`PQgetCopyData`[](<>)
在运行期间从服务器接收数据`抄写`状态
```
int PQgetCopyData(PGconn *conn,
char **buffer,
int async);
```
尝试在中断期间从服务器获取另一行数据`复制`.数据总是一次返回一个数据行;如果只有部分行可用,则不返回。数据行的成功返回涉及分配一块内存来保存数据。这*`缓冲`*参数必须是非`空值`.*\`*缓冲`* 设置为指向分配的内存,或者指向`空值`在没有返回缓冲区的情况下。一个非`空值`应使用 [ 释放结果缓冲区`PQfreemem\`](libpq-misc.html#LIBPQ-PQFREEMEM) 不再需要时。
当成功返回一行时,返回值为该行中的数据字节数(这将始终大于零)。返回的字符串始终以 null 结尾,尽管这可能仅对文本有用`复制`.结果为零表示`复制`仍在进行中,但还没有可用的行(这只有在*`异步`*是真的)。-1 的结果表明`复制`已经完成了。结果 -2 表示发生了错误(请参阅[`PQerrorMessage`](libpq-status.html#LIBPQ-PQERRORMESSAGE)由于这个原因)。
什么时候*`异步`*为真(非零),[`PQgetCopyData`](libpq-copy.html#LIBPQ-PQGETCOPYDATA)不会阻塞等待输入;如果`COPY`is still in progress but no complete row is available. (In this case wait for read-ready and then call[`PQconsumeInput` ](libpq-async.html#LIBPQ-PQCONSUMEINPUT)before calling[`PQgetCopyData`](libpq-copy.html#LIBPQ-PQGETCOPYDATA)again.) When*`async`*is false (zero),[`PQgetCopyData`](libpq-copy.html#LIBPQ-PQGETCOPYDATA)will block until data is available or the operation completes.
After[`PQgetCopyData`](libpq-copy.html#LIBPQ-PQGETCOPYDATA)returns -1, call[`PQgetResult`](libpq-async.html#LIBPQ-PQGETRESULT)to obtain the final result status of the`COPY`command. One can wait for this result to be available in the usual way. Then return to normal operation.
### 34.10.3. Obsolete Functions for`COPY`
These functions represent older methods of handling`COPY`. Although they still work, they are deprecated due to poor error handling, inconvenient methods of detecting end-of-data, and lack of support for binary or nonblocking transfers.
`PQgetline`[](<>)
Reads a newline-terminated line of characters (transmitted by the server) into a buffer string of size*`length`*.
```
int PQgetline(PGconn *conn,
char *buffer,
int length);
```
This function copies up to*`length`*-1 characters into the buffer and converts the terminating newline into a zero byte.[`PQgetline`](libpq-copy.html#LIBPQ-PQGETLINE)返回`EOF`在输入结束时,如果已读取整行,则为 0,如果缓冲区已满但尚未读取终止的换行符,则为 1。
请注意,应用程序必须检查新行是否包含两个字符`\。`,表示服务器已经完成发送结果`复制`命令。如果应用程序可能收到超过*`长度`*-1 个字符长,需要注意确保它能够识别`\。`线正确(例如,不会将长数据线的末端误认为是终止线)。
`PQgetlineAsync`[](<>)
读取一行`复制`数据(由服务器传输)进入缓冲区而不阻塞。
```
int PQgetlineAsync(PGconn *conn,
char *buffer,
int bufsize);
```
这个功能类似于[`PQgetline`](libpq-copy.html#LIBPQ-PQGETLINE),但它可以被必须阅读的应用程序使用`复制`数据异步,即不阻塞。发出了`复制`命令并得到一个`PGRES_COPY_OUT`响应,应用程序应该调用[`PQconsume输入` ](libpq-async.html#LIBPQ-PQCONSUMEINPUT)[`PQgetlineAsync`](libpq-copy.html#LIBPQ-PQGETLINEASYNC)直到检测到数据结束信号。
不像[`PQgetline`](libpq-copy.html#LIBPQ-PQGETLINE),这个函数负责检测数据结束。
在每次通话中,[`PQgetlineAsync`](libpq-copy.html#LIBPQ-PQGETLINEASYNC)如果在 libpq 的输入缓冲区中有完整的数据行,将返回数据。否则,在行的其余部分到达之前,不会返回任何数据。如果已识别出复制数据结束标记,则该函数返回 -1,如果没有数据可用,则返回 0,或者返回一个正数,表示返回的数据字节数。如果返回 -1,调用者必须下一次调用[`PQendcopy`](libpq-copy.html#LIBPQ-PQENDCOPY),然后返回正常处理。
返回的数据不会超出数据行边界。如果可能,将一次返回一整行。但是如果调用者提供的缓冲区太小而无法容纳服务器发送的行,则将返回部分数据行。对于文本数据,可以通过测试最后返回的字节是否为`\n`或不。(在二进制`复制`, 实际解析`复制`将需要数据格式来进行等效确定。)返回的字符串不是以空值结尾的。(如果要添加终止空值,请务必传递一个*`缓冲区大小`*比实际可用的房间小一个。)
`PQputline`[](<>)
向服务器发送一个以 null 结尾的字符串。如果 OK 并且返回 0`EOF`如果无法发送字符串。
```
int PQputline(PGconn *conn,
const char *string);
```
`复制`通过一系列调用发送的数据流[`PQputline`](libpq-copy.html#LIBPQ-PQPUTLINE)与返回的格式相同[`PQgetlineAsync`](libpq-copy.html#LIBPQ-PQGETLINEASYNC),除了应用程序没有义务每次只发送一个数据行[`PQputline`](libpq-copy.html#LIBPQ-PQPUTLINE)称呼;每次通话可以发送部分线路或多条线路。
### 笔记
在 PostgreSQL 协议 3.0 之前,应用程序需要显式发送这两个字符`\。`作为最后一行,向服务器表明它已完成发送`复制`数据。虽然这仍然有效,但它已被弃用,并且它的特殊含义`\。`预计将在未来的版本中删除。打电话就够了[`PQendcopy`](libpq-copy.html#LIBPQ-PQENDCOPY)在发送了实际数据之后。
`PQputnbytes`[](<>)
向服务器发送一个非空终止的字符串。如果 OK 并且返回 0`EOF`如果无法发送字符串。
```
int PQputnbytes(PGconn *conn,
const char *buffer,
int nbytes);
```
这就像[`PQputline`](libpq-copy.html#LIBPQ-PQPUTLINE),除了数据缓冲区不需要以空值结尾,因为要发送的字节数是直接指定的。发送二进制数据时使用此过程。
`PQendcopy`[](<>)
与服务器同步。
```
int PQendcopy(PGconn *conn);
```
该函数一直等到服务器完成复制。它应该在最后一个字符串被发送到服务器时使用[`PQputline`](libpq-copy.html#LIBPQ-PQPUTLINE)或者当从服务器接收到最后一个字符串时,使用`PQgetline`.必须发出它,否则服务器将与客户端“不同步”。从这个函数返回后,服务器准备好接收下一个 SQL 命令。成功完成时返回值为 0,否则为非零。(采用[`PQerrorMessage`](libpq-status.html#LIBPQ-PQERRORMESSAGE)如果返回值非零,则检索详细信息。)
使用时[`PQgetResult`](libpq-async.html#LIBPQ-PQGETRESULT),应用程序应响应`PGRES_COPY_OUT`结果通过执行[`PQgetline`](libpq-copy.html#LIBPQ-PQGETLINE)反复,接着[`PQendcopy`](libpq-copy.html#LIBPQ-PQENDCOPY)在看到终结符线之后。然后它应该返回到[`PQgetResult`](libpq-async.html#LIBPQ-PQGETRESULT)循环直到[`PQgetResult`](libpq-async.html#LIBPQ-PQGETRESULT)返回一个空指针。同样一个`PGRES_COPY_IN`结果由一系列处理[`PQputline`](libpq-copy.html#LIBPQ-PQPUTLINE)电话随后[`PQendcopy`](libpq-copy.html#LIBPQ-PQENDCOPY),然后返回[`PQgetResult`](libpq-async.html#LIBPQ-PQGETRESULT)环形。这种安排将确保一个`复制`嵌入在一系列 SQL 命令中的命令将被正确执行。
较早的申请可能会提交`复制`通过[`执行程序`](libpq-exec.html#LIBPQ-PQEXEC)并假设交易完成后[`PQendcopy`](libpq-copy.html#LIBPQ-PQENDCOPY).只有当`复制`是命令字符串中唯一的 SQL 命令。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
## 34.16. The Password File
[](<>)[](<>)
The file`.pgpass`in a user's home directory can contain passwords to be used if the connection requires a password (and no password has been specified otherwise). On Microsoft Windows the file is named`%APPDATA%\postgresql\pgpass.conf`(where`%APPDATA%`refers to the Application Data subdirectory in the user's profile). Alternatively, a password file can be specified using the connection parameter[passfile](libpq-connect.html#LIBPQ-CONNECT-PASSFILE)or the environment variable`PGPASSFILE`.
This file should contain lines of the following format:
```
hostname:port:database:username:password
```
(You can add a reminder comment to the file by copying the line above and preceding it with`#`.) Each of the first four fields can be a literal value, or`*`, which matches anything. The password field from the first line that matches the current connection parameters will be used. (Therefore, put more-specific entries first when you are using wildcards.) If an entry needs to contain`:`or`\`, 转义这个字符`\`.主机名字段与`主持人`如果指定了连接参数,则为`主机地址`参数(如果指定);如果两者都没有给出,那么主机名`本地主机`被搜索。主机名`本地主机`当连接是 Unix 域套接字连接并且`主持人`参数匹配 libpq 的默认套接字目录路径。在备用服务器中,数据库字段`复制`匹配到主服务器的流复制连接。否则,数据库字段的用处有限,因为用户对同一集群中的所有数据库都具有相同的密码。
在 Unix 系统上,密码文件的权限必须禁止对世界或组的任何访问;通过以下命令实现此目的`chmod 0600 ~/.pgpass`.如果权限不那么严格,则该文件将被忽略。在 Microsoft Windows 上,假定文件存储在安全的目录中,因此不进行特殊权限检查。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册