{"record":{"id":"168f6b523f9fef51","repo":"iflytek/astron-agent","slug":"column-names-must-be-used-in-update-set-clause-set-expr","errorCode":null,"errorMessage":"Column names must be used in UPDATE SET clause: {set_expr}","messagePattern":"Column names must be used in UPDATE SET clause: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"core/memory/database/api/v1/exec_dml.py","lineNumber":643,"sourceCode":"    return keys_to_validate\n\n\ndef _collect_update_keys(parsed: Any) -> list:\n    \"\"\"Collect key names from UPDATE statements.\"\"\"\n    keys_to_validate = []\n    for node in parsed.walk():\n        if not isinstance(node, exp.Update):\n            continue\n\n        for set_expr in node.expressions:\n            if not isinstance(set_expr, exp.EQ):\n                continue\n\n            left = set_expr.left\n            if isinstance(left, Column):\n                keys_to_validate.append(left.name)\n            elif not isinstance(left, Column):\n                raise ValueError(\n                    f\"Column names must be used in UPDATE SET clause: {set_expr}\"\n                )\n    return keys_to_validate\n\n\ndef _collect_columns_and_keys(parsed: Any) -> tuple[list, list, list]:\n    \"\"\"Collect column names and key names that need validation.\"\"\"\n    functions_to_validate = _collect_functions_names(parsed)\n    columns_to_validate = _collect_column_names(parsed)\n    insert_keys = _collect_insert_keys(parsed)\n    update_keys = _collect_update_keys(parsed)\n    keys_to_validate = insert_keys + update_keys\n    return functions_to_validate, columns_to_validate, keys_to_validate\n\n\ndef _validate_comparison_nodes(parsed: Any, uid: str, span_context: Any) -> Any:\n    \"\"\"Validate comparison operation nodes.\"\"\"\n    for node in parsed.walk():","sourceCodeStart":625,"sourceCodeEnd":661,"githubUrl":"https://github.com/iflytek/astron-agent/blob/5e758547a83371a5a4b29dadf4ac03e8dd527635/core/memory/database/api/v1/exec_dml.py#L625-L661","documentation":"_collect_update_keys validates the SET clause of a parsed UPDATE DML statement. Each SET target must be a plain Column identifier; anything else (literals, expressions, function calls) is rejected so column-level permission checks remain possible.","triggerScenarios":"Executing an UPDATE whose SET clause assigns to expressions rather than bare column names, e.g. SET a = a + 1, SET x = CONCAT(a,b), or quoted/aliased targets the SQLGlot parser does not classify as Column.","commonSituations":"Users submit DML through the database API that uses computed SET values or raw SQL copied from another database's dialect.","solutions":["Rewrite the SET clause to assign only bare column names and move computation into the WHERE or application layer","Use SET col = <literal> form only","Pre-validate the SQL with the same parser before submitting"],"exampleFix":"// before\nUPDATE t SET cnt = cnt + 1 WHERE id = 1\n// after\nUPDATE t SET cnt = 42 WHERE id = 1  -- computed values rejected; use literal per-column SET","handlingStrategy":"validation","validationCode":"import sqlglot\nstmt = sqlglot.parse_one(sql, read='mysql')\nfor a in stmt.find_all(sqlglot.exp.Update):\n    for eq in a.expressions:\n        if not isinstance(eq.this, sqlglot.exp.Column):\n            raise ValueError(f'SET target must be a column: {eq.this}')","typeGuard":"def is_plain_column_update(parsed) -> bool:\n    return all(isinstance(eq.this, Column) for eq in parsed.expressions)","tryCatchPattern":"try:\n    exec_dml(sql)\nexcept ValueError as e:\n    if 'SET clause' in str(e): return reject_dml('computed SET values not allowed')\n    raise","preventionTips":["Only allow SET col = literal in user-submitted DML","Reject expressions/literals-as-targets in a pre-parse lint","Document allowed DML grammar for API users"],"tags":["sql","dml","validation"],"backgroundTag":"invalid-argument-format","analyzedSha":"5e758547a83371a5a4b29dadf4ac03e8dd527635","analyzedAt":"2026-09-12T08:03:51.356Z","contentChangedAt":"2026-09-12T08:03:51.356Z","schemaVersion":2},"datasetVersion":"2026-09-19T12:17:13.211Z"}