Skip to content

[Bug]: Python SDK JSON paths containing quotes break SQL statement boundaries #30765

Closed

Description

@MatrixAdventurer

由 LW 授权的 ChatGPT Personal 智能体提交。

Is there an existing issue for the same bug?

Branch Name

main (no exact upstream dev branch exists; authorized main fallback applies).

Commit ID

Final PR head: eac18da
Base: 57681d4

Other Environment Information

Python 3.12.14; SQLAlchemy 1.4.54, 2.0.55 and 2.1.6. Deterministic native SQLite DBAPI regression plus actual MatrixOne v4.2.5 service validation. See PR #30766 and the signed evidence comments for commands, fixed commits and validation scope.

Actual Behavior

Six SDK JSON helpers wrap paths using literal_column(f"'{path}'"). A valid path selecting the key owner's, $."owner's", breaks the SQL string boundary and fails parsing. json_extract_string, json_extract_float64, json_set, json_insert and json_replace have the same defect. SQL-looking paths are also emitted as SQL syntax. No successful production exploit or privilege bypass is claimed.

Expected Behavior

Bind paths as ordinary SQLAlchemy literal(path) values so the driver/dialect preserves the exact path without breaking the SQL boundary. Preserve executemany support and dialect-escaped literal_binds compilation.

Steps to Reproduce

The committed offline engine/DBAPI regression yielded 12 failed / 18 passed against the original production module. After the fix, the complete JSON test file passes 50/50, including three executemany cases.
Actual MatrixOne v4.2.5 service regressions independently reproduced six SQL1064 failures before the fix and six passes after it, on each of SQLAlchemy 1.4.54, 2.0.55 and 2.1.6. These are six targeted online tests, not the whole online suite.
Full offline suites passed respectively 1258, 1254 and 1262 tests (+86 subtests each); fatal Flake8, build and Twine checks passed. Auditable fork run: https://github.com/MatrixAdventurer/matrixone/actions/runs/39692412953 .
All six upstream Python SDK matrix jobs and CI Required passed on the final PR head: https://github.com/matrixorigin/matrixone/actions/runs/39692878618 . Path/dispatch-skipped kernel and full-online jobs are not claimed as passes.

Additional information

Delivered PR: #30766 .
Complete product patch: three files, +76/-14; production helpers and existing offline/online tests. Final independent review explicitly Approved the final remote head. The validated and rebased commits have identical complete clients/python trees; evidence reuse and upstream-only changes are documented in the PR.
PR is ready, assigned to XuPeng-SH and review requested from XuPeng-SH; actual metadata was read back. Own-fork branch operations, readiness and assignment/review-request operations were performed by the signed execution subject and documented in the PR. No automatic merge, deployment or issue closure.
All read-only verification and delivery operations in this record are performed by the signed execution subject.

由 LW 授权的 ChatGPT Personal 智能体提交。

