github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/dbs/sequence.go (about)

     1  // Copyright 2020 WHTCORPS INC, Inc.
     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  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package dbs
    15  
    16  import (
    17  	"math"
    18  
    19  	"github.com/cznic/mathutil"
    20  	"github.com/whtcorpsinc/errors"
    21  	"github.com/whtcorpsinc/BerolinaSQL/ast"
    22  	"github.com/whtcorpsinc/BerolinaSQL/perceptron"
    23  	"github.com/whtcorpsinc/milevadb/dbs/soliton"
    24  	"github.com/whtcorpsinc/milevadb/schemareplicant"
    25  	"github.com/whtcorpsinc/milevadb/spacetime"
    26  	math2 "github.com/whtcorpsinc/milevadb/soliton/math"
    27  )
    28  
    29  func onCreateSequence(d *dbsCtx, t *spacetime.Meta, job *perceptron.Job) (ver int64, _ error) {
    30  	schemaID := job.SchemaID
    31  	tbInfo := &perceptron.BlockInfo{}
    32  	if err := job.DecodeArgs(tbInfo); err != nil {
    33  		// Invalid arguments, cancel this job.
    34  		job.State = perceptron.JobStateCancelled
    35  		return ver, errors.Trace(err)
    36  	}
    37  
    38  	tbInfo.State = perceptron.StateNone
    39  	err := checkBlockNotExists(d, t, schemaID, tbInfo.Name.L)
    40  	if err != nil {
    41  		if schemareplicant.ErrDatabaseNotExists.Equal(err) || schemareplicant.ErrBlockExists.Equal(err) {
    42  			job.State = perceptron.JobStateCancelled
    43  		}
    44  		return ver, errors.Trace(err)
    45  	}
    46  
    47  	ver, err = uFIDelateSchemaVersion(t, job)
    48  	if err != nil {
    49  		return ver, errors.Trace(err)
    50  	}
    51  
    52  	switch tbInfo.State {
    53  	case perceptron.StateNone:
    54  		// none -> public
    55  		tbInfo.State = perceptron.StatePublic
    56  		tbInfo.UFIDelateTS = t.StartTS
    57  		err = createSequenceWithCheck(t, job, schemaID, tbInfo)
    58  		if err != nil {
    59  			return ver, errors.Trace(err)
    60  		}
    61  		// Finish this job.
    62  		job.FinishBlockJob(perceptron.JobStateDone, perceptron.StatePublic, ver, tbInfo)
    63  		asyncNotifyEvent(d, &soliton.Event{Tp: perceptron.CausetActionCreateSequence, BlockInfo: tbInfo})
    64  		return ver, nil
    65  	default:
    66  		return ver, ErrInvalidDBSState.GenWithStackByArgs("sequence", tbInfo.State)
    67  	}
    68  }
    69  
    70  func createSequenceWithCheck(t *spacetime.Meta, job *perceptron.Job, schemaID int64, tbInfo *perceptron.BlockInfo) error {
    71  	err := checkBlockInfoValid(tbInfo)
    72  	if err != nil {
    73  		job.State = perceptron.JobStateCancelled
    74  		return errors.Trace(err)
    75  	}
    76  	var sequenceBase int64
    77  	if tbInfo.Sequence.Increment >= 0 {
    78  		sequenceBase = tbInfo.Sequence.Start - 1
    79  	} else {
    80  		sequenceBase = tbInfo.Sequence.Start + 1
    81  	}
    82  	return t.CreateSequenceAndSetSeqValue(schemaID, tbInfo, sequenceBase)
    83  }
    84  
    85  func handleSequenceOptions(SeqOptions []*ast.SequenceOption, sequenceInfo *perceptron.SequenceInfo) {
    86  	var (
    87  		minSetFlag   bool
    88  		maxSetFlag   bool
    89  		startSetFlag bool
    90  	)
    91  	for _, op := range SeqOptions {
    92  		switch op.Tp {
    93  		case ast.SequenceOptionIncrementBy:
    94  			sequenceInfo.Increment = op.IntValue
    95  		case ast.SequenceStartWith:
    96  			sequenceInfo.Start = op.IntValue
    97  			startSetFlag = true
    98  		case ast.SequenceMinValue:
    99  			sequenceInfo.MinValue = op.IntValue
   100  			minSetFlag = true
   101  		case ast.SequenceMaxValue:
   102  			sequenceInfo.MaxValue = op.IntValue
   103  			maxSetFlag = true
   104  		case ast.SequenceCache:
   105  			sequenceInfo.CacheValue = op.IntValue
   106  		case ast.SequenceNoCache:
   107  			sequenceInfo.Cache = false
   108  		case ast.SequenceCycle:
   109  			sequenceInfo.Cycle = true
   110  		case ast.SequenceNoCycle:
   111  			sequenceInfo.Cycle = false
   112  		}
   113  	}
   114  	// Fill the default value, min/max/start should be adjusted with the sign of sequenceInfo.Increment.
   115  	if !(minSetFlag && maxSetFlag && startSetFlag) {
   116  		if sequenceInfo.Increment >= 0 {
   117  			if !minSetFlag {
   118  				sequenceInfo.MinValue = perceptron.DefaultPositiveSequenceMinValue
   119  			}
   120  			if !startSetFlag {
   121  				sequenceInfo.Start = mathutil.MaxInt64(sequenceInfo.MinValue, perceptron.DefaultPositiveSequenceStartValue)
   122  			}
   123  			if !maxSetFlag {
   124  				sequenceInfo.MaxValue = perceptron.DefaultPositiveSequenceMaxValue
   125  			}
   126  		} else {
   127  			if !maxSetFlag {
   128  				sequenceInfo.MaxValue = perceptron.DefaultNegativeSequenceMaxValue
   129  			}
   130  			if !startSetFlag {
   131  				sequenceInfo.Start = mathutil.MinInt64(sequenceInfo.MaxValue, perceptron.DefaultNegativeSequenceStartValue)
   132  			}
   133  			if !minSetFlag {
   134  				sequenceInfo.MinValue = perceptron.DefaultNegativeSequenceMinValue
   135  			}
   136  		}
   137  	}
   138  }
   139  
   140  func validateSequenceOptions(seqInfo *perceptron.SequenceInfo) bool {
   141  	// To ensure that cache * increment will never overflows.
   142  	var maxIncrement int64
   143  	if seqInfo.Increment == 0 {
   144  		// Increment shouldn't be set as 0.
   145  		return false
   146  	}
   147  	if seqInfo.CacheValue <= 0 {
   148  		// Cache value should be bigger than 0.
   149  		return false
   150  	}
   151  	maxIncrement = math2.Abs(seqInfo.Increment)
   152  
   153  	return seqInfo.MaxValue >= seqInfo.Start &&
   154  		seqInfo.MaxValue > seqInfo.MinValue &&
   155  		seqInfo.Start >= seqInfo.MinValue &&
   156  		seqInfo.MaxValue != math.MaxInt64 &&
   157  		seqInfo.MinValue != math.MinInt64 &&
   158  		seqInfo.CacheValue < (math.MaxInt64-maxIncrement)/maxIncrement
   159  }
   160  
   161  func buildSequenceInfo(stmt *ast.CreateSequenceStmt, ident ast.Ident) (*perceptron.SequenceInfo, error) {
   162  	sequenceInfo := &perceptron.SequenceInfo{
   163  		Cache:      perceptron.DefaultSequenceCacheBool,
   164  		Cycle:      perceptron.DefaultSequenceCycleBool,
   165  		CacheValue: perceptron.DefaultSequenceCacheValue,
   166  		Increment:  perceptron.DefaultSequenceIncrementValue,
   167  	}
   168  
   169  	// Handle causet comment options.
   170  	for _, op := range stmt.TblOptions {
   171  		switch op.Tp {
   172  		case ast.BlockOptionComment:
   173  			sequenceInfo.Comment = op.StrValue
   174  		case ast.BlockOptionEngine:
   175  			// BlockOptionEngine will always be 'InnoDB', thus we do nothing in this branch to avoid error happening.
   176  		default:
   177  			return nil, ErrSequenceUnsupportedBlockOption.GenWithStackByArgs(op.StrValue)
   178  		}
   179  	}
   180  	handleSequenceOptions(stmt.SeqOptions, sequenceInfo)
   181  	if !validateSequenceOptions(sequenceInfo) {
   182  		return nil, ErrSequenceInvalidData.GenWithStackByArgs(ident.Schema.L, ident.Name.L)
   183  	}
   184  	return sequenceInfo, nil
   185  }