github.com/vescale/zgraph@v0.0.0-20230410094002-959c02d50f95/planner/plan_builder.go (about) 1 // Copyright 2022 zGraph Authors. All rights reserved. 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 planner 16 17 import ( 18 "bytes" 19 20 "github.com/pingcap/errors" 21 "github.com/vescale/zgraph/catalog" 22 "github.com/vescale/zgraph/expression" 23 "github.com/vescale/zgraph/meta" 24 "github.com/vescale/zgraph/parser/ast" 25 "github.com/vescale/zgraph/parser/format" 26 "github.com/vescale/zgraph/parser/model" 27 "github.com/vescale/zgraph/stmtctx" 28 ) 29 30 // builderContext represents the context of building plan. 31 type builderContext struct { 32 plan Plan 33 } 34 35 // Builder is used to build the AST into a plan. 36 type Builder struct { 37 sc *stmtctx.Context 38 stacks []*builderContext 39 } 40 41 // NewBuilder returns a plan builder. 42 func NewBuilder(sc *stmtctx.Context) *Builder { 43 return &Builder{ 44 sc: sc, 45 } 46 } 47 48 // Build builds a statement AST node into a Plan. 49 func (b *Builder) Build(node ast.StmtNode) (Plan, error) { 50 b.pushContext() 51 defer b.popContext() 52 53 var err error 54 switch stmt := node.(type) { 55 case ast.DDLNode: 56 err = b.buildDDL(stmt) 57 case *ast.UseStmt: 58 err = b.buildSimple(stmt) 59 case *ast.InsertStmt: 60 err = b.buildInsert(stmt) 61 case *ast.SelectStmt: 62 err = b.buildSelect(stmt) 63 case *ast.ShowStmt: 64 err = b.buildShow(stmt) 65 } 66 if err != nil { 67 return nil, err 68 } 69 70 return b.plan(), nil 71 } 72 73 func (b *Builder) pushContext() { 74 b.stacks = append(b.stacks, &builderContext{}) 75 } 76 77 func (b *Builder) popContext() { 78 b.stacks = b.stacks[:len(b.stacks)-1] 79 } 80 81 func (b *Builder) plan() Plan { 82 return b.stacks[len(b.stacks)-1].plan 83 } 84 85 func (b *Builder) setPlan(plan Plan) { 86 b.stacks[len(b.stacks)-1].plan = plan 87 } 88 89 func (b *Builder) buildDDL(ddl ast.DDLNode) error { 90 b.setPlan(&DDL{ 91 Statement: ddl, 92 }) 93 return nil 94 } 95 96 func (b *Builder) buildSimple(stmt ast.StmtNode) error { 97 b.setPlan(&Simple{ 98 Statement: stmt, 99 }) 100 return nil 101 } 102 103 func (b *Builder) buildInsert(stmt *ast.InsertStmt) error { 104 var intoGraph string 105 if !stmt.IntoGraphName.IsEmpty() { 106 intoGraph = stmt.IntoGraphName.L 107 } 108 var graph *catalog.Graph 109 if intoGraph == "" { 110 graph = b.sc.CurrentGraph() 111 } else { 112 graph = b.sc.Catalog().Graph(intoGraph) 113 } 114 if graph == nil { 115 return errors.Annotatef(meta.ErrGraphNotExists, "graph %s", intoGraph) 116 } 117 118 var fromPlan LogicalPlan 119 if stmt.From != nil { 120 p, err := b.buildMatch(stmt.From.Matches) 121 if err != nil { 122 return err 123 } 124 125 if stmt.Where != nil { 126 cond, err := RewriteExpr(stmt.Where, p) 127 if err != nil { 128 return err 129 } 130 where := &LogicalSelection{ 131 Condition: cond, 132 } 133 where.SetChildren(p) 134 p = where 135 } 136 fromPlan = p 137 138 } else { 139 fromPlan = &LogicalDual{} 140 } 141 142 var insertions []*ElementInsertion 143 for _, insertion := range stmt.Insertions { 144 var labels []*catalog.Label 145 for _, lbl := range insertion.LabelsAndProperties.Labels { 146 label := graph.Label(lbl.L) 147 if label == nil { 148 return errors.Annotatef(meta.ErrLabelNotExists, "label %s", lbl.L) 149 } 150 labels = append(labels, label) 151 } 152 var assignments []*expression.Assignment 153 for _, prop := range insertion.LabelsAndProperties.Assignments { 154 // Note: The property suppose to be exists because we have invoked property 155 // creation module before building plan. 156 propInfo := graph.Property(prop.PropertyAccess.PropertyName.L) 157 // Please fix bug in PropertyPreparation if the propInfo empty. 158 if propInfo == nil { 159 return errors.Errorf("property %s not exists", prop.PropertyAccess.PropertyName.L) 160 } 161 expr, err := RewriteExpr(prop.ValueExpression, fromPlan) 162 if err != nil { 163 return err 164 } 165 assignment := &expression.Assignment{ 166 VariableRef: &expression.VariableRef{Name: prop.PropertyAccess.VariableName}, 167 PropertyRef: &expression.PropertyRef{Property: propInfo}, 168 Expr: expr, 169 } 170 assignments = append(assignments, assignment) 171 } 172 var fromIDExpr, toIDExpr expression.Expression 173 if insertion.InsertionType == ast.InsertionTypeEdge { 174 fromExpr, err := RewriteExpr(&ast.VariableReference{VariableName: insertion.From}, fromPlan) 175 if err != nil { 176 return err 177 } 178 fromIDExpr, err = expression.NewFuncExpr("id", fromExpr) 179 if err != nil { 180 return err 181 } 182 toExpr, err := RewriteExpr(&ast.VariableReference{VariableName: insertion.To}, fromPlan) 183 if err != nil { 184 return err 185 } 186 toIDExpr, err = expression.NewFuncExpr("id", toExpr) 187 if err != nil { 188 return err 189 } 190 } 191 gi := &ElementInsertion{ 192 Type: insertion.InsertionType, 193 Labels: labels, 194 Assignments: assignments, 195 FromIDExpr: fromIDExpr, 196 ToIDExpr: toIDExpr, 197 } 198 insertions = append(insertions, gi) 199 } 200 201 plan := &Insert{ 202 Graph: graph, 203 Insertions: insertions, 204 } 205 if stmt.From != nil { 206 plan.MatchPlan = Optimize(fromPlan) 207 } 208 209 b.setPlan(plan) 210 return nil 211 } 212 213 func (b *Builder) buildSelect(stmt *ast.SelectStmt) error { 214 // Build source 215 plan, err := b.buildMatch(stmt.From.Matches) 216 if err != nil { 217 return err 218 } 219 220 // Build selection 221 if stmt.Where != nil { 222 expr, err := RewriteExpr(stmt.Where, plan) 223 if err != nil { 224 return err 225 } 226 where := &LogicalSelection{ 227 Condition: expr, 228 } 229 where.SetChildren(plan) 230 plan = where 231 } 232 233 // TODO: support GROUP BY clause. 234 // Explicit GROUP BY: SELECT * FROM MATCH (n) GROUP BY n.name; 235 // Implicit GROUP BY: SELECT COUNT(*) FROM MATCH (n); 236 if stmt.GroupBy != nil { 237 238 } 239 240 if stmt.Having != nil { 241 expr, err := RewriteExpr(stmt.Having.Expr, plan) 242 if err != nil { 243 return err 244 } 245 having := &LogicalSelection{ 246 Condition: expr, 247 } 248 having.SetChildren(plan) 249 plan = having 250 } 251 252 if stmt.OrderBy != nil { 253 byItems := make([]*ByItem, 0, len(stmt.OrderBy.Items)) 254 for _, item := range stmt.OrderBy.Items { 255 expr, err := RewriteExpr(item.Expr.Expr, plan) 256 if err != nil { 257 return err 258 } 259 byItems = append(byItems, &ByItem{ 260 Expr: expr, 261 AsName: item.Expr.AsName, 262 Desc: item.Desc, 263 NullOrder: item.NullOrder, 264 }) 265 } 266 orderby := &LogicalSort{ 267 ByItems: byItems, 268 } 269 orderby.SetChildren(plan) 270 plan = orderby 271 } 272 273 if stmt.Limit != nil { 274 offset, err := RewriteExpr(stmt.Limit.Offset, plan) 275 if err != nil { 276 return err 277 } 278 count, err := RewriteExpr(stmt.Limit.Count, plan) 279 if err != nil { 280 return err 281 } 282 limit := &LogicalLimit{ 283 Offset: offset, 284 Count: count, 285 } 286 limit.SetChildren(plan) 287 plan = limit 288 } 289 290 cols := make(ResultColumns, 0, len(stmt.Select.Elements)) 291 // TODO: support DISTINCT and wildcard. 292 proj := &LogicalProjection{} 293 for _, elem := range stmt.Select.Elements { 294 expr, err := RewriteExpr(elem.ExpAsVar.Expr, plan) 295 if err != nil { 296 return err 297 } 298 proj.Exprs = append(proj.Exprs, expr) 299 300 var colName model.CIStr 301 if elem.ExpAsVar.AsName.IsEmpty() { 302 var buf bytes.Buffer 303 restoreCtx := format.NewRestoreCtx(format.DefaultRestoreFlags, &buf) 304 if err := elem.ExpAsVar.Expr.Restore(restoreCtx); err != nil { 305 return err 306 } 307 colName = model.NewCIStr(buf.String()) 308 } else { 309 colName = elem.ExpAsVar.AsName 310 } 311 312 cols = append(cols, ResultColumn{ 313 Name: colName, 314 Type: expr.ReturnType(), 315 }) 316 317 } 318 proj.SetColumns(cols) 319 proj.SetChildren(plan) 320 321 b.setPlan(proj) 322 return nil 323 } 324 325 func (b *Builder) buildMatch(matches []*ast.MatchClause) (LogicalPlan, error) { 326 if len(matches) == 0 { 327 return &LogicalDual{}, nil 328 } 329 330 sgb := NewSubgraphBuilder(b.sc.CurrentGraph()) 331 for _, match := range matches { 332 sgb.AddPathPatterns(match.Paths...) 333 } 334 sg, err := sgb.Build() 335 if err != nil { 336 return nil, err 337 } 338 339 cols := ResultColumnsFromSubgraph(sg) 340 plan := &LogicalMatch{Subgraph: sg} 341 plan.SetColumns(cols) 342 343 return plan, nil 344 } 345 346 func (b *Builder) buildShow(stmt *ast.ShowStmt) error { 347 plan := &Simple{ 348 Statement: stmt, 349 } 350 b.setPlan(plan) 351 return nil 352 }