github.com/matrixorigin/matrixone@v1.2.0/pkg/sql/plan/apply_indices_master.go (about) 1 // Copyright 2024 Matrix Origin 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package plan 16 17 import ( 18 "github.com/matrixorigin/matrixone/pkg/common/mpool" 19 "github.com/matrixorigin/matrixone/pkg/container/types" 20 "github.com/matrixorigin/matrixone/pkg/container/vector" 21 "github.com/matrixorigin/matrixone/pkg/pb/plan" 22 "github.com/matrixorigin/matrixone/pkg/pb/timestamp" 23 "github.com/matrixorigin/matrixone/pkg/sql/plan/function" 24 ) 25 26 var ( 27 varcharType = types.T_varchar.ToType() 28 ) 29 30 func (builder *QueryBuilder) applyIndicesForFiltersUsingMasterIndex(nodeID int32, scanNode *plan.Node, indexDef *plan.IndexDef) int32 { 31 32 var pkPos = scanNode.TableDef.Name2ColIndex[scanNode.TableDef.Pkey.PkeyColName] 33 var pkType = scanNode.TableDef.Cols[pkPos].Typ 34 var colDefs = scanNode.TableDef.Cols 35 36 var prevIndexPkCol *Expr 37 var prevLastNodeId int32 38 var lastNodeId int32 39 40 //ts1 := scanNode.ScanTS 41 for i, filterExp := range scanNode.FilterList { 42 // TODO: node should hold snapshot info and account info 43 //idxObjRef, idxTableDef := builder.compCtx.Resolve(scanNode.ObjRef.SchemaName, indexDef.IndexTableName, timestamp.Timestamp{}) 44 idxObjRef, idxTableDef := builder.compCtx.Resolve(scanNode.ObjRef.SchemaName, indexDef.IndexTableName, Snapshot{TS: ×tamp.Timestamp{}}) 45 46 // 1. SELECT pk from idx WHERE prefix_eq(`__mo_index_idx_col`,serial_full("0","value")) 47 currIdxProjTag, currScanId := makeIndexTblScan(builder, builder.ctxByNode[nodeID], filterExp, idxTableDef, idxObjRef, scanNode.ScanSnapshot, colDefs) 48 49 // 2. (SELECT pk from idx1 WHERE prefix_eq(`__mo_index_idx_col`,serial_full("0","value1")) ) 50 // INNER JOIN 51 // (SELECT pk from idx2 WHERE prefix_eq(`__mo_index_idx_col` = serial_full("1","value2")) ) 52 // ON idx1.pk = idx2.pk 53 // ... 54 lastNodeId = currScanId 55 currIndexPkCol := &Expr{ 56 Typ: pkType, 57 Expr: &plan.Expr_Col{ 58 Col: &plan.ColRef{ 59 RelPos: currIdxProjTag, 60 ColPos: 0, // __mo_index_pk_col 61 }, 62 }, 63 } 64 if i != 0 { 65 wherePrevPkEqCurrPk, _ := BindFuncExprImplByPlanExpr(builder.GetContext(), "=", []*Expr{ 66 currIndexPkCol, 67 prevIndexPkCol, 68 }) 69 lastNodeId = builder.appendNode(&plan.Node{ 70 NodeType: plan.Node_JOIN, 71 JoinType: plan.Node_INNER, 72 Children: []int32{currScanId, prevLastNodeId}, 73 OnList: []*Expr{wherePrevPkEqCurrPk}, 74 }, builder.ctxByNode[nodeID]) 75 } 76 77 prevIndexPkCol = DeepCopyExpr(currIndexPkCol) 78 prevLastNodeId = lastNodeId 79 } 80 lastNodeFromIndexTbl := builder.qry.Nodes[lastNodeId] 81 lastNodeFromIndexTbl.Limit = DeepCopyExpr(scanNode.Limit) 82 lastNodeFromIndexTbl.Offset = DeepCopyExpr(scanNode.Offset) 83 scanNode.Limit, scanNode.Offset = nil, nil 84 85 // 3. SELECT * from tbl INNER JOIN ( 86 // (SELECT pk from idx1 WHERE prefix_eq(`__mo_index_idx_col`,serial_full("0","value1")) ) 87 // INNER JOIN 88 // (SELECT pk from idx2 WHERE prefix_eq(`__mo_index_idx_col`,serial_full("1","value2")) ) 89 // ON idx1.pk = idx2.pk 90 // ) ON tbl.pk = idx1.pk 91 wherePkEqPk, _ := BindFuncExprImplByPlanExpr(builder.GetContext(), "=", []*Expr{ 92 { 93 Typ: pkType, 94 Expr: &plan.Expr_Col{ 95 Col: &plan.ColRef{ 96 RelPos: scanNode.BindingTags[0], 97 ColPos: pkPos, // tbl.pk 98 }, 99 }, 100 }, 101 { 102 Typ: pkType, 103 Expr: &plan.Expr_Col{ 104 Col: &plan.ColRef{ 105 RelPos: prevIndexPkCol.GetCol().RelPos, // last idxTbl (may be join) relPos 106 ColPos: 0, // idxTbl.pk 107 }, 108 }, 109 }, 110 }) 111 lastNodeId = builder.appendNode(&plan.Node{ 112 NodeType: plan.Node_JOIN, 113 JoinType: plan.Node_INDEX, 114 Children: []int32{scanNode.NodeId, lastNodeId}, 115 OnList: []*Expr{wherePkEqPk}, 116 Limit: DeepCopyExpr(lastNodeFromIndexTbl.Limit), 117 Offset: DeepCopyExpr(lastNodeFromIndexTbl.Offset), 118 }, builder.ctxByNode[nodeID]) 119 120 return lastNodeId 121 } 122 123 func makeIndexTblScan(builder *QueryBuilder, bindCtx *BindContext, filterExp *plan.Expr, 124 idxTableDef *TableDef, idxObjRef *ObjectRef, scanSnapshot *Snapshot, colDefs []*plan.ColDef) (int32, int32) { 125 126 // a. Scan * WHERE prefix_eq(`__mo_index_idx_col`,serial_full("0","value")) 127 idxScanTag := builder.genNewTag() 128 args := filterExp.GetF().Args 129 130 var filterList *plan.Expr 131 indexKeyCol := &plan.Expr{ 132 Typ: makePlan2Type(&varcharType), 133 Expr: &plan.Expr_Col{ 134 Col: &plan.ColRef{ 135 RelPos: idxScanTag, //__mo_index_idx_col 136 ColPos: 0, 137 }, 138 }, 139 } 140 141 switch filterExp.GetF().Func.ObjName { 142 case "=": 143 serialExpr1, _ := BindFuncExprImplByPlanExpr(builder.GetContext(), "serial_full", 144 []*plan.Expr{ 145 makePlan2StringConstExprWithType(getColSeqFromColDef(colDefs[args[0].GetCol().GetColPos()])), // "0" 146 args[1], // value 147 }) 148 149 filterList, _ = BindFuncExprImplByPlanExpr(builder.GetContext(), "prefix_eq", []*Expr{ 150 indexKeyCol, // __mo_index_idx_col 151 serialExpr1, // serial_full("0","value") 152 }) 153 case "between": 154 serialExpr1, _ := BindFuncExprImplByPlanExpr(builder.GetContext(), "serial_full", []*plan.Expr{ 155 makePlan2StringConstExprWithType(getColSeqFromColDef(colDefs[args[0].GetCol().GetColPos()])), // "0" 156 args[1], // value1 157 }) 158 serialExpr2, _ := BindFuncExprImplByPlanExpr(builder.GetContext(), "serial_full", []*plan.Expr{ 159 makePlan2StringConstExprWithType(getColSeqFromColDef(colDefs[args[0].GetCol().GetColPos()])), // "0" 160 args[2], // value2 161 }) 162 filterList, _ = bindFuncExprAndConstFold(builder.GetContext(), builder.compCtx.GetProcess(), "prefix_between", []*Expr{ 163 indexKeyCol, // __mo_index_idx_col 164 serialExpr1, // serial_full("0","value1") 165 serialExpr2, // serial_full("0","value2") 166 }) 167 168 case "in": 169 // Since this master index specifically for varchar, we assume the `IN` to contain only varchar values. 170 inVecType := types.T_varchar.ToType() 171 172 // a. varchar vector ("value1", "value2", "value3") 173 arg1AsColValuesVec := vector.NewVec(inVecType) 174 _ = arg1AsColValuesVec.UnmarshalBinary(args[1].GetVec().GetData()) 175 inExprListLen := arg1AsColValuesVec.Length() 176 177 // b. const vector "0" 178 mp := mpool.MustNewZero() 179 arg0AsColNameVec, _ := vector.NewConstBytes(inVecType, []byte(getColSeqFromColDef(colDefs[args[0].GetCol().GetColPos()])), inExprListLen, mp) 180 181 // c. (serial_full("0","value1"), serial_full("0","value2"), serial_full("0","value3")) 182 ps := types.NewPackerArray(inExprListLen, mp) 183 defer func() { 184 for _, p := range ps { 185 p.FreeMem() 186 } 187 }() 188 function.SerialHelper(arg0AsColNameVec, nil, ps, true) 189 function.SerialHelper(arg1AsColValuesVec, nil, ps, true) 190 arg1ForPrefixInVec := vector.NewVec(inVecType) 191 for i := 0; i < inExprListLen; i++ { 192 _ = vector.AppendBytes(arg1ForPrefixInVec, ps[i].Bytes(), false, mp) 193 } 194 195 // d. convert result vector to LiteralVec 196 arg1ForPrefixInBytes, _ := arg1ForPrefixInVec.MarshalBinary() 197 arg1ForPrefixInLitVec := &plan.Expr{ 198 Typ: makePlan2Type(&varcharType), 199 Expr: &plan.Expr_Vec{ 200 Vec: &plan.LiteralVec{ 201 Len: int32(len(arg1ForPrefixInBytes)), 202 Data: arg1ForPrefixInBytes, 203 }, 204 }, 205 } 206 207 // e. free memory for arg0, arg1 vector. Packer's memory is freed in defer. 208 arg1ForPrefixInVec.Free(mp) 209 arg0AsColNameVec.Free(mp) 210 211 filterList, _ = bindFuncExprAndConstFold(builder.GetContext(), builder.compCtx.GetProcess(), "prefix_in", []*Expr{ 212 indexKeyCol, // __mo_index_idx_col 213 arg1ForPrefixInLitVec, // (serial_full("0","value1"), serial_full("0","value2"), serial_full("0","value3")) 214 }) 215 216 default: 217 panic("unsupported filter expression") 218 } 219 220 scanId := builder.appendNode(&Node{ 221 NodeType: plan.Node_TABLE_SCAN, 222 TableDef: idxTableDef, 223 ObjRef: idxObjRef, 224 FilterList: []*plan.Expr{filterList}, 225 BindingTags: []int32{idxScanTag}, 226 //ScanTS: &scanTs, 227 ScanSnapshot: scanSnapshot, 228 }, bindCtx) 229 230 // b. Project __mo_index_pk_col 231 projPkCol := &Expr{ 232 Typ: makePlan2Type(&varcharType), 233 Expr: &plan.Expr_Col{ 234 Col: &plan.ColRef{ 235 RelPos: idxScanTag, //__mo_index_pk_col 236 ColPos: 1, 237 }, 238 }, 239 } 240 idxProjectTag := builder.genNewTag() 241 projectId := builder.appendNode(&Node{ 242 NodeType: plan.Node_PROJECT, 243 Children: []int32{scanId}, 244 ProjectList: []*Expr{projPkCol}, 245 BindingTags: []int32{idxProjectTag}, 246 }, bindCtx) 247 248 return idxProjectTag, projectId 249 } 250 251 func isKeyPresentInList(key string, list []string) bool { 252 for _, item := range list { 253 if key == item { 254 return true 255 } 256 } 257 return false 258 }