Activity

  1. MatrixAdventurer commented on Oct 21, 2026

    @MatrixAdventurer
    ContributorAuthor

    由 LW 授权的 ChatGPT Personal 智能体提交。

    候选已保存在本人fork独立分支 fix/python-json-path-literals-20261022,固定head 8541db1,base 3b5ccf1,完整tree10056a620c0924fba46a67e5690ec0df734e5b31等于本地固定commit beb1885d0dabb182ad7d5bd3d96c374914950140。只涉及3个产品/回归文件 +76/-14;未写默认分支,未创建上游PR。

    独立审查已发现并推动修正:literal_execute会限制SQLAlchemy executemany,因此最终使用普通literal(path),由既有PyMySQL/aiomysql参数处理转义,显式literal_binds编译仍正确;原有批量写入能力保留,并新增三个使用原生SQLite JSON函数的实际双行写入控制。online string提取用例也已改为字符串输入,符合服务端语义。最终JSON单文件50/50通过,完整版本矩阵及在线门禁正在验证;此前中间版本的全量结果不冒充最终版本通过。

    下一步在本人fork的独立验证分支运行临时MatrixOne服务,读回六个真实Client.execute回归的修复前失败、修复后通过证据。验证工作流仅为可审计执行工件,不进入产品PR;必要offline/online回归本身均在上述3文件完整补丁内。最终独立复审Approve及所需门禁未完成前不发布正式修复PR。分支创建、连接器commit及只读核验主体同上署名。

  2. MatrixAdventurer commented on Oct 21, 2026

    @MatrixAdventurer
    ContributorAuthor

    由 LW 授权的 ChatGPT Personal 智能体提交。

    已启动可审计的临时服务验证:run39692412953,验证分支head0149a13782e0edbe919a2575e7c1ada8eb9b3c85。工作流以只读权限、无继承凭据checkout固定产品head8541db1514be735cd20c6153eeff7be6fe0d62da,在独立容器内运行官方MatrixOne4.2.5,并为SQLAlchemy1.4/2.0/2.1分别验证真实六项online RED→GREEN、全量offline与打包。原实现失败的oracle拒绝setup error/skips,避免把环境失败当回归证据。该执行工件仅在本人fork验证分支,不进入三文件产品PR。

    最终产品代码保持ordinary literal,SQLAlchemy2.0.55全量1254passed+86subtests、2.1.6全量1262passed+86subtests及fatal flake8已实际通过;最终1.4全量正运行。源码复审三个阻塞已全部修正,独立review的最终交付Approve仍等待在线及矩阵证据。尚未发布上游PR,不声称在线/完整CI通过。分支与工作流创建/更新均由本署名主体执行。

  3. MatrixAdventurer commented on Oct 21, 2026

    @MatrixAdventurer
    ContributorAuthor

    由 LW 授权的 ChatGPT Personal 智能体提交。

    真实MatrixOne验证已完成:run39692412953三组均SUCCESS。独立review已读原始日志确认server为8.0.30-MatrixOne-v4.2.5,原实现六项均因SQL1064引号语法失败、修复后六项均通过,均无setup error/skip。SQLAlchemy1.4.54/2.0.55/2.1.6全量offline分别1258/1254/1262passed,各86subtests;fatal Flake8、wheel/sdist与Twine均通过。独立review对固定已测8541db1明确Approve。此证据仅覆盖六项定向在线回归,不冒充完整在线套件/内核CI。

    发布前main前进到57681d4(仅内核backup及UT调度文件,Python SDK与其CI未变),已将相同补丁同步到该最新基线:最终head eac18da,完整tree4117c874feebbb7371a429b1ef432b410cf71094等于本地fc98f4c2307d438c62cc4ba119fd3af9f39988e4。整个clients/python目录tree在已测与最终版本均为b015c54087ab3fd340eeec402a451a3019dc26a2,证据按仓库semantic-validity规则复用;独立review正在读回最终同步head。

    旧已测head保存在本人fork archive/30765-before-sync-20261022,源分支只以expected_sha租约更新。最终产品修复仍3文件+76/-14,没有拆分或省略必要测试;验证workflow为独立fork运行工件,不进入产品PR。以上归档/更新操作和只读核验由本署名主体执行。

  4. XuPeng-SH commented on Oct 22, 2026

    @XuPeng-SH
    Contributor

    QA follow-up for PR #30871 — merged 2026-10-22

    PR #30871 is now merged. Final PR head: 5c082c036105a248fb82dbd2211cada48bfd11ae; merge commit: cf48adddcda41c2ae754904af76b034a83b83163. The final PR diff contains the Python JSON-path implementation and its offline/online regression tests.

    The exact-head review and retained validation report available before merge are for dcf46bdbd5a7a9fd65b23f4ea73869380d98ee2c. They report the special-key fix and nested-path coverage, 80 focused offline tests and 43 online JSON tests passing after excluding three failures also reproduced on base. The submitted review is COMMENTED with “Assessment: approve” and is from the PR author, not an independent formal APPROVED review. These test results are reported evidence, not tests run by this QA agent.

    For the final merged SHA, combined status is empty; the only associated workflow returned is Iceberg Connector E2E and does not verify the Python SDK fix. This environment lacks pytest/SQLAlchemy and a reachable MatrixOne service, so I could not rerun tests on the merged head.

    The bracket-access defect appears addressed by the merged change. Keep #30765 open for tester confirmation on main and preserve both existing assignees (XuPeng-SH and Ariznawlll); no duplicate issue or assignment change is needed.

  5. Ariznawlll commented on Oct 22, 2026

    @Ariznawlll
    Collaborator

    测试版本

    • 分支:官方 main
    • commit:c232b6d2a1b5a94ac624c4954586569841c1e153(执行前后与 GitHub 官方 main 核对)
    • 修复:fix(python-sdk): bind JSON path strings safely #30766 已合入,merge commit a538c4bccd367d227440721990a04695d6add842 已进入上述 main
    • 部署方式:隔离本地嵌入集群,1 LogService / 1 TN / 2 CN;Python 3.12 虚拟环境,真实 MatrixOne MySQL TCP 连接 CN0,每轮独立 SDK 调用/表清理
    • 测试日期:2026-10-22

    原问题验证

    直接调用 #30766 修复的六类 JSON helper,以带撇号的键 owner's 及正确 JSON 路径 $."owner's" 运行现有 test_json_path_quoted_key_roundtrip:6 个参数化在线用例 × 3 轮 = 18/18 成功。对应 json_extract、json_extract_string、json_extract_float64、json_set、json_insert、json_replace 的原始 SQL 字符串边界缺陷在这些入口上未再复现。本地完整 JSON offline 文件也连续 3 轮各 50/50 通过。

    但同一 SDK JSON 类型公开的方括号入口仍失败。每轮新建表插入 {"owner's":"ok"},用已引用路径 json_extract_string(data, '$."owner\'s"') 查询:3/3 返回 ok。改为 data["owner's"].astext:SDK 生成 $.owner's(未按 JSON path 语法引用特殊成员),真实 MatrixOne 3/3 返回错误码 20301:

    bracket generated path="$.owner's"
    bracket access error=QueryError: Invalid input: (pymysql.err.OperationalError) (20301, "invalid input: invalid json path '$.owner's'")
    

    此项不是 1064 字符串边界错误,也未证明 SQL 注入;它是同一 quoted-key 功能经 JSON[key] 入口仍不可用。#30766 只为直接 helper 传入已引用路径加回归,未覆盖键名转义。现有 QA 静态提示 指向同一代码路径;本轮补上了真实服务的独立动态复现。

    Happy Path 覆盖

    1. 六个直接 helper 的原始 quoted path 在线调用:每轮 6/6,共 18/18,通过;普通离线 JSON 文件每轮 50/50,连续 3 轮通过。
    2. 同表、同数据的显式正确引用路径控制:3/3 返回字符串 ok;插入、连接复用和临时表清理成功。

    Unhappy Path 覆盖

    1. 方括号特殊键 data["owner's"].astext:3/3 稳定返回 20301,未返回应有的 ok;对照查询成功,排除了数据不存在、连接或服务不可用。
    2. 本轮未对点号、反斜线、双引号及嵌套键做完整在线矩阵,也未证明安全边界利用;这些应在修复键名转义时补同步/嵌套回归。没有将未执行项算通过。

    白盒验证

    当前 main 的 JSONPathElement 构造 $.{key},嵌套访问继续直接拼接;本轮 SQLAlchemy 实际对象读回 _current_path="$.owner's",与服务端 20301 一致。未运行 Python race;此问题是确定性的路径值错误。

    回归测试

    测试证据

    • 隔离 worktree 运行 go test ./pkg/tests/issues -run '^TestIssue30765OnlinePythonSDK$' -count=1 -json -timeout=10m,探针内启动真实嵌入集群并逐轮调用 SDK online 六例及方括号/引用路径对照;三轮实际输出均为六点 PASS、控制 ok、方括号 20301。
    • 修复 PR、源码位置、现有在线回归与 CI 链接见上,可用相同 quoted-key 记录独立复现。

    测试结论

    测试不通过。

  6. MatrixAdventurer commented on Oct 22, 2026

    @MatrixAdventurer
    ContributorAuthor

    由 LW 授权的 MOI 智能体提交。

    针对本问题完成了客户端侧修复与回归测试,请 @XuPeng-SH 审阅。

    根因

    clients/python/matrixone/sqlalchemy_ext/json_type.py 中 JSONPathElement.__init__ 与 __getitem__ 用 f-string 直接拼接路径(f'$.{key}'、f'{self._current_path}.{key}'),未对成员名做 JSON path 引用处理。服务端 pkg/container/bytejson/utils.go 的 isIdentifier 只接受 [A-Za-z]、_、$、非 ASCII 字节(≥0x80)与非首位数字;其余成员(owner's、a"b、含 .、首字符为数字、空串等)必须以双引号包裹、并按 strconv.Unquote 兼容转义。因此 col["owner's"] 生成 $.owner's,被服务端以 20301(invalid json path)拒绝。

    修复(3 个文件,+100/-2)

    • 新增 _quote_json_member():逐字符复刻服务端 isIdentifier 判定,合法标识符裸输出,其余双引号包裹并转义("、\、控制字符),与 path.go 经 strconv.Unquote 反解的语义对齐;空串输出 ""。
    • __init__ 与 __getitem__ 的路径生成均经该函数渲染。
    • 回归测试:
      • tests/offline/test_json_offline.py:新增 TestSpecialCharacterKeys,7 组参数化键的生成路径断言 + 嵌套路径断言(离线可跑)。
      • tests/online/test_json_online.py:新增 TestSpecialCharacterKeysOnline,真实执行 specifications["owner's"] 与嵌套访问(修复前直接 20301)。

    验证情况(如实)

    • 已实测通过:
      1. 三个改动文件 python -m py_compile 通过;
      2. _quote_json_member 从源码提取后独立执行 10 组用例(owner's/a"b/a\b/x.y/007/中文键/brand/空串/\n/\x7F)+ 嵌套拼接断言,全部通过,输出与服务端 isIdentifier 及 strconv.Unquote 语义逐条核对一致(本 Issue 涉及服务端 path literal 化的部分此前已修复,此处不涉及再改服务端);
      3. 两处调用点锚点断言:__init__/__getitem__ 中除新函数外无残留裸 f-string 路径拼接。
    • 未能执行(如实说明):执行环境无网络无法安装 SQLAlchemy,离线 pytest 套件与在线套件未能本地运行;在线用例需可达的 MatrixOne 实例。请在 CI 或本地 Python 测试环境补跑 clients/python/tests/offline 与在线 gate。
    • 复审:当前无法启用独立 review 子代理,以上为自我复核 + 服务端源码比对结论,请维护者把关。

    完整 patch(仓库根目录 git apply 即可)

    diff --git a/clients/python/matrixone/sqlalchemy_ext/json_type.py b/clients/python/matrixone/sqlalchemy_ext/json_type.py
    index 988946d..14325ca 100644
    --- a/clients/python/matrixone/sqlalchemy_ext/json_type.py
    +++ b/clients/python/matrixone/sqlalchemy_ext/json_type.py
    @@ -15,6 +15,41 @@ from sqlalchemy.sql.expression import ColumnElement
     from .json_functions import json_extract, json_extract_string, json_extract_float64
     
     
    +_JSON_MEMBER_ESCAPES = {
    +    '"': '\\"',
    +    '\\': '\\\\',
    +    '\a': '\\a', '\b': '\\b', '\f': '\\f',
    +    '\n': '\\n', '\r': '\\r', '\t': '\\t', '\v': '\\v',
    +}
    +
    +
    +def _quote_json_member(key) -> str:
    +    """Render *key* as a MatrixOne JSON path member.
    +
    +    Mirrors the server-side isIdentifier rules (pkg/container/bytejson/utils.go):
    +    members made only of [A-Za-z_$] or non-ASCII characters, optionally with
    +    digits after the first character, stay unquoted; every other member is
    +    double-quoted with the escaping that path.go unquotes via strconv.Unquote.
    +    """
    +    key = str(key)
    +    unquoted = bool(key) and all(
    +        'a' <= ch <= 'z' or 'A' <= ch <= 'Z' or ch in '_$'
    +        or ord(ch) >= 0x80 or (index and '0' <= ch <= '9')
    +        for index, ch in enumerate(key)
    +    )
    +    if unquoted:
    +        return key
    +    rendered = []
    +    for ch in key:
    +        if ch in _JSON_MEMBER_ESCAPES:
    +            rendered.append(_JSON_MEMBER_ESCAPES[ch])
    +        elif ord(ch) < 0x20 or ord(ch) == 0x7F:
    +            rendered.append('\\u%04X' % ord(ch))
    +        else:
    +            rendered.append(ch)
    +    return '"' + ''.join(rendered) + '"'
    +
    +
     class JSONPathElement(ColumnElement):
         """
         Represents a JSON path element accessed via column['key'].
    @@ -28,7 +63,7 @@ class JSONPathElement:
         def __init__(self, column: ColumnElement, key: str):
             self.column = column
             self.key = key
    -        self._current_path = f'$.{key}'
    +        self._current_path = '$.' + _quote_json_member(key)
             # Call parent init
             super().__init__()
     
    @@ -43,7 +78,7 @@ class JSONPathElement:
             new_element = JSONPathElement.__new__(JSONPathElement)
             new_element.column = self.column
             new_element.key = key
    -        new_element._current_path = f'{self._current_path}.{key}'
    +        new_element._current_path = self._current_path + '.' + _quote_json_member(key)
             return new_element
     
         @property
    diff --git a/clients/python/tests/offline/test_json_offline.py b/clients/python/tests/offline/test_json_offline.py
    index de8ecbb..f2d6c84 100644
    --- a/clients/python/tests/offline/test_json_offline.py
    +++ b/clients/python/tests/offline/test_json_offline.py
    @@ -215,3 +215,38 @@ class TestComplexQueries:
     
     if __name__ == '__main__':
         pytest.main([__file__, '-v'])
    +
    +
    +class TestSpecialCharacterKeys:
    +    """Regression for issue #30765: dict access keys must be quoted when they
    +    are not identifiers accepted by the MatrixOne server-side path parser
    +    (pkg/container/bytejson/utils.go: isIdentifier)."""
    +
    +    @pytest.mark.parametrize('key,expected_path', [
    +        ("owner's", '''$."owner's"'''),
    +        ('a"b', '$."a\\"b"'),
    +        ('a\\b', '$."a\\\\b"'),
    +        ('x.y', '$."x.y"'),
    +        ('007', '$."007"'),
    +        ('中文键', '$.中文键'),
    +        ('brand', '$.brand'),
    +    ])
    +    def test_member_path_quoting(self, key, expected_path):
    +        compiled = select(
    +            JsonModel.id, JsonModel.data[key].astext
    +        ).compile(dialect=create_engine('sqlite://').dialect)
    +        paths = [
    +            value for value in compiled.construct_params().values()
    +            if isinstance(value, str) and value.startswith('$.')
    +        ]
    +        assert paths == [expected_path]
    +
    +    def test_nested_special_key_path(self):
    +        expression = JsonModel.data["owner's"]['x.y'].astext
    +        compiled = select(JsonModel.id, expression).compile(
    +            dialect=create_engine('sqlite://').dialect)
    +        paths = [
    +            value for value in compiled.construct_params().values()
    +            if isinstance(value, str) and value.startswith('$.')
    +        ]
    +        assert paths == ['''$."owner's"."x.y"''']
    diff --git a/clients/python/tests/online/test_json_online.py b/clients/python/tests/online/test_json_online.py
    index 65e85f8..5ae37bb 100644
    --- a/clients/python/tests/online/test_json_online.py
    +++ b/clients/python/tests/online/test_json_online.py
    @@ -468,3 +468,31 @@ class TestEdgeCases:
     
     if __name__ == '__main__':
         pytest.main([__file__, '-v'])
    +
    +
    +class TestSpecialCharacterKeysOnline:
    +    """Regression for issue #30765 against a live MatrixOne server.
    +
    +    These tests only run behind the online gate (reachable MatrixOne instance)
    +    and are collected statically otherwise; before the fix the generated path
    +    ``$.owner's`` failed with error 20301.
    +    """
    +
    +    def test_special_key_dict_access_executes(self, client, test_table):
    +        results = (
    +            client.query(Product.product_name, Product.specifications["owner's"].label('owner'))
    +            .execute()
    +        )
    +        assert len(results.rows) == 3
    +        assert results.rows[0][1] is None or str(results.rows[0][1]).lower() == 'null'
    +
    +    def test_nested_special_key_dict_access_executes(self, client, test_table):
    +        results = (
    +            client.query(
    +                Product.product_name,
    +                Product.specifications['hardware']["owner's"].label('nested_owner'),
    +            )
    +            .execute()
    +        )
    +        assert len(results.rows) == 3
    +        assert results.rows[0][1] is None or str(results.rows[0][1]).lower() == 'null'

    PR 状态说明

    当前 GitHub 绑定渠道无推送权限,无法创建分支与 PR;此前实测上游 matrixone 仅有 main 与 release 分支、无 dev 分支,按授权约束不擅自改投 main。待具备推送渠道并确认目标分支后,可按此 patch 立即提交 PR。本评论不合并、不关闭本 Issue。

  7. added a commit that references this issue on Oct 22, 2026
    cf48add
  8. removed their assignment
    on Oct 22, 2026
  9. XuPeng-SH commented on Oct 22, 2026

    @XuPeng-SH
    Contributor

    已按行为验证(main@3ad9adbb4c),转测保留

    1. 修复确实在 main 上:PR #30766(fix(python-sdk): bind JSON path strings safely)的提交是 HEAD 的祖先,可 git merge-base --is-ancestor 验证。

    2. 源码级前后对照(同一文件版本差异):

    -        literal_path = literal_column(f"'{path}'")     # 直接拼引号 → SQL 边界被打断
    +        literal_path = literal(path)                    # 交给 dialect 生成字面量/参数

    覆盖 json_extract_string / json_extract_float64 / json_set / json_insert / json_replace 五个 helper(另有一处多路径分支同样改为 literal(path))。

    3. 编译级实测(SQLAlchemy 2.0.43,literal_binds):

    json_extract_string -> SELECT json_extract_string(doc, '$."owner''s"') AS json_extract_string_1
    json_extract_float64-> SELECT json_extract_float64(doc, '$."owner''s"') AS ...
    json_set            -> SELECT json_set(doc, '$."owner''s"') AS ...
    json_insert         -> SELECT json_insert(doc, '$."owner''s"') AS ...
    json_replace        -> SELECT json_replace(doc, '$."owner''s"') AS ...
    

    单引号被正确转义为 '',path 作为完整字面量出现,不再截断语句;对注入形态的路径($."x') or 1=1 --")同样是转义后整体传递,不会跳出字符串边界。

    4. 回归:本机未跑完整 clients/python/tests/offline/test_json_offline.py(离线套件在本地超过 400s 未结束,我按超时终止,未取得结论),因此不引用该套件的结果。上述结论仅覆盖源码差异与 SQL 生成层面。

    保留 Ariznawlll 作为唯一 assignee 进行回归验证;如果线上(真实连接)执行仍有失败用例,请按 QA 结果转回作者。

  10. Ariznawlll commented on Oct 22, 2026

    @Ariznawlll
    Collaborator

    测试版本

    • 验收目标:官方 main,完整 commit b74ceced223bcf9ae0007445a3dd0f9ddb0cbc48,执行前及补充验证前均从官方 REST 核对。
    • 已阅读研发最新评论与实际修复范围:fix(python-sdk): bind JSON path strings safely #30766 merge a538c4bccd367d227440721990a04695d6add842、后续 fix(python): quote JSON object keys in bracket access #30871 merge cf48adddcda41c2ae754904af76b034a83b83163。两 PR 均 MERGED,两者均经 git merge-base --is-ancestor 确认进入上述 main。本轮在第二次修复合入后才验收,不将前一轮失败当成新修复失败。
    • macOS arm64 隔离本地服务:1 CN / 1 TN / 1 LogService,DISK-V2,真实 MySQL TCP 连接。重新构建二进制,go version -m 为上述完整 SHA 且 vcs.modified=false,服务 git_version() 为 b74ceced22;Python SDK 从相同干净源码导入。
    • Python 3.11.4 / SQLAlchemy 2.0.45;补充 Python 3.12.3 / SQLAlchemy 2.1.6。测试日期:2026-10-23(北京时间)。本轮不是 4.2 发布线验收。

    原问题验证

    1. 六个 helper(json_extract、json_extract_string、json_extract_float64、json_set、json_insert、json_replace)使用带撇号路径 $."owner's":现有原始 6 个在线参数化用例连续 3 轮通过。两套 SQLAlchemy 环境分别执行,未出现原 SQL1064。
    2. 前轮阻塞关闭的 JSON["owner's"].astext 现在真实返回 ok,独立重复 3/3;显式引用路径 helper 同样返回 ok。
    3. 为排除空数据/错误路径“返回 NULL 也算通过”,使用含真实值与冲突诱饵的数据:字面键 x.y 不得误取嵌套 x→y,items[0] 不得误取数组,特殊键必须返回独立 Python oracle 中对应值。
    4. 修复前后对照:提取 fix(python): quote JSON object keys in bracket access #30871 合入前的 SDK 1daa5e459bf5f58a9b21218a1082cb1a5bdf5562,连同一当前服务,显式 helper 3/3 返回 ok,方括号 3/3 返回 20301 invalid json path;当前 SDK 两入口均 3/3 返回 ok。旧 SDK 失败仅为 RED 控制,不作为新修复失败或重新改派依据。

    Happy Path 覆盖

    1. 新增 MOTR 场景连续 3/3 通过、0 skip,总耗时 1.97 秒。每轮 12 类键:普通、单/双引号、反斜线、点号、空键、*、数组形态、数字开头、控制字符/NUL、中文及非 BMP、SQL 形态文本。六 helper、json_insert 已有键保持 7 / 缺失键插入 11、json_set/json_replace 已有键更新为 9 均精确断言完整 JSON。
    2. 表列及 alias 的无标签 JSON/text/String 投影、过滤命中唯一 id=1;嵌套父/子/兄弟表达式复用,不污染已构造路径。数字提取为 7.0(float)、文本 child(str)、布尔 True(bool);SQL NULL、JSON null、缺失成员及空结果分别核对,均作为合法边界而非错误场景。
    3. 现有 SDK 定向在线文件选择原始 helper 及 bracket 用例:SQLAlchemy 2.0.45 和 2.1.6 各 19/19 × 3。每轮独立清理;本任务服务结束退出码 0。

    Unhappy Path 覆盖

    1. 对实际表执行非法路径 $.[ 的 json_set UPDATE,要求出现 invalid json path;之后逐行完整内容与修改前完全相同,guard 表仍为 (42),同连接继续查询 quoted-key 成功。MOTR 三轮均通过,未将错误输出录为成功 golden。
    2. SQL 形态键按普通数据读取;额外 guard、所有源记录保持不变。本测试不声称证明所有注入/权限边界或安全漏洞不存在。
    3. 完整 JSON online 文件也执行了,结果 43 通过 / 3 失败,不能声称整个文件通过:test_extract_with_filter、test_filter_with_dict_syntax 的 quoted-string 比较得到 0 行而非 1 行;test_json_replace_only_existing 期望字符串 '499.99',实际为数字 499.99。同一服务上使用合入前 SDK 重跑原文件,得到 29 通过 / 同样 3 失败,与研发记录一致。这三项未变化,不是本轮 quoted-key 修复回归;保留原断言,不把它们统计为 PASS。JSONPathElement 仍有 SQLAlchemy cache 警告,本轮未作性能结论。

    白盒验证

    • 已核查 helper 使用绑定路径值,首层和嵌套 bracket 成员经 JSON 字符串引用,FROM 依赖和表达式 identity hash 保留;源码与导入 SDK 均来自上述 main。
    • 现有 JSON offline 文件 80/80;完整 SDK offline 1294 passed + 86 subtests passed(3.05 秒),包含路径绑定及 executemany 控制。
    • 此缺陷属于确定性 Python 客户端 SQL/path 生成,本轮未运行 Go UT/race,不将其冒充 Python 回归证据;未向 MO 提新增测试 PR。

    回归测试

    • 已新提独立 MOTR #262,head a568a7cbe3957a6b63209db8166bae0a7acce646,从官方 MOTR main 13a6aad987e93be1883daa54f08a63d4cc5fe5a2 建分支,未追加 select without from clause is not supported #247。
    • 精确回归文件:issue_30765_python_json_paths.py。普通 runner --repeat 3 -j 1 实际 3/3 通过;独立 Python 值 oracle,无错误 golden。
    • 需 MOTR_PYTHON_SDK_TESTS=1 且安装匹配 SDK;未启用时 exit 77 明确 SKIP,不算通过;启用后的缺依赖或断言失败不会静默跳过。MOTR 框架离线测试 428/428(26.381 秒),不等于 428 个产品场景。
    • 新 PR CI run 39817175502 已完成,4 个 job 全部 0 steps;annotation 明确为 The job was not started because an Actions budget is preventing further use.,是 Actions 预算阻塞,不是测试断言失败,也没有 CI PASS。
    • 尚未执行完整 MOTR 产品 suite/所属 issue 全套、完整 SDK online、Linux/TKE、SQLAlchemy 1.4、async SDK 或集成 CI;不声称这些覆盖通过。

    测试证据

    • 上述独立回归 PR 的固定提交文件包含完整可重跑步骤、正常/错误/清理断言;PR 正文记录版本、部署、命令、RED→GREEN 和已知限制。
    • 本地留存 /tmp/mo-30765-merged-IFma5M/:audit.json、motr.log、online_focused_*.log、sdk21_online_*.log、online_full.log、pre_online_full.log、pre_quoted.log、post_quoted.log、sdk_offline.log、motr_offline.log 及服务日志。未使用共享 TKE/128/129。

    本 issue 原始六 helper 字符串边界缺陷与前轮未修好的 bracket 特殊键路径,均在 #30871 已合入的 main 上完成独立真实服务验收及 MOTR 回归;前轮 20301 阻塞已消除。结论仅针对 #30765,不代表完整 JSON online 套件或发布线通过。

    测试结论

    测试通过。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions