dssysolyatin commented on code in PR #4572:
URL: https://github.com/apache/calcite/pull/4572#discussion_r2416247477


##########
core/src/main/java/org/apache/calcite/rel/rel2sql/RelToSqlConverter.java:
##########
@@ -1141,16 +1138,21 @@ public Result visit(TableModify modify) {
       return result(sqlInsert, ImmutableList.of(), modify, null);
     }
     case UPDATE: {
+      final List<String> updateColumnList =
+          requireNonNull(modify.getUpdateColumnList(),
+              () -> "modify.getUpdateColumnList() is null for " + modify);
       final Result input = visitInput(modify, 0);
+      final SqlSelect sourceSelect = input.asSelect();

Review Comment:
   Let's assume we have this input expression:
   ```
   UPDATE `foodmart`.`product` SET `product_name` = `product_name` || 'calcite' 
WHERE `product_id` > 10
   ```
   
   calcite parser will parse it as:
   ```
   SqlUpdate(
       targetColumnList = [product_name], 
       sourceExpressionList = [`product_name` || 'calcite'], 
       condition = `product_id` > 10,
       sourceSelect = null <-- sourceSelect is null
   )
   ```
   
   Then, `ValidatorImpl.createSourceSelectForUpdate` changes it into:
   ```
   SqlUpdate(
       targetColumnList = [product_name], 
       sourceExpressionList = [`product_name` || 'calcite'], 
       condition = `product_id` > 10,
       sourceSelect = "SELECT *, `product_name` || 'calcite' AS `EXPR$0` FROM 
`foodmart`.`product` WHERE `product_id` > 10"
   )
   ```
   
   Next, `SqlToRelConverter` converts it into this logical plan:
   ```
   LogicalTableModify(
     table=[[foodmart, product]], operation=[UPDATE], 
     updateColumnList=[[product_name]], 
     sourceExpressionList=[[CAST(||($3, 'calcite')):VARCHAR(60) NOT NULL]], 
     flattened=[true]
   )
     LogicalProject(product_class_id=[$0], product_id=[$1], <all 14 fields>,  
EXPR$0=[||($3, 'calcite')])
       LogicalFilter(condition=[>($1, 10)])
         LogicalTableScan(table=[[foodmart, product]])
   ```
   
   `LogicalTableModify.sourceExpressionList` is built using the blackboard from 
LogicalProject, but it doesn’t use expressions directly from `LogicalProject`. 
(This is one more reason my previous fix was incorrect. It lost type coercion 
in this case).
   
   Now, answer on your question: "What is this SqlSelect node"
   
   `RelToSqlConverter` transforms `TableModify.input` into:
   ```
   SELECT `product_class_id`, `product_id`, `brand_name`, `product_name`, 
`SKU`, `SRP`, `gross_weight`, `net_weight`, `recyclable_package`, `low_fat`, 
`units_per_case`, `cases_per_pallet`, `shelf_width`, `shelf_height`, 
`shelf_depth`, `product_name` || 'calcite' AS `EXPR$0`
   FROM `foodmart`.`product`
   WHERE `product_id` > 10
   ```
   
   Calcite takes the WHERE clause for the UPDATE from this SELECT. ~(This is 
not completely correct. if we later support `UPDATE FROM` syntax, it will be 
wrong. Instead, we should build the `WHERE` clause based on the `SELECT` 
context, rather than reusing parts of the `SELECT`)~
   
   We also need to convert `TableModify.sourceExpressionList` into a `SqlNode` 
using the context of this SELECT, similar to how we use the LogicalProject 
blackboard when converting a SqlNode to a RelNode. My current fix uses this 
approach



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to