[SERVER-60152] Undefined slot accessor s6 in $bucket translation Created: 22/Sep/21  Updated: 29/Oct/23  Resolved: 23/Sep/21

Status: Closed
Project: Core Server
Component/s: None
Affects Version/s: None
Fix Version/s: 5.1.0-rc0

Type: Bug Priority: Major - P3
Reporter: Eric Cox (Inactive) Assignee: Yoon Soo Kim
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Backwards Compatibility: Fully Compatible
Operating System: ALL
Steps To Reproduce:

Start a mongod with the `featureFlagSBEGroupPushdown` flag on,
 

./build/ninja/install/bin/mongod --setParameter internalQueryEnableSlotBasedExecutionEngine=true --setParameter featureFlagSBEGroupPushdown=true

In the shell

var coll = db.collation_bucket;
coll.drop();
function insertData() {
  coll.insert([
    {num: "1"},
    {num: "2"},
    {num: "5"},
    {num: "10"},
    {num: "20"},
    {num: "50"},
    {num: "100"},
    {num: "200"},
    {num: "500"},
  ]);
}
insertData();
coll.aggregate([{$bucket: {groupBy: "$num", boundaries: ["1", "10", "100", "1000"]}}]); >
uncaught exception: Error: command failed: {uncaught exception: Error: command failed: {
    "ok" : 0,
    "errmsg" : "undefined slot accessor:5",
    "code" : 4946301,
    "codeName" : "Location4946301"} with original command request: {
    "aggregate" : "collation_bucket",
    "pipeline" : [
        {
            "$bucket" : {
                 "groupBy" : "$num",
                 "boundaries" : [ "1", "10", "100", "1000" ]
            }
        }
    ],    "explain" : true, "cursor" : {
 }, "lsid" : { "id" : UUID("931d91de-ed3d-4af1-87df-66c2c15444d4") }

The best place to drop the DebugPrinter statement is here,

diff --git a/src/mongo/db/query/sbe_stage_builder.cpp b/src/mongo/db/query/sbe_stage_builder.cpp
index 1b772d0276..bf5c7545c9 100644
--- a/src/mongo/db/query/sbe_stage_builder.cpp
+++ b/src/mongo/db/query/sbe_stage_builder.cpp
@@ -688,6 +688,8 @@ std::unique_ptr<sbe::PlanStage> SlotBasedStageBuilder::build(const QuerySolution
 
     // Build the SBE plan stage tree.
     auto [stage, outputs] = build(root, reqs);
+    sbe::DebugPrinter p;
+    std::cerr << p.print(*stage.get()) << "\n";

Sprint: QE 2021-10-04
Participants:

 Description   

When we generate the sub-tree for the _id expression of $bucket we end up with a giant plan that has s6 as an undefined slot accessor,

3] mkbson s30 [_id = s27, count = s29] true false
[3] project [s29 = if (! exists (s28) || typeMatch (s28, 0x00000440), 0, doubleDoubleSumFinalize (s28))]
[3] group [s27] [s28 = aggDoubleDoubleSum (1)] s2
[3] project [s27 = fillEmpty (s26, null)]
[3] nlj [] []
    left
        [2] mkbson s6 s4 [num] keep [] true false
        [1] scan s4 s5 none none none none [] @"e7d535a3-511e-4d2e-b17a-7c62e468b67f" true false
    right
        [3] limit 1
        [3] union [s26] [
            [s24] [3] nlj [s11] [s11]
                left
                    [3] filter {let [l15.0 = s11] exists (l15.0) && ! typeMatch (l15.0, 0x00000440) && l15.0 <=> false != 0 && l15.0 <=> 0 != 0}
                    [3] limit 1
                    [3] union [s11] [
                        [s9] [3] project [s9 = false]
                        [3] filter {! let [l4.0 = let [l1.0 = s7, l1.1 = "1"] fillEmpty (l1.0 <=>[s2] l1.1 >= 0, exists (l1.0) && typeMatch (l1.0, 0xFFFFFFBF) >= exists (l1.1) && typeMatch (l1.1, 0xFFFFFFBF))] exists (l4.0) && ! typeMatch (l4.0, 0x00000440) && l4.0 <=> false != 0 && l4.0 <=> 0 != 0}
                        [3] project [s7 = getField (s6, "num")]
                        [3] limit 1
                        [3] coscan ,
                        [s10] [3] project [s10 = let [l3.0 = let [l2.0 = s8, l2.1 = "10"] fillEmpty (l2.0 <=>[s2] l2.1 < 0, exists (l2.0) && typeMatch (l2.0, 0xFFFFFFBF) < exists (l2.1) && typeMatch (l2.1, 0xFFFFFFBF))] exists (l3.0) && ! typeMatch (l3.0, 0x00000440) && l3.0 <=> false != 0 && l3.0 <=> 0 != 0]
                        [3] project [s8 = getField (s6, "num")]
                        [3] limit 1
                        [3] coscan
                   ]
                right
                    [3] project [s24 = "1"]
                    [3] limit 1
                    [3] coscan
 
            ,
            [s23] [3] nlj [s16] [s16]
                left
                    [3] filter {let [l14.0 = s16] exists (l14.0) && ! typeMatch (l14.0, 0x00000440) && l14.0 <=> false != 0 && l14.0 <=> 0 != 0}
                    [3] limit 1
                    [3] union [s16] [
                        [s14] [3] project [s14 = false]
                        [3] filter {! let [l8.0 = let [l5.0 = s12, l5.1 = "10"] fillEmpty (l5.0 <=>[s2] l5.1 >= 0, exists (l5.0) && typeMatch (l5.0, 0xFFFFFFBF) >= exists (l5.1) && typeMatch (l5.1, 0xFFFFFFBF))] exists (l8.0) && ! typeMatch (l8.0, 0x00000440) && l8.0 <=> false != 0 && l8.0 <=> 0 != 0}
                        [3] project [s12 = getField (s6, "num")]
                        [3] limit 1
                        [3] coscan ,
                        [s15] [3] project [s15 = let [l7.0 = let [l6.0 = s13, l6.1 = "100"] fillEmpty (l6.0 <=>[s2] l6.1 < 0, exists (l6.0) && typeMatch (l6.0, 0xFFFFFFBF) < exists (l6.1) && typeMatch (l6.1, 0xFFFFFFBF))] exists (l7.0) && ! typeMatch (l7.0, 0x00000440) && l7.0 <=> false != 0 && l7.0 <=> 0 != 0]
                        [3] project [s13 = getField (s6, "num")]
                        [3] limit 1
                        [3] coscan
                   ]
                right
                    [3] project [s23 = "10"]
                    [3] limit 1
                    [3] coscan
 
            ,
            [s22] [3] nlj [s21] [s21]
                left
                    [3] filter {let [l13.0 = s21] exists (l13.0) && ! typeMatch (l13.0, 0x00000440) && l13.0 <=> false != 0 && l13.0 <=> 0 != 0}
                    [3] limit 1
                    [3] union [s21] [
                        [s19] [3] project [s19 = false]
                        [3] filter {! let [l12.0 = let [l9.0 = s17, l9.1 = "100"] fillEmpty (l9.0 <=>[s2] l9.1 >= 0, exists (l9.0) && typeMatch (l9.0, 0xFFFFFFBF) >= exists (l9.1) && typeMatch (l9.1, 0xFFFFFFBF))] exists (l12.0) && ! typeMatch (l12.0, 0x00000440) && l12.0 <=> false != 0 && l12.0 <=> 0 != 0}
                        [3] project [s17 = getField (s6, "num")]
                        [3] limit 1
                        [3] coscan ,
                        [s20] [3] project [s20 = let [l11.0 = let [l10.0 = s18, l10.1 = "1000"] fillEmpty (l10.0 <=>[s2] l10.1 < 0, exists (l10.0) && typeMatch (l10.0, 0xFFFFFFBF) < exists (l10.1) && typeMatch (l10.1, 0xFFFFFFBF))] exists (l11.0) && ! typeMatch (l11.0, 0x00000440) && l11.0 <=> false != 0 && l11.0 <=> 0 != 0]
                        [3] project [s18 = getField (s6, "num")]
                        [3] limit 1
                        [3] coscan
                   ]
                right
                    [3] project [s22 = "100"]
                    [3] limit 1
                    [3] coscan
 
            ,
            [s25] [3] project [s25 = fail ( 4934200 ,$switch could not find a matching branch for an input, and no default was specified.)]
            [3] limit 1
            [3] coscan
       ]

Note: I believe there's another build failure due to the same issue, it might be nice to see if this fix also fixes this failure,

https://evergreen.mongodb.com/lobster/build/ca9324421d26b1c4be849f9c5d7f086f/test/61493e37be07c444b80485e2#bookmarks=0%2C105&l=1&shareLine=18



 Comments   
Comment by Vivian Ge (Inactive) [ 06/Oct/21 ]

Updating the fixversion since branching activities occurred yesterday. This ticket will be in rc0 when it’s been triggered. For more active release information, please keep an eye on #server-release. Thank you!

Comment by Githook User [ 23/Sep/21 ]

Author:

{'name': 'Yoonsoo Kim', 'email': 'yoonsoo.kim@mongodb.com', 'username': 'yun-soo'}

Message: SERVER-60152 Add the proper out slot for child eval stage
Branch: master
https://github.com/mongodb/mongo/commit/4ae62e32c166d8483992ff49d53c00d238ba1aea

Comment by Yoon Soo Kim [ 22/Sep/21 ]

The root cause was generateExpression expects that EvalStage stage param has a valid outSlot but was not given. So, generated top nlj could not set up correlated slot(s) properly.

Comment by Yoon Soo Kim [ 22/Sep/21 ]

For coll.aggregate([{$bucket: {groupBy: "$num", boundaries: ["1", "10"]}}])'s id expression, got the following plan tree.

[3] project [s14 = fillEmpty (s13, null)]
[3] nlj [] []
    left
        [2] mkbson s5 s3 [num] keep [] true false
        [1] scan s3 s4 none none none none [] @"e841372d-2bf1-4ff4-9beb-ccb485a99202" true false
    right
        [3] limit 1
        [3] union [s13] [
            [s11] [3] nlj [s10] [s10]
                left
                    [3] filter {let [l5.0 = s10] exists (l5.0) && ! typeMatch (l5.0, 0x00000440) && l5.0 <=> false != 0 && l5.0 <=> 0 != 0}
                    [3] limit 1
                    [3] union [s10] [
                        [s8] [3] project [s8 = false]
                        [3] filter {! let [l4.0 = let [l1.0 = s6, l1.1 = "1"] fillEmpty (l1.0 <=> l1.1 >= 0, exists (l1.0) && typeMatch (l1.0, 0xFFFFFFBF) >= exists (l1.1) && typeMatch (l1.1, 0xFFFFFFBF))] exists (l4.0) && ! typeMatch (l4.0, 0x00000440) && l4.0 <=> false != 0 && l4.0 <=> 0 != 0}
                        [3] project [s6 = getField (s5, "num")]
                        [3] limit 1
                        [3] coscan ,
                        [s9] [3] project [s9 = let [l3.0 = let [l2.0 = s7, l2.1 = "10"] fillEmpty (l2.0 <=> l2.1 < 0, exists (l2.0) && typeMatch (l2.0, 0xFFFFFFBF) < exists (l2.1) && typeMatch (l2.1, 0xFFFFFFBF))] exists (l3.0) && ! typeMatch (l3.0, 0x00000440) && l3.0 <=> false != 0 && l3.0 <=> 0 != 0]
                        [3] project [s7 = getField (s5, "num")]
                        [3] limit 1
                        [3] coscan
                   ]
                right
                    [3] project [s11 = "1"]
                    [3] limit 1
                    [3] coscan
 
            ,
            [s12] [3] project [s12 = fail ( 4934200 ,$switch could not find a matching branch for an input, and no default was specified.)]
            [3] limit 1
            [3] coscan
       ]

nlj's inner side refers to s5 but we didn't set up correlated slots properly for nlj. nlj [] [] should nlj [s5] [s5]

Comment by Yoon Soo Kim [ 22/Sep/21 ]

It looks like there might be a bug in converting boundaries to $switch, looking at the following output:

[s24] [3] project [s24 = fail ( 4934200 ,$switch could not find a matching branch for an input, and no default was specified.)]

There is supposed to be a case for "1000" above. Instead, we got an error: "$switch could not find a matching branch for an input, and no default was specified".

Likely we missed adding "default" case when we convert $bucket's boundaries to $switch.

Update: this was not relevant to a root cause. Please, disregard this comment.

Comment by Yoon Soo Kim [ 22/Sep/21 ]

eric.cox, thanks for the minimal repro!

Generated at Thu Feb 08 05:49:05 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.