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  }