Bb 13.1 bar mdev 39563 - #5566
Conversation
|
|
There was a problem hiding this comment.
Pull request overview
Implements MDEV-39563 by extending the parser and execution pipeline to support UPDATE ... RETURNING ... INTO (Oracle mode), including support for assigning returned values into SP variables (including ROW/ROWTYPE fields) and assoc array scenarios, with new/updated MTR coverage.
Changes:
- Extend grammar to allow an optional
INTO <varlist>afterUPDATE ... RETURNING .... - Plumb
RETURNING ... INTOinto the UPDATE execution path by reusing a parse-timeselect_result(e.g.,select_dumpvar) when applicable. - Add/extend tests covering user variables, SP variables, ROW variables/fields, ROW TYPE OF (table/cursor), and assoc array behaviors; plus negative tests for unsupported DML contexts.
Reviewed changes
Copilot reviewed 21 out of 21 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| sql/sql_yacc.yy | Adds opt_into... support for RETURNING ... INTO and refactors INTO-varlist init rule reuse. |
| sql/sql_update.h | Adds a setter to inject a prebuilt select_result for UPDATE RETURNING. |
| sql/sql_update.cc | Adjusts returning result creation/reuse across executions (esp. SP/PS reuse). |
| sql/sql_type_row.cc | Adds runtime-by-name assignment path for ROWTYPE-based row-field OUT vars. |
| sql/sql_lex.h | Declares LEX::handle_returning_into_varlist(). |
| sql/sql_lex.cc | Implements LEX::handle_returning_into_varlist() to bind RETURNING ... INTO to UPDATE only. |
| sql/sp_rcontext.h | Declares set_variable_row_field_by_name() for runtime field lookup. |
| sql/sp_rcontext.cc | Implements runtime row-field assignment by field name. |
| plugin/type_assoc_array/mysql-test/type_assoc_array/sp-assoc-array-returning.test | New assoc-array focused test coverage for UPDATE RETURNING INTO. |
| plugin/type_assoc_array/mysql-test/type_assoc_array/sp-assoc-array-returning.result | Expected results for the new assoc-array tests. |
| mysql-test/main/update_returning.test | New core coverage for UPDATE RETURNING INTO, including ROW/ROWTYPE cases and repeated execution. |
| mysql-test/main/update_returning.result | Expected results for UPDATE RETURNING INTO tests. |
| mysql-test/main/update_returning_into_row_var.inc | Shared include for ROW/ROWTYPE INTO test permutations. |
| mysql-test/main/select_into_row.test | New coverage for SELECT INTO ROWTYPE field stability (MDEV-40790). |
| mysql-test/main/select_into_row.result | Expected results for SELECT INTO row tests. |
| mysql-test/main/replace_returning.test | Adds negative coverage for unsupported REPLACE ... RETURNING ... INTO. |
| mysql-test/main/replace_returning.result | Expected results for the new REPLACE negative test. |
| mysql-test/main/insert_returning.test | Adds negative coverage for unsupported INSERT ... RETURNING ... INTO. |
| mysql-test/main/insert_returning.result | Expected results for the new INSERT negative test. |
| mysql-test/main/delete_returning.test | Adds negative coverage for unsupported DELETE ... RETURNING ... INTO. |
| mysql-test/main/delete_returning.result | Expected results for the new DELETE negative test. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| bool LEX::handle_returning_into_varlist() | ||
| { | ||
| if (!result) | ||
| return false; // No INTO | ||
| if (m_sql_cmd) | ||
| { | ||
| Sql_cmd_update *update; | ||
| if ((update= dynamic_cast<Sql_cmd_update*>(m_sql_cmd))) | ||
| { | ||
| update->set_returning_result(result); | ||
| return false; | ||
| } | ||
| } | ||
| my_error(ER_NOT_ALLOWED_IN_THIS_CONTEXT, MYF(0), "RETURNING..INTO"); | ||
| return true; | ||
| } |
| int sp_rcontext::set_variable_row_field_by_name(THD *thd, uint var_idx, | ||
| const Lex_ident_sys_st &field_name, | ||
| Item **value) | ||
| { | ||
| DBUG_ENTER("sp_rcontext::set_variable_row_field"); | ||
| DBUG_ASSERT(value); | ||
| uint field_idx= 0; | ||
| if (find_row_field_by_name_or_error(&field_idx, var_idx, field_name)) | ||
| DBUG_RETURN(true); | ||
| Virtual_tmp_table *vtable= virtual_tmp_table_for_row(var_idx); | ||
| DBUG_RETURN(thd->sp_eval_expr(vtable->field[field_idx], value)); | ||
| } |
| bool check_assignability(THD *thd, const List<Item> &select_list, | ||
| bool *assign_as_row) const override | ||
| { | ||
| *assign_as_row= false; | ||
| return select_list.elements == 1; | ||
| } |
| else | ||
| { | ||
| /* | ||
| Otherwise it is: | ||
| 1. A non-RETURNING statement at all | ||
| 2. Or a statement returning into an SP variable list: | ||
| UPDATE t1 SET a=a+1 WHERE a=10 RETURNING a INTO va; | ||
| In this case returning_result was created during parse time | ||
| and we preserve it for the second and further executions. | ||
| */ | ||
| DBUG_ASSERT(!returning_result || | ||
| dynamic_cast<select_dumpvar*>(returning_result)); | ||
| } |
a657340 to
668c6c4
Compare
…es the server The server crashed on DBUG_ASSERT on a SELECT into: - a `ROW TYPE OF table1` field variable - a `ROW TYPE OF cursor1` field variable Fix: - Adding a class my_var_sp_row_field_by_name - Adding a method sp_rcontext::set_variable_row_field_by_name() - Fixing the DBUG_ASSERT
6c23b8f to
72ba557
Compare
Adding support for UPDATE .. RETURNING .. INTO queries. For example: UPDATE t1 SET a=10,b=20 RETURNING a,b INTO va,vb; UPDATE t1 SET a=10,b=20 RETURNING a,b INTO @A,@b; Limitations: 1. These types of queries: - REPLACE .. RETURNING .. INTO - DELETE .. RETURNING .. INTO - INSERT .. RETURNING .. INTO do not work - they return an error. They will be implemented separately, when needed. 2. UPDATE..RETURNING..INTO with --binlog_format=statement is not allowed and an error is raised. 3. Using OLD_VALUE(col) inside UPDATE..RETURNING..INTO is not allowed and an error is raised. 4. Multi-table updates, as well as single table updates with a subquery to the same table in WHERE (which get converted to multi-table) do not work and an error is raised. Notes: 1. ANALYZE and EXPLAIN Both ANALYZE UPDATE .. RETURNING .. INTO .. EXPLAIN UPDATE .. RETURNING .. INTO .. return this error: 'RETURNING..INTO' is not allowed in this context 2. Behavior on no data a. In case of degenerated plans (WHERE 1=0, LIMIT 0), no errors are raised. b. If the updated table contains no rows, the behavior depends on the engine, for example: - MyISAM returns no errors - InnoDB raises No data - zero rows fetched, selected, or processed This behavior is engine dependent because some engines (e.g. MyISAM) quickly know that the table has no records and execute the statement using a degenerated plan. c. If there are some rows, but non of them match the WHERE condition, then this error is raised: No data - zero rows fetched, selected, or processed d. If some rows where found but none of them actually got changed by the SET, still this error is raised: No data - zero rows fetched, selected, or processed The error message might be misleading. However, if we read it as "zero rows [that required updates] fetched", it looks OK. Let's not introduce a new error message for now. Helper changes: 1. The grammar in analyze_stmt_command was changed to have LEX::analyze_stmt set to true earlier, so LEX::set_returning_into_result() already knows if this is an ANALYZE statement. 2. The Sql_cmd_update constructor is now called earlier in the grammar, to be able to call Sql_cmd_update::set_with_old_value_items() in the SET and RETURNING clauses. 3. Sql_cmd_dml::lex is now set during the constructor time. It makes things easier: - Sql_cmd_update::returns_result_set() needs the lex. - Sql_cmd_delete::orig_multitable and Sql_cmd_update::orig_multitable are not needed any more. They were used only in Sql_cmd_delete::sql_command_code() and Sql_cmd_update::sql_command_code(). Sql_cmd_dml::sql_command_code() now returns lex->sql_command. The overrides Sql_cmd_delete::sql_command_code() and Sql_cmd_update::sql_command_code() were removed.
72ba557 to
99929e2
Compare
This PR imlements MDEV-39563 Implement UPDATE ... RETURNING ... INTO