百科 / 错误代码 / Class 22 数据异常
2202E array_subscript_error
数组下标错误
ERROR 已实测 详解 实测通过
- 条件名
array_subscript_error- 宏名称
ERRCODE_ARRAY_SUBSCRIPT_ERRORERRCODE_ARRAY_ELEMENT_ERRORERRCODE_ARRAY_ELEMENT_ERROR- 启用版本
- 7.4
- 状态
- 活跃
版本覆盖
速览
2202E 是类别 22 Data Exception 中的 array_subscript_error 条件。目录同时保留 ERRCODE_ARRAY_ELEMENT_ERROR 这一兼容别名,并使用 ERRCODE_ARRAY_SUBSCRIPT_ERROR 作为带条件名的宏。两个宏编码的是同一个 SQLSTATE。
不要把所有看起来越界的表达式都当成错误。PostgreSQL 文档明确说明,读取当前边界之外的数组下标会返回 NULL;提供错误数量的下标同样返回 NULL。数组切片还有独立的历史规则:完全位于边界外的切片可以产生空的零维数组,部分重叠的切片则缩减为重叠部分。
当其他路径校验形状或下标并拒绝它时才会抛出 2202E。核心源码中的这类路径包括数组拼接或构造时维度不兼容、无效切片边界,以及部分带下标赋值检查。诊断时,操作本身和下标数值同样重要。
可执行的代表性案例是 incompatible_array_dimensions。它在 PostgreSQL 18.6 和 10.21 上均通过:不兼容的拼接抛出 2202E,随后同一自动提交连接保持 IDLE,并成功执行有效的后续拼接。下面的 SQL 摘录是共享注册表中的完整有序语句对;测试执行器仍是建表和清理的唯一来源。
含义与触发路径
18.6 目录中的定义是类别 22 下的 2202E E ERRCODE_ARRAY_SUBSCRIPT_ERROR array_subscript_error。前面的别名行是 2202E E ERRCODE_ARRAY_ELEMENT_ERROR;源码注释解释 SQL99 的 “array element error” 实际上就是数组下标错误。因此,仍使用别名的代码指向同一 SQLSTATE,而不是另一种条件。
数组具有秩、每个维度的长度以及下界。PostgreSQL 不要求数组从 1 开始,所以诊断时应读取实际下界,而不是作这个假设。文档中的 array_ndims、array_dims、array_lower、array_upper 和 cardinality 函数可以查看所需的元数据。需要诊断错误时,应在同一会话中实际调用这些检查函数;它们是检查工具,不代表已经触发了某个特定错误。
核心路径主要包括:
- 数组元素或切片赋值。
arrayfuncs.c会校验下标和切片边界。一维数组可以通过给新元素赋值来扩展,中间位置填入NULL;多维数组不支持这种扩展。给空数组赋切片时必须提供两个边界。因此,赋值访问当前读取边界之外的位置时,应按赋值操作分析,不能从SELECT a[n]的结果推断。 - 数组拼接。 当同秩数组的非拼接维度的长度或下界不同时,
array_cat抛出2202E。代表性案例覆盖的就是这条路径。 - 多维构造。 表达式执行器在用于构造多维数组的非空数组表达式维度不兼容时,也会抛出同一条件。
源码中还存在其他调用方,包括数据类型辅助路径。类别 22 是宽泛的数据异常类别;具体是哪个形状或下标契约失败,要由 2202E 条目、源码函数和报文共同确定。
报文与诊断
可执行摘录如下:
SELECT ARRAY[[1,2]] || ARRAY[[3]];
SELECT ARRAY[1,2] || ARRAY[3,4];
第一条语句的两个二维数组内层维度不同。PostgreSQL 18.6 报告:
SQLSTATE: 2202E
severity: ERROR
message_primary: cannot concatenate incompatible arrays
message_detail: Arrays with differing element dimensions are not compatible for concatenation.
source: array_userfuncs.c / array_cat / line 450
PostgreSQL 10.21 的同一案例给出相同的主报文和详细信息文本,历史源码行号是 356。第二条语句返回 {1,2,3,4}。这些报文和详细信息属于拼接路径,不是所有 2202E 调用方都必然使用的措辞。
其他源码确认的模板包括 array subscript out of range、array slice subscript must provide both boundaries(详细信息会解释给空数组赋值的要求),以及 upper bound cannot be less than lower bound。如果驱动程序提供这些字段,请保留 message_detail、message_hint、source_file、source_function 和 source_line;它们往往能区分切片校验与拼接校验。
报文模板
源码里的格式串,不是某一次运行的输出。%s 之类是占位符,实际报文会填入对象名与取值。适用范围一栏是核验时留下的原始英文记录,未经翻译。
cannot concatenate incompatible arrays
Arrays with differing element dimensions are not compatible for concatenation.
来源:src/backend/utils/adt/array_userfuncs.c(lines 443-450, array_cat dimension checks) @ REL_18_6
适用范围:The template belongs to array_cat; runtime source lines are 450 on 18.6 and 356 on 10.21.
array subscript out of range
来源:src/backend/utils/adt/arrayfuncs.c(lines 2644-2653, 2881-2888, 2976-2990, 3008-3017) @ REL_18_6
适用范围:This template is emitted by validated assignment/slice paths; a plain out-of-bounds read is documented to return NULL.
array slice subscript must provide both boundaries
When assigning to a slice of an empty array value, slice boundaries must be fully specified.
来源:src/backend/utils/adt/arrayfuncs.c(lines 2644-2653, 2881-2888, 2976-2990, 3008-3017) @ REL_18_6
适用范围:This is the empty-array slice assignment path and is not a general read diagnostic.
upper bound cannot be less than lower bound
来源:src/backend/utils/adt/arrayfuncs.c(lines 2644-2653, 2881-2888, 2976-2990, 3008-3017) @ REL_18_6
适用范围:This template is emitted by the slice boundary validation branch.
诊断
先按表达式分类:
- 普通元素读取如
a[999]可以合法返回NULL。在称为服务器错误前,检查数组本身、下标表达式以及存储的边界。 - 切片读取根据文档规则可能返回
NULL、空的零维数组或缩减后的重叠部分。没有错误响应时不要把这些值映射成2202E。 - 赋值、数组构造和拼接会执行校验代码。记录数组秩、维度、下界、提供的下标数量,以及语句是否在修改值。
遇到真实错误时,记录 SQLSTATE、严重级别、主报文、详细信息、提示、语句位置以及关系对象或函数上下文。使用同一个值或源表达式配合 array_ndims、array_dims、array_lower 和 array_upper 对照。拼接时比较每一个非拼接维度和下界;切片时检查两个边界及其顺序;构造时检查每个子数组的形状。
在 PL/pgSQL 中,处理器可以捕获 array_subscript_error 或 SQLSTATE '2202E',但处理器的事务行为取决于代码块。带 EXCEPTION 子句的代码块会让受保护主体在子事务中运行;主体出错后,主体内对持久数据库状态的修改会先回滚,再运行处理器。OTHERS 也有文档规定的排除项,应用要修复数组操作时应使用具体条件。
处理
修复违反形状契约的操作。拼接前统一维度和下界;提供完整且顺序正确的切片边界;只有在确实需要 NULL 填充语义时才使用一维扩展;或者使用形状匹配的子数组重新构造多维值。如果读取返回 NULL 是合法结果,应先按值处理,不要在判断应用是否需要区分“缺少元素”和“存储的 NULL 元素”前就用 COALESCE 掩盖它。
代表性错误在自动提交下运行。失败后连接状态为 IDLE,有效拼接成功。在显式事务中,ERROR 通常会让事务进入中止状态,直到 ROLLBACK 或回滚到保存点;连接本身不一定需要关闭。带异常子句的 PL/pgSQL 代码块可以让受保护主体在子事务中封装失败,主体内的修改会在处理器运行前回滚。应读取客户端的实际事务状态,不要仅凭 2202E 推断连接结局。
可复现案例
在一次性实例上执行过的场景。其中 1 个附有可执行 SQL,正文相应小节里给出。
incompatible_array_dimensions PG 10 / 18 有 SQL
前置条件
- A dedicated autocommit connection
触发
Concatenate two arrays whose element dimensions are incompatible.
断言
- SQLSTATE is 2202E
- The diagnostic explains the incompatible dimensions
- A valid array operation succeeds afterward
处置
Validate rank, bounds, and element dimensions before concatenation or assignment.
清理
Drop the case schema with an owner connection.
版本
目录记录 2202E 存在于锁定的 7.4–8.4.22 pre-9.0 正式源码、9.0.23 至 18.6 的全部正式快照及 19 Beta 3 预览快照。同 tag 的 REL8_1_4 errcodes.sgml 表已经列出 2202E 和条件名 array_subscript_error,因此至少可以确认 8.1.4 已有该条件名。7.0–7.3 仍有候选源码缺口,因此 7.4 观察结果只是存在边界,不是精确引入版本。18.6 固定源码 commit 为 724edf9bde9d356724ad384a2e196edc3c9f80f7;其 errcodes.txt 同时保留别名宏和带条件名的宏。
不兼容维度案例在 PostgreSQL 18.6 和 10.21 上均通过,主报文和详细信息文本相同而源码行号不同。这个跨版本结果不保证所有旧小版本或其他 2202E 调用路径的措辞都不变。
来源
- 上游源码 doc/src/sgml/errcodes.sgml 第 305–307 行
- 核验材料 verify/cases/2202E/cases.json
- 核验材料 doc/src/sgml/array.sgml
- 核验材料 doc/src/sgml/func.sgml
- 核验材料 doc/src/sgml/xact.sgml
- 核验材料 sources/manifest.lock.json
- 核验材料 verify/cases/2202E/snippets.json
- 核验材料 src/backend/utils/adt/array_userfuncs.c 第 443–450 行
- 核验材料 src/backend/utils/adt/arrayfuncs.c 第 2644–2653 行
- 核验材料 src/backend/utils/errcodes.txt
- 核验材料 src/backend/executor/execExprInterp.c 第 3549–3565 行
证据
断言
每条断言都写明了是怎么核实的,以及它不覆盖什么。这一层是核验时留下的原始英文记录,照原样呈现,未经翻译。
-
2202E is the array_subscript_error condition in Class 22, Data Exception.
-
ERRCODE_ARRAY_ELEMENT_ERROR is retained as an alias for the same 2202E SQLSTATE; ERRCODE_ARRAY_SUBSCRIPT_ERROR carries the array_subscript_error condition name.
-
An array element read outside the current bounds, or a read with the wrong number of subscripts, returns NULL rather than raising an error.
-
A slice completely outside the current bounds can yield an empty zero-dimensional array, while a partially overlapping slice is reduced to the overlap.
-
One-dimensional subscript assignment can enlarge an array and fill intervening positions with NULL; multidimensional enlargement is not supported, and empty-array slice assignment requires both boundaries.
-
array_cat raises 2202E when equal-rank arrays have differing non-concatenated dimensions or lower bounds.
-
The expression evaluator raises 2202E when non-empty array expressions used to form a multidimensional array have incompatible dimensions.
-
array_ndims, array_dims, array_lower, array_upper, and cardinality expose the rank, dimensions, bounds, and item count needed to inspect an array operation.
-
The incompatible_array_dimensions case returned 2202E with the incompatible concatenation diagnostic and then successfully executed a valid concatenation on the same connection.
-
The representative 2202E ERROR left the autocommit connection IDLE and the follow-up valid statement succeeded; explicit transaction and PL/pgSQL handler outcomes must be handled at their own boundaries.
-
The locked catalogue records 2202E in the 7.4–8.4.22 pre-9.0 formal sources, every listed formal snapshot from 9.0.23 through 18.6, and 19beta3. The same-tag REL8_1_4 errcodes.sgml row already lists 2202E as array_subscript_error, confirming that condition-name observation by 8.1.4. Candidate source gaps remain for 7.0–7.3, so 7.4 is a presence boundary rather than an exact introduction version.
运行记录
| 目标 | 服务器版本 | 结果 | 覆盖案例 |
|---|---|---|---|
| latest | 18.6 (Homebrew) | passed | incompatible_array_dimensions |
| pg10 | 10.21 (Debian 10.21-1.pgdg90+1) | passed | incompatible_array_dimensions |
同类错误代码
Class 22 数据异常 下的其他成员。
22000data_exception22001string_data_right_truncation22002null_value_no_indicator_parameter22003numeric_value_out_of_range22004null_value_not_allowed22005error_in_assignment22007invalid_datetime_format22008datetime_field_overflow22009invalid_time_zone_displacement_value2200Bescape_character_conflict2200Cinvalid_use_of_escape_character2200Dinvalid_escape_octet2200Fzero_length_character_string2200Gmost_specific_type_mismatch2200Hsequence_generator_limit_exceeded2200Lnot_an_xml_document2200Minvalid_xml_document2200Ninvalid_xml_content2200Sinvalid_xml_comment2200Tinvalid_xml_processing_instruction22010invalid_indicator_parameter_value22011substring_error22012division_by_zero22013invalid_preceding_or_following_size22014invalid_argument_for_ntile_function22015interval_field_overflow22016invalid_argument_for_nth_value_function22018invalid_character_value_for_cast22019invalid_escape_character2201Binvalid_regular_expression2201Einvalid_argument_for_logarithm2201Finvalid_argument_for_power_function2201Ginvalid_argument_for_width_bucket_function2201Winvalid_row_count_in_limit_clause2201Xinvalid_row_count_in_result_offset_clause22021character_not_in_repertoire22022indicator_overflow22023invalid_parameter_value22024unterminated_c_string22025invalid_escape_sequence22026string_data_length_mismatch22027trim_error2202Ginvalid_tablesample_repeat2202Hinvalid_tablesample_argument22030duplicate_json_object_key_value22031invalid_argument_for_sql_json_datetime_function22032invalid_json_text22033invalid_sql_json_subscript22034more_than_one_sql_json_item22035no_sql_json_item22036non_numeric_sql_json_item22037non_unique_keys_in_a_json_object22038singleton_sql_json_item_required22039sql_json_array_not_found2203Asql_json_member_not_found2203Bsql_json_number_not_found2203Csql_json_object_not_found2203Dtoo_many_json_array_elements2203Etoo_many_json_object_members2203Fsql_json_scalar_required2203Gsql_json_item_cannot_be_cast_to_target_type22P01floating_point_exception22P02invalid_text_representation22P03invalid_binary_representation22P04bad_copy_file_format22P05untranslatable_character22P06nonstandard_use_of_escape_character