From 9b4255e3f7888d03b427bdd3b96cd782b081d2d0 Mon Sep 17 00:00:00 2001 From: liangxiangyu Date: Tue, 6 Feb 2024 14:21:10 +0800 Subject: [PATCH 01/41] bugfix for unterminated listing block in v3.0 --- EN/modules/ROOT/pages/v3.0/3.adoc | 1 - 1 file changed, 1 deletion(-) diff --git a/EN/modules/ROOT/pages/v3.0/3.adoc b/EN/modules/ROOT/pages/v3.0/3.adoc index 23c4c72..b42c8f5 100644 --- a/EN/modules/ROOT/pages/v3.0/3.adoc +++ b/EN/modules/ROOT/pages/v3.0/3.adoc @@ -59,7 +59,6 @@ To compile the IvorySQL from the source code, you have to ensure that prerequisi ---- [highgo@ivorysql IvorySQL]$ make [highgo@ivorysql IvorySQL]$ make install ----- **Installation completed** From 75130f86a8f5f104f2a3d7284e82b85c0f8f71b9 Mon Sep 17 00:00:00 2001 From: liangxiangyu Date: Mon, 4 Nov 2024 10:31:59 +0800 Subject: [PATCH 02/41] bugfix v3.0 compatible mode --- CN/modules/ROOT/pages/v3.0/7.adoc | 2 +- EN/modules/ROOT/pages/v3.0/7.adoc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CN/modules/ROOT/pages/v3.0/7.adoc b/CN/modules/ROOT/pages/v3.0/7.adoc index b57fff6..787df66 100644 --- a/CN/modules/ROOT/pages/v3.0/7.adoc +++ b/CN/modules/ROOT/pages/v3.0/7.adoc @@ -1987,7 +1987,7 @@ SELECT concat_lower_or_upper('Hello', 'World', uppercase => true); ==== `compatible_mode (enum)` -此参数控制数据库服务器的行为。 默认值为 `postgres`,表示它是原生安装,服务器将作为原生 PG 安装。 如果它设置为“oracle”,那么查询的输出和系统行为整体会发生变化,因为它会更像 Oracle。 +此参数控制数据库服务器的行为。 默认值为 `pg`,表示它是原生安装,服务器将作为原生 PG 安装。 如果它设置为“oracle”,那么查询的输出和系统行为整体会发生变化,因为它会更像 Oracle。 当设置为 `oracle` 时,此参数会隐式地将同样名字的Schema添加到 `search_path`。 以便可以定位 Oracle 兼容对象。 diff --git a/EN/modules/ROOT/pages/v3.0/7.adoc b/EN/modules/ROOT/pages/v3.0/7.adoc index 1d1768b..f934107 100644 --- a/EN/modules/ROOT/pages/v3.0/7.adoc +++ b/EN/modules/ROOT/pages/v3.0/7.adoc @@ -2084,7 +2084,7 @@ Parameters are set in the same way as in native IvorySQL. All parameter names ar ==== `compatible_mode (enum)` -This parameter controls the behavior of the database server. The default value is `postgres`, which means it is a native installation and the server will be installed as a native PG. If it is set to `oracle`, then the query output and overall system behavior will change, as it will be more Oracle-like. +This parameter controls the behavior of the database server. The default value is `pg`, which means it is a native installation and the server will be installed as a native PG. If it is set to `oracle`, then the query output and overall system behavior will change, as it will be more Oracle-like. When set to `oracle`, this parameter will implicitly add a Schema with the same name to `search_path`. so that Oracle-compatible objects can be located. From 563d6b915127c5833d9001dff6ef346d9426e21c Mon Sep 17 00:00:00 2001 From: liangxiangyu Date: Mon, 4 Nov 2024 10:43:57 +0800 Subject: [PATCH 03/41] fixed again for compatible_mode --- CN/modules/ROOT/pages/v3.0/7.adoc | 2 +- EN/modules/ROOT/pages/v3.0/7.adoc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CN/modules/ROOT/pages/v3.0/7.adoc b/CN/modules/ROOT/pages/v3.0/7.adoc index 787df66..7af7288 100644 --- a/CN/modules/ROOT/pages/v3.0/7.adoc +++ b/CN/modules/ROOT/pages/v3.0/7.adoc @@ -1987,7 +1987,7 @@ SELECT concat_lower_or_upper('Hello', 'World', uppercase => true); ==== `compatible_mode (enum)` -此参数控制数据库服务器的行为。 默认值为 `pg`,表示它是原生安装,服务器将作为原生 PG 安装。 如果它设置为“oracle”,那么查询的输出和系统行为整体会发生变化,因为它会更像 Oracle。 +此参数控制数据库服务器的行为。如果它设置为`pg`,表示它是原生安装,服务器将作为原生 PG 安装。 如果它设置为“oracle”,那么查询的输出和系统行为整体会发生变化,因为它会更像 Oracle。 当设置为 `oracle` 时,此参数会隐式地将同样名字的Schema添加到 `search_path`。 以便可以定位 Oracle 兼容对象。 diff --git a/EN/modules/ROOT/pages/v3.0/7.adoc b/EN/modules/ROOT/pages/v3.0/7.adoc index f934107..dd48c1d 100644 --- a/EN/modules/ROOT/pages/v3.0/7.adoc +++ b/EN/modules/ROOT/pages/v3.0/7.adoc @@ -2084,7 +2084,7 @@ Parameters are set in the same way as in native IvorySQL. All parameter names ar ==== `compatible_mode (enum)` -This parameter controls the behavior of the database server. The default value is `pg`, which means it is a native installation and the server will be installed as a native PG. If it is set to `oracle`, then the query output and overall system behavior will change, as it will be more Oracle-like. +This parameter controls the behavior of the database server. If it is set to `pg`, which means it is a native installation and the server will be installed as a native PG. If it is set to `oracle`, then the query output and overall system behavior will change, as it will be more Oracle-like. When set to `oracle`, this parameter will implicitly add a Schema with the same name to `search_path`. so that Oracle-compatible objects can be located. From 7b3ab1c7b2ba9aa9c0c6cdfae91d6032c72ecb29 Mon Sep 17 00:00:00 2001 From: liangxiangyu Date: Wed, 20 Nov 2024 18:58:11 +0800 Subject: [PATCH 04/41] update the code for IvorySQL v1.8 release --- CN/antora.yml | 4 +- CN/modules/ROOT/nav.adoc | 9 +- CN/modules/ROOT/pages/v3.0/1.adoc | 198 +- CN/modules/ROOT/pages/v3.0/15.adoc | 1 - CN/modules/ROOT/pages/v3.0/16.adoc | 61 +- CN/modules/ROOT/pages/v3.0/18.adoc | 69 - CN/modules/ROOT/pages/v3.0/19.adoc | 49 - CN/modules/ROOT/pages/v3.0/2.adoc | 14 - CN/modules/ROOT/pages/v3.0/20.adoc | 101 - CN/modules/ROOT/pages/v3.0/21.adoc | 965 ------ CN/modules/ROOT/pages/v3.0/3.adoc | 71 +- CN/modules/ROOT/pages/v3.0/6.adoc | 209 +- CN/modules/ROOT/pages/v3.0/7.adoc | 4040 ----------------------- CN/modules/ROOT/pages/v3.0/8.adoc | 1437 -------- CN/modules/ROOT/pages/v3.0/9.adoc | 726 ---- CN/modules/ROOT/pages/v3.0/welcome.adoc | 2 +- EN/antora.yml | 4 +- EN/modules/ROOT/nav.adoc | 9 +- EN/modules/ROOT/pages/v3.0/1.adoc | 198 +- EN/modules/ROOT/pages/v3.0/15.adoc | 1 - EN/modules/ROOT/pages/v3.0/16.adoc | 65 +- EN/modules/ROOT/pages/v3.0/18.adoc | 69 - EN/modules/ROOT/pages/v3.0/19.adoc | 49 - EN/modules/ROOT/pages/v3.0/2.adoc | 15 +- EN/modules/ROOT/pages/v3.0/20.adoc | 85 - EN/modules/ROOT/pages/v3.0/21.adoc | 963 ------ EN/modules/ROOT/pages/v3.0/3.adoc | 62 +- EN/modules/ROOT/pages/v3.0/6.adoc | 211 +- EN/modules/ROOT/pages/v3.0/7.adoc | 4039 ---------------------- EN/modules/ROOT/pages/v3.0/8.adoc | 1404 -------- EN/modules/ROOT/pages/v3.0/9.adoc | 719 ---- EN/modules/ROOT/pages/v3.0/welcome.adoc | 2 +- 32 files changed, 174 insertions(+), 15677 deletions(-) delete mode 100644 CN/modules/ROOT/pages/v3.0/18.adoc delete mode 100644 CN/modules/ROOT/pages/v3.0/19.adoc delete mode 100644 CN/modules/ROOT/pages/v3.0/20.adoc delete mode 100644 CN/modules/ROOT/pages/v3.0/21.adoc delete mode 100644 CN/modules/ROOT/pages/v3.0/7.adoc delete mode 100644 CN/modules/ROOT/pages/v3.0/8.adoc delete mode 100644 CN/modules/ROOT/pages/v3.0/9.adoc delete mode 100644 EN/modules/ROOT/pages/v3.0/18.adoc delete mode 100644 EN/modules/ROOT/pages/v3.0/19.adoc delete mode 100644 EN/modules/ROOT/pages/v3.0/20.adoc delete mode 100644 EN/modules/ROOT/pages/v3.0/21.adoc delete mode 100644 EN/modules/ROOT/pages/v3.0/7.adoc delete mode 100644 EN/modules/ROOT/pages/v3.0/8.adoc delete mode 100644 EN/modules/ROOT/pages/v3.0/9.adoc diff --git a/CN/antora.yml b/CN/antora.yml index 1d17feb..ee4db97 100644 --- a/CN/antora.yml +++ b/CN/antora.yml @@ -1,7 +1,7 @@ name: ivorysql-doc title: IvorySQL -version: v3.0 -start_page: v3.0/welcome.adoc +version: v1.8 +start_page: v1.8/welcome.adoc asciidoc: attributes: source-language: asciidoc@ diff --git a/CN/modules/ROOT/nav.adoc b/CN/modules/ROOT/nav.adoc index 889241c..24812e4 100644 --- a/CN/modules/ROOT/nav.adoc +++ b/CN/modules/ROOT/nav.adoc @@ -6,19 +6,12 @@ ** xref:v3.0/4.adoc[管理员指南] ** xref:v3.0/5.adoc[运维人员指南] * xref:v3.0/6.adoc[安装部署] -* xref:v3.0/7.adoc[开发者指南] -* xref:v3.0/8.adoc[运维管理指南] -* xref:v3.0/9.adoc[迁移指南] * xref:v3.0/10.adoc[社区贡献指南] * xref:v3.0/11.adoc[工具参考] * xref:v3.0/12.adoc[FAQ] * 功能列表 ** xref:v3.0/14.adoc[1、Ivorysql框架设计] ** xref:v3.0/15.adoc[2、GUC框架] -** xref:v3.0/16.adoc[3、大小写转换] +** xref:v3.0/16.adoc[3、适配插件] ** xref:v3.0/17.adoc[4、双模式设计] -** xref:v3.0/18.adoc[5、兼容Oracle like] -** xref:v3.0/19.adoc[6、兼容Oracle匿名块] -** xref:v3.0/20.adoc[7、兼容Oracle函数与存储过程] -** xref:v3.0/21.adoc[8、内置数据类型与内置函数] ** xref:v3.0/22.adoc[9、新增Oracle兼容模式的端口与Ip] diff --git a/CN/modules/ROOT/pages/v3.0/1.adoc b/CN/modules/ROOT/pages/v3.0/1.adoc index fe8ad99..fd2f0c6 100644 --- a/CN/modules/ROOT/pages/v3.0/1.adoc +++ b/CN/modules/ROOT/pages/v3.0/1.adoc @@ -4,111 +4,9 @@ == 版本介绍 -[**发行日期:2023年11月17日**] +[**发行日期:2024年11月20日**] -IvorySQL 3.0 基于 PostgreSQL 16.0 ,包含来自 PostgreSQL 16.0 的各种修复。有关 PostgreSQL 16.0 中更详细的更新和错误修复,请参阅官方 https://www.postgresql.org/docs/release/16.0/[PostgreSQL 16.0 发行说明] 。 - - -== 版本差异 -IvorySQL 3.0 版本在架构上发生了很大的变化,其使用方式与 2.3 版本不同。还有一些以前在 2.3 版本中可用的功能尚不受支持,以下是两个版本的功能差异。 - -|==== -| 功能模块 | 功能|IvorySQL-2.3|IvorySQL-3.0 -.14+|内置数据类型|char|不支持|支持 -|varchar|支持|支持 -|varchar2|支持|支持 -|number|不支持|支持 -|binary_float|不支持|支持 -|binary_double|不支持|支持 -|date|支持|支持 -|timestamp|不支持|支持 -|timestamp with time zone|不支持|支持 -|timestamp with local time zone|不支持|支持 -|interval year to month|不支持|支持 -|interval day to second|不支持|支持 -|raw|不支持|支持 -|long|不支持|支持 -.44+|内置函数|char|不支持|支持 -|sysdate|支持|支持 -|systimestamp|支持|支持 -|add_months|支持|支持 -|last_day|支持|支持 -|next_day| 不支持|支持 -|months_between|支持 | 支持 -|current_date | 不支持 | 支持 -|current_timestamp | 不支持 | 支持 -|new_time | 支持 | 支持 -|tz_offset | 不支持 | 支持 -|trunc | 支持 | 支持 -|instr | 不支持 | 支持 -|instrb | 不支持 | 支持 -|substr | 不支持 | 支持 -|substrb | 支持 | 支持 -|trim | 不支持 | 支持 -|ltrim | 不支持 | 支持 -|rtrim | 不支持 | 支持 -|length | 不支持 | 支持 -|lengthb | 不支持 | 支持 -|rawtohex | 不支持 | 支持 -|replace | 不支持 | 支持 -|regexp_replace | 不支持 | 支持 -|regexp_substr | 不支持 | 支持 -|regexp_instr | 不支持 | 支持 -|regexp_like | 不支持 | 支持 -|to_number | 支持 | 支持 -|to_char | 支持 | 支持 -|to_date | 支持 | 支持 -|to_timestamp | 支持 | 支持 -|to_timestamp_tz | 支持 | 支持 -|to_yminterval | 不支持 | 支持 -|to_dsinterval | 支持 | 支持 -|numtodsinterval | 支持 | 支持 -|numtoyminterval | 支持 | 支持 -|localtimestamp | 不支持 | 支持 -|new_time | 不支持 | 支持 -|from_tz | 支持 | 支持 -|sys_extract_utc | 支持 | 支持 -|sessiontimezone | 支持 | 支持 -|hextoraw | 不支持 | 支持 -|uid | 不支持 | 支持 -|USERENV | 不支持 | 支持 -.4+|NLS参数|NLS_LENGTH_SEMANTICS|不支持|支持 -|NLS_DATE_FORMAT|不支持|支持 -|NLS_TIMESTAMP_FORMAT|不支持|支持 -|NLS_TIMESTAMP_TZ_FORMAT|不支持|支持 -|Function(函数)|支持语法兼容,并支持OUT参数|支持 | 支持 -|Procedure(存储过程|支持语法兼容,并支持OUT参数|支持 | 支持 -|Anonymous block(匿名块)|支持语法兼容,并支持OUT参数|不支持 | 支持 -|嵌套子过程|支持嵌套存储过程、函数等|不支持 | 支持 -|Merge|支持PG的Merge功能以及兼容Oralce语法的Merge功能|不支持 | 支持 -|q`|支持兼容的转义符|支持 | 支持 -|关键字处理|支持数据库中关键字的处理|不支持 | 支持 -.4+|对象大小写转换|全部大写加双引号转换为小写|不支持 | 支持 -|全部小写加双引号转换为大写|不支持 | 支持 -|大小写混合加双引号保持不变|不支持 | 支持 -|不加双引号(默认)全部转为小写|不支持 | 支持 -|Search Path|支持兼容模式下,默认搜索为sys模式,再搜索pg_catalog模式|不支持 | 支持 -|空串|支持Oracle兼容将空串转为NULL|不支持 | 支持 -|词法解析器分离|3.0框架的一部分|不支持 | 支持 -|包||支持|不支持 -|全局唯一索引||支持 | 支持 -|GUC切换oracle或pg||支持 | 支持 -|层级查询||支持 | 不支持 -|NANVL ||支持 | 不支持 -|GREATEST||支持 | 不支持 -|LEAST||支持 | 不支持 -|ADD_DAYS_TO_TIMESTAMP||支持 | 不支持 -|DAYS_BETWEEN ||支持 | 不支持 -|DAYS_BETWEEN_TMTZ ||支持 | 不支持 -|DBTIMEZONE||支持 | 不支持 -|TO_MULTI_BYTE||支持 | 不支持 -|TO_SINGLE_BYTE||支持 | 不支持 -|INTERVAL_TO_SECONDS||支持 |不支持 -|HEX_TO_DECIMAL||支持 | 不支持 -|TO_BINARY_DOUBLE||支持 | 不支持 -|TO_BINARY_FLOAT||支持 | 不支持 -|BIN_TO_NUM||支持 | 不支持 -|==== +IvorySQL 1.8 基于 PostgreSQL 14.8 ,包含来自 PostgreSQL 14.8 的各种修复。有关 PostgreSQL 14.8 中更详细的更新和错误修复,请参阅官方 https://www.postgresql.org/docs/release/14.8/[PostgreSQL 14.8 发行说明] 。 == 已知问题 @@ -116,57 +14,19 @@ IvorySQL 3.0 版本在架构上发生了很大的变化,其使用方式与 2.3 == 增强功能 -=== IvorySQL 框架 - - -* 添加双Parser支持不同的数据库parser https://github.com/IvorySQL/IvorySQL/issues/208[问题细节] -* 添加双端口支持不同的数据库端口号 https://github.com/IvorySQL/IvorySQL/issues/200[问题细节] -* 添加 initdb -m,支持postgres模式或 Oracle模式 https://github.com/IvorySQL/IvorySQL/issues/212[问题细节] - - -=== SQL兼容 - -* 兼容oracle merge command https://github.com/IvorySQL/IvorySQL/issues/262[问题细节] -* 兼容oracle q转义 https://github.com/IvorySQL/IvorySQL/issues/293[问题细节] -* 兼容oracle like https://github.com/IvorySQL/IvorySQL/issues/291[问题细节] - -=== PL/SQL兼容 - -* 解决PL/SQL 创建函数/存储过程存在问题 https://github.com/IvorySQL/IvorySQL/issues/477[问题细节] -* 兼容Oracle匿名块 https://github.com/IvorySQL/IvorySQL/issues/304[问题细节] -* 在 SQL parser中创建函数或过程支持嵌套子过程 https://github.com/IvorySQL/IvorySQL/issues/312[问题细节] -* 嵌套的子进程和函数 is/as 不需要声明 https://github.com/IvorySQL/IvorySQL/issues/303[问题细节] - -=== 其它 -* 在action中增加meson编译 https://github.com/IvorySQL/IvorySQL/issues/512[问题细节] -* 支持meson编译 https://github.com/IvorySQL/IvorySQL/issues/325[问题细节] -* 添加兼容的测试用例 https://github.com/IvorySQL/IvorySQL/issues/479[问题细节] -* 添加contrib回归 https://github.com/IvorySQL/IvorySQL/issues/452[问题细节] -* 兼容btree_gist索引 https://github.com/IvorySQL/IvorySQL/issues/354[问题细节] -* 兼容btree_gin索引 https://github.com/IvorySQL/IvorySQL/issues/353[问题细节] -* 添加Oracle数据类型 GIN索引操作 https://github.com/IvorySQL/IvorySQL/issues/347[问题细节] -* 添加Oracle数据类型 Gist索引操作 https://github.com/IvorySQL/IvorySQL/issues/341[问题细节] -* 兼容Oracle内置数据类型与内置函数 https://github.com/IvorySQL/IvorySQL/issues/239[问题细节] -* 添加plisql扩展 https://github.com/IvorySQL/IvorySQL/issues/211[问题细节] - -> 说明:关于新增功能更多介绍请参考本文档中心功能列表 - - -== 问题修复 - -* 使用meson编译后,initdb执行失败 https://github.com/IvorySQL/IvorySQL/issues/520[问题细节] -* 字符类型 null 值的运算符结果不正确 https://github.com/IvorySQL/IvorySQL/issues/499[问题细节] -* 还原备份时出错 https://github.com/IvorySQL/IvorySQL/issues/483[问题细节] -* ivorysql_ora部分测试用例失败 https://github.com/IvorySQL/IvorySQL/issues/461[问题细节] -* nls参数指定ff精度与表指定精度的三种关系下,对超出长度的数据处理不一致 https://github.com/IvorySQL/IvorySQL/issues/436[问题细节] -* 日期格式中的DD HH.MI,SS AM中数据出现特殊符号后的数据处理与Oracle不一致 https://github.com/IvorySQL/IvorySQL/issues/435[问题细节] -* 对日期格式,各部分 位数校验均存在问题 https://github.com/IvorySQL/IvorySQL/issues/434[问题细节] -* NLS相关参数校验问题 https://github.com/IvorySQL/IvorySQL/issues/433[问题细节] -* 解决NLS参数设置为12小时制,默认完成AM/PM关键字的规则与Oracle不一致问题 https://github.com/IvorySQL/IvorySQL/issues/405[问题细节] -* 带默认值创建的函数/存储过程xx_arguments视图中DEFAULTED字段值为N 问题 https://github.com/IvorySQL/IvorySQL/issues/379[问题细节] -* 无权限的函数/存储过程 可以被all_procedures/all_arguments/all_source视图查看 https://github.com/IvorySQL/IvorySQL/issues/378[问题细节] -* 当自增列类型为numer类型,且指定了精度时,by default on null插入null值时,不是插入的具体序列值,而是插入的null值 https://github.com/IvorySQL/IvorySQL/issues/386[问题细节] +* PostgreSQL 14.8 +1. 防止 CREATE SCHEMA 操作破坏 search_path 中的更改。 +2. 在内联集合返回函数后,正确执行行级安全策略。 +3. 修复在 CREATE SCHEMA 中省略新架构名称时可能导致的崩溃问题。 +4. 修复分区表中克隆触发器的启用/禁用问题。 +5. 禁止修改存储在索引中的复合类型。 +* IvorySQL 1.8 +1. 添加默认数据库 "ivorysql"。 +2. 支持 X86 和 ARM 架构。 +3. 兼容国产操作系统,例如麒麟 V10。 +4. 更新部分 IvorySQL 回归测试。 +5. 支持更多开源插件,例如 ddlx 0.20、pgvector v0.8.0 和 PGroonga 3.0.0。 == 源代码 @@ -178,26 +38,12 @@ IvorySQL主要包含2个代码仓库,数据库IvorySQL代码仓、IvorySQL网 == 贡献人员 以下个人作为补丁作者、提交者、审阅者、测试者或问题报告者为本版本做出了贡献。 -- IvorySQL Pro开发及测试团队 -- 谭洋 -- 王杰 -- 穆帅楠 -- 张洪源 -- Cary Huang - Grant Zhou -- David Zhang -- 王守波 -- 任娇 -- 刘政 -- 肖哲凯 -- 金华建 -- 王丽 -- 宋金周 -- Leo X.M. Zeng -- 严少安 -- M.Imran Zaheer -- Yunhe Xu -- 王皓 -- 董小姐 -- 韩伟博 - +- 高雪玉 +- 矫顺田 +- 梁翔宇 +- 吕新杰 +- 马继超 +- 牛世继 +- 仇振超 +- 王颖泽 diff --git a/CN/modules/ROOT/pages/v3.0/15.adoc b/CN/modules/ROOT/pages/v3.0/15.adoc index 3585295..5615018 100644 --- a/CN/modules/ROOT/pages/v3.0/15.adoc +++ b/CN/modules/ROOT/pages/v3.0/15.adoc @@ -24,7 +24,6 @@ | ivorysql.database_mode | 表示当前数据库的模式(pg/oracle),可以通过show命令查看,set/reset/reset all命令不影响该变量 | ivorysql.datetime_ignore_nls_mask | 表示日期格式是否会受NLS参数影响,默认为0,可以通过set命令设置,reset 命令重置,reset all命令会重置该变量 | ivorysql.enable_emptystring_to_NULL | 取值为(on/off),该变量为on时,会将插入的空字符串转成NULL值存储 -| ivorysql.identifier_case_switch | 设置字符大小写转换模式 | ivorysql.listen_address | 表示兼容模式监听的地址,在初始化数据库时,从ivorysql.conf文件中读取该配置,在配置文件中修改该值,需要重启数据库生效,可以通过show命令查看 | ivorysql.port | 表示兼容模式下连接的端口号,在初始化数据库时,从ivorysql.conf文件中读取该配置,在配置文件中修改该值,需要重启数据库生效,可以通过show命令查看 | nls_date_format | 表示默认的日期格式,可以通过show命令查看,默认为‘YYYY-MM-DD’,可以通过set命令设置,可以通过reset命令重置回默认值,reset all 命令会重置该变量 diff --git a/CN/modules/ROOT/pages/v3.0/16.adoc b/CN/modules/ROOT/pages/v3.0/16.adoc index 16c334b..a661a00 100644 --- a/CN/modules/ROOT/pages/v3.0/16.adoc +++ b/CN/modules/ROOT/pages/v3.0/16.adoc @@ -2,63 +2,24 @@ :sectnums: :sectnumlevels: 5 -= 引用标识符的大小写转换设计 += 适配插件 == 目的 -- 为了满足PG和Oracle的引用标识符大小写兼容,ivorysql设计了三种引用标识符的大小写转换模式。通过guc参数“identifier_case_switch”选择转换模式; +- 通过RPM包安装的用户已经涵盖了如上插件,用户可以根据自身需求连接数据库后执行create extension语句即可。对于其他插件,用户可自行下载源码并于IvorySQL结合使用进行探索。 -== 功能 -=== 大小写转换的三种模式(默认为interchange) +== 说明 -- 如果 guc参数“identifier_case_switch”值为“interchange”: +- 通过RPM包安装的用户已经涵盖了如上插件,用户可以根据自身需求连接数据库后执行create extension语句即可。对于其他插件,用户可自行下载源码并于IvorySQL结合使用进行探索。 - 1). 如果双引号所引用的标识符中的字母全部为大写,则将大写转换为小写。 - - 2). 如果双引号所引用的标识符中的字母全部为小写,则将小写转换为大写。 - - 3). 如果用双引号引起来的标识符中的字母是大小写混合的,则保持标识符不变。 - -=== 初始化数据库集簇时 - -- 在initdb程序中加入 -C选项设置大小写转换模式,-C对应的值为: - - "normal" ------ "0"同义 - - "interchange" ------ "1"同义 - - "lowercase" ------ "2"同义 - - 在初始化数据库集簇的过程中,将大小写转换模式保存到data目录的global/pg_control文件中。 - -=== 测试用例 - -``` -SET ivorysql.enable_case_switch = true; -SET ivorysql.identifier_case_switch = interchange; -CREATE TABLE "ABC"(c1 int, c2 int); -SELECT relname FROM pg_class WHERE relname = 'ABC'; -SELECT relname FROM pg_class WHERE relname = 'abc'; -SELECT * FROM "ABC"; -SELECT * FROM ABC; -SELECT * FROM abc; -SELECT * FROM Abc; -SELECT * FROM "Abc"; -- ERROR -DROP TABLE abc; - -CREATE TABLE "Abc"(c1 int, c2 int); -SELECT relname FROM pg_class WHERE relname = 'ABC'; -SELECT relname FROM pg_class WHERE relname = 'abc'; -SELECT relname FROM pg_class WHERE relname = 'Abc'; -SELECT * FROM "ABC"; -- ERROR -SELECT * FROM ABC; -- ERROR -SELECT * FROM abc; -- ERROR -SELECT * FROM Abc; -- ERROR -SELECT * FROM "Abc"; -DROP TABLE "Abc"; - -``` +== 使用 +详细使用说明请参照插件对应项目网址: +|==== +|pgddl | https://github.com/lacanoid/pgddl +|pgvector | https://github.com/pgvector/pgvector +|pgroonga | https://github.com/pgroonga/pgroonga +|==== diff --git a/CN/modules/ROOT/pages/v3.0/18.adoc b/CN/modules/ROOT/pages/v3.0/18.adoc deleted file mode 100644 index 0cf48a5..0000000 --- a/CN/modules/ROOT/pages/v3.0/18.adoc +++ /dev/null @@ -1,69 +0,0 @@ -:sectnums: -:sectnumlevels: 5 - -:imagesdir: ./_images - -= 兼容Oracle like - -== 目的 - -- 本文档意在为使用 like 模糊查询的人员提供一个深入了解兼容Oracle 的模糊查询like实现的过程,是like兼容的实现文档。 - -== 功能说明 -|==== -|数据库名称|like模糊查询 -|oracle|oracle的字符串类型是varchar2,支持对数字、日期、字符串字段类型的列用Like关键字配合通配符来实现模糊查询 -|IvorySQL|IvorySQL的字符串基本类型是text,所以like是以text为基础上,其他IvorySQL的类型能隐式转换成text,这样不用创建opeartor就能自动转换 -|==== - -== 测试用例 - -``` - -create table t_ora_like (id int ,str1 varchar(8), date1 timestamp with time zone, date2 time with time zone, num int, str2 varchar(8)); -insert into t_ora_like (id ,str1 ,date1 ,date2) values (123456,'test1','2022-09-26 16:39:20','2022-09-26 16:39:20'); -insert into t_ora_like (id ,str1 ,date1 ,date2) values (123457,'test2','2022-09-26 16:40:20','2022-09-26 16:40:20'); -insert into t_ora_like (id ,str1 ,date1 ,date2) values (223456,'test3','2022-09-26 16:41:20','2022-09-26 16:41:20'); -insert into t_ora_like (id ,str1 ,date1 ,date2) values (123458,'test4','2022-09-26 16:42:20','2022-09-26 16:42:20'); - -select * from t_ora_like where str1 like 'test%'; - id | str1 | date1 | date2 | num | str2 ---------+-------+-----------------------------------+-------------+-----+------ - 123456 | test1 | 2022-09-26 16:39:20.000000 +08:00 | 16:39:20+08 | | - 123457 | test2 | 2022-09-26 16:40:20.000000 +08:00 | 16:40:20+08 | | - 223456 | test3 | 2022-09-26 16:41:20.000000 +08:00 | 16:41:20+08 | | - 123458 | test4 | 2022-09-26 16:42:20.000000 +08:00 | 16:42:20+08 | | -(4 rows) - -select * from t_ora_like where date1 like '2022%'; - id | str1 | date1 | date2 | num | str2 ---------+-------+-----------------------------------+-------------+-----+------ - 123456 | test1 | 2022-09-26 16:39:20.000000 +08:00 | 16:39:20+08 | | - 123457 | test2 | 2022-09-26 16:40:20.000000 +08:00 | 16:40:20+08 | | - 223456 | test3 | 2022-09-26 16:41:20.000000 +08:00 | 16:41:20+08 | | - 123458 | test4 | 2022-09-26 16:42:20.000000 +08:00 | 16:42:20+08 | | -(4 rows) - -select * from t_ora_like where date2 like '16%'; - id | str1 | date1 | date2 | num | str2 ---------+-------+-----------------------------------+-------------+-----+------ - 123456 | test1 | 2022-09-26 16:39:20.000000 +08:00 | 16:39:20+08 | | - 123457 | test2 | 2022-09-26 16:40:20.000000 +08:00 | 16:40:20+08 | | - 223456 | test3 | 2022-09-26 16:41:20.000000 +08:00 | 16:41:20+08 | | - 123458 | test4 | 2022-09-26 16:42:20.000000 +08:00 | 16:42:20+08 | | -(4 rows) - -select * from t_ora_like where id like '123%'; - id | str1 | date1 | date2 | num | str2 ---------+-------+-----------------------------------+-------------+-----+------ - 123456 | test1 | 2022-09-26 16:39:20.000000 +08:00 | 16:39:20+08 | | - 123457 | test2 | 2022-09-26 16:40:20.000000 +08:00 | 16:40:20+08 | | - 123458 | test4 | 2022-09-26 16:42:20.000000 +08:00 | 16:42:20+08 | | -(3 rows) - -select * from t_ora_like where id like null; - id | str1 | date1 | date2 | num | str2 -----+------+-------+-------+-----+------ -(0 rows) - -``` diff --git a/CN/modules/ROOT/pages/v3.0/19.adoc b/CN/modules/ROOT/pages/v3.0/19.adoc deleted file mode 100644 index ef13fd8..0000000 --- a/CN/modules/ROOT/pages/v3.0/19.adoc +++ /dev/null @@ -1,49 +0,0 @@ -:sectnums: -:sectnumlevels: 5 - -:imagesdir: ./_images - -= 兼容Oracle匿名块 - -== 目的 - -- 本文档是PLSQL匿名块(anonymous block)兼容Oracle语法功能的设计文档,目的是可以在IvorySQL中兼容Oracle的匿名块语句。 - -== 功能说明 - -- 匿名块是能够动态地创建和执行过程代码的PLSQL结构,而不需要以持久化的方式将代码作为数据库对象储存在系统目录中。本次实现中IvorySQL主要兼容的是PLSQL匿名块的语法格式,我们主要处理的部分包括客户端工具psql、主服务器和PSQL端支持。 - -== 测试用例 - -``` - -declare -i integer := 10; -begin - raise notice '%', i; - raise notice '%', main.i; -end; -/ -NOTICE: 10 -NOTICE: 10 - -``` - -``` - -DECLARE - grade CHAR(1); -BEGIN - grade := 'B'; - CASE grade - WHEN 'A' THEN raise notice 'Excellent'; - WHEN 'B' THEN raise notice 'Very Good'; - END CASE; -EXCEPTION - WHEN CASE_NOT_FOUND THEN - raise notice 'No such grade'; -END; -/ -NOTICE: Very Good - -``` diff --git a/CN/modules/ROOT/pages/v3.0/2.adoc b/CN/modules/ROOT/pages/v3.0/2.adoc index 355f2c7..3fb0a15 100644 --- a/CN/modules/ROOT/pages/v3.0/2.adoc +++ b/CN/modules/ROOT/pages/v3.0/2.adoc @@ -13,8 +13,6 @@ IvorySQL社区始终承诺与PostgreSQL数据库保持100%兼容,并且可以 IvorySQL增加了一个名为 `ivorysql.compatible_mode` 的GUC参数用以控制IvorySQL的兼容模式,该参数有 `oracle` 和 `pg` 两种值。在初始化数据目录的时候,通过指定 `-m` 参数来指定数据目录的兼容模式,`-m pg` 则数据目录为PostgreSQL模式,该模式下 `ivorysql.compatible_mode` 参数将会失效,`-m oracle` 或者不指定 `-m` 参数则数据目录为兼容Oracle模式,该模式下 `ivorysql.compatible_mode` 参数初始值为 `oracle` 并且不支持部分PostgreSQL的语法,通过 `set ivorysql.compatible_mode to pg` 就可以使得数据库100%支持PostgreSQL的语法及功能。 -IvorySQL的亮点之一是PL/iSQL过程语言,它支持Oracle的PL/SQL语法。同时,IvorySQL通过增加与内核绑定的插件 *ivorysql_ora* 来实现兼容Oracle的功能,目前实现的功能包括内置函数、数据类型、系统视图、merge以及GUC参数的增加,未来将会继续以绑定内核的插件的形式来实现新的兼容功能。 - IvorySQL项目是在Apache 2.0许可证下发布的,社区鼓励且欢迎所有类型的贡献和参与。 === 产品目标和范围 @@ -66,15 +64,3 @@ Ivory数据库的主要应用场景: == 主要、基本功能 IvorySQL是一个功能强大的开源对象关系数据库管理系统(ORDBMS)。 用于安全地存储数据,支持最佳做法,并允许在处理请求时检索它们。除此之外,还兼容了Oracle的语法,适用于使用Oracle的场景。 - -== 与Oracle的兼容性 - -* https://docs.ivorysql.org/cn/ivorysql-doc/v3.0/v3.0/14[ivorysql框架设计] -* https://docs.ivorysql.org/cn/ivorysql-doc/v3.0/v3.0/15[GUC框架] -* https://docs.ivorysql.org/cn/ivorysql-doc/v3.0/v3.0/16[大小写转换] -* https://docs.ivorysql.org/cn/ivorysql-doc/v3.0/v3.0/17[双模式设计] -* https://docs.ivorysql.org/cn/ivorysql-doc/v3.0/v3.0/18[兼容Oracle like] -* https://docs.ivorysql.org/cn/ivorysql-doc/v3.0/v3.0/19[兼容Oracle匿名块] -* https://docs.ivorysql.org/cn/ivorysql-doc/v3.0/v3.0/20[兼容Oracle函数与存储过程] -* https://docs.ivorysql.org/cn/ivorysql-doc/v3.0/v3.0/21[内置数据类型与内置函数] -* https://docs.ivorysql.org/cn/ivorysql-doc/v3.0/v3.0/22[新增Oracle兼容模式的端口与ip] diff --git a/CN/modules/ROOT/pages/v3.0/20.adoc b/CN/modules/ROOT/pages/v3.0/20.adoc deleted file mode 100644 index 33b7ea2..0000000 --- a/CN/modules/ROOT/pages/v3.0/20.adoc +++ /dev/null @@ -1,101 +0,0 @@ -:sectnums: -:sectnumlevels: 5 - -:imagesdir: ./_images - -= 兼容Oracle函数与存储过程 - -== 目的 - -- 本文档意在兼容Oracle PLSQL函数和存储过程的语法,在IvorySQL中我们称其为PLISQL语言。 - -== 功能说明 - -.函数(FUNCTION) -|==== -|CREATE FUNCTION语法支持EDITIONABLE/NONEDITIONABLE -|CREATE FUNCTION语法支持RETURN, IS关键字,不指定language -|CREATE FUNCTION语法函数没有参数,函数名后面不带() -|CREATE FUNCTION参数个数最多是32767 -|CREATE FUNCTION语法中END; 在psql中以/结束 -|CREATE FUNCTION语法变量声明前面没有DECLARE关键字 -|CREATE FUNCTION语法支持OUT 参数NOCOPY功能 -|CREATE FUNCTION语法支持sharing_clause -|CREATE FUNCTION语法支持invoker_rights_clause,默认权限改成DR(DEFINER) -|CREATE FUNCTION语法支持ACCESSIBLE BY  -|CREATE FUNCTION语法支持DEFAULT COLLATION -|CREATE FUNCTION语法支持result_cache_clause  -|CREATE FUNCTION语法支持aggregate_clause -|CREATE FUNCTION语法支持pipelined_clause -|CREATE FUNCTION语法支持sql_macro_clause -|ALTER FUNCTION语法 -|函数和存储过程相关的视图 -|==== - - -.存储过程(PROCEDURE) -|==== -|CREATE PROCEDURE语法支持EDITIONABLE/NONEDITIONABLE -|CREATE PROCEDURE语法函数没有参数,函数名后面不带() -|CREATE PROCEDURE参数个数最多是32767 -|CREATE PROCEDURE语法中END; 在psql中以/结束 -|CREATE PROCEDURE语法支持sharing_clause -|CREATE PROCEDURE语法支持DEFAULT COLLATION -|CREATE PROCEDURE语法支持invoker_rights_clause -|CREATE PROCEDURE语法支持ACCESSIBLE BY  -|ALTER PROCEDURE语法 -|存储过程没有参数,调用支持不带() -|存储过程调用支持EXEC -|在PL/SQL 中调用存储过程,可以省略CALL,直接使用存储过程名字 -|支持--和/**/两种注释方法 -|==== - - -== 测试用例 - -``` - -CREATE or replace FUNCTION ora_func RETURN integer AS -BEGIN - RETURN 1; -END; -/ - -CREATE OR REPLACE FUNCTION test_nocopy(a IN int, b OUT NOCOPY int, c IN OUT NOCOPY int) -RETURN record -IS -BEGIN - b := a; - c := a; -END; -/ - -``` -``` - -CREATE OR REPLACE PROCEDURE ora_procedure() -AS - p integer := 20; -begin - raise notice '%', p; -end; -/ -call ora_procedure(); - -CREATE OR REPLACE PROCEDURE ora_procedure -SHARING = METADATA -DEFAULT COLLATION USING_NLS_COMP -AUTHID CURRENT_USER -ACCESSIBLE BY ( FUNCTION A.B ) -IS - p integer := 20; -begin - raise notice '%', p; -end; -/ - -``` - - - - diff --git a/CN/modules/ROOT/pages/v3.0/21.adoc b/CN/modules/ROOT/pages/v3.0/21.adoc deleted file mode 100644 index 91d1171..0000000 --- a/CN/modules/ROOT/pages/v3.0/21.adoc +++ /dev/null @@ -1,965 +0,0 @@ -:sectnums: -:sectnumlevels: 5 - -:imagesdir: ./_images - -= 内置数据类型与内置函数 - -== 内置数据类型 - -|==== -|char -|varchar -|varchar2 -|number -|binary_float -|binary_double -|date -|timestamp -|timestamp with time zone -|timestamp with local time zone -|interval year to month -|interval day to second -|raw -|long -|==== - -== 内置函数类型 - -|==== -|sysdate -|systimestamp -|add_months -|last_day -|next_day -|months_between -|current_date -|current_timestamp -|new_time -|tz_offset -|trunc -|instrb -|substr -|substrb -|trim -|ltrim -|rtrim -|length -|lengthb -|rawtohex -|replace -|regexp_replace -|regexp_substr -|regexp_instr -|regexp_like -|to_number -|to_char -|to_date -|to_timestamp -|to_timestamp_tz -|to_yminterval -|to_dsinterval -|numtodsinterval -|numtoyminterval -|localtimestamp -|from_tz -|sys_extract_utc -|sessiontimezone -|hextoraw -|uid -|USERENV -|==== - -== 内置函数说明 - -1、兼容sysdate函数,功能:查看对应的日期与时间,测试用例如下: -查询当前系统的日期: - -``` -select sysdate() from dual; - sysdate ------------- - 2023-07-06 -(1 row) -``` - -查询往前推1天的日期: - -``` -select sysdate()-1 from dual; - ?column? ------------- - 2023-07-05 -(1 row) -``` - -2、兼容systimestamp函数,功能:返回本机数据库上当前系统日期和时间(包括微秒和时区),测试用例如下: -查询当前日期的日期和时间: - -``` -select systimestamp() from dual; - systimestamp ------------------------------------ - 2023-07-06 10:18:31.674322 +08:00 -(1 row) -``` - -3、兼容add_months函数,功能:函数将一个月数(n)添加一个日期,并返回相隔n月的同一天,支持参数:date, number;测试用例如下: -查询当前日期(七月六日)的下个月的同一天: - -``` -select add_months(sysdate(),1) from dual; - add_months ------------- - 2023-08-06 -(1 row) -``` - -查询当前日期的上个月的同一天: - -``` -select add_months(sysdate(),-1) from dual; - add_months ------------- - 2023-06-06 -(1 row) -``` - -4、兼容last_day函数,功能:返回指定日期所在月份的最后一天,支持参数:date,测试用例如下: -查询当天所在月份的最后一天: - -``` -select last_day(sysdate())from dual; - last_day ------------- - 2023-07-31 -(1 row) -``` - -查询某一天所在月份的最后一天: - -``` -select last_day(to_date('2019-09-01'))from dual; - last_day ------------- - 2019-09-30 -(1 row) -``` - -5、兼容next_day函数,功能:返回指定日期的下一个日期。支持参数:date, integer /date ,text, 说明:当函数中第二个参数传的星期数比现有星期数小时,会返回下一个星期的日期;当函数中第二个参数所传的日期比现有星期数大,会返回本周相应星期日期。测试用例如下: -查询当前日期的下一天: - -``` -select next_day(sysdate(),1) from dual; - next_day ------------- - 2023-07-07 -(1 row) -``` - -查询当前日期的下个星期五: - -``` -select next_day(sysdate(),'FRIDAY') from dual; - next_day ------------- - 2023-07-07 -(1 row) -``` - -6、兼容months_between函数,功能:返回日期类型的date1和date2之间相差的月份,支持参数:date,date,说明:如果date1晚于date2,返回正数;如果date1早于date2返回负数;如果date1和date2是某月里的同一天,返回结果为整数;如果不是同一天,会在每月31天的基础上返回带有小数部分的结果。测试用例如下: -查询不同月份同一天之间相差的月份: - -``` -select months_between(to_date('2023-07-06'),to_date('2023-08-06')) from dual; - months_between ----------------- - -1 -(1 row) -``` - -查询不同月份不同日期之间相差的月份: - -``` -select months_between(to_date('2023-07-06'),to_date('2023-08-05')) from dual; - months_between --------------------- - -0.967741935483871 -(1 row) -``` - -7、兼容current_date函数,功能:返回当前时区的当前日期,测试用例如下: -查询当前时区的当前日期: - -``` -select current_date from dual; - current_date --------------- - 2023-07-06 -(1 row) -``` - -8、兼容current_timestamp函数,功能:返回当前时区的当前日期与当前时间,包含当前时区信息。支持参数:integer, 说明:返回的时间可调整精度。测试用例如下: -查询当前时区的当前日期与时间: - -``` -select current_timestamp from dual; - current_timestamp ------------------------------------ - 2023-07-06 10:27:01.440600 +08:00 -(1 row) -``` - -查询当前时区的当前日期与时间(精度调整为前三位小数): - -``` -select current_timestamp(3) from dual; - current_timestamp ------------------------------------ - 2023-07-06 10:27:14.182000 +08:00 -(1 row) -``` - -9、兼容new_time函数,功能:返回某个时间在某时区所对应的在另一个时区的日期,支持参数:date, text, text ,测试用例如下: -返回当前日期在另一个时区对应的日期: - -``` -select sysdate() bj_time,new_time(sysdate(),'PDT','GMT')los_angles from dual; - bj_time | los_angles -------------+------------ - 2023-07-06 | 2023-07-06 -(1 row) -``` - -10、兼容tz_offset函数,功能:返回给定时区与标准时区的偏移量,支持参数:text,测试用例如下: -返回给定时区与标准时区偏移量: - -``` -select tz_offset('US/Eastern') from dual; - tz_offset ------------ - -04:00 -(1 row) -``` - -11、兼容trunc函数,功能:可以截取日期,得到想要的数值,如年,月,日,时,分,支持参数:date/date,text,测试用例如下: -截取当前日期: - -``` -select trunc(sysdate()) from dual; - trunc ------------- - 2023-07-06 -(1 row) -``` - -截取年,返回值只有年是正确的,月和日不是准确值: - -``` -select trunc(sysdate(),'yyyy') from dual; - trunc ------------- - 2023-01-01 -(1 row) -``` - -截取月,返回值只有月是正确的,年和日不是准确值: - -``` -select trunc(sysdate(),'mm') from dual; - trunc ------------- - 2023-07-01 -(1 row) -``` - -12、兼容instrb函数,功能:字符串查找函数,返回字符串的位置,支持参数: varchar2, text, number DEFAULT 1, number DEFAULT 1,以下为测试用例: -返回CORPORATE FLOOR中默认第一次出现OR时字符串的位置: - -``` -SELECT INSTRB('CORPORATE FLOOR','OR') "Instring in bytes" FROM DUAL; - Instring in bytes -------------------- - 2 -(1 row) -``` - -返回corporate floor中从第五个字符开始查询,第二次出现or时字符串的位置: - -``` -SELECT INSTRB('CORPORATE FLOOR','OR',5,2) "Instring in bytes" FROM DUAL; - Instring in bytes -------------------- - 14 -(1 row) -``` - -13、兼容substr函数,功能:截取字符串函数,以字符为单位截取,支持参数:text, integer, 测试用例如下: -截取’今天天气很好’中从第五个字符开始,往后的字符串: - -``` -SELECT SUBSTR('今天天气很好',5) "Substring with bytes" FROM DUAL; - - Substring with bytes ----------------------- - 很好 -(1 row) -``` - -14、兼容substrb函数,功能:截取字符串函数,以字节为单位截取,支持参数:varchar2, number/varchar2, number,number,测试用例如下: -截取’今天天气很好’中从第五个字节开始,往后的字符串: - -``` -SELECT SUBSTRB('今天天气很好',5) "Substring with bytes" FROM DUAL; - Substring with bytes ----------------------- - 天气很好 -(1 row) -``` - -截取’今天天气很好’中从第五个字节开始,第八个字节结束的字符串: - -``` -SELECT SUBSTRB('今天天气很好',5,8) "Substring with bytes" FROM DUAL; - Substring with bytes ----------------------- - 天气 -(1 row) -``` - -15、兼容trim函数,功能:去除指定字符串的左右空格或对应数据,支持参数:varchar2 /varchar2,varchar2,测试用例如下: -去除' aaa bbb ccc '的左右空格: - -``` -select trim(' aaa bbb ccc ')trim from dual; - trim -------------- - aaa bbb ccc -(1 row) -``` - -去除'aaa bbb ccc'中的aaa: - -``` -select trim('aaa bbb ccc','aaa')trim from dual; - trim ----------- - bbb ccc -(1 row) -``` - -16、兼容ltrim函数,功能:去除指定字符串的左侧空格或对应数据,支持参数:varchar2 /varchar2,varchar2,测试用例如下: -去除' abcdefg '的左侧空格: - -``` -select ltrim(' abcdefg ')ltrim from dual; - ltrim ------------- - abcdefg -(1 row) -``` - -从'abcdefg'左侧开始遍历,一旦存在某字符出现在'fegab'中就去除,不存在则返回结果: - -``` -select ltrim('abcdefg','fegab')ltrim from dual; - ltrim -------- - cdefg -(1 row) -``` - -17、兼容rtrim函数,功能:去除指定字符串的右侧空格,测试用例如下: -去除' abcdefg '的右侧空格: - -``` -select rtrim(' abcdefg ')rtrim from dual; - rtrim ----------------- - abcdefg -(1 row) -``` - -从'abcdefg'右侧开始遍历,一旦存在某字符出现在'fegab'中就去除,不存在则返回结果: - -``` -select rtrim('abcdefg','fegab')rtrim from dual; - rtrim -------- - abcd -(1 row) -``` - -18、兼容length函数,功能:求取指定字符串字符的长度,支持参数:char/integer/varchar2测试用例如下: -查询223的字符长度: - -``` -select length(223) from dual; - length --------- - 3 -(1 row) -``` - -查询'223'的字符长度: - -``` -select length('223') from dual; - length --------- - 3 -(1 row) -``` - -查询'ivorysql数据库'的字符长度: - -``` -select length('ivorysql数据库') from dual; - length --------- - 11 -(1 row) -``` - -19、兼容lengthb功能:求取指定字符串字节的长度,支持参数:char/bytea/varchar2测试用例如下: -查询'ivorysql'的字节长度: - -``` -select lengthb('ivorysq'::char) from dual; - lengthb ---------- - 1 -(1 row) -``` - -查询'0x2C'的字节长度: - -``` -select lengthb('0x2C'::bytea) from dual; - lengthb ---------- - 4 -(1 row) -``` - -查询'ivorysql数据库'的字节长度: - -``` -select lengthb('ivorysql数据库'::varchar2) from dual; - lengthb ---------- - 17 -(1 row) -``` - -20、兼容replace函数,功能:替换指定字符串中的字符或删除字符,支持参数:text, text, text/varchar2, varchar2, varchar2 DEFAULT NULL::varchar2, 测试用例如下: -替换'jack and jue'中的'j'为'bl': - -``` -select replace('jack and jue','j','bl') from dual; - replace ----------------- - black and blue -(1 row) -``` - -删除'jack and jue'中的'j': - -``` -select replace('jack and jue','j') from dual; - replace ------------- - ack and ue -(1 row) -``` - -21、兼容regexp_replace函数,此函数为replace函数的扩展。功能:用于通过正则表达式来进行匹配替换。支持参数:text, text, text /text, text, text, integer/varchar2, varchar2/varchar2, varchar2 varchar2, 测试用例如下: -将匹配到的数字替换为*#: - -``` -select regexp_replace('01234abcd56789','[0-9]','*#')from dual; - regexp_replace --------------------------- - *#*#*#*#*#abcd*#*#*#*#*# -(1 row) -``` - -从第二个数开始将匹配到的数字替换为*#: - -``` -select regexp_replace('01234abcd56789','[0-9]','*#',2)from dual; - regexp_replace -------------------------- - 0*#*#*#*#abcd*#*#*#*#*# -``` - -删除'01234abcd56789'中的'01': - -``` -select regexp_replace('01234abcd56789','01')from dual; - regexp_replace ----------------- - 234abcd56789 -(1 row) -``` - -用'xxx'替换01234abcd56789'中的012: - -``` -select regexp_replace('01234abcd56789','012','xxx')from dual; - regexp_replace ----------------- - xxx34abcd56789 -(1 row) -``` - -22、兼容regexp_substr函数,功能:拾取合符正则表达式描述的字符子串,支持参数:text, text,integer /text, text, integer, integer/ text, text, integer, integer, text /varchar2 ,varchar2,测试用例如下: -查询'012ab34'中从第一个数开始的012字串: - -``` -select regexp_substr('012ab34', '012',1) from dual; - regexp_substr ---------------- - 012 -(1 row) -``` - -查询'012ab34'中从第一个数第一组开始的012字串: -``` -select regexp_substr('012ab34', '012',1,1) from dual; - regexp_substr ---------------- - 012 -(1 row) -``` - -查询'012a012Ab34'中从第一个数第一组开始不区分大小写的012字串: - -``` -select regexp_substr('012a012Ab34', '012A',1,1,'i') from dual; - regexp_substr ---------------- - 012a -(1 row) -``` - -查询'012a012Ab34'中从第一个数第一组开始区分大小写的012字串: - -``` -select regexp_substr('012a012Ab34', '012A',1,1,'c') from dual; - regexp_substr ---------------- - 012A -(1 row) -``` - -查询'数据库'中 '数据'子串: - -``` -select regexp_substr('数据库', '数据') from dual; - regexp_substr ---------------- - 数据 -(1 row) -``` - -23、兼容regexp_instr函数,功能:用于标定符合正则表达式的字符子串的开始位置,支持参数:text, text,integer /text, text, integer, integer/ text, text, integer, integer, text/text, text, integer, integer, text, integer/ varchar2, varchar2,测试用例如下: -查询'abcaBcabc'中从第一个字符开始,出现abc子串的位置: - -``` -SELECT regexp_instr('abcaBcabc', 'abc', 1); - regexp_instr --------------- - 1 -(1 row) -``` - -查询'abcaBcabc'中从第一个字符开始,第三次出现abc子串的位置: - -``` -SELECT regexp_instr('abcaBcabc', 'abc', 1, 3); - regexp_instr --------------- - 7 -(1 row) -``` - -查询'abcabcabc'中从第一个字符开始,第二次出现abc子串后发生的位置: - -``` -SELECT regexp_instr('abcaBcabc', 'abc', 1, 2,1); - regexp_instr --------------- - 7 -(1 row) -``` - -查询'abcaBcabc'中从第一个字符开始,第一次出现abc子串后发生的位置(区分大小写): - -``` -SELECT regexp_instr('abcaBcabc', 'abc',1,2,1,'c'); - regexp_instr --------------- - 7 -(1 row) -``` - -查询'数据库'中'库'出现的位置: - -``` -SELECT regexp_instr('数据库', '库'); - regexp_instr --------------- - 3 -(1 row) -``` - -24、兼容regexp_like函数,功能:与like类似,用于模糊查询。支持参数:varchar2, varchar2 /varchar2, varchar2 varchar2, -首先创建一个regexp_like表用于测试用例查询: - -``` -create table t_regexp_like -( - id varchar(4), - value varchar(10) - -); -insert into t_regexp_like values ('1','1234560'); -insert into t_regexp_like values ('2','1234560'); -insert into t_regexp_like values ('3','1b3b560'); -insert into t_regexp_like values ('4','abc'); -insert into t_regexp_like values ('5','abcde'); -insert into t_regexp_like values ('6','ADREasx'); -insert into t_regexp_like values ('7','123 45'); -insert into t_regexp_like values ('8','adc de'); -insert into t_regexp_like values ('9','adc,.de'); -insert into t_regexp_like values ('10','abcbvbnb'); -insert into t_regexp_like values ('11','11114560'); -``` - -测试用例如下: -查询t_regexp_like表中带有abc的列: - -``` -select * from t_regexp_like where regexp_like(value,'abc'); - id | value -----+---------- - 4 | abc - 5 | abcde - 10 | abcbvbnb -(3 rows) - -``` - -查询t_regexp_like表中带有ABC的列(不区分大小写): - -``` -select * from t_regexp_like where regexp_like(value,'ABC','i'); - id | value -----+---------- - 4 | abc - 5 | abcde - 10 | abcbvbnb -(3 rows) - -``` - -25、兼容to_number函数,功能:是将一些处理过的按一定格式编排过的字符串变回数值型的格式,支持参数:text/text,text测试用例如下: -将字符串'-34,338,492'转换为数值型格式: - -``` -SELECT to_number('34,338,492', '99,999,999') from dual; - to_number ------------ - -34338492 -(1 row) -``` - -将字符串'5.01-'转换为数值型格式: - -``` -SELECT to_number('5.01-', '9.99S'); - - to_number ------------ - -5.01 -(1 row) -``` - -26、兼容to_char函数,功能:将数字或日期转换为字符类型,支持参数:date/date,text/timestamp/timestamp,text测试用例如下: -将当前系统日期转换为字符格式: - -``` -select to_char(sysdate()) from dual; - to_char ------------- - 2023-07-10 -(1 row) -``` - -将当前系统日期转换为月份/日期/年字符格式: - -``` -select to_char(sysdate(),'mm/dd/yyyy') from dual; - to_char ------------- - 07/10/2023 -(1 row) -``` - -将当前日期的timestamp格式转换为字符格式: - -``` -SELECT to_char(sysdate()::timestamp); - to_char ----------------------------- - 2023-07-10 09:46:44.000000 -``` - -将当前日期的timestamp格式转换为月份/日期/年字符格式: - -``` -SELECT to_char(sysdate()::timestamp,'MM-YYYY-DD'); - to_char ------------- - 07-2023-10 -(1 row) -``` - -27、兼容to_date函数,功能:将字符类型转换为日期类型,支持参数:text/text,text测试用例如下: -将'2023/07/06'转换为日期类型: - -``` -select to_date('20230706') from dual; - to_date ------------- - 2023-07-06 -(1 row) -``` - -将'-44-02-01'转换为日期类型: - -``` -SELECT to_date('-44,0201','YYYY-MM-DD'); - to_date ------------- - 0044-02-01 -(1 row) -``` - -28、兼容to_timestamp函数,功能:可以存储年、月、日、小时、分钟、秒,同时还可以存储秒的小数部分。支持参数:text/text,text测试用例如下: -查询'2018-11-02 12:34:56.025'以日期形式输出: - -``` -SELECT to_timestamp('20181102.12.34.56.025'); - to_timestamp ----------------------------- - 2018-11-02 12:34:56.025000 -(1 row) -``` - -查询’2011,12,18 11:38’以日期形式输出: - -``` -SELECT to_timestamp('2011,12,18 11:38 ', 'YYYY-MM-DD HH24:MI:SS'); - to_timestamp ----------------------------- - 2011-12-18 11:38:00.000000 -(1 row) -``` - -29、兼容to_timestamp_tz函数,功能:根据时间查询,时间字符串有T,Z并有毫秒,时区。测试用例如下: -查询'2016-10-9 14:10:10.123000'以日期形式输出: - -``` - SELECT to_timestamp_tz('2016-10-9 14:10:10.123000') FROM DUAL; - to_timestamp_tz ------------------------------------ - 2016-10-09 14:10:10.123000 +08:00 -(1 row) -``` - -查询'10-9-2016 14:10:10.123000 +8:30'以日期形式输出: - -``` - SELECT to_timestamp_tz('10-9-2016 14:10:10.123000 +8:30', 'DD-MM-YYYY HH24:MI:SS.FF TZH:TZM') FROM DUAL; - to_timestamp_tz ------------------------------------ - 2016-09-10 13:40:10.123000 +08:00 -(1 row) -``` - -30、兼容to_yminterval函数,功能:将一个字符串类型转化为年和月的时间差类型,支持参数:text, 测试用例如下: -查询'20110101'以后两个年零八个月后的日期: - -``` -select to_date('20110101','yyyymmdd')+to_yminterval('02-08') from dual; - ?column? ------------- - 2013-09-01 -(1 row) -``` - -31、兼容to_dsinterval函数,功能:将一个日期加上一定的小时或者天数变成另外一个日期,支持参数:text,测试用例如下: -查询当前系统时间加上9个半小时后的日期(当前为2023-07-06,18:00): - -``` -select sysdate()+to_dsinterval('0 09:30:00')as newdate from dual; - newdate ------------- - 2023-07-07 -(1 row) -``` - -32、兼容numtodsinterval函数,功能:将数字转换成时间间隔类型的数据。支持参数:double precision, text测试用例如下: -转换100.00个小时为时间间隔类型数据: - -``` -SELECT NUMTODSINTERVAL(100.00, 'hour'); - numtodsinterval -------------------------------- - +000000004 04:00:00.000000000 -(1 row) -``` - -转换100分钟为时间间隔类型数据: - -``` -SELECT NUMTODSINTERVAL(100, 'minute'); - numtodsinterval -------------------------------- - +000000000 01:40:00.000000000 -(1 row) -``` - -33、兼容numtoyminterval函数,功能:将数字转换成日期间隔类型的数据。 -支持参数:double precision,text,测试用例如下: -转换1.00,year为日期间隔: - -``` -SELECT NUMTOYMINTERVAL(1.00,'year'); - numtoyminterval ------------------ - +000000001-00 -(1 row) -``` - -转换1,mouth为日期间隔: - -``` -SELECT NUMTOYMINTERVAL(1,'month'); - numtoyminterval ------------------ - +000000000-01 -(1 row) -``` - -34、兼容localtimestamp函数,功能:返回会话中的日期和时间,支持参数:integer, 函数中增加参数为精度,测试用例如下: -返回当前会话中的日期和时间: - -``` -select localtimestamp from dual; - localtimestamp ----------------------------- - 2023-07-07 09:18:15.896472 -(1 row) -``` - -返回当前会话中的日期和时间(精度为1): - -``` -select localtimestamp(1) from dual; - localtimestamp ----------------------------- - 2023-07-07 09:18:16.100000 -(1 row) -``` - -35、兼容from_tz函数,功能:将时间从一个时区转换为另一个时区,支持参数;timestamp, text ,测试用例如下: -将'2000-03-28 08:00:00', '3:00'转换为当前时区: - -``` -SELECT FROM_TZ(TIMESTAMP '2000-03-28 08:00:00', '3:00') FROM DUAL; - from_tz ------------------------------------ - 2000-03-28 13:00:00.000000 +08:00 -(1 row) -``` - -36、兼容sys_extract_utc函数,功能:将一个timestamptz转换为UTC时区时间。支持参数:timestamp with time zone 测试用例如下: -查询转换timestamp '2000-03-28 11:30:00.00 -8:00'为UTC时区后的时间: - -``` -select sys_extract_utc(timestamp '2000-03-28 11:30:00.00 -8:00') from dual; - sys_extract_utc ----------------------------- - 2000-03-28 19:30:00.000000 -(1 row) -``` - -37、兼容sessiontimezone函数,功能:查看时区详细信息,测试用例如下: -查看当前时区的详细信息: - -``` -select sessiontimezone() from dual; - sessiontimezone ------------------ - Asia/Shanghai -(1 row) -``` - -修改timezone后,查看时区相信信息: - -``` -set timezone = 'Asia/Hong_Kong'; -SET -select sessiontimezone() from dual; - sessiontimezone ------------------ - Asia/Hong_Kong -(1 row) -``` - -38、兼容hextoraw函数,功能:将字符串表示的二进制数值转换为一个raw数值。支持参数:text,测试用例如下: -将字符串'abcdef'转换为raw数值: - -``` -select hextoraw('abcdef')from dual; - hextoraw ----------- - \xabcdef -(1 row) -``` - -39、兼容uid函数,功能:获取数据库的实例名。测试用例如下: -获取当前数据库的实例名: - -``` -select uid() from dual; - uid ------ - 10 -(1 row) -``` - -40、兼容USERENV函数,功能:返回当前用户环境的信息,测试用例如下: -查看当前用户是否是dba,如果是返回ture: - -``` -select userenv('isdba')from dual; - get_isdba ------------ - TRUE -(1 row) -``` - -查看会话标志: - -``` -select userenv('sessionid')from dual; - get_sessionid ---------------- - 1 -(1 row) -``` - diff --git a/CN/modules/ROOT/pages/v3.0/3.adoc b/CN/modules/ROOT/pages/v3.0/3.adoc index bc66d1a..78dd1e1 100644 --- a/CN/modules/ROOT/pages/v3.0/3.adoc +++ b/CN/modules/ROOT/pages/v3.0/3.adoc @@ -115,7 +115,7 @@ image::p19.png[] [source,] ---- [highgo@ivorysql ~]$ psql -d postgres -psql (16devel) +psql (14.8) Type "help" for help. postgres=# @@ -138,7 +138,7 @@ undefined [root@localhost ~]# su - ivorysql Last login: Wed Feb 24 10:47:32 CST 2023 on pts/0 -bash-4.2$ psql -psql (14.2) +psql (14.8) Type "help" for help. ivorysql=# @@ -169,28 +169,21 @@ image::p2.png[] 安装包:rpm -下载YUM源:在Centos7上使用wget下载 +下载RPM包:在Centos7上使用wget下载 -wget https://yum.highgo.ca/dists/ivorysql-rpms/repo/ivorysql-release-1.0-2.noarch.rpm - -安装源 -[source,] ----- -yum install ivorysql-release-1.0-2.noarch.rpm ----- +wget https://github.com/IvorySQL/IvorySQL/releases/download/Ivory_REL_1_8/ivorysql1-1.8-1.el7.x86_64.rpm -安装库 +安装IvorySQL [source,] ---- -yum install -y ivorysql2-server +yum install ivorysql1-1.8-1.el7.x86_64.rpm ---- 初始化单机数据库 [source,] ---- -cd /usr/local/ivorysql/ivorysql-2/bin -./initdb -D ../data +/opt/IvorySQL-1.8/bin/initdb -D data/ ---- ===== 集群安装(一主一备) @@ -199,28 +192,23 @@ cd /usr/local/ivorysql/ivorysql-2/bin 安装包:rpm -下载YUM源:在Centos7上使用wget下载 +下载RPM包:在Centos7上使用wget下载 -wget https://yum.highgo.ca/dists/ivorysql-rpms/repo/ivorysql-release-1.0-2.noarch.rpm +wget https://github.com/IvorySQL/IvorySQL/releases/download/Ivory_REL_1_8/ivorysql1-1.8-1.el7.x86_64.rpm -安装源 +安装IvorySQL [source,] ---- -yum install ivorysql-release-1.0-2.noarch.rpm +yum install ivorysql1-1.8-1.el7.x86_64.rpm ---- -安装库 -[source,] ----- -yum install -y ivorysql2-server ----- **主节点** 初始化主节点 [source,] ---- -cd /usr/local/ivorysql/ivorysql-2/bin +/opt/IvorySQL-1.8/bin/initdb -D data/ ./initdb ../data-primary -U postgres ---- @@ -247,7 +235,7 @@ host replication all 0.0.0.0/0 trust 1、 基础备份 [source,shell] ---- -cd /usr/local/ivorysql/ivorysql-2/bin +cd /opt/IvorySQL-1.8/bin ./pg_basebackup -h 127.0.0.1 -p 5333 -U repl -W -Fp -Xs -Pv -R -D ../data-standby01 ---- @@ -270,29 +258,20 @@ vi ../data-standby01/postgresql.conf 安装包:rpm -下载YUM源:在Centos7上使用wget下载 - -wget https://yum.highgo.ca/dists/ivorysql-rpms/repo/ivorysql-release-1.0-2.noarch.rpm +下载RPM包:在Centos7上使用wget下载 +wget https://github.com/IvorySQL/IvorySQL/releases/download/Ivory_REL_1_8/ivorysql1-1.8-1.el7.x86_64.rpm -安装源 +安装IvorySQL [source,] ---- -yum install ivorysql-release-1.0-2.noarch.rpm ----- - - -安装库 -[source,] ----- -yum install -y ivorysql2-server +yum install ivorysql1-1.8-1.el7.x86_64.rpm ---- 初始化主节点 [source,] ---- -cd /usr/local/ivorysql/ivorysql-2/bin -./initdb ../data-primary -U postgres +/opt/IvorySQL-1.8/bin/initdb -D data/ ---- 启动服务,创建用户 @@ -332,22 +311,18 @@ host replication all 0.0.0.0/0 trust 安装包:rpm -下载YUM源:在Centos7上使用wget下载 - -wget https://yum.highgo.ca/dists/ivorysql-rpms/repo/ivorysql-release-1.0-2.noarch.rpm - -安装源 +下载RPM包:在Centos7上使用wget下载 - yum install ivorysql-release-1.0-2.noarch.rpm +wget https://github.com/IvorySQL/IvorySQL/releases/download/Ivory_REL_1_8/ivorysql1-1.8-1.el7.x86_64.rpm -安装库 +安装IvorySQL - yum install -y ivorysql2-server + yum install ivorysql1-1.8-1.el7.x86_64.rpm 1、 基础备份 [source,shell] ---- -cd /usr/local/ivorysql/ivorysql-2/bin +cd /opt/IvorySQL-1.8/bin ./pg_basebackup -h 192.168.xx.xx -p 5333 -U repl -W -Fp -Xs -Pv -R -D ../data-standby01 ---- diff --git a/CN/modules/ROOT/pages/v3.0/6.adoc b/CN/modules/ROOT/pages/v3.0/6.adoc index 422f3a0..d58160a 100644 --- a/CN/modules/ROOT/pages/v3.0/6.adoc +++ b/CN/modules/ROOT/pages/v3.0/6.adoc @@ -7,15 +7,15 @@ == 安装概述 -本文介绍 Ivorysql 在Linux平台(以CentOS 7为例)的安装过程及注意事项。本文主要演示数据库在Centos 7环境下yum源安装步骤、rpm包安装步骤、源码安装步骤。 +本文介绍 Ivorysql 在Linux平台(以CentOS 7为例)的安装过程及注意事项。本文主要演示数据库在Centos 7环境下rpm包安装步骤、源码安装步骤。 === 软硬件要求 ==== 软件资源介绍 |==== -|操作系统|Yum源下载地址 -|CentOS 7、CentOS 8|https://yum.highgo.ca/ivorysql.html +|操作系统|RPM包下载地址 +|CentOS 7、CentOS 8|https://github.com/IvorySQL/IvorySQL/releases |==== @@ -34,7 +34,7 @@ ==== 查看资源 -IvorySQL 数据库支持CentOS 7.X,8.X操作系统。详细信息,参考<<#_软硬件要求>> +IvorySQL 数据库支持CentOS 7.X操作系统。详细信息,参考<<#_软硬件要求>> ==== 查看操作系统 @@ -81,8 +81,8 @@ sudo yum groupinstall -y 'Development Tools' 3.自行编译安装:前面通过获取的源码在文件夹IvorySQL里,接下来我们就进入这个文件夹进行操作。 3.1 配置:Root用户执行以下命令进行配置: - - ./configure --prefix=/usr/local/ivorysql/ivorysql-3 + git checkout tags/Ivory_REL_1_8 + ./configure --prefix=/usr/local/ivorysql/ivorysql-1.8 > 说明: 由于没有提供 `--prefix`,默认安装在 `/usr/local/ivorysql`,故需要指定路径。 > @@ -108,13 +108,7 @@ make all-check-world 1. 运行以下命令,下载 IvorySQL 安装包。 ---- -wget https://github.com/IvorySQL/IvorySQL/releases/tag/Ivorysql_3.0_Beta/ivorysql3-3.0-1.rhel7.x86_64.rpm - -wget https://github.com/IvorySQL/IvorySQL/releases/tag/Ivorysql_3.0_Beta/ivorysql3-contrib-3.0-1.rhel7.x86_64.rpm - -wget https://github.com/IvorySQL/IvorySQL/releases/tag/Ivorysql_3.0_Beta/ivorysql3-libs-3.0-1.rhel7.x86_64.rpm - -wget https://github.com/IvorySQL/IvorySQL/releases/tag/Ivorysql_3.0_Beta/ivorysql3-server-3.0-1.rhel7.x86_64.rpm +wget https://github.com/IvorySQL/IvorySQL/releases/download/Ivory_REL_1_8/ivorysql1-1.8-1.el7.x86_64.rpm ---- > 注意:示例中的安装包可能不是最新版本,建议您下载最新的安装包。 @@ -123,10 +117,7 @@ wget https://github.com/IvorySQL/IvorySQL/releases/tag/Ivorysql_3.0_Beta/ivorysq ---- -- 先安装依赖 yum install -y libicu libxslt python3 -rpm -ivh ivorysql3-libs-3.0-1.rhel7.x86_64.rpm -rpm -ivh ivorysql3-3.0-1.rhel7.x86_64.rpm -rpm -ivh ivorysql3-contrib-3.0-1.rhel7.x86_64.rpm --nodeps -rpm -ivh ivorysql3-server-3.0-1.rhel7.x86_64.rpm +rpm -ivh ivorysql1-1.8-1.el7.x86_64.rpm ---- === 初始化数据库服务 @@ -136,23 +127,17 @@ rpm -ivh ivorysql3-server-3.0-1.rhel7.x86_64.rpm 1. 创建操作系统用户:用户root会话下,新建用户 ivorysql: ---- /usr/sbin/groupadd ivorysql -/usr/sbin/useradd -g ivorysql ivorysql -c "IvorySQL3.0 Server" +/usr/sbin/useradd -g ivorysql ivorysql -c "IvorySQL1.8" passwd ivorysql ---- -2.修改权限:在root会话下执行以下命令: ----- -chown -R ivorysql.ivorysql /var/lib/ivorysql/ivorysql-3 ----- - -> 注意:这里没按RPM安装将数据目录放置到 `/var/lib/ivorysql/ivorysql-3/data`。 -3.环境变量:切换到用户ivorysql,修改文件 `/home/ivorysql/.bash_profile`,配置环境变量: +2.环境变量:切换到用户ivorysql,修改文件 `/home/ivorysql/.bash_profile`,配置环境变量: ---- umask 022 -export LD_LIBRARY_PATH=/usr/local/ivorysql/ivorysql-3/lib:$LD_LIBRARY_PATH -export PATH=/usr/local/ivorysql/ivorysql-3/bin:$PATH -export PGDATA=/var/lib/ivorysql/ivorysql-3/data +export LD_LIBRARY_PATH=/opt/IvorySQL-1.8/lib:$LD_LIBRARY_PATH +export PATH=/opt/IvorySQL-1.8/bin:$PATH +export PGDATA=/home/ivorysql/data ---- 使环境变量在当前ivorysql用户会话中生效: @@ -161,7 +146,7 @@ export PGDATA=/var/lib/ivorysql/ivorysql-3/data 也可以重新登录或开启一个新的用户ivorysql的会话。 -4.设置防火墙:如果开启了防火墙,还需要将端口1521或者5432开放: +3.设置防火墙:如果开启了防火墙,还需要将端口1521或者5432开放: ---- firewall-cmd --zone=public --add-port=1521/tcp --permanent firewall-cmd --reload @@ -169,14 +154,14 @@ firewall-cmd --reload > 说明:默认端口是1521,如果不开放该端口,外部客户端通过ip连接会失败。 -5.初始化:在用户ivorysql下,简单执行initdb就可以完成初始化: +4.初始化:在用户ivorysql下,简单执行initdb就可以完成初始化: initdb > 说明:initdb操作与PostgreSQL一样,可以按照PG的习惯去初始化。 -6.启动数据库:使用pg_ctl启动数据库服务: +5.启动数据库:使用pg_ctl启动数据库服务: pg_ctl start @@ -186,7 +171,7 @@ firewall-cmd --reload === 配置服务 -1. 客户端验证:修改 /ivorysql/1.2/data/pg_hba.conf,追加以下内容: +1. 客户端验证:修改 /home/ivorysql/data/pg_hba.conf,追加以下内容: host all all 0.0.0.0/0 trust @@ -218,7 +203,7 @@ firewall-cmd --reload 编辑内容如下: ---- [Unit] -Description=IvorySQL 3.0 database server +Description=IvorySQL 1.8 database server Documentation=https://www.ivorysql.org Requires=network.target local-fs.target After=network.target local-fs.target @@ -229,18 +214,19 @@ Type=forking User=ivorysql Group=ivorysql -Environment=PGDATA=/var/lib/ivorysql/ivorysql-3/data +Environment=PGDATA=/home/ivorysql/data OOMScoreAdjust=-1000 -ExecStart=/usr/local/ivorysql/bin/pg_ctl start -D ${PGDATA} -ExecStop=/usr/local/ivorysql/bin/pg_ctl stop -D ${PGDATA} -ExecReload=/usr/local/ivorysql/bin/pg_ctl reload -D ${PGDATA} +ExecStart=/opt/IvorySQL-1.8/bin/pg_ctl start -D ${PGDATA} +ExecStop=/opt/IvorySQL-1.8/bin/pg_ctl stop -D ${PGDATA} +ExecReload=/opt/IvorySQL-1.8/bin/pg_ctl reload -D ${PGDATA} TimeoutSec=0 [Install] WantedBy=multi-user.target + ---- > 说明:service的写法有很多,在生产环境使用时需谨慎,请多次重复测试。 @@ -258,121 +244,17 @@ systemctl status ivorysql.service --查看数据库状态 systemctl reload ivorysql.service --可以满足部分数据库配置修改完后生效 ---- -=== 安装 - -==== yum源 - -1. 下载YUM源:在Centos7上使用wget下载 - - wget https://yum.highgo.ca/dists/ivorysql-rpms/repo/ivorysql-release-1.0-1.noarch.rpm - -安装ivorysql-release-1.0-1.noarch.rpm: - - rpm -ivh ivorysql-release-1.0-1.noarch.rpm - -安装后,将创建YUM源配置文件:/etc/yum.repos.d/ivorysql.repo。 - -搜索查看相关安装包: - - yum search ivorysql - -搜索结果说明见表1: - -.YUN源说明 -|==== -|**序号**|**包名**|**描述** -|1| https://yum.highgo.ca/dists/ivorysql-rpms/1/redhat/rhel-7-x86_64/ivorysql1-1.2-1.rhel7.x86_64.rpm[ivorysql1.x86_64] | IvorySQL客户端程序和库文件 -|2| https://yum.highgo.ca/dists/ivorysql-rpms/1/redhat/rhel-7-x86_64/ivorysql1-contrib-1.2-1.rhel7.x86_64.rpm[ivorysql1-contrib.x86_64] | 随IvorySQL发布的已贡献的源代码和二进制文件 -|3| ivorysql1-devel.x86_64| IvorySQL开发头文件和库 -|4| ivorysql1-docs.x86_64| IvorySQL的额外文档 -|5| https://yum.highgo.ca/dists/ivorysql-rpms/1/redhat/rhel-7-x86_64/ivorysql1-libs-1.2-1.rhel7.x86_64.rpm[ivorysql1-libs.x86_64] | 所有IvorySQL客户端所需的共享库 -|6| ivorysql1-llvmjit.x86_64 | 对IvorySQL的即时编译支持 -|7| ivorysql1-plperl.x86_64 | 用于IvorySQL的过程语言Perl -|8| ivorysql1-plpython3.x86_64 | 用于IvorySQL的过程语言Python3 -|9| ivorysql1-pltcl.x86_64 | 用于IvorySQL的过程语言Tcl -|10| https://yum.highgo.ca/dists/ivorysql-rpms/1/redhat/rhel-7-x86_64/ivorysql1-server-1.2-1.rhel7.x86_64.rpm[ivorysql1-server.x86_64] | 创建和运行IvorySQL服务器所需的程序 -|11| ivorysql1-test.x86_64 | 随IvorySQL发布的测试套件 -|12| ivorysql-release.noarch | 瀚高基础软件股份有限公司的Yum源配置RPM包 -|==== - - -2.安装IvorySQL - -要安装数据库服务,需要安装ivorysql1-server。 在用户root会话下执行以下命令: - - yum install -y ivorysql1-server - -**安装清单:** - - ivorysql1-server.x86_64 0:1.2-1.rhel7 - -**依赖安装:** ----- -ivorysql1.x86_64 0:1.2-1.rhel7 ivorysql1-contrib.x86_64 0:1.2-1.rhel7 -ivorysql1-libs.x86_64 0:1.2-1.rhel7 libicu.x86_64 0:50.2-4.el7_7 -libtirpc.x86_64 0:0.2.4-0.16.el7 libxslt.x86_64 0:1.1.28-6.el7 -python3.x86_64 0:3.6.8-18.el7 python3-libs.x86_64 0:3.6.8-18.el7 -python3-pip.noarch 0:9.0.3-8.el7 python3-setuptools.noarch 0:39.2.0-10.el7 ----- - -3.已安装目录 - -表2 对YUM安装过程产生的文件目录进行说明。 - -.安装目录文件说明 -|==== -|**序号**|**文件路径**|**描述** -|1| /usr/local/ivorysql/ivorysql-3 |软件安装目录 -|2| /var/lib/ivorysql/ivorysql-3/data| 数据目录(默认) -|3| /usr/bin/ivorysql-3-setup | 帮助管理员进行基本的数据库集群管理 -|4| /usr/lib/systemd/system/ivorysql-3.service | 守护服务 -|==== - -==== deb安装 - -验证环境:Linux 20.04.1-Ubuntu - -1、从官网获取deb包 - -> 说明:目前还未提供。 - -2、安装deb包 - -``` -dpkg -i ivorysql.deb -``` -> 说明:ivorysql.deb 为待安装包名。 - -3、配置环境变量 - -``` -vi ~/.bashrc - export PATH=/xxx/ivorysql/bin:$PATH - export LD_LIBRARY_PATH=/xxx/ivorysql/lib - -source .bashrc -``` - -> 说明:根据实际情况添加,有的可以不用添加。 -> - -4、卸载deb包 - -``` -dpkg -r ivorysql -``` - === 卸载 IvorySQL 数据库 ==== 编译卸载 -1.备份数据:数据目录在“/var/lib/ivorysql/ivorysql-3/data”下,所以我们将该目录保护好就可以,最好停止数据库服务后做备份。 +1.备份数据:我们需要将数据目录保护好,最好停止数据库服务后做备份。 ``` systemctl stop ivorysql.service ``` -2.编译卸载:oot会话下切到源码目录下,分别执行以下命令: +2.编译卸载:root会话下切到源码目录下,分别执行以下命令: ``` make uninstall @@ -384,44 +266,7 @@ make clean ``` systemctl disable ivorysql.servicemake --禁用服务 mv /usr/lib/systemd/system/ivorysql.service /tmp/ --服务文件移到/tmp,删除也可以 -rm -fr /usr/local/ivorysql/ivorysql-3 --删除残留安装目录 -``` - -> 说明:还有用户ivorysql以及对应的环境变量,可以根据情况是否清理。剩下的就是数据目录“/var/lib/ivorysql/ivorysql-3/data”了,请务必做好备份再做处理。还有安装的依赖包,可根据情况决定是否卸载。 - -==== YUM卸载 - -1.停止数据库服务: - -``` -systemctl stop ivorysql-3.service -``` - -先使用“yum history list”确定yum安装的事务ID: - -``` -[root@Node02 ~]# yum history list -Loaded plugins: fastestmirror -ID | Login user | Date and time | Action(s) | Altered -------------------------------------------------------------------------------- - 5 | root | 2022-04-27 12:38 | Install | 11 < - 4 | root | 2022-03-26 16:08 | Install | 35 > - 3 | root | 2022-03-26 16:07 | I, U | 19 - 2 | root | 2022-03-26 16:07 | I, U | 73 - 1 | System | 2022-03-26 15:59 | Install | 299 -history list -``` - -可以看到ID为5的是执行安装的事务。执行命令卸载(需将XX替换为“5”): - -``` -yum history undo XX -``` - -2.卸载: - -``` -yum remove ivorysql-server +rm -fr /opt/IvorySQL-1.8 --删除残留安装目录 ``` -但该命令卸载并不彻底,只卸载了2个依赖,还有8个依赖未能卸载。可以根据是否保留这些依赖而决定是否使用这种方式卸载。 +> 说明:还有用户ivorysql以及对应的环境变量,可以根据情况是否清理。剩下的就是数据目录了,请务必做好备份再做处理。还有安装的依赖包,可根据情况决定是否卸载。 \ No newline at end of file diff --git a/CN/modules/ROOT/pages/v3.0/7.adoc b/CN/modules/ROOT/pages/v3.0/7.adoc deleted file mode 100644 index 7af7288..0000000 --- a/CN/modules/ROOT/pages/v3.0/7.adoc +++ /dev/null @@ -1,4040 +0,0 @@ - -:sectnums: -:sectnumlevels: 5 - -:imagesdir: ./_images - -= 开发者指南 - -== 概览 - -IvorySQL在开源PostgreSQL数据库的基础上提供独特的附加功能。 - -IvorySQL致力于通过创新和建立在开源数据库解决方案之上为其终端用户提供价值。我们的目标是为中小型企业提供一个具有高性能、可扩展性、可靠性和易于使用的解决方案。 - -IvorySQL提供的扩展功能将使用户能够建立高性能和可扩展的PostgreSQL数据库集群,具有更好的数据库兼容性和管理。这简化了从其他DBMS迁移到PostgreSQL的过程,增强了数据库管理经验。 - -### 架构概述 - -为了对原有的 PostgreSQL 改动最小的前提下,实现对 Oracle 兼容。我们需要实现双 parser、双端口、模式 PL/pgSQL 实现 PL/iSQL 的框架。实现流程图如下: - -image::p4.png[] -image::p5.png[] - -### 系统表的变化 - -下图描述了对PostgreSQL现有系统表的变化以及所做的补充。 - -image::p6.png[] - -== 数据库建模(第一章创建库+第二章创建表) - -=== 创建一个数据库 - -看看你能否访问数据库服务器的第一个例子就是试着创建一个数据库。 一台运行着的IvorySQL服务器可以管理许多数据库。 通常我们会为每个项目和每个用户单独使用一个数据库。 - -你的站点管理员可能已经为你创建了可以使用的数据库。 如果这样你就可以省略这一步, 并且跳到下一节。 - -要创建一个新的数据库,在我们这个例子里叫`mydb`,你可以使用下面的命令: - -``` -$ createdb mydb -``` - -如果不产生任何响应则表示该步骤成功,你可以跳过本节的剩余部分。 - -如果你看到类似下面这样的信息: - -``` -createdb: command not found -``` - -那么就是IvorySQL没有安装好。或者是根本没安装, 或者是你的shell搜索路径没有设置正确。尝试用绝对路径调用该命令试试: - -``` -$ /usr/local/pgsql/bin/createdb mydb -``` - -在你的站点上这个路径可能不一样。和你的站点管理员联系或者看看安装指导获取正确的位置。 - -另外一种响应可能是这样: - -``` -createdb: error: connection to server on socket "/tmp/.s.PGSQL.5432" failed: No such file or directory - Is the server running locally and accepting connections on that socket? -``` - -这意味着该服务器没有启动,或者在`createdb`期望去连接它的时候没有在监听。同样, 你也要查看安装指导或者咨询管理员。 - -另外一个响应可能是这样: - -``` -createdb: error: connection to server on socket "/tmp/.s.PGSQL.5432" failed: FATAL: role "joe" does not exist -``` - -在这里提到了你自己的登录名。如果管理员没有为你创建IvorySQL用户帐号, 就会发生这些现象。(IvorySQL用户帐号和操作系统用户帐号是不同的。) 如果你是管理员,参阅 http://www.postgres.cn/docs/14/user-manag.html[第 22 章] 获取创建用户帐号的帮助。 你需要变成安装IvorySQL的操作系统用户的身份(通常是 `postgres`)才能创建第一个用户帐号。 也有可能是赋予你的IvorySQL用户名和你的操作系统用户名不同; 这种情况下,你需要使用`-U`选项或者使用`PGUSER`环境变量指定你的IvorySQL用户名。 - -如果你有个数据库用户帐号,但是没有创建数据库所需要的权限,那么你会看到下面的信息: - -``` -createdb: error: database creation failed: ERROR: permission denied to create database -``` - -并非所有用户都被许可创建新数据库。 如果IvorySQL拒绝为你创建数据库, 那么你需要让站点管理员赋予你创建数据库的权限。出现这种情况时请咨询你的站点管理员。 如果你自己安装了IvorySQL, 那么你应该以你启动数据库服务器的用户身份登录然后参考手册完成权限的赋予工作。 http://www.postgres.cn/docs/14/tutorial-createdb.html#ftn.id-1.4.3.4.10.4[[1\]] - -你还可以用其它名字创建数据库。IvorySQL允许你在一个站点上创建任意数量的数据库。 数据库名必须是以字母开头并且小于 63 个字符长。 一个方便的做法是创建和你当前用户名同名的数据库。 许多工具假设该数据库名为缺省数据库名,所以这样可以节省你的敲键。 要创建这样的数据库,只需要键入: - -``` -$ createdb -``` - - - -如果你再也不想使用你的数据库了,那么你可以删除它。 比如,如果你是数据库`mydb`的所有人(创建人), 那么你就可以用下面的命令删除它: - -``` -$ dropdb mydb -``` - -(对于这条命令而言,数据库名不是缺省的用户名,因此你就必须声明它) 。这个动作将在物理上把所有与该数据库相关的文件都删除并且不可取消, 因此做这中操作之前一定要考虑清楚。 - -更多关于 `createdb` 和 `dropdb` 的信息可以分别在 http://www.postgres.cn/docs/14/app-createdb.html[createdb] 和 http://www.postgres.cn/docs/14/app-dropdb.html[dropdb] 中找到。 - -=== 创建一个新表 - -你可以通过指定表的名字和所有列的名字及其类型来创建表∶ - -``` -CREATE TABLE weather ( - city varchar(80), - temp_lo int, -- 最低温度 - temp_hi int, -- 最高温度 - prcp real, -- 湿度 - date date -); -``` - -你可以在 `psql` 输入这些命令以及换行符。`psql` 可以识别该命令直到分号才结束。 - -你可以在 SQL 命令中自由使用空白(即空格、制表符和换行符)。 这就意味着你可以用和上面不同的对齐方式键入命令,或者将命令全部放在一行中。两个划线(“`--`”)引入注释。 任何跟在它后面直到行尾的东西都会被忽略。SQL 是对关键字和标识符大小写不敏感的语言,只有在标识符用双引号包围时才能保留它们的大小写(上例没有这么做)。 - -`varchar(80)` 指定了一个可以存储最长 80 个字符的任意字符串的数据类型。 `int` 是普通的整数类型。 `real` 是一种用于存储单精度浮点数的类型。 `date` 类型应该可以自解释(没错,类型为`date`的列名字也是 `date`。 这么做可能比较方便或者容易让人混淆 — 你自己选择)。 - -IvorySQL支持标准的SQL类型 `int`、`smallint`、`real`、`double precision`、`char(*N*)`、`varchar(*N*)`、`date`、`time`、`timestamp` 和 `interval`,还支持其他的通用功能的类型和丰富的几何类型。IvorySQL中可以定制任意数量的用户定义数据类型。因而类型名并不是语法关键字,除了SQL标准要求支持的特例外。 - -第二个例子将保存城市和它们相关的地理位置: - -``` -CREATE TABLE cities ( - name varchar(80), - location point -); -``` - -类型 `point` 就是一种IvorySQL特有数据类型的例子。 - -最后,我们还要提到如果你不再需要某个表,或者你想以不同的形式重建它,那么你可以用下面的命令删除它: - -``` -DROP TABLE tablename; -``` - -== 写入数据(SQL写入)参考第 6 章 数据操纵 - -当一个表被创建后,它不包含任何数据。在数据库发挥作用之前,首先要做的是插入数据。一次插入一行数据。你也可以在一个命令中插入多行,但不能插入不完整的行。即使只知道其中一些列的值,也必须创建完整的行。 - -要创建一个新行,使用 http://www.postgres.cn/docs/14/sql-insert.html[INSERT] 命令。这条命令要求提供表的名字和其中列的值。例如,考虑 http://www.postgres.cn/docs/14/ddl.html[第 5 章] 中的产品表: - -``` -CREATE TABLE products ( - product_no integer, - name text, - price numeric -); -``` - -一个插入一行的命令将是: - -``` -INSERT INTO products VALUES (1, 'Cheese', 9.99); -``` - -数据的值是按照这些列在表中出现的顺序列出的,并且用逗号分隔。通常,数据的值是文字(常量),但也允许使用标量表达式。 - -上面的语法的缺点是你必须知道表中列的顺序。要避免这个问题,你也可以显式地列出列。例如,下面的两条命令都有和上文那条 命令一样的效果: - -``` -INSERT INTO products (product_no, name, price) VALUES (1, 'Cheese', 9.99); -INSERT INTO products (name, price, product_no) VALUES ('Cheese', 9.99, 1); -``` - -许多用户认为明确列出列的名字是个好习惯。 - -如果你没有获得所有列的值,那么你可以省略其中的一些。在这种情况下,这些列将被填充为它们的缺省值。例如: - -``` -INSERT INTO products (product_no, name) VALUES (1, 'Cheese'); -INSERT INTO products VALUES (1, 'Cheese'); -``` - -第二种形式是IvorySQL的一个扩展。它从使用给出的值从左开始填充列,有多少个给出的列值就填充多少个列,其他列的将使用缺省值。 - -为了保持清晰,你也可以显式地要求缺省值,用于单个的列或者用于整个行: - -``` -INSERT INTO products (product_no, name, price) VALUES (1, 'Cheese', DEFAULT); -INSERT INTO products DEFAULT VALUES; -``` - - - -你可以在一个命令中插入多行: - -``` -INSERT INTO products (product_no, name, price) VALUES - (1, 'Cheese', 9.99), - (2, 'Bread', 1.99), - (3, 'Milk', 2.99); -``` - - - -也可以插入查询的结果(可能没有行、一行或多行): - -``` -INSERT INTO products (product_no, name, price) - SELECT product_no, name, price FROM new_products - WHERE release_date = 'today'; -``` - -这提供了用于计算要插入的行的SQL查询机制( http://www.postgres.cn/docs/14/queries.html[第 7 章] )的全部功能。 - -.提示 -**** -在一次性插入大量数据时,考虑使用 http://www.postgres.cn/docs/14/sql-copy.html[COPY] 命令。它不如 http://www.postgres.cn/docs/14/sql-insert.html[INSERT] 命令那么灵活,但是更高效。 -**** - -== 查询数据 参考 第七章查询的组合查询 第十五章 并行查询 - -=== 组合查询 - -两个查询的结果可以用集合操作并、交、差进行组合。语法是 - -``` -query1 UNION [ALL] query2 -query1 INTERSECT [ALL] query2 -query1 EXCEPT [ALL] query2 -``` - -*`query1`*和*`query2`*都是可以使用以上所有特性的查询。集合操作也可以嵌套和级连,例如 - -``` -query1 UNION query2 UNION query3 -``` - -实际执行的是: - -``` -(query1 UNION query2) UNION query3 -``` - - - -`UNION`有效地把*`query2`*的结果附加到*`query1`*的结果上(不过我们不能保证这就是这些行实际被返回的顺序)。此外,它将删除结果中所有重复的行, 就象`DISTINCT`做的那样,除非你使用了`UNION ALL`。 - -`INTERSECT`返回那些同时存在于*`query1`*和*`query2`*的结果中的行,除非声明了`INTERSECT ALL`, 否则所有重复行都被消除。 - -`EXCEPT`返回所有在*`query1`*的结果中但是不在*`query2`*的结果中的行(有时侯这叫做两个查询的*差*)。同样的,除非声明了`EXCEPT ALL`,否则所有重复行都被消除。 - -为了计算两个查询的并、交、差,这两个查询必须是“并操作兼容的”,也就意味着它们都返回同样数量的列, 并且对应的列有兼容的数据类型,如 http://www.postgres.cn/docs/14/typeconv-union-case.html[第 10.5 节] 中描述的那样。 - -=== 并行查询 - -==== 并行查询如何工作 - -当优化器判断对于某一个特定的查询,并行查询是最快的执行策略时,优化器将创建一个查询计划。该计划包括一个 *Gather*或者*Gather Merge*节点。下面是一个简单的例子: - -``` -EXPLAIN SELECT * FROM pgbench_accounts WHERE filler LIKE '%x%'; - QUERY PLAN -------------------------------------------------------------------------------------- - Gather (cost=1000.00..217018.43 rows=1 width=97) - Workers Planned: 2 - -> Parallel Seq Scan on pgbench_accounts (cost=0.00..216018.33 rows=1 width=97) - Filter: (filler ~~ '%x%'::text) -(4 rows) -``` - - - -在所有的情形下,`Gather`或*Gather Merge*节点都只有一个子计划,它是将被并行执行的计划的一部分。如果`Gather`或*Gather Merge*节点位于计划树的最顶层,那么整个查询将并行执行。如果它位于计划树的其他位置,那么只有查询中在它之下的那一部分会并行执行。在上面的例子中,查询只访问了一个表,因此除`Gather`节点本身之外只有一个计划节点。因为该计划节点是`Gather`节点的孩子节点,所以它会并行执行。 - -http://www.postgres.cn/docs/14/using-explain.html[使用 EXPLAIN] 命令, 你能看到规划器选择的工作者数量。当查询执行期间到达`Gather`节点时,实现用户会话的进程将会请求和规划器选中的工作者数量一样多的 http://www.postgres.cn/docs/14/bgworker.html[后台工作者进程] 。规划器将考虑使用的后台工作者的数量被限制为最多 http://www.postgres.cn/docs/14/runtime-config-resource.html#GUC-MAX-PARALLEL-WORKERS-PER-GATHER[max_parallel_workers_per_gather] 个。任何时候能够存在的后台工作者进程的总数由 http://www.postgres.cn/docs/14/runtime-config-resource.html#GUC-MAX-WORKER-PROCESSES[max_worker_processes] 和 http://www.postgres.cn/docs/14/runtime-config-resource.html#GUC-MAX-PARALLEL-WORKERS[max_parallel_workers] 限制。因此,一个并行查询可能会使用比规划中少的工作者来运行,甚至有可能根本不使用工作者。最优的计划可能取决于可用的工作者的数量,因此这可能会导致不好的查询性能。如果这种情况经常发生,那么就应当考虑一下提高`max_worker_processes`和`max_parallel_workers`的值,这样更多的工作者可以同时运行;或者降低`max_parallel_workers_per_gather`,这样规划器会要求少一些的工作者。 - -为一个给定并行查询成功启动的后台工作者进程都将会执行计划的并行部分。这些工作者的领导者也将执行该计划,不过它还有一个额外的任务:它还必须读取所有由工作者产生的元组。当整个计划的并行部分只产生了少量元组时,领导者通常将表现为一个额外的加速查询执行的工作者。反过来,当计划的并行部分产生大量的元组时,领导者将几乎全用来读取由工作者产生的元组并且执行`Gather`或`Gather Merge`节点上层计划节点所要求的任何进一步处理。在这些情况下,领导者所作的执行并行部分的工作将会很少。 - -当计划的并行部分的顶层节点是`Gather Merge`而不是`Gather`时,它表示每个执行计划并行部分的进程会产生有序的元组,并且领导者执行一种保持顺序的合并。相反,`Gather`会以任何方便的顺序从工作者读取元组,这会破坏可能已经存在的排序顺序。 - -==== 何时会用到并行查询? - -有几种设置会导致查询规划器在任何情况下都不生成并行查询计划。为了让并行查询计划能够被生成,必须配置好下列设置。 - -- http://www.postgres.cn/docs/14/runtime-config-resource.html#GUC-MAX-PARALLEL-WORKERS-PER-GATHER[max_parallel_workers_per_gather] 必须被设置为大于零的值。这是一种特殊情况,更加普遍的原则是所用的工作者数量不能超过`max_parallel_workers_per_gather`所配置的数量。 - -此外,系统一定不能运行在单用户模式下。因为在单用户模式下,整个数据库系统运行在单个进程中,没有后台工作者进程可用。 - -如果下面的任一条件为真,即便对一个给定查询通常可以产生并行查询计划,规划器都不会为它产生并行查询计划: - -- 查询要写任何数据或者锁定任何数据库行。如果一个查询在顶层或者 CTE 中包含了数据修改操作,那么不会为该查询产生并行计划。一种例外是,`CREATE TABLE ... AS`、`SELECT INTO`以及`CREATE MATERIALIZED VIEW`这些创建新表并填充它的命令可以使用并行计划。 -- 查询可能在执行过程中被暂停。只要在系统认为可能发生部分或者增量式执行,就不会产生并行计划。例如:用 http://www.postgres.cn/docs/14/sql-declare.html[DECLARE CURSOR] 创建的游标将永远不会使用并行计划。类似地,一个`FOR x IN query LOOP .. END LOOP`形式的 PL/pgSQL 循环也永远不会使用并行计划,因为当并行查询进行时,并行查询系统无法验证循环中的代码执行起来是安全的。 -- 使用了任何被标记为`PARALLEL UNSAFE`的函数的查询。大多数系统定义的函数都被标记为`PARALLEL SAFE`,但是用户定义的函数默认被标记为`PARALLEL UNSAFE`。参见 http://www.postgres.cn/docs/14/parallel-safety.html[第 15.4 节] 中的讨论。 -- 该查询运行在另一个已经存在的并行查询内部。例如,如果一个被并行查询调用的函数自己发出一个 SQL 查询,那么该查询将不会使用并行计划。这是当前实现的一个限制,但是或许不值得移除这个限制,因为它会导致单个查询使用大量的进程。 - -即使对于一个特定的查询已经产生了并行查询计划,在一些情况下执行时也不会并行执行该计划。如果发生这种情况,那么领导者将会自己执行该计划在`Gather`节点之下的部分,就好像`Gather`节点不存在一样。上述情况将在满足下面的任一条件时发生: - -- 因为后台工作者进程的总数不能超过 http://www.postgres.cn/docs/14/runtime-config-resource.html#GUC-MAX-WORKER-PROCESSES[max_worker_processes],导致不能得到后台工作者进程。 -- 由于为并行查询目的启动的后台工作者数量不能超过 http://www.postgres.cn/docs/14/runtime-config-resource.html#GUC-MAX-PARALLEL-WORKERS[max_parallel_workers] 这一限制而不能得到后台工作者。 -- 客户端发送了一个执行消息,并且消息中要求取元组的数量不为零。执行消息可见 http://www.postgres.cn/docs/14/protocol-flow.html#PROTOCOL-FLOW-EXT-QUERY[扩展查询协议] 中的讨论。因为 http://www.postgres.cn/docs/14/libpq.html[libpq] 当前没有提供方法来发送这种消息,所以这种情况只可能发生在不依赖 libpq 的客户端中。如果这种情况经常发生,那在它可能发生的会话中设置 http://www.postgres.cn/docs/14/runtime-config-resource.html#GUC-MAX-PARALLEL-WORKERS-PER-GATHER[max_parallel_workers_per_gather] 为零是一个很好的主意,这样可以避免产生连续运行时次优的查询计划。 - -==== 并行计划 - -因为每个工作者只执行完成计划的并行部分,所以不可能简单地产生一个普通查询计划并使用多个工作者运行它。每个工作者都会产生输出结果集的一个完全,因而查询并不会比普通查询运行得更快甚至还会产生不正确的结果。相反,计划的并行部分一定被查询优化器在内部当作一个*部分计划*,即它必须被构建出来,这样每一个执行该计划的进程将以无重复地方式产生输出行的一个子集,即保证每一个所需要的输出行正好只被一个合作进程生成。通常,这意味着该查询的驱动表上的扫描必须是一种可并行的扫描。 - -===== 并行扫描 - -当前支持下列可并行的表扫描。 - -- 在一个***并行顺序扫描\***中,表块将在合作进程之间被划分。一次会分发一个块,这样对表的访问还是保持顺序方式。 -- 在一个***并行位图堆扫描\***中,一个进程被选为领导者。这个进程执行对一个或者多个索引的扫描并且构建出一个位图指示需要访问哪些表块。这些表块接着会在合作进程之间划分(和并行顺序扫描中一样)。换句话说,堆扫描以并行方式进行但底层的索引扫描不是并行。 -- 在一个***并行索引扫描\***或者***并行只用索引的扫描\***中,合作进程轮流从索引读取数据。当前,并行索引扫描仅有B-树索引支持。每一个进程将认领一个索引块并且扫描和返回该索引块引用的所有元组,其他进程可以同时地从一个不同的索引块返回元组。并行B-树扫描的结果会以每个工作者进程内的顺序返回。 - -其他扫描类型(例如非B-树索引的扫描)可能会在未来支持并行扫描。 - -===== 并行连接 - -正如在非并行计划中那样,驱动表可能被使用嵌套循环、哈希连接或者归并连接连接到一个或者多个其他表。连接的内侧可以是任何类型的被规划器支持的非并行计划,假设它能够安全地在并行工作者中运行。根据连接类型,内侧还可以是一种并行计划。 - -- 在一个***嵌套循环连接\***中,内侧总是非并行的。尽管它会被完全执行,如果内侧是一个索引扫描也会很高效,因为外侧元组以及在索引中查找值的循环会被划分到多个合作进程。 -- 在一个***归并连接\***中,内侧总是一个非并行计划并且因此会被完全执行。这可能是不太高效的,特别是在排序必须被执行时,因为在每一个合作进程中工作数据和结果数据是重复的。 -- 在一个***哈希连接\***(没有“并行”前缀)中,每个合作进程都会完全执行内侧以构建哈希表的相同。如果哈希表很大或者该计划开销很大,这种方式就很低效。在一个***并行哈希连接\***中,内侧是一个***并行哈希\***,它把构建共享哈希表的工作划分到多个合作进程。 - -===== 并行聚集 - -IvorySQL通过按两个阶段进行聚集来支持并行聚集。首先,每个参与到查询并行部分的进程执行一个聚集步骤,为该进程注意到的每个分组产生一个部分结果。这在计划中反映为一个`Partial Aggregate`节点。然后,部分结果通过`Gather`或者`Gather Merge`被传输到领导者。最后,领导者对来自所有工作者的结果进行重新聚集得到最终的结果。这在计划中反映为一个`Finalize Aggregate`节点。 - -因为`Finalize Aggregate`节点运行在领导者进程上,如果查询产生的分组数相对于其输入行数来说比较大,则查询规划器不会喜欢它。例如,在最坏的情况下,`Finalize Aggregate`节点看到的分组数可能与所有工作者进程在`Partial Aggregate`阶段看到的输入行数一样多。对于这类情况,使用并行聚集显然得不到性能收益。查询规划器会在规划过程中考虑这一点并且不太会在这种情况下选择并行聚集。 - -并行聚集并非在所有情况下都被支持。每一个聚集都必须是对并行 http://www.postgres.cn/docs/14/parallel-safety.html[安全的] 并且必须有一个组合函数。如果该聚集有一个类型为`internal`的转移状态,它必须有序列化和反序列化函数。更多细节请参考 http://www.postgres.cn/docs/14/sql-createaggregate.html[CREATE AGGREGATE]。如果任何聚集函数调用包含`DISTINCT`或`ORDER BY`子句,则不支持并行聚集。对于有序集聚集或者当查询涉及`GROUPING SETS`时,也不支持并行聚集。只有在查询中涉及的所有连接也是该计划并行部分的组成部分时,才能使用并行聚集。 - -===== 并行Append - -只要当IvorySQL需要从多个源中整合行到一个单一结果集时,它会使用`Append`或`MergeAppend`计划节点。在实现`UNION ALL`或扫描分区表时常常会发生这种情况。就像这些节点可以被用在任何其他计划中一样,它们可以被用在并行计划中。不过,在并行计划中,规划器使用的是`Parallel Append`节点。 - -当一个`Append`节点被用在并行计划中时,每个进程将按照子计划出现的顺序执行子计划,这样所有的参与进程会合作执行第一个子计划直到它被完成,然后同时移动到第二个计划。而在使用`Parallel Append`时,执行器将把它的子计划尽可能均匀地散布在参与进程中,这样多个子计划会被同时执行。这避免了竞争,也避免了子计划在那些不执行它的进程中产生启动代价。 - -此外,和常规的`Append`节点不同(在并行计划中使用时仅有部分子计划),`Parallel Append`节点既可以有部分子计划也可以有非部分子计划。非部分子计划将仅被单个进程扫描,因为扫描它们不止一次会产生重复的结果。因此涉及到追加多个结果集的计划即使在没有有效的部分计划可用时,也能实现粗粒度的并行。例如,考虑一个针对分区表的查询,它只能通过使用一个不支持并行扫描的索引来实现。规划器可能会选择常规`Index Scan`计划的`Parallel Append`。每个索引扫描必须被单一的进程执行完,但不同的扫描可以由不同的进程同时执行。 - -http://www.postgres.cn/docs/14/runtime-config-query.html#GUC-ENABLE-PARALLEL-APPEND[enable_parallel_append] 可以被用来禁用这种特性。 - -===== 并行计划小贴士 - -如果我们想要一个查询能产生并行计划但事实上又没有产生,可以尝试减小 http://www.postgres.cn/docs/14/runtime-config-query.html#GUC-PARALLEL-SETUP-COST[parallel_setup_cost] 或者 http://www.postgres.cn/docs/14/runtime-config-query.html#GUC-PARALLEL-TUPLE-COST[parallel_tuple_cost]。当然,这个计划可能比规划器优先产生的顺序计划还要慢,但也不总是如此。如果将这些设置为很小的值(例如把它们设置为零)也不能得到并行计划,那就可能是有某种原因导致查询规划器无法为你的查询产生并行计划。可能的原因可见 http://www.postgres.cn/docs/14/when-can-parallel-query-be-used.html[第 15.2 节] 和 http://www.postgres.cn/docs/14/parallel-safety.html[第 15.4 节]。 - -在执行一个并行计划时,可以用`EXPLAIN (ANALYZE,VERBOSE)`来显示每个计划节点在每个工作者上的统计信息。这些信息有助于确定是否所有的工作被均匀地分发到所有计划节点以及从总体上理解计划的性能特点。 - -== 事务(参考Sql命令) - -=== ABORT — 中止当前事务 - -==== 大纲 - -``` -ABORT [ WORK | TRANSACTION ] [ AND [ NO ] CHAIN ] -``` - -==== 描述 - -`ABORT`回滚当前事务并且导致由该事务所作的所有更新被丢弃。这个命令的行为与标准SQL命令 http://www.postgres.cn/docs/14/sql-rollback.html[`ROLLBACK`] 的行为一样,并且只是为了历史原因存在。 - -==== 参数 - -- `WORK` `TRANSACTION` - - 可选关键词。它们没有效果。 - -- `AND CHAIN` - - 如果规定了`AND CHAIN` ,新事务立即启动,具有与刚刚完成的事务相同的事务特征(参见 http://www.postgres.cn/docs/14/sql-set-transaction.html[`SET TRANSACTION`])。否则,不会启动新事务。 - -==== 注解 - -使用 http://www.postgres.cn/docs/14/sql-commit.html[`COMMIT`] 成功地终止一个事务。 - -在一个事务块之外发出`ABORT`会发出一个警告消息并且不会产生效果。 - -==== 例子 - -中止所有更改: - -``` -ABORT; -``` - -==== 兼容性 - -这个命令是一个因为历史原因而存在的IvorySQL扩展。`ROLLBACK`是等效的标准 SQL 命令。 - -=== BEGIN — 开始一个事务块 - -==== 大纲 - -``` -BEGIN [ WORK | TRANSACTION ] [ transaction_mode [, ...] ] - -其中 transaction_mode 是以下之一: - - ISOLATION LEVEL { SERIALIZABLE | REPEATABLE READ | READ COMMITTED | READ UNCOMMITTED } - READ WRITE | READ ONLY - [ NOT ] DEFERRABLE -``` - -==== 描述 - -`BEGIN`开始一个事务块,也就是说所有 `BEGIN`命令之后的所有语句将被在一个 事务中执行,直到给出一个显式的 http://www.postgres.cn/docs/14/sql-commit.html[`COMMIT`] 或者 http://www.postgres.cn/docs/14/sql-rollback.html[`ROLLBACK`]。 默认情况下(没有`BEGIN`), IvorySQL在 “自动提交”模式中执行事务,也就是说每个语句都 在自己的事务中执行并且在语句结束时隐式地执行一次提交(如果执 行成功,否则会完成一次回滚)。 - -在一个事务块内的语句会执行得更快,因为事务的开始/提交也要求可观 的 CPU 和磁盘活动。在进行多个相关更改时,在一个事务内执行多个语 句也有助于保证一致性:在所有相关更新还没有完成之前,其他会话将不 能看到中间状态。 - -如果指定了隔离级别、读/写模式或者延迟模式,新事务也会有那些特性, 就像执行了 http://www.postgres.cn/docs/14/sql-set-transaction.html[`SET TRANSACTION`]一样。 - -==== 参数 - -- `WORK` `TRANSACTION` - - 可选的关键词。它们没有效果。 - -这个语句其他参数的含义请参考 http://www.postgres.cn/docs/14/sql-set-transaction.html[SET TRANSACTION]。 - -==== 注解 - -http://www.postgres.cn/docs/14/sql-start-transaction.html[`START TRANSACTION`]具有和`BEGIN` 相同的功能。 - -使用 http://www.postgres.cn/docs/14/sql-commit.html[`COMMIT`] 或者 http://www.postgres.cn/docs/14/sql-rollback.html[`ROLLBACK`]来终止一个事务块。 - -在已经在一个事务块中时发出`BEGIN`将惹出一个警告 消息。事务状态不会被影响。要在一个事务块中嵌套事务,可以使用保 存点(见 http://www.postgres.cn/docs/14/sql-savepoint.html[SAVEPOINT])。 - -由于向后兼容的原因,连续的 *`transaction_modes`* 之间的逗号可以被省略。 - -==== 示例 - -开始一个事务块: - -``` -BEGIN; -``` - -==== 兼容性 - -`BEGIN` 是一种 IvorySQL语言扩展。它等效于 SQL 标准的命令 http://www.postgres.cn/docs/14/sql-start-transaction.html[`START TRANSACTION`],它的参考页 包含额外的兼容性信息。 - -`DEFERRABLE` *`transaction_mode`* 是一种IvorySQL语言扩展。 - -附带地,`BEGIN` 关键词被用于嵌入式 SQL 中的一种 不同目的。在移植数据库应用时,我们建议小心对待事务语义。 - - -=== COMMIT — 提交当前事务 - -==== 大纲 - -`COMMIT`提交当前事务。所有由该事务所作的更改会变得对他人可见并且被保证在崩溃发生时仍能持久。 - -==== 参数 - -`WORK` `TRANSACTION`:: -可选的关键词。它们没有效果。 - -`AND CHAIN`:: -如果指定了 `AND CHAIN`,则立即启动与刚刚完成的事务具有相同事务特征(参见 http://www.postgres.cn/docs/14/sql-set-transaction.html[SET TRANSACTION])的新事务。 否则,没有新事务被启动。 - -==== 注解 - -使用http://www.postgres.cn/docs/14/sql-rollback.html[ROLLBACK]中止一个事务。 - -当不在一个事务内时发出 `COMMIT` 不会 产生危害,但是它会产生一个警告消息。当 `COMMIT AND CHAIN` 不在事务内时是一个错误。 - -==== 示例 - -要提交当前事务并且让所有更改持久化: - -``` -COMMIT; -``` - -==== 兼容性 - -命令 `COMMIT` 符合 SQL 标准。 表单 `COMMIT TRANSACTION` 为IvorySQL扩展。 - -=== COMMIT PREPARED — 提交一个早前为两阶段提交预备的事务 - -==== 大纲 - -``` -COMMIT PREPARED transaction_id -``` - -==== 描述 - -`COMMIT PREPARED` 提交一个处于预备状态的事务。 - -==== 参数 - -*`transaction_id`*:: -要被提交的事务的事务标识符。 - -==== 注解 - -要提交一个预备的事务,你必须是原先执行该事务的同一用户或者超级用户。 但是不需要处于执行该事务的同一会话中。 - -这个命令不能在一个事务块中执行。该预备事务将被立刻提交。 - -http://www.postgres.cn/docs/14/view-pg-prepared-xacts.html[`pg_prepared_xacts`] 系统视图中列出了所有当前可用的预备事务。 - -==== 例子 - -提交由事务标识符`foobar`标识的事务: - -``` -COMMIT PREPARED 'foobar'; -``` - -==== 兼容性 - -`COMMIT PREPARED` 是一种 IvorySQL扩展。其意图是用于 外部事务管理系统,其中有些已经被标准涵盖(例如 X/Open XA), 但是那些系统的 SQL 方面未被标准化。 - -=== END - 提交当前事务 - -==== 大纲 - -``` -END [ WORK | TRANSACTION ] [ AND [ NO ] CHAIN ] -``` - -==== 描述 - -`END`提交当前事务。 所有该事务做的更改便得对他人可见并且被保证发生崩溃时仍然是持久的。 这个命令是一种IvorySQL扩展,它等效于 http://www.postgres.cn/docs/14/sql-commit.html[`COMMIT`]。 - -==== 参数 - -`WORK` `TRANSACTION`:: -可选关键词,它们没有效果。 - -`AND CHAIN`:: -如果规定了`AND CHAIN`,则立即启动与刚完成事务具有相同事务特征(参见 http://www.postgres.cn/docs/14/sql-set-transaction.html[SET TRANSACTION])的新事务。否则,没有新事务被启动。 - -==== 注解 - -使用 http://www.postgres.cn/docs/14/sql-rollback.html[`ROLLBACK`]可以中止一个事务。 - -当不在一个事务中时发出 `END` 没有危害,但是会 产生一个警告消息。 - -==== 示例 - -要提交当前事务并且让所有更改持久化: - -``` -END; -``` - -==== 兼容性 - -`END` 是一种IvorySQL扩展,它提供和 http://www.postgres.cn/docs/14/sql-commit.html[`COMMIT`]等效的功能,后者在 SQL 标准中指定。 - -=== PREPARE TRANSACTION — 为两阶段提交准备当前事务 - -==== 大纲 - -``` -PREPARE TRANSACTION transaction_id -``` - -==== 描述 - -`PREPARE TRANSACTION` 为两阶段提交准备 当前事务。在这个命令之后,该事务不再与当前会话关联。相反,它的状态 被完全存储在磁盘上,并且有很高的可能性它会被提交成功(即便在请求提 交前发生数据库崩溃)。 - -一旦被准备好,事务稍后就可以分别用 http://www.postgres.cn/docs/14/sql-commit-prepared.html[`COMMIT PREPARED`]或者 http://www.postgres.cn/docs/14/sql-rollback-prepared.html[`ROLLBACK PREPARED`]提交或者回滚。 可以从任何会话而不仅仅是执行原始事务的会话中发出这些命令。 - -从发出命令的会话的角度来看,`PREPARE TRANSACTION`不像 `ROLLBACK` 命令: 在执行它之后,就没有活跃的当前事务,并且该预备事务的效果也不再可见( 如果该事务被提交,效果将重新变得可见)。 - -如果由于任何原因 `PREPARE TRANSACTION` 命令失败,它会变成一个 `ROLLBACK` :当前事务会被取消。 - -==== 参数 - -*`transaction_id`*:: -一个任意的事务标识符, `COMMIT PREPARED` 或者`ROLLBACK PREPARED` 以后将用这个标识符来标识这个事务。该标识符必须写成一个字符串,并且长度必须小于 200 字节。它也不能与任何当前已经准备好的事务的标识符相同。 - -==== 注解 - -`PREPARE TRANSACTION` 并不是设计为在应用或者交互式 会话中使用。它的目的是允许一个外部事务管理器在多个数据库或者其他事务性 来源之间执行原子的全局事务。除非你在编写一个事务管理器,否则你可能不会 用到`PREPARE TRANSACTION`。 - -这个命令必须在一个事务块中使用。事务块用 http://www.postgres.cn/docs/14/sql-begin.html[`BEGIN`]开始。 - -当前在已经执行过任何涉及到临时表或者会话的临时命名空间、创建带 `WITH HOLD` 的游标或者执行 `LISTEN`、`UNLISTEN` 或 `NOTIFY` 的 事务中,不允许`PREPARE`该事务。这些特性与当前会话 绑定得太过紧密,所以对一个要被准备的事务来说没有什么用处。 - -如果用 `SET`(不带 `LOCAL` 选项)修改过事务的 任何运行时参数,这些效果会持续到 `PREPARE TRANSACTION` 之后,并且将不会被后续的任何 `COMMIT PREPARED` 或 `ROLLBACK PREPARED` 所影响。因此,在这一 方面`PREPARE TRANSACTION` 的行为更像 `COMMIT` 而不是`ROLLBACK`。 - -所有当前可用的准备好事务被列在 http://www.postgres.cn/docs/14/view-pg-prepared-xacts.html[`pg_prepared_xacts`]系统视图中。 - -==== 小心 - -让一个事务处于准备好状态太久是不明智的。这将会干扰 `VACUUM` 回收存储的能力,并且在极限情况下可能导致 数据库关闭以阻止事务 ID 回卷(见 http://www.postgres.cn/docs/14/routine-vacuuming.html#VACUUM-FOR-WRAPAROUND[第 25.1.5 节])。还要记住,该事务会继续持有 它已经持有的锁。该特性的设计用法是,只要一个外部事务管理器已经验证 其他数据库也准备好了要提交,一个准备好的事务将被正常地提交或者回滚。 - -如果没有建立一个外部事务管理器来跟踪准备好的事务并且确保它们被迅速地 结束,最好禁用准备好事务特性(设置 http://www.postgres.cn/docs/14/runtime-config-resource.html#GUC-MAX-PREPARED-TRANSACTIONS[max_prepared_transactions] 为零)。这将防止意外 地创建准备好事务,不然该事务有可能被忘记并且最终导致问题。 - -==== 例子 - -为两阶段提交准备当前事务,使用 `foobar` 作为事务标识符: - -``` -PREPARE TRANSACTION 'foobar'; -``` - -==== 兼容性 - -`PREPARE TRANSACTION` 是一种 IvorySQL扩展。其意图是用于 外部事务管理系统,其中有些已经被标准涵盖(例如 X/Open XA), 但是那些系统的 SQL 方面未被标准化。 - -=== ROLLBACK — 中止当前事务 - -==== 大纲 - -``` -ROLLBACK [ WORK | TRANSACTION ] [ AND [ NO ] CHAIN ] -``` - -==== 描述 - -`ROLLBACK` 回滚当前事务并且导致 该事务所作的所有更新都被抛弃。 - -==== 参数 - -`WORK` `TRANSACTION`:: -可选关键词,没有效果。 - -`AND CHAIN`:: -如果指定了 `AND CHAIN` ,则立即启动与刚刚完成事务具有相同事务特征(参见 http://www.postgres.cn/docs/14/sql-set-transaction.html[SET TRANSACTION])的新事务。 否则,不会启动任何新事务。 - -==== 注解 - -使用 http://www.postgres.cn/docs/14/sql-commit.html[`COMMIT`]可成功地终止一个事务。 - -在一个事务块之外发出 `ROLLBACK` 会发出一个警告并且不会有效果。 事务块之外的 `ROLLBACK AND CHAIN` 是一个错误。 - -==== 示例 - -要中止所有更改: - -``` -ROLLBACK; -``` - -==== 兼容性 - -命令 `ROLLBACK` 符合 SQL 标准。窗体 `ROLLBACK TRANSACTION` 是一个IvorySQL扩展。 - -=== ROLLBACK PREPARED — 取消一个之前为两阶段提交准备好的事务 - -==== 大纲 - -``` -ROLLBACK PREPARED transaction_id -``` - -==== 描述 - -`ROLLBACK PREPARED` 回滚一个处于准备好状态的事务。 - -==== 参数 - -*`transaction_id`*:: -要被回滚的事务的事务标识符。 - -==== 注解 - -要回滚一个准备好的事务,你必须是原先执行该事务的同一个用户或者 是一个超级用户。但是你必须处在执行该事务的同一个会话中。 - -这个命令不能在一个事务块内被执行。准备好的事务会被立刻回滚。 - -http://www.postgres.cn/docs/14/view-pg-prepared-xacts.html[`pg_prepared_xacts`] 系统视图中列出了当前可用的所有准备好的事务。 - -==== 例子 - -用事务标识符 `foobar` 回滚对应的事务: - -``` -ROLLBACK PREPARED 'foobar'; -``` - -==== 兼容性 - -`ROLLBACK PREPARED` 是一种 IvorySQL扩展。其意图是用于 外部事务管理系统,其中有些已经被标准涵盖(例如 X/Open XA), 但是那些系统的 SQL 方面未被标准化。 - -=== SAVEPOINT — 在当前事务中定义一个新的保存点 - -==== 大纲 - -``` -SAVEPOINT savepoint_name -``` - -==== 描述 - -`SAVEPOINT` 在当前事务中建立一个新保存点。 - -保存点是事务内的一种特殊标记,它允许所有在它被建立之后执行的命令被回滚,把该事务的状态恢复到它处于保存点时的样子。 - -==== 参数 - -*`savepoint_name`*:: -给新保存点的名字。 - -==== 注解 - -使用 http://www.postgres.cn/docs/14/sql-rollback-to.html[`ROLLBACK TO`]回滚到一个保存点。 使用 http://www.postgres.cn/docs/14/sql-release-savepoint.html[`RELEASE SAVEPOINT`]销毁一个保存点, 但保持在它被建立之后执行的命令的效果。 - -保存点只能在一个事务块内建立。可以在一个事务内定义多个保存点。 - -==== 示例 - -要建立一个保存点并且后来撤销在它建立之后执行的所有命令的效果: - -``` -BEGIN; - INSERT INTO table1 VALUES (1); - SAVEPOINT my_savepoint; - INSERT INTO table1 VALUES (2); - ROLLBACK TO SAVEPOINT my_savepoint; - INSERT INTO table1 VALUES (3); -COMMIT; -``` - -上面的事务将插入值 1 和 3,但不会插入 2。 - -要建立并且稍后销毁一个保存点: - -``` -BEGIN; - INSERT INTO table1 VALUES (3); - SAVEPOINT my_savepoint; - INSERT INTO table1 VALUES (4); - RELEASE SAVEPOINT my_savepoint; -COMMIT; -``` - -上面的事务将插入 3 和 4。 - -==== 兼容性 - -当建立另一个同名保存点时,SQL要求之前的那个保存点自动被销毁。在IvorySQL中,旧的保存点会被保留,不过在进行 回滚或释放时只能使用最近的那一个(用 `RELEASE SAVEPOINT`释放较新的保存点将会导致较旧的保存点再次变得可以被 `ROLLBACK TO SAVEPOINT` 和 `RELEASE SAVEPOINT` 访问)。在其他方面,`SAVEPOINT`完全符合SQL。 - -=== SET CONSTRAINTS — 为当前事务设置约束检查时机 - -==== 大纲 - -``` -SET CONSTRAINTS { ALL | name [, ...] } { DEFERRED | IMMEDIATE } -``` - -==== 描述 - -`SET CONSTRAINTS` 设置当前事务内约束检查的行为。`IMMEDIATE` 约束在每个语句结束时被检查。 `DEFERRED` 约束直到事务提交时才被检查。每个约束都有 自己的 `IMMEDIATE` 或 `DEFERRED` 模式。 - -在创建时,一个约束会被给定三种特性之一: `DEFERRABLE INITIALLY DEFERRED`、 `DEFERRABLE INITIALLY IMMEDIATE` 或者 `NOT DEFERRABLE` 。第三类总是 `IMMEDIATE` 并且不会受到 `SET CONSTRAINTS` 命令的影响。前两类在每个 事务开始时都处于指定的模式,但是它们的行为可以在一个事务内用 `SET CONSTRAINTS` 更改。 - -带有一个约束名称列表的 `SET CONSTRAINTS` 只更改那些约束(都必须是可延迟的)的模式。每一个约束名称都可以是 模式限定的。如果没有指定模式名称,则当前的模式搜索路径将被用来寻找 第一个匹配的名称。`SET CONSTRAINTS ALL` 更改所有可延迟约束的模式。 - -当 `SET CONSTRAINTS` 把一个约束的模式从 `DEFERRED` 改成 `IMMEDIATE` 时, 新模式会有追溯效果:任何还没有解决的数据修改(本来会在事务结束时 被检查)会转而在 `SET CONSTRAINTS` 命令 的执行期间被检查。如果任何这种约束被违背, `SET CONSTRAINTS` 将会失败(并且不会改 变该约束模式)。这样,`SET CONSTRAINTS` 可以被用来在一个事务中的特定点强制进 行约束检查。 - -当前,只有 `UNIQUE`、`PRIMARY KEY`、 `REFERENCES`(外键)以及 `EXCLUDE` 约束受到这个设置的影响。 `NOT NULL` 以及 `CHECK` 约束总是在一行 被插入或修改时立即检查(**不是**在语句结束时)。 没有被声明为 `DEFERRABLE` 的唯一和排除约束也会被 立刻检查。 - -被声明为“约束触发器”的触发器的引发也受到这个设置 的控制 — 它们会在相关约束被检查的同时被引发。 - -==== 注解 - -因为IvorySQL并不要求约束名称在模式内唯一(但是在表内要求唯一),可能有多于一个约束匹配指定的约束名称。在这种 情况下 `SET CONSTRAINTS` 将会在所有的匹配上操作。 对于一个非模式限定的名称,一旦在搜索路径中的某个模式中发现一个或者多个匹配,路径中后面的模式将不会被搜索。 - -这个命令只修改当前事务内约束的行为。在事务块外部发出这个命令会产生一个警告并且也不会有任何效果。 - -==== 兼容性 - -这个命令符合 SQL 标准中定义的行为,但有一点限制:在 IvorySQL中,它不会应用在 `NOT NULL` 和 `CHECK` 约束上。还有,IvorySQL会立刻检查非可延迟的 唯一约束,而不是按照标准建议的在语句结束时检查。 - -=== SET TRANSACTION — 设置当前事务的特性 - -==== 大纲 - -``` -SET TRANSACTION transaction_mode [, ...] -SET TRANSACTION SNAPSHOT snapshot_id -SET SESSION CHARACTERISTICS AS TRANSACTION transaction_mode [, ...] - -其中 transaction_mode 是下列之一: - - ISOLATION LEVEL { SERIALIZABLE | REPEATABLE READ | READ COMMITTED | READ UNCOMMITTED } - READ WRITE | READ ONLY - [ NOT ] DEFERRABLE -``` - -==== 描述 - -`SET TRANSACTION` 命令设置当前 会话的特性。`SET SESSION CHARACTERISTICS` 设置一个会话后续事务的默认 事务特性。在个体事务中可以用 `SET TRANSACTION`覆盖这些默认值。 - -可用的事务特性是事务隔离级别、事务访问模式(读/写或只读)以及 可延迟模式。此外,可以选择一个快照,不过只能用于当前事务而不能 作为会话默认值。 - -一个事务的隔离级别决定当其他事务并行运行时该事务能看见什么数据: - -`READ COMMITTED`:: -一个语句只能看到在它开始前提交的行。这是默认值。 - -`REPEATABLE READ`:: -当前事务的所有语句只能看到这个事务中执行的第一个查询或者数据修改语句之前提交的行。 - -`SERIALIZABLE`:: -当前事务的所有语句只能看到这个事务中执行的第一个查询或者数据修改语句之前提交的行。如果并发的可序列化事务间的读写模式可能导致一种那些事务串行(一次一个)执行时不可能出现的情况,其中之一将会被回滚并且得到一个 `serialization_failure`错误。 - -SQL 标准定义了一种额外的级别:`READ UNCOMMITTED`。在IvorySQL中 `READ UNCOMMITTED` 被视作 `READ COMMITTED`。 - -一个事务执行了第一个查询或者数据修改语句( `SELECT`、 `INSERT`、`DELETE`、 `UPDATE`、`FETCH` 或 `COPY`)之后就无法更改事务隔离级别。 更多有关事务隔离级别和并发控制的信息可见 http://www.postgres.cn/docs/14/mvcc.html[第 13 章]。 - -事务的访问模式决定该事务是否为读/写或者只读。读/写是默认值。 当一个事务为只读时,如果SQL命令 `INSERT`、`UPDATE`、 `DELETE` 和 `COPY FROM` 要写的表不是一个临时表,则它们不被允许。不允许 `CREATE`、`ALTER`以及 `DROP` 命令。不允许 `COMMENT`、 `GRANT`、`REVOKE`、 `TRUNCATE`。如果 `EXPLAIN ANALYZE` 和`EXECUTE` 要执行的命令是上述命令之一,则它们也不被允许。这是一种高层的只读概念,它不能阻止所有对磁盘的写入。 - -只有事务也是 `SERIALIZABLE` 以及 `READ ONLY` 时,`DEFERRABLE` 事务属性才会有效。当一个事务的所有这三个属性都被选择时,该事务在第一次获取其快照时可能会阻塞,在那之后它运行时就不会有 `SERIALIZABLE` 事务的开销并且不会有任何牺牲或者被一次序列化失败取消的风险。这种模式很适合于长时间运行的报表或者备份。 - -`SET TRANSACTION SNAPSHOT` 命令允许新的事务使用与一个现有事务相同的 *快照* 运行。已经存在的事务必须已经把它的快照用 `pg_export_snapshot` 函数(见 http://www.postgres.cn/docs/14/functions-admin.html#FUNCTIONS-SNAPSHOT-SYNCHRONIZATION[第 9.27.5 节])导出。该函数会返回一个快照标识符,`SET TRANSACTION SNAPSHOT` 需要被给定一个快照标识符来指定要导入的快照。在这个命令中该标识符必须被写成一个字符串,例如 `'000003A1-1'`。 `SET TRANSACTION SNAPSHOT` 只能在一个事务的开始执行,并且要在该事务的第一个查询或者数据修改语句( `SELECT`、 `INSERT`、`DELETE`、 `UPDATE`、`FETCH`或 `COPY`)之前执行。此外,该事务必须已经被设置为`SERIALIZABLE` 或者 `REPEATABLE READ` 隔离级别(否则,该快照将被立刻抛弃,因为 `READ COMMITTED` 模式会为每一个命令取一个新快照)。如果导入事务使用了`SERIALIZABLE` 隔离级别,那么导入快照的事务必须也使用该隔离级别。还有,一个非只读可序列化事务不能导入来自只读事务的快照。 - -==== 注解 - -如果执行 `SET TRANSACTION` 之前没有 `START TRANSACTION` 或者 `BEGIN`,它会发出一个警告并且不会有任何效果。 - -可以通过在 `BEGIN` 或者 `START TRANSACTION` 中指定想要的 `*transaction_modes*` 来省掉 `SET TRANSACTION`。但是在 `SET TRANSACTION SNAPSHOT` 中该选项不可用。 - -会话默认的事务模式也可以通过配置参数 http://www.postgres.cn/docs/14/runtime-config-client.html#GUC-DEFAULT-TRANSACTION-ISOLATION[default_transaction_isolation]、 http://www.postgres.cn/docs/14/runtime-config-client.html#GUC-DEFAULT-TRANSACTION-READ-ONLY[default_transaction_read_only] 和 http://www.postgres.cn/docs/14/runtime-config-client.html#GUC-DEFAULT-TRANSACTION-DEFERRABLE[default_transaction_deferrable] 来设置或检查(实际上 `SET SESSION CHARACTERISTICS`只是用 `SET` 设置这些变量的等效体)。这意味着可以通过配置文件、 `ALTER DATABASE` 等方式设置默认值。详见 http://www.postgres.cn/docs/14/runtime-config.html[第 20 章]。 - -当前事务的模式可以类似的通过配置参数 http://www.postgres.cn/docs/14/runtime-config-client.html#GUC-TRANSACTION-ISOLATION[transaction_isolation]、 http://www.postgres.cn/docs/14/runtime-config-client.html#GUC-TRANSACTION-READ-ONLY[transaction_read_only]、和 http://www.postgres.cn/docs/14/runtime-config-client.html#GUC-TRANSACTION-DEFERRABLE[transaction_deferrable] 来设置或检查。设置这其中一个参数的作用与相应的 `SET TRANSACTION` 选项相同,在它何时可以完成方面,也有相同的限制。但是,这些参数不能在配置文件中设置,或者从活动SQL以外的任何来源来设置。 - -==== 示例 - -要用一个已经存在的事务的同一快照开始一个新事务,首先要从该现有 事务导出快照。这将会返回快照标识符,例如: - -``` -BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; -SELECT pg_export_snapshot(); - pg_export_snapshot ---------------------- - 00000003-0000001B-1 -(1 row) -``` - -然后在一个新开始的事务的开头把该快照标识符用在一个 `SET TRANSACTION SNAPSHOT` 命令中: - -``` -BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; -SET TRANSACTION SNAPSHOT '00000003-0000001B-1'; -``` - -==== 兼容性 - -SQL标准中定义了这些命令,不过 `DEFERRABLE` 事务模式和 `SET TRANSACTION SNAPSHOT` 形式除外,这两者是 IvorySQL扩展。 - -`SERIALIZABLE` 是标准中默认的事务隔离级别。在 IvorySQL中默认值是普通的 `READ COMMITTED`,但是你可以按上述的方式更改。 - -在SQL标准中,可以用这些命令设置一个其他的事务特性:诊断区域 的尺寸。这个概念与嵌入式SQL有关,并且因此没有在IvorySQL服务器中实现。 - -SQL 标准要求连续的 *`transaction_modes`* 之间有逗号,但是出于历史原因IvorySQL允许省略逗号。 - -=== START TRANSACTION — 开始一个事务块 - -==== 大纲 - -``` -START TRANSACTION [ transaction_mode [, ...] ] - -其中 transaction_mode 是下列之一: - - ISOLATION LEVEL { SERIALIZABLE | REPEATABLE READ | READ COMMITTED | READ UNCOMMITTED } - READ WRITE | READ ONLY - [ NOT ] DEFERRABLE -``` - -==== 描述 - -这个命令开始一个新的事务块。如果指定了隔离级别、读写模式 或者可延迟模式,新的事务将会具有这些特性,就像执行了 http://www.postgres.cn/docs/14/sql-set-transaction.html[`SET TRANSACTION`]一样。这和 http://www.postgres.cn/docs/14/sql-begin.html[`BEGIN`]命令一样。 - -==== 参数 - -这些参数对于这个语句的含义可参考 http://www.postgres.cn/docs/14/sql-set-transaction.html[SET TRANSACTION]。 - -==== 兼容性 - -在标准中,没有必要发出 `START TRANSACTION` 来开始一个事务块:任何SQL命令会隐式地开始一个块。 IvorySQL的行为可以被视作在每个命令之后隐式地发出一个没有跟随在 `START TRANSACTION` ( 或者`BEGIN`)之后的 `COMMIT` 并且因此通常被称作 “自动提交”。为了方便,其他关系型数据库系统也可能会 提供自动提交特性。 - -`DEFERRABLE` *`transaction_mode`* 是一种IvorySQL语言扩展。 - -SQL标准要求在连续的 *`transaction_modes`* 之间有逗号,但是由于历史原因IvorySQL允许省略逗号。 - -== Sql参考(第 4 章 SQL语法) - -=== 词法结构 - -SQL输入由一个 *命令* 序列组成。一个命令由一个 *记号* 的序列构成,并由一个分号(“;”)终结。输入流的末端也会标志一个命令的结束。具体哪些记号是合法的与具体命令的语法有关。 - -一个记号可以是一个 *关键词*、一个 *标识符*、一个 *带引号的标识符*、一个 *literal*(或常量)或者一个特殊字符符号。记号通常以空白(空格、制表符、新行)来分隔,但在无歧义时并不强制要求如此(唯一的例子是一个特殊字符紧挨着其他记号)。 - -例如,下面是一个(语法上)合法的SQL输入: - -``` -SELECT * FROM MY_TABLE; -UPDATE MY_TABLE SET A = 5; -INSERT INTO MY_TABLE VALUES (3, 'hi there'); -``` - -这是一个由三个命令组成的序列,每一行一个命令(尽管这不是必须地,在同一行中可以有超过一个命令,而且命令还可以被跨行分割)。 - -另外,*注释* 也可以出现在SQL输入中。它们不是记号,它们和空白完全一样。 - -根据标识命令、操作符、参数的记号不同,SQL的语法不很一致。最前面的一些记号通常是命令名,因此在上面的例子中我们通常会说一个“SELECT”、一个“UPDATE”和一个“INSERT”命令。但是例如 `UPDATE` 命令总是要求一个 `SET` 记号出现在一个特定位置,而 `INSERT` 则要求一个 `VALUES` 来完成命令。每个命令的精确语法规则在 http://www.postgres.cn/docs/14/reference.html[第 VI 部分] 中介绍。 - -==== 标识符和关键词 - -上例中的 `SELECT`、`UPDATE` 或 `VALUES` 记号是 *关键词* 的例子,即SQL语言中具有特定意义的词。记号 `MY_TABLE` 和 `A` 则是 *标识符* 的例子。它们标识表、列或者其他数据库对象的名字,取决于使用它们的命令。因此它们有时也被简称为“名字”。关键词和标识符具有相同的词法结构,这意味着我们无法在没有语言知识的前提下区分一个标识符和关键词。一个关键词的完整列表可以在 http://www.postgres.cn/docs/14/sql-keywords-appendix.html[附录 C]中找到。 - -SQL标识符和关键词必须以一个字母(`a`-`z`,也可以是带变音符的字母和非拉丁字母)或一个下划线( _ )开始。后续字符可以是字母、下划线( `_`)、数字(`0`-`9`)或美元符号(`$`)。注意根据SQL标准的字母规定,美元符号是不允许出现在标识符中的,因此它们的使用可能会降低应用的可移植性。SQL标准不会定义包含数字或者以下划线开头或结尾的关键词,因此这种形式的标识符不会与未来可能的标准扩展冲突 。 - -系统中一个标识符的长度不能超过 `NAMEDATALEN`-1 字节,在命令中可以写超过此长度的标识符,但是它们会被截断。默认情况下,`NAMEDATALEN` 的值为64,因此标识符的长度上限为63字节。如果这个限制有问题,可以在 `src/include/pg_config_manual.h` 中修改 `NAMEDATALEN` 常量。 - -关键词和不被引号修饰的标识符是大小写不敏感的。因此: - -``` -UPDATE MY_TABLE SET A = 5; -``` - -可以等价地写成: - -``` -uPDaTE my_TabLE SeT a = 5; -``` - -一个常见的习惯是将关键词写成大写,而名称写成小写,例如: - -``` -UPDATE my_table SET a = 5; -``` - - - -这里还有第二种形式的标识符:*受限标识符*或*被引号修饰的标识符*。它是由双引号(`"`)包围的一个任意字符序列。一个受限标识符总是一个标识符而不会是一个关键字。因此 `"select"` 可以用于引用一个名为“select”的列或者表,而一个没有引号修饰的 `select` 则会被当作一个关键词,从而在本应使用表或列名的地方引起解析错误。在上例中使用受限标识符的例子如下: - -``` -UPDATE "my_table" SET "a" = 5; -``` - -受限标识符可以包含任何字符,除了代码为0的字符(如果要包含一个双引号,则写两个双引号)。这使得可以构建原本不被允许的表或列的名称,例如包含空格或花号的名字。但是长度限制依然有效。 - -引用标识符也使其区分大小写,而未引用的名称总是折叠成小写。例如,标识符 `FOO`、`foo` 和 `"foo"` 在IvorySQL中被认为是相同的,但是 `"Foo"` 和 `"FOO"` 与这三个不同,并且彼此不同。(在IvorySQL中,将不带引号的名称折叠为小写与SQL标准不兼容,SQL标准规定不带引号的名称应折叠为大写。因此,根据标准,`foo` 应等同于 `"FOO"` 而不是 `"foo"`。如果您想编写可移植应用程序,建议您始终引用某个特定的名称,或者永远不要引用它。) - - - -一种受限标识符的变体允许包括转义的用代码点标识的Unicode字符。这种变体以 `U&` (大写或小写U跟上一个花号)开始,后面紧跟双引号修饰的名称,两者之间没有任何空白,如 `U&"foo"`(注意这里与操作符 `&` 似乎有一些混淆,但是在`&`操作符周围使用空白避免了这个问题) 。在引号内,Unicode字符可以以转义的形式指定:反斜线接上4位16进制代码点号码或者反斜线和加号接上6位16进制代码点号码。例如,标识符 `"data"` 可以写成: - -``` -U&"d\0061t\+000061" -``` - -下面的例子用斯拉夫语字母写出了俄语单词 “slon”(大象): - -``` -U&"\0441\043B\043E\043D" -``` - - - -如果希望使用其他转义字符来代替反斜线,可以在字符串后使用 `UESCAPE` 子句,例如: - -``` -U&"d!0061t!+000061" UESCAPE '!' -``` - -转义字符可以是除了16进制位、加号、单引号、双引号、空白字符之外的任意单个字符。请注意,转义字符在 `UESCAPE` 之后用单引号而不是双引号书写。 - -为了在标识符中包括转义字符本身,将其写两次即可。 - -4位或6位转义形式都可以被用来定义UTF-16代理对来组成代码点大于U+FFFF的字符,尽管6位形式的存在使得这种做法变得不必要(代理对并不被直接存储,而是绑定成一个单独的代码点)。 - -如果服务器编码不是UTF-8,则由其中一个转义序列标识的Unicode代码点转换为实际的服务器编码;如果不可能,则报告错误。 - -==== 常量 - -在IvorySQL中有三种 *隐式类型常量*:字符串、位串和数字。常量也可以被指定显式类型,这可以使得它被更精确地展示以及更有效地处理。这些选择将会在后续小节中讨论。 - -===== 字符串常量 - -在SQL中,一个字符串常量是一个由单引号( `'` )包围的任意字符序列,例如 `'This is a string'`。为了在一个字符串中包括一个单引号,可以写两个相连的单引号,例如 `'Dianne''s horse'`。注意这和一个双引号( `"` )**不**同。 - -两个只由空白及**至少一个新行**分隔的字符串常量会被连接在一起,并且将作为一个写在一起的字符串常量来对待。例如: - -``` -SELECT 'foo' -'bar'; -``` - -等同于: - -``` -SELECT 'foobar'; -``` - -但是: - -``` -SELECT 'foo' 'bar'; -``` - -则不是合法的语法(这种有些奇怪的行为是SQL指定的,IvorySQL遵循了该标准)。 - -===== C风格转义的字符串常量 - -IvorySQL也接受“转义”字符串常量,这也是SQL标准的一个扩展。一个转义字符串常量可以通过在开单引号前面写一个字母 `E`(大写或小写形式)来指定,例如 `E'foo'`(当一个转义字符串常量跨行时,只在第一个开引号之前写 `E` )。在一个转义字符串内部,一个反斜线字符( `\` )会开始一个 C 风格的 *反斜线转义* 序列,在其中反斜线和后续字符的组合表示一个特殊的字节值(如 http://www.postgres.cn/docs/14/sql-syntax-lexical.html#SQL-BACKSLASH-TABLE[表 4.1] 中所示)。 - -**表 4.1. 反斜线转义序列** -|==== -| 反斜线转义序列 | 解释 -| `\b` | 退格 -| `\f` | 换页 -| `\n` | 换行 -| `\r` | 回车 -| `\t` | 制表符 -| `\*`o`*`, `\*`oo`*`, `\*`ooo`*` (*`o`* = 0–7) | 八进制字节值 -| `\x*`h`*`, `\x*`hh`*` (*`h`* = 0–9, A–F) | 十六进制字节值 -| `\u*`xxxx`*`, `\U*`xxxxxxxx`*` (*`x`* = 0–9, A–F) | 16 或 32-位十六进制 Unicode 字符值 -|==== - -跟随在一个反斜线后面的任何其他字符被当做其字面意思。因此,要包括一个反斜线字符,请写两个反斜线( `\\` )。在一个转义字符串中包括一个单引号除了普通方法 `''` 之外,还可以写成 `\'` 。 - -你要负责保证你创建的字节序列由服务器字符集编码中合法的字符组成,特别是在使用八进制或十六进制转义时。一个有用的替代方法是使用Unicode转义或替代的Unicode转义语法,如 http://www.postgres.cn/docs/14/sql-syntax-lexical.html#SQL-SYNTAX-STRINGS-UESCAPE[第 4.1.2.3 节] 中所述;然后服务器将检查字符转换是否可行。 - -.小心 -**** -如果配置参数 http://www.postgres.cn/docs/14/runtime-config-compatible.html#GUC-STANDARD-CONFORMING-STRINGS[standard_conforming_strings] 为 `off` ,那么IvorySQL对常规字符串常量和转义字符串常量中的反斜线转义都识别。不过,从IvorySQL 9.1 开始,该参数的默认值为 `on` ,意味着只在转义字符串常量中识别反斜线转义。这种行为更兼容标准,但是可能打断依赖于历史行为(反斜线转义总是会被识别)的应用。作为一种变通,你可以设置该参数为 `off` ,但是最好迁移到符合新的行为。如果你需要使用一个反斜线转义来表示一个特殊字符,为该字符串常量写上一个 `E`。在 `standard_conforming_strings` 之外,配置参数 http://www.postgres.cn/docs/14/runtime-config-compatible.html#GUC-ESCAPE-STRING-WARNING[escape_string_warning] 和 http://www.postgres.cn/docs/14/runtime-config-compatible.html#GUC-BACKSLASH-QUOTE[backslash_quote] 也决定了如何对待字符串常量中的反斜线。代码零的字符不能出现在一个字符串常量中。 -**** - -===== 带有 Unicode 转义的字符串常量 - -IvorySQL也支持另一种类型的字符串转义语法,它允许用代码点指定任意 Unicode 字符。一个 Unicode 转义字符串常量开始于 `U&` (大写或小写形式的字母 U,后跟花号),后面紧跟着开引号,之间没有任何空白,例如 `U&'foo'` (注意这产生了与操作符 `&` 的混淆。在操作符周围使用空白来避免这个问题)。在引号内,Unicode 字符可以通过写一个后跟 4 位十六进制代码点编号或者一个前面有加号的 6 位十六进制代码点编号的反斜线来指定。例如,字符串 `'data'` 可以被写为 - -``` -U&'d\0061t\+000061' -``` - -下面的例子用斯拉夫字母写出了俄语的单词“slon”(大象): - -``` -U&'\0441\043B\043E\043D' -``` - - - -如果想要一个不是反斜线的转义字符,可以在字符串之后使用 `UESCAPE` 子句来指定,例如: - -``` -U&'d!0061t!+000061' UESCAPE '!' -``` - -转义字符可以是出一个十六进制位、加号、单引号、双引号或空白字符之外的任何单一字符。 - -要在一个字符串中包括一个表示其字面意思的转义字符,把它写两次。 - -4位或6位转义形式可用于指定UTF-16代理项对,以组成代码点大于U+FFFF的字符,尽管从技术上讲,6位形式的可用性使得这是不必要的(代理项对不是直接存储的,而是合并到单个代码点中。) - -如果服务器编码不是 UTF-8,则由这些转义序列之一标识的 Unicode 代码点将转换为实际的服务器编码; 如果不可能,则会报告错误。 - -此外,字符串常量的 Unicode 转义语法仅在配置参数 http://www.postgres.cn/docs/14/runtime-config-compatible.html#GUC-STANDARD-CONFORMING-STRINGS[standard_conforming_strings] 开启时才有效。 这是因为否则这种语法可能会混淆解析 SQL 语句的客户端,可能导致 SQL 注入和类似的安全问题。 如果该参数设置为 off,则此语法将被拒绝并显示错误消息。 - -===== 美元引用的字符串常量 - -虽然用于指定字符串常量的标准语法通常都很方便,但是当字符串中包含了很多单引号或反斜线时很难理解它,因为每一个都需要被双写。要在这种情形下允许可读性更好的查询,IvorySQL提供了另一种被称为“美元引用”的方式来书写字符串常量。一个美元引用的字符串常量由一个美元符号( `$` )、一个可选的另个或更多字符的“标签”、另一个美元符号、一个构成字符串内容的任意字符序列、一个美元符号、开始这个美元引用的相同标签和一个美元符号组成。例如,这里有两种不同的方法使用美元引用指定字符串“Dianne's horse”: - -``` -$$Dianne's horse$$ -$SomeTag$Dianne's horse$SomeTag$ -``` - -注意在美元引用字符串中,单引号可以在不被转义的情况下使用。事实上,在一个美元引用字符串中不需要对字符进行转义:字符串内容总是按其字面意思写出。反斜线不是特殊的,并且美元符号也不是特殊的,除非它们是匹配开标签的一个序列的一部分。 - -可以通过在每一个嵌套级别上选择不同的标签来嵌套美元引用字符串常量。这最常被用在编写函数定义上。例如: - -``` -$function$ -BEGIN - RETURN ($1 ~ $q$[\t\r\n\v\\]$q$); -END; -$function$ -``` - -这里,序列 `$q$[\t\r\n\v\\]$q$` 表示一个美元引用的文字串 `[\t\r\n\v\\]`,当该函数体被IvorySQL执行时它将被识别。但是因为该序列不匹配外层的美元引用的定界符 `$function$`,它只是一些在外层字符串所关注的常量中的字符而已。 - -一个美元引用字符串的标签(如果有)遵循一个未被引用标识符的相同规则,除了它不能包含一个美元符号之外。标签是大小写敏感的,因此 `$tag$String content$tag$` 是正确的,但是 `$TAG$String content$tag$` 不正确。 - -一个跟着一个关键词或标识符的美元引用字符串必须用空白与之分隔开,否则美元引用定界符可能会被作为前面标识符的一部分。 - -美元引用不是SQL标准的一部分,但是在书写复杂字符串文字方面,它常常是一种比兼容标准的单引号语法更方便的方法。当要表示的字符串常量位于其他常量中时它特别有用,这种情况常常在过程函数定义中出现。如果用单引号语法,上一个例子中的每个反斜线将必须被写成四个反斜线,这在解析原始字符串常量时会被缩减到两个反斜线,并且接着在函数执行期间重新解析内层字符串常量时变成一个。 - -===== 位串常量 - -位串常量看起来像常规字符串常量在开引号之前(中间无空白)加了一个 `B`(大写或小写形式),例如 `B'1001'` 。位串常量中允许的字符只有 `0` 和 `1` 。 - -作为一种选择,位串常量可以用十六进制记号法指定,使用一个前导 `X`(大写或小写形式),例如 `X'1FF'`。这种记号法等价于一个用四个二进制位取代每个十六进制位的位串常量。 - -两种形式的位串常量可以以常规字符串常量相同的方式跨行继续。美元引用不能被用在位串常量中。 - -===== 数字常量 - -在这些一般形式中可以接受数字常量: - -``` -digits -digits.[digits][e[+-]digits] -[digits].digits[e[+-]digits] -digitse[+-]digits -``` - -其中 *`digits`* 是一个或多个十进制数字(0 到 9)。如果使用了小数点,在小数点前面或后面必须至少有一个数字。如果存在一个指数标记( `e` ),在其后必须跟着至少一个数字。在该常量中不能嵌入任何空白或其他字符。注意任何前导的加号或减号并不实际被考虑为常量的一部分,它是一个应用到该常量的操作符。 - -这些是合法数字常量的例子: - ----- -42 -3.5 -4. -.001 -5e2 -1.925e-3 ----- - - -如果一个不包含小数点和指数的数字常量的值适合类型 `integer` (32 位),它首先被假定为类型 `integer` 。否则如果它的值适合类型 `bigint` (64 位),它被假定为类型 `bigint` 。再否则它会被取做类型 `numeric` 。包含小数点和/或指数的常量总是首先被假定为类型 `numeric` 。 - -一个数字常量初始指派的数据类型只是类型转换算法的一个开始点。在大部分情况中,常量将被根据上下文自动被强制到最合适的类型。必要时,你可以通过造型它来强制一个数字值被解释为一种指定数据类型。例如,你可以这样强制一个数字值被当做类型 `real` ( `float4` ): - -``` -REAL '1.23' -- string style -1.23::REAL -- IvorySQL (historical) style -``` - -这些实际上只是接下来要讨论的一般造型记号的特例。 - -===== 其他类型的常量 - -一种**任意**类型的一个常量可以使用下列记号中的任意一种输入: - -``` -type 'string' -'string'::type -CAST ( 'string' AS type ) -``` - -字符串常量的文本被传递到名为 *`type`* 的类型的输入转换例程中。其结果是指定类型的一个常量。如果对该常量的类型没有歧义(例如,当它被直接指派给一个表列时),显式类型造型可以被忽略,在那种情况下它会被自动强制。 - -字符串常量可以使用常规 SQL 记号或美元引用书写。 - -也可以使用一个类似函数的语法来指定一个类型强制: - -``` -typename ( 'string' ) -``` - -但是并非所有类型名都可以用在这种方法中,详见 http://www.postgres.cn/docs/14/sql-expressions.html#SQL-SYNTAX-TYPE-CASTS[第 4.2.9 节]。 - -如 http://www.postgres.cn/docs/14/sql-expressions.html#SQL-SYNTAX-TYPE-CASTS[第 4.2.9 节] 中讨论的,`::`、`CAST()` 以及函数调用语法也可以被用来指定任意表达式的运行时类型转换。要避免语法歧义,`*type 'string'*` 语法只能被用来指定简单文字常量的类型。`*type 'string'*` 语法上的另一个限制是它无法对数组类型工作,指定一个数组常量的类型可使用 `::` 或 `CAST()` 。 - -`CAST()` 语法符合SQL。`type 'string'` 语法是该标准的一般化:SQL指定这种语法只用于一些数据类型,但是IvorySQL允许它用于所有类型。带有 `::` 的语法是IvorySQL的历史用法,就像函数调用语法一样。 - -==== 操作符 - -一个操作符名是最多 `NAMEDATALEN` -1(默认为 63)的一个字符序列,其中的字符来自下面的列表: - ----- -\+ - * / < > = ~ ! @ # % ^ & | ` ? ----- - -不过,在操作符名上有一些限制: - -- `--` 和 `/*` 不能在一个操作符名的任何地方出现,因为它们将被作为一段注释的开始。 - -- 一个多字符操作符名不能以 `+` 或 `-` 结尾,除非该名称也至少包含这些字符中的一个: - - - ~ ! @ # % ^ & | ` ? - -例如,`@-` 是一个被允许的操作符名,但 `*-` 不是。这些限制允许IvorySQL解析 SQL 兼容的查询而不需要在记号之间有空格。 - - - -当使用非 SQL 标准的操作符名时,你通常需要用空格分隔相邻的操作符来避免歧义。例如,如果你定义了一个名为 `@` 的前缀操作符,你不能写 `X*@Y`,你必须写 `X* @Y` 来确保IvorySQL把它读作两个操作符名而不是一个。 - -==== 特殊字符 - -一些不是数字字母的字符有一种不同于作为操作符的特殊含义。这些字符的详细用法可以在描述相应语法元素的地方找到。这一节只是为了告知它们的存在以及总结这些字符的目的。 - -- 跟随在一个美元符号( `$` )后面的数字被用来表示在一个函数定义或一个预备语句中的位置参数。在其他上下文中该美元符号可以作为一个标识符或者一个美元引用字符串常量的一部分。 -- 圆括号( `()` )具有它们通常的含义,用来分组表达式并且强制优先。在某些情况中,圆括号被要求作为一个特定 SQL 命令的固定语法的一部分。 -- 方括号( `[]` )被用来选择一个数组中的元素。更多关于数组的信息见 http://www.postgres.cn/docs/14/arrays.html[第 8.15 节]。 -- 逗号( `,` )被用在某些语法结构中来分割一个列表的元素。 -- 分号( `;` )结束一个 SQL 命令。它不能出现在一个命令中间的任何位置,除了在一个字符串常量中或者一个被引用的标识符中。 -- 冒号( `:` )被用来从数组中选择“切片”(见 http://www.postgres.cn/docs/14/arrays.html[第 8.15 节])。在某些 SQL 的“方言”(例如嵌入式 SQL)中,冒号被用来作为变量名的前缀。 -- 星号( `*` )被用在某些上下文中标记一个表的所有域或者组合值。当它被用作一个聚集函数的参数时,它还有一种特殊的含义,即该聚集不要求任何显式参数。 -- 句点( `.` )被用在数字常量中,并且被用来分割模式、表和列名。 - -==== 注释 - -一段注释是以双横杠开始并且延伸到行结尾的一个字符序列,例如: - -``` --- This is a standard SQL comment -``` - -另外,也可以使用 C 风格注释块: - -``` -/* multiline comment - * with nesting: /* nested block comment */ - */ -``` - -这里该注释开始于 `/*` 并且延伸到匹配出现的 `*/`。这些注释块可按照 SQL 标准中指定的方式嵌套,但和 C 中不同。这样我们可以注释掉一大段可能包含注释块的代码。 - -在进一步的语法分析前,注释会被从输入流中被移除并且实际被替换为空白。 - -===== 操作符优先级 - -http://www.postgres.cn/docs/14/sql-syntax-lexical.html#SQL-PRECEDENCE-TABLE[表 4.2] 显示了IvorySQL中操作符的优先级和结合性。大部分操作符具有相同的优先并且是左结合的。操作符的优先级和结合性被硬写在解析器中。 如果您希望以不同于优先级规则所暗示的方式解析具有多个运算符的表达式,请添加括号。 - -**表 4.2. 操作符优先级(从高到低)** -|==== -| 操作符/元素 | 结合性 | 描述 -| `.` | 左 | 表/列名分隔符 -| `::` | 左 | IvorySQL-风格的类型转换 -| `[` `]` | 左 | 数组元素选择 -| `+` `-` | 右 | 一元加、一元减 -| `^` | 左 | 指数 -| `*` `/` `%` | 左 | 乘、除、模 -| `+` `-` | 左 | 加、减 -| (任意其他操作符) | 左 | 所有其他本地以及用户定义的操作符 -| `BETWEEN` `IN` `LIKE` `ILIKE` `SIMILAR` | | 范围包含、集合成员关系、字符串匹配 -| `<` `>` `=` `<=` `>=` `<>` | | 比较操作符 -| `IS` `ISNULL` `NOTNULL` | | `IS TRUE`、`IS FALSE`、`IS NULL`、`IS DISTINCT FROM`等 -| `NOT` | 右 | 逻辑否定 -| `AND` | 左 | 逻辑合取 -| `OR` | 左 | 逻辑析取 -|==== - -注意该操作符有限规则也适用于与上述内建操作符具有相同名称的用户定义的操作符。例如,如果你为某种自定义数据类型定义了一个“+”操作符,它将具有和内建的“+”操作符相同的优先级,不管你的操作符要做什么。 - -当一个模式限定的操作符名被用在`OPERATOR`语法中时,如下面的例子: - -``` -SELECT 3 OPERATOR(pg_catalog.+) 4; -``` - -`OPERATOR`结构被用来为“任意其他操作符”获得 http://www.postgres.cn/docs/14/sql-syntax-lexical.html#SQL-PRECEDENCE-TABLE[表 4.2] 中默认的优先级。不管出现在`OPERATOR()`中的是哪个指定操作符,这都是真的。 - -.注意 -**** -版本 9.5 之前的IvorySQL使用的操作符优先级 规则略有不同。特别是,`<=`、`>=` 和 `<>` 习惯于被当作普通操作符,`IS` 测试习惯于具有较高的优先级。并且在一些认为 `NOT` 比 `BETWEEN` 优先级高的情况下,`NOT BETWEEN` 和相关的结构的行为不一致。为了更好地兼容 SQL 标准并且减少对 逻辑上等价的结构不一致的处理,这些规则也得到了修改。在大部分情况下, 这些变化不会导致行为上的变化,或者可能会产生“no such operator” 错误,但可以通过增加圆括号解决。不过在一些极端情况中,查询可能在 没有被报告解析错误的情况下发生行为的改变。 -**** - -=== 值表达式 - -值表达式被用于各种各样的环境中,例如在 `SELECT` 命令的目标列表中、作为 `INSERT` 或 `UPDATE` 中的新列值或者若干命令中的搜索条件。为了区别于一个表表达式(是一个表)的结果,一个值表达式的结果有时候被称为一个 *标量*。值表达式因此也被称为 *标量表达式*(或者甚至简称为 *表达式*)。表达式语法允许使用算数、逻辑、集合和其他操作从原始部分计算值。 - -一个值表达式是下列之一: - -- 一个常量或文字值 -- 一个列引用 -- 在一个函数定义体或预备语句中的一个位置参数引用 -- 一个下标表达式 -- 一个域选择表达式 -- 一个操作符调用 -- 一个函数调用 -- 一个聚集表达式 -- 一个窗口函数调用 -- 一个类型转换 -- 一个排序规则表达式 -- 一个标量子查询 -- 一个数组构造器 -- 一个行构造器 -- 另一个在圆括号(用来分组子表达式以及重载优先级)中的值表达式 - -在这个列表之外,还有一些结构可以被分类为一个表达式,但是它们不遵循任何一般语法规则。这些通常具有一个函数或操作符的语义并且在 http://www.postgres.cn/docs/14/functions.html[第 9 章] 中的合适位置解释。一个例子是 `IS NULL` 子句。 - -我们已经在 http://www.postgres.cn/docs/14/sql-syntax-lexical.html#SQL-SYNTAX-CONSTANTS[第 4.1.2 节] 中讨论过常量。下面的小节会讨论剩下的选项。 - -==== 列引用 - -一个列可以以下面的形式被引用: - -``` -correlation.columnname -``` - - - -*`correlation`* 是一个表(有可能以一个模式名限定)的名字,或者是在 `FROM` 子句中为一个表定义的别名。如果列名在当前索引所使用的表中都是唯一的,关联名称和分隔用的句点可以被忽略(另见 http://www.postgres.cn/docs/14/queries.html[第 7 章])。 - -==== 位置参数 - -一个位置参数引用被用来指示一个由 SQL 语句外部提供的值。参数被用于 SQL 函数定义和预备查询中。某些客户端库还支持独立于 SQL 命令字符串来指定数据值,在这种情况中参数被用来引用那些线外数据值。一个参数引用的形式是: - -``` -$number -``` - - - -例如,考虑一个函数 `dept` 的定义: - -``` -CREATE FUNCTION dept(text) RETURNS dept - AS $$ SELECT * FROM dept WHERE name = $1 $$ - LANGUAGE SQL; -``` - -这里 `$1` 引用函数被调用时第一个函数参数的值。 - -==== 下标 - -如果一个表达式得到了一个数组类型的值,那么可以抽取出该数组值的一个特定元素: - -``` -expression[subscript] -``` - -或者抽取出多个相邻元素(一个“数组切片”): - -``` -expression[lower_subscript:upper_subscript] -``` - -(这里,方括号 `[ ]` 表示其字面意思)。每一个 *`下标`* 自身是一个表达式,它将四舍五入到最接近的整数值。 - -通常,数组 *`表达式`* 必须被加上括号,但是当要被加下标的表达式只是一个列引用或位置参数时,括号可以被忽略。还有,当原始数组是多维时,多个下标可以被连接起来。例如: - -``` -mytable.arraycolumn[4] -mytable.two_d_column[17][34] -$1[10:42] -(arrayfunction(a,b))[42] -``` - -最后一个例子中的圆括号是必需的。详见 http://www.postgres.cn/docs/14/arrays.html[第 8.15 节]。 - -==== 域选择 - -如果一个表达式得到一个组合类型(行类型)的值,那么可以抽取该行的指定域 - -``` -expression.fieldname -``` - - - -通常行 *`表达式`* 必须被加上括号,但是当该表达式是仅从一个表引用或位置参数选择时,圆括号可以被忽略。例如: - -``` -mytable.mycolumn -$1.somecolumn -(rowfunction(a,b)).col3 -``` - -(因此,一个被限定的列引用实际上只是域选择语法的一种特例)。一种重要的特例是从一个组合类型的表列中抽取一个域: - -``` -(compositecol).somefield -(mytable.compositecol).somefield -``` - -这里需要圆括号来显示 `compositecol` 是一个列名而不是一个表名,在第二种情况中则是显示 `mytable` 是一个表名而不是一个模式名。 - -你可以通过书写 `.*` 来请求一个组合值的所有域: - -``` -(compositecol).* -``` - -这种记法的行为根据上下文会有不同,详见 http://www.postgres.cn/docs/14/rowtypes.html#ROWTYPES-USAGE[第 8.16.5 节]。 - -==== 操作符调用 - -对于一次操作符调用,有两种可能的语法: -|==== -| *`expression`* *`operator`* *`expression`*(二元中缀操作符) -| *`operator`* *`expression`*(一元前缀操作符) -|==== - -其中 *`operator`* 记号遵循 http://www.postgres.cn/docs/14/sql-syntax-lexical.html#SQL-SYNTAX-OPERATORS[第 4.1.3 节] 的语法规则,或者是关键词`AND`、`OR`和`NOT`之一,或者是一个如下形式的受限定操作符名: - -``` -OPERATOR(schema.operatorname) -``` - -哪个特定操作符存在以及它们是一元的还是二元的取决于由系统或用户定义的那些操作符。 http://www.postgres.cn/docs/14/functions.html[第 9 章] 描述了内建操作符。 - -==== 函数调用 - -一个函数调用的语法是一个函数的名称(可能受限于一个模式名)后面跟上封闭于圆括号中的参数列表: - -``` -function_name ([expression [, expression ... ]] ) -``` - - - -例如,下面会计算 2 的平方根: - -``` -sqrt(2) -``` - - - -当在一个某些用户不信任其他用户的数据库中发出查询时,在编写函数调用时应遵守 http://www.postgres.cn/docs/14/typeconv-func.html[第 10.3 节] 中的安全防范措施。 - -内建函数的列表在 http://www.postgres.cn/docs/14/functions.html[第 9 章] 中。其他函数可以由用户增加。 - -参数可以有选择地被附加名称。详见 http://www.postgres.cn/docs/14/sql-syntax-calling-funcs.html[第 4.3 节]。 - -.注意 -**** -一个采用单一组合类型参数的函数可以被有选择地称为域选择语法,并且反过来域选择可以被写成函数的风格。也就是说,记号`col(table)`和`table.col`是可以互换的。这种行为是非 SQL 标准的但是在IvorySQL中被提供,因为它允许函数的使用来模拟“计算域”。 -**** - - -==== 聚集表达式 - -一个 *聚集表达式* 表示在由一个查询选择的行上应用一个聚集函数。一个聚集函数将多个输入减少到一个单一输出值,例如对输入的求和或平均。一个聚集表达式的语法是下列之一: - -``` -aggregate_name (expression [ , ... ] [ order_by_clause ] ) [ FILTER ( WHERE filter_clause ) ] -aggregate_name (ALL expression [ , ... ] [ order_by_clause ] ) [ FILTER ( WHERE filter_clause ) ] -aggregate_name (DISTINCT expression [ , ... ] [ order_by_clause ] ) [ FILTER ( WHERE filter_clause ) ] -aggregate_name ( * ) [ FILTER ( WHERE filter_clause ) ] -aggregate_name ( [ expression [ , ... ] ] ) WITHIN GROUP ( order_by_clause ) [ FILTER ( WHERE filter_clause ) ] -``` - -这里 *`aggregate_name`* 是一个之前定义的聚集(可能带有一个模式名限定),并且 *`expression`* 是任意自身不包含聚集表达式的值表达式或一个窗口函数调用。可选的 *`order_by_clause`* 和 *`filter_clause`* 描述如下。 - -第一种形式的聚集表达式为每一个输入行调用一次聚集。第二种形式和第一种相同,因为 `ALL` 是默认选项。第三种形式为输入行中表达式的每一个可区分值(或者对于多个表达式是值的可区分集合)调用一次聚集。第四种形式为每一个输入行调用一次聚集,因为没有特定的输入值被指定,它通常只对于 `count(*)` 聚集函数有用。最后一种形式被用于 *有序集* 聚集函数,其描述如下。 - -大部分聚集函数忽略空输入,这样其中一个或多个表达式得到空值的行将被丢弃。除非另有说明,对于所有内建聚集都是这样。 - -例如,`count(*)` 得到输入行的总数。 `count(f1)` 得到输入行中 `f1` 为非空的数量,因为 `count` 忽略空值。而 `count(distinct f1)` 得到 `f1` 的非空可区分值的数量。 - -一般地,交给聚集函数的输入行是未排序的。在很多情况中这没有关系,例如不管接收到什么样的输入, `min` 总是产生相同的结果。但是,某些聚集函数(例如 `array_agg` 和 `string_agg` )依据输入行的排序产生结果。当使用这类聚集时,可选的 *`order_by_clause`* 可以被用来指定想要的顺序。*`order_by_clause`* 与查询级别的 `ORDER BY` 子句(如 http://www.postgres.cn/docs/14/queries-order.html[第 7.5 节] 所述)具有相同的语法,除非它的表达式总是仅有表达式并且不能是输出列名称或编号。例如: - -``` -SELECT array_agg(a ORDER BY b DESC) FROM table; -``` - - - -在处理多参数聚集函数时,注意 `ORDER BY` 出现在所有聚集参数之后。例如,要这样写: - -``` -SELECT string_agg(a, ',' ORDER BY a) FROM table; -``` - -而不能这样写: - -``` -SELECT string_agg(a ORDER BY a, ',') FROM table; -- 不正确 -``` - -后者在语法上是合法的,但是它表示用两个`ORDER BY`键来调用一个单一参数聚集函数(第二个是无用的,因为它是一个常量)。 - -如果在 *`order_by_clause`* 之外指定了 `DISTINCT` ,那么所有的 `ORDER BY` 表达式必须匹配聚集的常规参数。也就是说,你不能在 `DISTINCT` 列表没有包括的表达式上排序。 - -.注意 -**** -在一个聚集函数中指定 `DISTINCT` 以及 `ORDER BY` 的能力是一种IvorySQL扩展。按照到目前为止的描述,如果一般目的和统计性聚集中 排序是可选的,在要为它排序输入行时可以在该聚集的常规参数 列表中放置 `ORDER BY` 。有一个聚集函数的子集叫做 *有序集聚集* ,它**要求**一个 *`order_by_clause`*,通常是因为该聚集的计算只对其输入行的特定顺序有意义。有序集聚集的典 型例子包括排名和百分位计算。按照上文的最后一种语法,对于 一个有序集聚集, *`order_by_clause`* 被写在 `WITHIN GROUP (...)` 中。 *`order_by_clause`* 中的表达式 会像普通聚集参数一样对每一个输入行计算一次,按照每个 *`order_by_clause`* 的要求排序并 且交给该聚集函数作为输入参数(这和非 `WITHIN GROUP` *`order_by_clause`* 的情况不同,在其中表达 式的结果不会被作为聚集函数的参数)。如果有在 `WITHIN GROUP` 之前的参数表达式,会把它们称 为 *直接参数* 以便与列在 *`order_by_clause`* 中的 *聚集参数* 相区分。与普通聚集参数不同,针对 每次聚集调用只会计算一次直接参数,而不是为每一个输入行 计算一次。这意味着只有那些变量被 `GROUP BY` 分组时,它们才能包含这些变量。这个限制同样适用于根本不在 一个聚集表达式内部的直接参数。直接参数通常被用于百分数 之类的东西,它们只有作为每次聚集计算用一次的单一值才有意 义。直接参数列表可以为空,在这种情况下,写成 `()` 而不是 `(*)`(实际上 IvorySQL接受两种拼写,但是只有第一种符合 SQL 标准)。 -**** - -有序集聚集的调用例子: - -``` -SELECT percentile_cont(0.5) WITHIN GROUP (ORDER BY income) FROM households; - percentile_cont ------------------ - 50489 -``` - -这会从表 `households` 的 `income` 列得到第 50 个百分位或者中位的值。 这里`0.5`是一个直接参数,对于百分位部分是一个 在不同行之间变化的值的情况它没有意义。 - -如果指定了 `FILTER` ,那么只有对 *`filter_clause`* 计算为真的输入行会被交给该聚集函数,其他行会被丢弃。例如: - -``` -SELECT - count(*) AS unfiltered, - count(*) FILTER (WHERE i < 5) AS filtered -FROM generate_series(1,10) AS s(i); - unfiltered | filtered -------------+---------- - 10 | 4 -(1 row) -``` - -预定义的聚集函数在 http://www.postgres.cn/docs/14/functions-aggregate.html[第 9.21 节] 中描述。其他聚集函数可以由用户增加。 - -一个聚集表达式只能出现在 `SELECT` 命令的结果列表或是 `HAVING` 子句中。在其他子句(如 `WHERE` )中禁止使用它,因为那些子句的计算在逻辑上是在聚集的结果被形成之前。 - -当一个聚集表达式出现在一个子查询中(见 http://www.postgres.cn/docs/14/sql-expressions.html#SQL-SYNTAX-SCALAR-SUBQUERIES[第 4.2.11 节] 和 http://www.postgres.cn/docs/14/functions-subquery.html[第 9.23 节]),聚集通常在该子查询的行上被计算。但是如果该聚集的参数(以及 *`filter_clause`*,如果有)只包含外层变量则会产生一个异常:该聚集则属于最近的那个外层,并且会在那个查询的行上被计算。该聚集表达式从整体上则是对其所出现于的子查询的一种外层引用,并且在那个子查询的任意一次计算中都作为一个常量。只出现在结果列表或 `HAVING` 子句的限制适用于该聚集所属的查询层次。 - -==== 窗口函数调用 - -一个*窗口函数调用*表示在一个查询选择的行的某个部分上应用一个聚集类的函数。和非窗口聚集函数调用不同,这不会被约束为将被选择的行分组为一个单一的输出行 — 在查询输出中每一个行仍保持独立。不过,窗口函数能够根据窗口函数调用的分组声明( `PARTITION BY` 列表)访问属于当前行所在分组中的所有行。一个窗口函数调用的语法是下列之一: - -``` -function_name ([expression [, expression ... ]]) [ FILTER ( WHERE filter_clause ) ] OVER window_name -function_name ([expression [, expression ... ]]) [ FILTER ( WHERE filter_clause ) ] OVER ( window_definition ) -function_name ( * ) [ FILTER ( WHERE filter_clause ) ] OVER window_name -function_name ( * ) [ FILTER ( WHERE filter_clause ) ] OVER ( window_definition ) -``` - -其中 *`window_definition`* 的语法是 - -``` -[ existing_window_name ] -[ PARTITION BY expression [, ...] ] -[ ORDER BY expression [ ASC | DESC | USING operator ] [ NULLS { FIRST | LAST } ] [, ...] ] -[ frame_clause ] -``` - -可选的 *`frame_clause`* 是下列之一 - -``` -{ RANGE | ROWS | GROUPS } frame_start [ frame_exclusion ] -{ RANGE | ROWS | GROUPS } BETWEEN frame_start AND frame_end [ frame_exclusion ] -``` - -其中 *`frame_start`* 和 *`frame_end`* 可以是下面形式中的一种 - -``` -UNBOUNDED PRECEDING -offset PRECEDING -CURRENT ROW -offset FOLLOWING -UNBOUNDED FOLLOWING -``` - -而 *`frame_exclusion`* 可以是下列之一 - -``` -EXCLUDE CURRENT ROW -EXCLUDE GROUP -EXCLUDE TIES -EXCLUDE NO OTHERS -``` - - - -这里,*`expression`* 表示任何自身不含有窗口函数调用的值表达式。 - -*`window_name`* 是对定义在查询的 `WINDOW` 子句中的一个命名窗口声明的引用。还可以使用在 `WINDOW` 子句中定义命名窗口的相同语法在圆括号内给定一个完整的 *`window_definition`*,详见 http://www.postgres.cn/docs/14/sql-select.html[SELECT] 参考页。值得指出的是,`OVER wname` 并不严格地等价于 `OVER (wname ...)`,后者表示复制并修改窗口定义,并且在被引用窗口声明包括一个帧子句时会被拒绝。 - -`PARTITION BY` 选项将查询的行分组成为 *分区*,窗口函数会独立地处理它们。`PARTITION BY` 工作起来类似于一个查询级别的 `GROUP BY` 子句,不过它的表达式总是只是表达式并且不能是输出列的名称或编号。如果没有 `PARTITION BY`,该查询产生的所有行被当作一个单一分区来处理。`ORDER BY` 选项决定被窗口函数处理的一个分区中的行的顺序。它工作起来类似于一个查询级别的 `ORDER BY` 子句,但是同样不能使用输出列的名称或编号。如果没有 `ORDER BY`,行将被以未指定的顺序被处理。 - -*`frame_clause`* 指定构成 *窗口帧* 的行集合,它是当前分区的一个子集,窗口函数将作用在该帧而不是整个分区。帧中的行集合会随着哪一行是当前行而变化。在 `RANGE`、`ROWS` 或者 `GROUPS` 模式中可以指定帧,在每一种情况下,帧的范围都是从 *`frame_start`* 到 *`frame_end`*。如果 *`frame_end`* 被省略,则末尾默认为 `CURRENT ROW`。 - -`UNBOUNDED PRECEDING` 的一个 *`frame_start`* 表示该帧开始于分区的第一行,类似地 `UNBOUNDED FOLLOWING` 的一个 *`frame_end`* 表示该帧结束于分区的最后一行。 - -在 `RANGE` 或 `GROUPS` 模式中,`CURRENT ROW` 的一个 *`frame_start`* 表示帧开始于当前行的第一个 *平级* 行(被窗口的 `ORDER BY` 子句排序为与当前行等效的行),而 `CURRENT ROW` 的一个 *`frame_end`* 表示帧结束于当前行的最后一个平级行。在 `ROWS` 模式中,`CURRENT ROW` 就表示当前行。 - -在 *`offset`* `PRECEDING` 以及 *`offset`* `FOLLOWING` 帧选项中,*`offset`* 必须是一个不包含任何变量、聚集函数或者窗口函数的表达式。*`offset`* 的含义取决于帧模式: - -- 在 `ROWS` 模式中, *`offset`* 必须得到一个非空、非负的整数,并且该选项表示帧开始于当前行之前或者之后指定数量的行。 -- 在 `GROUPS` 模式中,*`offset`* 也必须得到一个非空、非负的整数,并且该选项表示帧开始于当前行的平级组之前或者之后指定数量的*平级组*,这里平级组是在 `ORDER BY` 顺序中等效的行集合(要使用 `GROUPS` 模式,在窗口定义中就必须有一个 `ORDER BY` 子句)。 -- 在 `RANGE` 模式中,这些选项要求 `ORDER BY` 子句正好指定一列。*`offset`* 指定当前行中那一列的值与它在该帧中前面或后面的行中的列值的最大差值。*`offset`* 表达式的数据类型会随着排序列的数据类型而变化。对于数字的排序列,它通常是与排序列相同的类型,但对于日期时间排序列它是一个 `interval`。例如,如果排序列是类型 `date` 或者 `timestamp`,我们可以写 `RANGE BETWEEN '1 day' PRECEDING AND '10 days' FOLLOWING`。*`offset`* 仍然要求是非空且非负,不过“非负”的含义取决于它的数据类型。 - -在任何一种情况下,到帧末尾的距离都受限于到分区末尾的距离,因此对于离分区末尾比较近的行来说,帧可能会包含比较少的行。 - -注意在 `ROWS` 以及 `GROUPS` 模式中, `0 PRECEDING` 和 `0 FOLLOWING` 与 `CURRENT ROW` 等效。通常在 `RANGE` 模式中,这个结论也成立(只要有一种合适的、与数据类型相关的“零”的含义)。 - -*`frame_exclusion`* 选项允许当前行周围的行被排除在帧之外,即便根据帧的开始和结束选项应该把它们包括在帧中。`EXCLUDE CURRENT ROW` 会把当前行排除在帧之外。`EXCLUDE GROUP` 会把当前行以及它在顺序上的平级行都排除在帧之外。`EXCLUDE TIES` 把当前行的任何平级行都从帧中排除,但不排除当前行本身。`EXCLUDE NO OTHERS` 只是明确地指定不排除当前行或其平级行的这种默认行为。 - -默认的帧选项是 `RANGE UNBOUNDED PRECEDING`,它和 `RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW` 相同。如果使用 `ORDER BY`,这会把该帧设置为从分区开始一直到当前行的最后一个 `ORDER BY` 平级行的所有行。如果不使用 `ORDER BY`,就意味着分区中所有的行都被包括在窗口帧中,因为所有行都成为了当前行的平级行。 - -限制是 *`frame_start`* 不能是 `UNBOUNDED FOLLOWING` 、*`frame_end`* 不能是 `UNBOUNDED PRECEDING`,并且在上述 *`frame_start`* 和 *`frame_end`* 选项的列表中 *`frame_end`* 选择不能早于 *`frame_start`* 选择出现 — 例如不允许 `RANGE BETWEEN CURRENT ROW AND *offset* PRECEDING`,但允许 `ROWS BETWEEN 7 PRECEDING AND 8 PRECEDING` ,虽然它不会选择任何行。 - -如果指定了 `FILTER` ,那么只有对 *`filter_clause`* 计算为真的输入行会被交给该窗口函数,其他行会被丢弃。只有是聚集的窗口函数才接受 `FILTER` 。 - -内建的窗口函数在 http://www.postgres.cn/docs/14/functions-window.html#FUNCTIONS-WINDOW-TABLE[表 9.60] 中介绍。用户可以加入其他窗口函数。此外,任何内建的或者用户定义的通用聚集或者统计性聚集都可以被用作窗口函数(有序集和假想集聚集当前不能被用作窗口函数)。 - -使用 `\*` 的语法被用来把参数较少的聚集函数当作窗口函数调用,例如 `count(*) OVER (PARTITION BY x ORDER BY y)`。星号(`*`)通常不被用于窗口相关的函数。窗口相关的函数不允许在函数参数列表中用 `DISTINCT` 或 `ORDER BY`。 - -只有在 `SELECT` 列表和查询的 `ORDER BY` 子句中才允许窗口函数调用。 - -更多关于窗口函数的信息可以在 http://www.postgres.cn/docs/14/tutorial-window.html[第 3.5 节]、 http://www.postgres.cn/docs/14/functions-window.html[第 9.22 节] 以及 http://www.postgres.cn/docs/14/queries-table-expressions.html#QUERIES-WINDOW[第 7.2.5 节] 中找到。 - -==== 类型转换 - -一个类型造型指定从一种数据类型到另一种数据类型的转换。IvorySQL接受两种等价的类型造型语法: - -``` -CAST ( expression AS type ) -expression::type -``` - -`CAST` 语法遵从 SQL,而用 `::` 的语法是IvorySQL的历史用法。 - -当一个造型被应用到一种未知类型的值表达式上时,它表示一种运行时类型转换。只有已经定义了一种合适的类型转换操作时,该造型才会成功。注意这和常量的造型(如 http://www.postgres.cn/docs/14/sql-syntax-lexical.html#SQL-SYNTAX-CONSTANTS-GENERIC[第 4.1.2.7 节] 中所示)使用不同。应用于一个未修饰串文字的造型表示一种类型到一个文字常量值的初始赋值,并且因此它将对任意类型都成功(如果该串文字的内容对于该数据类型的输入语法是可接受的)。 - -如果一个值表达式必须产生的类型没有歧义(例如当它被指派给一个表列),通常可以省略显式类型造型,在这种情况下系统会自动应用一个类型造型。但是,只有对在系统目录中被标记为“OK to apply implicitly”的造型才会执行自动造型。其他造型必须使用显式造型语法调用。这种限制是为了防止出人意料的转换被无声无息地应用。 - -还可以用像函数的语法来指定一次类型造型: - -``` -typename ( expression ) -``` - -不过,这只对那些名字也作为函数名可用的类型有效。例如,`double precision` 不能以这种方式使用,但是等效的 `float8` 可以。还有,如果名称 `interval`、`time` 和 `timestamp` 被用双引号引用,那么由于语法冲突的原因,它们只能以这种风格使用。因此,函数风格的造型语法的使用会导致不一致性并且应该尽可能被避免。 - -.注意 -**** -函数风格的语法事实上只是一次函数调用。当两种标准造型语法之一被用来做一次运行时转换时,它将在内部调用一个已注册的函数来执行该转换。简而言之,这些转换函数具有和它们的输出类型相同的名字,并且因此“函数风格的语法”无非是对底层转换函数的一次直接调用。显然,一个可移植的应用不应当依赖于它。详见 http://www.postgres.cn/docs/14/sql-createcast.html[CREATE CAST]。 -**** - -==== 排序规则表达式 - -`COLLATE` 子句会重载一个表达式的排序规则。它被追加到它适用的表达式: - -``` -expr COLLATE collation -``` - -这里 *`collation`* 可能是一个受模式限定的标识符。`COLLATE` 子句比操作符绑得更紧,需要时可以使用圆括号。 - -如果没有显式指定排序规则,数据库系统会从表达式所涉及的列中得到一个排序规则,如果该表达式没有涉及列,则会默认采用数据库的默认排序规则。 - -`COLLATE` 子句的两种常见使用是重载 `ORDER BY` 子句中的排序顺序,例如: - -``` -SELECT a, b, c FROM tbl WHERE ... ORDER BY a COLLATE "C"; -``` - -以及重载具有区域敏感结果的函数或操作符调用的排序规则,例如: - -``` -SELECT * FROM tbl WHERE a > 'foo' COLLATE "C"; -``` - -注意在后一种情况中,`COLLATE` 子句被附加到我们希望影响的操作符的一个输入参数上。`COLLATE` 子句被附加到该操作符或函数调用的哪个参数上无关紧要,因为被操作符或函数应用的排序规则是考虑所有参数得来的,并且一个显式的 `COLLATE` 子句将重载所有其他参数的排序规则(不过,附加非匹配 `COLLATE` 子句到多于一个参数是一种错误。详见 http://www.postgres.cn/docs/14/collation.html[第 24.2 节])。因此,这会给出和前一个例子相同的结果: - -``` -SELECT * FROM tbl WHERE a COLLATE "C" > 'foo'; -``` - -但是这是一个错误: - -``` -SELECT * FROM tbl WHERE (a > 'foo') COLLATE "C"; -``` - -因为它尝试把一个排序规则应用到 `>` 操作符的结果,而它的数据类型是非可排序数据类型 `boolean`。 - -==== 标量子查询 - -一个标量子查询是一种圆括号内的普通 `SELECT` 查询,它刚好返回一行一列(关于书写查询可见 http://www.postgres.cn/docs/14/queries.html[第 7 章])。`SELECT`查询被执行并且该单一返回值被使用在周围的值表达式中。将一个返回超过一行或一列的查询作为一个标量子查询使用是一种错误(但是如果在一次特定执行期间该子查询没有返回行则不是错误,该标量结果被当做为空)。该子查询可以从周围的查询中引用变量,这些变量在该子查询的任何一次计算中都将作为常量。对于其他涉及子查询的表达式还可见 http://www.postgres.cn/docs/14/functions-subquery.html[第 9.23 节]。 - -例如,下列语句会寻找每个州中最大的城市人口: - -``` -SELECT name, (SELECT max(pop) FROM cities WHERE cities.state = states.name) - FROM states; -``` - -==== 数组构造器 - -一个数组构造器是一个能构建一个数组值并且将值用于它的成员元素的表达式。一个简单的数组构造器由关键词 `ARRAY`、一个左方括号 `[` 、一个用于数组元素值的表达式列表(用逗号分隔)以及最后的一个右方括号 `]` 组成。例如: - -``` -SELECT ARRAY[1,2,3+4]; - array ---------- - {1,2,7} -(1 row) -``` - -默认情况下,数组元素类型是成员表达式的公共类型,使用和 `UNION` 或 `CASE` 结构(见 http://www.postgres.cn/docs/14/typeconv-union-case.html[第 10.5 节])相同的规则决定。你可以通过显式将数组构造器造型为想要的类型来重载,例如: - -``` -SELECT ARRAY[1,2,22.7]::integer[]; - array ----------- - {1,2,23} -(1 row) -``` - -这和把每一个表达式单独地造型为数组元素类型的效果相同。关于造型的更多信息请见 http://www.postgres.cn/docs/14/sql-expressions.html#SQL-SYNTAX-TYPE-CASTS[第 4.2.9 节]。 - -多维数组值可以通过嵌套数组构造器来构建。在内层的构造器中,关键词 `ARRAY` 可以被忽略。例如,这些语句产生相同的结果: - -``` -SELECT ARRAY[ARRAY[1,2], ARRAY[3,4]]; - array ---------------- - {{1,2},{3,4}} -(1 row) - -SELECT ARRAY[[1,2],[3,4]]; - array ---------------- - {{1,2},{3,4}} -(1 row) -``` - -因为多维数组必须是矩形的,处于同一层次的内层构造器必须产生相同维度的子数组。任何被应用于外层 `ARRAY` 构造器的造型会自动传播到所有的内层构造器。 - -多维数组构造器元素可以是任何得到一个正确种类数组的任何东西,而不仅仅是一个子- `ARRAY` 结构。例如: - -``` -CREATE TABLE arr(f1 int[], f2 int[]); - -INSERT INTO arr VALUES (ARRAY[[1,2],[3,4]], ARRAY[[5,6],[7,8]]); - -SELECT ARRAY[f1, f2, '{{9,10},{11,12}}'::int[]] FROM arr; - array ------------------------------------------------- - {{{1,2},{3,4}},{{5,6},{7,8}},{{9,10},{11,12}}} -(1 row) -``` - - - -你可以构造一个空数组,但是因为无法得到一个无类型的数组,你必须显式地把你的空数组造型成想要的类型。例如: - -``` -SELECT ARRAY[]::integer[]; - array -------- - {} -(1 row) -``` - - - -也可以从一个子查询的结果构建一个数组。在这种形式中,数组构造器被写为关键词 `ARRAY` 后跟着一个加了圆括号(不是方括号)的子查询。例如: - -``` -SELECT ARRAY(SELECT oid FROM pg_proc WHERE proname LIKE 'bytea%'); - array ------------------------------------------------------------------- - {2011,1954,1948,1952,1951,1244,1950,2005,1949,1953,2006,31,2412} -(1 row) - -SELECT ARRAY(SELECT ARRAY[i, i*2] FROM generate_series(1,5) AS a(i)); - array ----------------------------------- - {{1,2},{2,4},{3,6},{4,8},{5,10}} -(1 row) -``` - -子查询必须返回一个单一列。如果子查询的输出列是非数组类型, 结果的一维数组将为该子查询结果中的每一行有一个元素, 并且有一个与子查询的输出列匹配的元素类型。如果子查询的输出列 是一种数组类型,结果将是同类型的一个数组,但是要高一个维度。 在这种情况下,该子查询的所有行必须产生同样维度的数组,否则结果 就不会是矩形形式。 - -用 `ARRAY` 构建的一个数组值的下标总是从一开始。更多关于数组的信息,请见 http://www.postgres.cn/docs/14/arrays.html[第 8.15 节]。 - -==== 行构造器 - -一个行构造器是能够构建一个行值(也称作一个组合类型)并用值作为其成员域的表达式。一个行构造器由关键词 `ROW`、一个左圆括号、用于行的域值的零个或多个表达式(用逗号分隔)以及最后的一个右圆括号组成。例如: - -``` -SELECT ROW(1,2.5,'this is a test'); -``` - -当在列表中有超过一个表达式时,关键词 `ROW` 是可选的。 - -一个行构造器可以包括语法 *`rowvalue`* `.\*`,它将被扩展为该行值的元素的一个列表,就像在一个顶层 `SELECT` 列表(见 http://www.postgres.cn/docs/14/rowtypes.html#ROWTYPES-USAGE[第 8.16.5 节])中使用 `.*` 时发生的事情一样。例如,如果表 `t` 有列 `f1` 和 `f2`,那么这些是相同的: - -``` -SELECT ROW(t.*, 42) FROM t; -SELECT ROW(t.f1, t.f2, 42) FROM t; -``` - -.注意 -**** -在IvorySQL 8.2 以前,`.\*` 语法不会在行构造器中被扩展,这样写 `ROW(t.*, 42)` 会创建一个有两个域的行,其第一个域是另一个行值。新的行为通常更有用。如果你需要嵌套行值的旧行为,写内层行值时不要用 `.*`,例如 `ROW(t, 42)`。 -**** - -默认情况下,由一个 `ROW` 表达式创建的值是一种匿名记录类型。如果必要,它可以被造型为一种命名的组合类型 — 或者是一个表的行类型,或者是一种用 `CREATE TYPE AS` 创建的组合类型。为了避免歧义,可能需要一个显式造型。例如: - -``` -CREATE TABLE mytable(f1 int, f2 float, f3 text); - -CREATE FUNCTION getf1(mytable) RETURNS int AS 'SELECT $1.f1' LANGUAGE SQL; - --- 不需要造型因为只有一个 getf1() 存在 -SELECT getf1(ROW(1,2.5,'this is a test')); - getf1 -------- - 1 -(1 row) - -CREATE TYPE myrowtype AS (f1 int, f2 text, f3 numeric); - -CREATE FUNCTION getf1(myrowtype) RETURNS int AS 'SELECT $1.f1' LANGUAGE SQL; - --- 现在我们需要一个造型来指示要调用哪个函数: -SELECT getf1(ROW(1,2.5,'this is a test')); -ERROR: function getf1(record) is not unique - -SELECT getf1(ROW(1,2.5,'this is a test')::mytable); - getf1 -------- - 1 -(1 row) - -SELECT getf1(CAST(ROW(11,'this is a test',2.5) AS myrowtype)); - getf1 -------- - 11 -(1 row) -``` - - - -行构造器可以被用来构建存储在一个组合类型表列中的组合值,或者被传递给一个接受组合参数的函数。还有,可以比较两个行值,或者用 `IS NULL` 或 `IS NOT NULL` 测试一个行,例如: - -``` -SELECT ROW(1,2.5,'this is a test') = ROW(1, 3, 'not the same'); - -SELECT ROW(table.*) IS NULL FROM table; -- detect all-null rows -``` - -详见 http://www.postgres.cn/docs/14/functions-comparisons.html[第 9.24 节]。如 http://www.postgres.cn/docs/14/functions-subquery.html[第 9.23 节] 中所讨论的,行构造器也可以被用来与子查询相连接。 - -==== 表达式计算规则 - -子表达式的计算顺序没有被定义。特别地,一个操作符或函数的输入不必按照从左至右或其他任何固定顺序进行计算。 - -此外,如果一个表达式的结果可以通过只计算其一部分来决定,那么其他子表达式可能完全不需要被计算。例如,如果我们写: - -``` -SELECT true OR somefunc(); -``` - -那么 `somefunc()` 将(可能)完全不被调用。如果我们写成下面这样也是一样: - -``` -SELECT somefunc() OR true; -``` - -注意这和一些编程语言中布尔操作符从左至右的“短路”不同。 - -因此,在复杂表达式中使用带有副作用的函数是不明智的。在 `WHERE` 和 `HAVING` 子句中依赖副作用或计算顺序尤其危险,因为在建立一个执行计划时这些子句会被广泛地重新处理。这些子句中布尔表达式( `AND` / `OR` / `NOT` 的组合)可能会以布尔代数定律所允许的任何方式被重组。 - -当有必要强制计算顺序时,可以使用一个 `CASE` 结构(见 http://www.postgres.cn/docs/14/functions-conditional.html[第 9.18 节])。例如,在一个 `WHERE` 子句中使用下面的方法尝试避免除零是不可靠的: - -``` -SELECT ... WHERE x > 0 AND y/x > 1.5; -``` - -但是这是安全的: - -``` -SELECT ... WHERE CASE WHEN x > 0 THEN y/x > 1.5 ELSE false END; -``` - -一个以这种风格使用的 `CASE` 结构将使得优化尝试失败,因此只有必要时才这样做(在这个特别的例子中,最好通过写 `y > 1.5*x` 来回避这个问题)。 - -不过,`CASE` 不是这类问题的万灵药。上述技术的一个限制是, 它无法阻止常量子表达式的提早计算。如 http://www.postgres.cn/docs/14/xfunc-volatility.html[第 38.7 节] 中所述,当查询被规划而不是被执行时,被标记成 `IMMUTABLE` 的函数和操作符可以被计算。因此 - -``` -SELECT CASE WHEN x > 0 THEN x ELSE 1/0 END FROM tab; -``` - -很可能会导致一次除零失败,因为规划器尝试简化常量子表达式。即便是 表中的每一行都有 `x > 0`(这样运行时永远不会进入到 `ELSE` 分支)也是这样。 - -虽然这个特别的例子可能看起来愚蠢,没有明显涉及常量的情况可能会发生 在函数内执行的查询中,因为因为函数参数的值和本地变量可以作为常量 被插入到查询中用于规划目的。例如,在PL/pgSQL函数 中,使用一个 `IF` -`THEN` -`ELSE` 语句来 保护一种有风险的计算比把它嵌在一个 `CASE` 表达式中要安全得多。 - -另一个同类型的限制是,一个 `CASE` 无法阻止其所包含的聚集表达式 的计算,因为在考虑 `SELECT` 列表或 `HAVING` 子句中的 其他表达式之前,会先计算聚集表达式。例如,下面的查询会导致一个除零错误, 虽然看起来好像已经这种情况加以了保护: - -``` -SELECT CASE WHEN min(employees) > 0 - THEN avg(expenses / employees) - END - FROM departments; -``` - -`min()` 和 `avg()` 聚集会在所有输入行上并行地计算, 因此如果任何行有 `employees` 等于零,在有机会测试 `min()` 的结果之前,就会发生除零错误。取而代之的是,可以使用 一个 `WHERE` 或 `FILTER` 子句来首先阻止有问题的输入行到达一个聚集函数。 - -=== 调用函数 - -IvorySQL允许带有命名参数的函数被使用 *位置* 或 *命名* 记号法调用。命名记号法对于有大量参数的函数特别有用,因为它让参数和实际参数之间的关联更明显和可靠。在位置记号法中,书写一个函数调用时,其参数值要按照它们在函数声明中被定义的顺序书写。在命名记号法中,参数根据名称匹配函数参数,并且可以以任何顺序书写。对于每一种记法,还要考虑函数参数类型的效果,这些在 http://www.postgres.cn/docs/14/typeconv-func.html[第 10.3 节] 有介绍。 - -在任意一种记号法中,在函数声明中给出了默认值的参数根本不需要在调用中写出。但是这在命名记号法中特别有用,因为任何参数的组合都可以被忽略。而在位置记号法中参数只能从右往左忽略。 - -IvorySQL也支持 *混合* 记号法,它组合了位置和命名记号法。在这种情况中,位置参数被首先写出并且命名参数出现在其后。 - -下列例子将展示所有三种记号法的用法: - -``` -CREATE FUNCTION concat_lower_or_upper(a text, b text, uppercase boolean DEFAULT false) -RETURNS text -AS -$$ - SELECT CASE - WHEN $3 THEN UPPER($1 || ' ' || $2) - ELSE LOWER($1 || ' ' || $2) - END; -$$ -LANGUAGE SQL IMMUTABLE STRICT; -``` - -函数 `concat_lower_or_upper` 有两个强制参数,`a` 和 `b`。此外,有一个可选的参数 `uppercase`,其默认值为 `false`。`a` 和 `b` 输入将被串接,并且根据 `uppercase` 参数被强制为大写或小写形式。这个函数的剩余细节对这里并不重要(详见 http://www.postgres.cn/docs/14/extend.html[第 38 章])。 - -==== 使用位置记号 - -在IvorySQL中,位置记号法是给函数传递参数的传统机制。一个例子: - -``` -SELECT concat_lower_or_upper('Hello', 'World', true); - concat_lower_or_upper ------------------------ - HELLO WORLD -(1 row) -``` - -所有参数被按照顺序指定。结果是大写形式,因为 `uppercase` 被指定为 `true`。另一个例子: - -``` -SELECT concat_lower_or_upper('Hello', 'World'); - concat_lower_or_upper ------------------------ - hello world -(1 row) -``` - -这里,`uppercase` 参数被忽略,因此它接收它的默认值 `false`,并导致小写形式的输出。在位置记号法中,参数可以按照从右往左被忽略并且因此而得到默认值。 - -==== 使用命名记号 - -在命名记号法中,每一个参数名都用 `=>` 指定来把它与参数表达式分隔开。例如: - -``` -SELECT concat_lower_or_upper(a => 'Hello', b => 'World'); - concat_lower_or_upper ------------------------ - hello world -(1 row) -``` - -再次,参数 `uppercase` 被忽略,因此它被隐式地设置为 `false`。使用命名记号法的一个优点是参数可以用任何顺序指定,例如: - -``` -SELECT concat_lower_or_upper(a => 'Hello', b => 'World', uppercase => true); - concat_lower_or_upper ------------------------ - HELLO WORLD -(1 row) - -SELECT concat_lower_or_upper(a => 'Hello', uppercase => true, b => 'World'); - concat_lower_or_upper ------------------------ - HELLO WORLD -(1 row) -``` - - - -为了向后兼容性,基于 ":=" 的旧语法仍被支持: - -``` -SELECT concat_lower_or_upper(a := 'Hello', uppercase := true, b := 'World'); - concat_lower_or_upper ------------------------ - HELLO WORLD -(1 row) -``` - -==== 使用混合记号 - -混合记号法组合了位置和命名记号法。不过,正如已经提到过的,命名参数不能超越位置参数。例如: - -``` -SELECT concat_lower_or_upper('Hello', 'World', uppercase => true); - concat_lower_or_upper ------------------------ - HELLO WORLD -(1 row) -``` - -在上述查询中,参数 `a` 和 `b` 被以位置指定,而 `uppercase` 通过名字指定。在这个例子中,这只增加了一点文档。在一个具有大量带默认值参数的复杂函数中,命名的或混合的记号法可以节省大量的书写并且减少出错的机会。 - -.注意 -**** -命名的和混合的调用记号法当前不能在调用聚集函数时使用(但是当聚集函数被用作窗口函数时它们可以被使用)。 -**** - -== Oracle兼容功能 - -=== 配置参数 - -参数设置采用与原生 PostgreSQL 相同的方法。 所有参数名称都不区分大小写。每个参数都采用以下五种类型之一的值:布尔值、字符串、整数、浮点数或枚举 (enum)。 - -==== `compatible_mode (enum)` - -此参数控制数据库服务器的行为。如果它设置为`pg`,表示它是原生安装,服务器将作为原生 PG 安装。 如果它设置为“oracle”,那么查询的输出和系统行为整体会发生变化,因为它会更像 Oracle。 - -当设置为 `oracle` 时,此参数会隐式地将同样名字的Schema添加到 `search_path`。 以便可以定位 Oracle 兼容对象。 - -该参数可以通过 `postgresql.conf` 配置文件设置,对整个数据库生效。 或者可以通过客户端使用 `set` 命令在会话上进行设置。 - -==== `nls_length_semantics (enum)` - -此参数控制如何根据长度语义创建 `CHAR` 和 `VARCHAR2` 列。 默认设置为 `NONE`,这不会产生任何影响。 `BYTE` 可以设置为以字节长度语义存储数据。 `CHAR` 使用字符长度语义。 - -**标识:** - -- https://www.ivorysql.org/zh-CN/docs/tags/compatibility-parameters[Compatibility Parameters] - -=== 包 - -本节将介绍PostgreSQL的“Oracle风格包”。根据定义,包是一个对象或一组对象打包在一起。就数据库而言,这将转换为一个命名的模式对象,该对象将过程、函数、变量、游标、用户定义的记录类型和引用记录的逻辑分组集合打包在自己内部。希望用户熟悉PostgreSQL,并且对SQL语言有很好的理解,以便更好地理解这些包并更有效地使用它们。 - -==== 对软件包的需求 - -与其他各种编程语言中的类似构造一样,将包与SQL一起使用有很多好处。在本节中,我们将要讲几个。 - -1.代码包的可靠性和可复用性:: - - Packages使您能够创建封装代码的模块化对象。这使得总体设计和实现更加简单。通过封装变量和相关类型、存储过程/函数以及游标,它允许您创建一个简单、易于理解、易于维护和使用的独立的模块。封装通过公开包接口而不是包体的实现细节发挥作用。因此,这在许多方面都有好处。它允许应用程序和用户引用一致的界面,而不必担心其主体的内容。此外,它还防止用户根据代码实现做出任何决策,因为代码实现从来没有向他们公开过。 - -2.易用性:: - - 在PostgreSQL中创建一致的功能接口的能力有助于简化应用程序开发,因为它允许在没有主体的情况下编译包。在开发阶段之后,包允许用户管理整个包的访问控制,而不是单个对象。这非常有价值,尤其是当包包含许多模式对象时。 - -3.性能:: - - 包是加载到内存中进行维护,因此使用的I/O资源最少。重新编译很简单,仅限于更改的对象;不重新编译从属对象。 - -4.附加功能:: - - 除了性能和易用性之外,软件包还为变量和游标提供了会话范围的持久性。这意味着变量和游标与数据库会话具有相同的生存期,并在会话被销毁时被销毁。 - -==== 包组件 - -包有一个接口和一个主体,这是组成包的主要组件。 - -1.包规格 - -包规格指定了包内从外部使用的任何对象。这指的是可公开访问的接口。它不包含它们的定义或实现,即功能和程序。它只定义了标题,而没有正文定义。可以初始化变量。以下是可在规范中列出的对象列表: - - - Functions - - Procedures - - Cursors - - Types - - Variables - - Constants - - Record types - -2.包体 - -包体包含包的所有实现代码,包括公共接口和私有对象。如果规范不包含任何子程序或游标,则包体是可选的。 - -它必须包含规范中声明的子程序的定义,并且相应的定义必须匹配。 - -包体可以包含其自己的子程序和规范中未指定的任何内部对象的类型声明。这些对象被认为是私有的。无法在包外部访问私有对象。 - -除了子程序定义外,它还可以选择性地包含一个初始化程序块,用于初始化规范中声明的变量,并且在会话中首次调用包时仅执行一次。 - -.**注意** -**** -如果规范更改,则包体将失效。在标识公共接口和私有接口时,必须小心,以避免将关键函数和变量暴露在包之外。 -**** - -==== 包语法 - -===== 包规范语法 - -```SQL -CREATE [ OR REPLACE ] PACKAGE [schema.] *package_name* [invoker_rights_clause] [IS | AS] - item_list[, item_list ...] -END [*package_name*]; - - -invoker_rights_clause: - AUTHID [CURRENT_USER | DEFINER] - -item_list: -[ - function_declaration | - procedure_declaration | - type_definition | - cursor_declaration | - item_declaration -] - - -function_declaration: - FUNCTION function_name [(parameter_declaration[, ...])] RETURN datatype; - -procedure_declaration: - PROCEDURE procedure_name [(parameter_declaration[, ...])] - -type_definition: - record_type_definition | - ref_cursor_type_definition - -cursor_declaration: - CURSOR name [(cur_param_decl[, ...])] RETURN rowtype; - -item_declaration: - cursor_declaration | - cursor_variable_declaration | - record_variable_declaration | - variable_declaration | - -record_type_definition: - TYPE record_type IS RECORD ( variable_declaration [, variable_declaration]... ) ; - -ref_cursor_type_definition: - TYPE type IS REF CURSOR [ RETURN type%ROWTYPE ]; - -cursor_variable_declaration: - curvar curtype; - -record_variable_declaration: - recvar { record_type | rowtype_attribute | record_type%TYPE }; - -variable_declaration: - varname datatype [ [ NOT NULL ] := expr ] - -parameter_declaration: - parameter_name [IN] datatype [[:= | DEFAULT] expr] -``` - -===== 包体语法 - -```SQL -CREATE [ OR REPLACE ] PACKAGE BODY [schema.] package_name [IS | AS] - [item_list[, item_list ...]] | - item_list_2 [, item_list_2 ...] - [initialize_section] -END [package_name]; - - -initialize_section: - BEGIN statement[, ...] - -item_list: -[ - function_declaration | - procedure_declaration | - type_definition | - cursor_declaration | - item_declaration -] - -item_list_2: -[ - function_declaration - function_definition - procedure_declaration - procedure_definition - cursor_definition -] - -function_definition: - FUNCTION function_name [(parameter_declaration[, ...])] RETURN datatype [IS | AS] - [declare_section] body; - -procedure_definition: - PROCEDURE procedure_name [(parameter_declaration[, ...])] [IS | AS] - [declare_section] body; - -cursor_definition: - CURSOR name [(cur_param_decl[, ...])] RETURN rowtype IS select_statement; - -body: - BEGIN statement[, ...] END [name]; - -statement: - [<