github.com/vescale/zgraph@v0.0.0-20230410094002-959c02d50f95/executor/ddl.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 executor 16 17 import ( 18 "context" 19 20 "github.com/pingcap/errors" 21 "github.com/vescale/zgraph/catalog" 22 "github.com/vescale/zgraph/datum" 23 "github.com/vescale/zgraph/meta" 24 "github.com/vescale/zgraph/parser/ast" 25 "github.com/vescale/zgraph/parser/model" 26 "github.com/vescale/zgraph/storage/kv" 27 ) 28 29 // DDLExec is used to execute a DDL operation. 30 type DDLExec struct { 31 baseExecutor 32 33 done bool 34 statement ast.DDLNode 35 } 36 37 // Next implements the Executor interface. 38 func (e *DDLExec) Next(_ context.Context) (datum.Row, error) { 39 if e.done { 40 return nil, nil 41 } 42 e.done = true 43 44 // TODO: prevent executing DDL in transaction context. 45 // Prevent executing DDL concurrently. 46 e.sc.Catalog().MDLock() 47 defer e.sc.Catalog().MDUnlock() 48 49 var patch *catalog.Patch 50 err := kv.Txn(e.sc.Store(), func(txn kv.Transaction) error { 51 m := meta.New(txn) 52 var err error 53 switch stmt := e.statement.(type) { 54 case *ast.CreateGraphStmt: 55 patch, err = e.createGraph(m, stmt) 56 case *ast.DropGraphStmt: 57 patch, err = e.dropGraph(m, stmt) 58 case *ast.CreateLabelStmt: 59 patch, err = e.createLabel(m, stmt) 60 case *ast.DropLabelStmt: 61 patch, err = e.dropLabel(m, stmt) 62 63 default: 64 return errors.Errorf("unknown DDL(%T)", e.statement) 65 } 66 return err 67 }) 68 if err != nil { 69 return nil, err 70 } 71 72 // Apply the patch to catalog after the DDL changes have persistent in storage. 73 if patch != nil { 74 e.sc.Catalog().Apply(patch) 75 } 76 return nil, nil 77 } 78 79 func (e *DDLExec) createGraph(m *meta.Meta, stmt *ast.CreateGraphStmt) (*catalog.Patch, error) { 80 graph := e.sc.Catalog().Graph(stmt.Graph.L) 81 if graph != nil { 82 if stmt.IfNotExists { 83 return nil, nil 84 } 85 return nil, meta.ErrGraphExists 86 } 87 88 // Persistent to storage. 89 id, err := m.NextGlobalID() 90 if err != nil { 91 return nil, err 92 } 93 graphInfo := &model.GraphInfo{ 94 ID: id, 95 Name: stmt.Graph, 96 Query: stmt.Text(), 97 } 98 err = m.CreateGraph(graphInfo) 99 if err != nil { 100 return nil, err 101 } 102 103 patch := &catalog.Patch{ 104 Type: catalog.PatchTypeCreateGraph, 105 Data: graphInfo, 106 } 107 return patch, nil 108 } 109 110 func (e *DDLExec) dropGraph(m *meta.Meta, stmt *ast.DropGraphStmt) (*catalog.Patch, error) { 111 graph := e.sc.Catalog().Graph(stmt.Graph.L) 112 if graph == nil { 113 if stmt.IfExists { 114 return nil, nil 115 } 116 return nil, meta.ErrGraphNotExists 117 } 118 119 // Persistent to storage. 120 graphID := graph.Meta().ID 121 labels := graph.Labels() 122 for _, label := range labels { 123 err := m.DropLabel(graphID, label.Meta().ID) 124 if err != nil { 125 return nil, err 126 } 127 } 128 properties := graph.Properties() 129 for _, property := range properties { 130 err := m.DropProperty(graphID, property.ID) 131 if err != nil { 132 return nil, err 133 } 134 } 135 err := m.DropGraph(graphID) 136 if err != nil { 137 return nil, err 138 } 139 140 patch := &catalog.Patch{ 141 Type: catalog.PatchTypeDropGraph, 142 Data: graph.Meta(), 143 } 144 return patch, nil 145 } 146 147 func (e *DDLExec) createLabel(m *meta.Meta, stmt *ast.CreateLabelStmt) (*catalog.Patch, error) { 148 graph := e.sc.CurrentGraph() 149 if graph == nil { 150 return nil, meta.ErrGraphNotExists 151 } 152 label := graph.Label(stmt.Label.L) 153 if label != nil { 154 if stmt.IfNotExists { 155 return nil, nil 156 } 157 return nil, meta.ErrLabelExists 158 } 159 160 // Persistent to storage. 161 id, err := m.NextGlobalID() 162 if err != nil { 163 return nil, err 164 } 165 labelInfo := &model.LabelInfo{ 166 ID: id, 167 Name: stmt.Label, 168 Query: stmt.Text(), 169 } 170 err = m.CreateLabel(graph.Meta().ID, labelInfo) 171 if err != nil { 172 return nil, err 173 } 174 175 patch := &catalog.Patch{ 176 Type: catalog.PatchTypeCreateLabel, 177 Data: &catalog.PatchLabel{ 178 GraphID: graph.Meta().ID, 179 LabelInfo: labelInfo, 180 }, 181 } 182 return patch, nil 183 } 184 185 func (e *DDLExec) dropLabel(m *meta.Meta, stmt *ast.DropLabelStmt) (*catalog.Patch, error) { 186 graph := e.sc.CurrentGraph() 187 if graph == nil { 188 return nil, meta.ErrGraphNotExists 189 } 190 label := graph.Label(stmt.Label.L) 191 if label == nil { 192 if stmt.IfExists { 193 return nil, nil 194 } 195 return nil, meta.ErrLabelNotExists 196 } 197 198 // Persistent to storage. 199 err := m.DropLabel(graph.Meta().ID, label.Meta().ID) 200 if err != nil { 201 return nil, err 202 } 203 204 patch := &catalog.Patch{ 205 Type: catalog.PatchTypeDropLabel, 206 Data: &catalog.PatchLabel{ 207 GraphID: graph.Meta().ID, 208 LabelInfo: label.Meta(), 209 }, 210 } 211 return patch, nil 212 }