-
Notifications
You must be signed in to change notification settings - Fork 3.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
84034: sql: add sequence option info for identity columns under information_schema r=rafiss a=ZhouXing19 Previously, for a column created with the `GENERATED ... AS IDENTITY (seq_options)` syntax, the info for the sequence option is not saved in the information schema. This commit is to fix it. We parse the sequence options saved as a string in the the descriptor, so that it's much easier to extract specific options such as sequence's start value or increment size. To make sure that we get the same sequence option to generate the sequence, we reuse `assignSequenceOptions()` by breaking it into several helper functions. fixes #82064 fixes #83208 Release note (sql): add sequence option info for identity columns under information_schema 84389: sql: fix auto-retries for upgraded transactions r=ZhouXing19 a=rafiss This is implemented by adding more state to the conn executor state machine. Now, it tracks if the open transaction was upgraded from an implicit to an explicit txn. If so, when doing an auto retry, the transaction is marked as an implicit again, so that the statements in the transaction can upgrade it to explicit. No release note is needed for v22.2, but we should use the following note when backporting to v22.1. Placeholder note (bug fix): Fixed a bug where some statements in a batch would not get executed if the following conditions were met: - A batch of statements is sent in a single string. - A BEGIN statement appears in the middle of the batch. - The enable_implicit_transaction_for_batch_statements session variable is set to true. (This defaults to false in v22.1.x) This bug was introduced in v22.1.2. (#82681) Release note: None 84575: sql/schemachanger/sctest: don't rewrite if not enabled r=ajwerner a=ajwerner This commit changes the explain diagram testing to check the output as opposed to unconditionally rewriting. Before this change, the bazel build was broken because the sandbox was not writable. Also, we weren't actually testing anything. Release note: None Co-authored-by: Jane Xing <[email protected]> Co-authored-by: Rafi Shamim <[email protected]> Co-authored-by: Andrew Werner <[email protected]>
- Loading branch information
Showing
19 changed files
with
1,012 additions
and
370 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,322 @@ | ||
// Copyright 2022 The Cockroach Authors. | ||
// | ||
// Use of this software is governed by the Business Source License | ||
// included in the file licenses/BSL.txt. | ||
// | ||
// As of the Change Date specified in that file, in accordance with | ||
// the Business Source License, use of this software will be governed | ||
// by the Apache License, Version 2.0, included in the file | ||
// licenses/APL.txt. | ||
|
||
package schemaexpr | ||
|
||
import ( | ||
"math" | ||
|
||
"github.com/cockroachdb/cockroach/pkg/sql/catalog/descpb" | ||
"github.com/cockroachdb/cockroach/pkg/sql/parser" | ||
"github.com/cockroachdb/cockroach/pkg/sql/sem/tree" | ||
"github.com/cockroachdb/cockroach/pkg/sql/types" | ||
"github.com/cockroachdb/cockroach/pkg/util/errorutil/unimplemented" | ||
"github.com/cockroachdb/errors" | ||
) | ||
|
||
// ParseSequenceOpts is to transform the sequence options saved the | ||
// descriptor to a descpb.TableDescriptor_SequenceOpts. | ||
// Note that this function is used to acquire the sequence option for the | ||
// information schema table, so it doesn't parse for the sequence owner info. | ||
func ParseSequenceOpts(s string) (*descpb.TableDescriptor_SequenceOpts, error) { | ||
stmt, err := parser.ParseOne("CREATE SEQUENCE fake_seq " + s) | ||
if err != nil { | ||
return nil, errors.Wrap(err, "cannot parse sequence option") | ||
} | ||
|
||
createSeqNode, ok := stmt.AST.(*tree.CreateSequence) | ||
if !ok { | ||
return nil, errors.New("cannot convert parsed result to tree.CreateSequence") | ||
} | ||
|
||
opts := &descpb.TableDescriptor_SequenceOpts{ | ||
Increment: 1, | ||
} | ||
if err := AssignSequenceOptions( | ||
opts, | ||
createSeqNode.Options, | ||
true, /* setDefaults */ | ||
nil, /* existingType */ | ||
); err != nil { | ||
return nil, err | ||
} | ||
|
||
return opts, nil | ||
} | ||
|
||
func getSequenceIntegerBounds( | ||
integerType *types.T, | ||
) (lowerIntBound int64, upperIntBound int64, err error) { | ||
switch integerType { | ||
case types.Int2: | ||
return math.MinInt16, math.MaxInt16, nil | ||
case types.Int4: | ||
return math.MinInt32, math.MaxInt32, nil | ||
case types.Int: | ||
return math.MinInt64, math.MaxInt64, nil | ||
} | ||
|
||
return 0, 0, errors.AssertionFailedf( | ||
"CREATE SEQUENCE option AS received type %s, must be integer", | ||
integerType, | ||
) | ||
} | ||
|
||
func setSequenceIntegerBounds( | ||
opts *descpb.TableDescriptor_SequenceOpts, | ||
integerType *types.T, | ||
isAscending bool, | ||
setMinValue bool, | ||
setMaxValue bool, | ||
) error { | ||
var minValue int64 = math.MinInt64 | ||
var maxValue int64 = math.MaxInt64 | ||
|
||
if isAscending { | ||
minValue = 1 | ||
|
||
switch integerType { | ||
case types.Int2: | ||
maxValue = math.MaxInt16 | ||
case types.Int4: | ||
maxValue = math.MaxInt32 | ||
case types.Int: | ||
// Do nothing, it's the default. | ||
default: | ||
return errors.AssertionFailedf( | ||
"CREATE SEQUENCE option AS received type %s, must be integer", | ||
integerType, | ||
) | ||
} | ||
} else { | ||
maxValue = -1 | ||
switch integerType { | ||
case types.Int2: | ||
minValue = math.MinInt16 | ||
case types.Int4: | ||
minValue = math.MinInt32 | ||
case types.Int: | ||
// Do nothing, it's the default. | ||
default: | ||
return errors.AssertionFailedf( | ||
"CREATE SEQUENCE option AS received type %s, must be integer", | ||
integerType, | ||
) | ||
} | ||
} | ||
if setMinValue { | ||
opts.MinValue = minValue | ||
} | ||
if setMaxValue { | ||
opts.MaxValue = maxValue | ||
} | ||
return nil | ||
} | ||
|
||
// AssignSequenceOptions moves options from the AST node to the sequence options descriptor, | ||
// starting with defaults and overriding them with user-provided options. | ||
func AssignSequenceOptions( | ||
opts *descpb.TableDescriptor_SequenceOpts, | ||
optsNode tree.SequenceOptions, | ||
setDefaults bool, | ||
existingType *types.T, | ||
) error { | ||
wasAscending := opts.Increment > 0 | ||
|
||
// Set the default integer type of a sequence. | ||
var integerType = types.Int | ||
// All other defaults are dependent on the value of increment | ||
// and the AS integerType. (i.e. whether the sequence is ascending | ||
// or descending, bigint vs. smallint) | ||
for _, option := range optsNode { | ||
if option.Name == tree.SeqOptIncrement { | ||
opts.Increment = *option.IntVal | ||
} else if option.Name == tree.SeqOptAs { | ||
integerType = option.AsIntegerType | ||
opts.AsIntegerType = integerType.SQLString() | ||
} | ||
} | ||
if opts.Increment == 0 { | ||
return errors.New("INCREMENT must not be zero") | ||
} | ||
isAscending := opts.Increment > 0 | ||
|
||
// Set increment-dependent defaults. | ||
if setDefaults { | ||
if isAscending { | ||
opts.MinValue = 1 | ||
opts.MaxValue = math.MaxInt64 | ||
opts.Start = opts.MinValue | ||
} else { | ||
opts.MinValue = math.MinInt64 | ||
opts.MaxValue = -1 | ||
opts.Start = opts.MaxValue | ||
} | ||
opts.CacheSize = 1 | ||
} | ||
|
||
lowerIntBound, upperIntBound, err := getSequenceIntegerBounds(integerType) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
// Set default MINVALUE and MAXVALUE if AS option value for integer type is specified. | ||
if opts.AsIntegerType != "" { | ||
// We change MINVALUE and MAXVALUE if it is the originally set to the default during ALTER. | ||
setMinValue := setDefaults | ||
setMaxValue := setDefaults | ||
if !setDefaults && existingType != nil { | ||
existingLowerIntBound, existingUpperIntBound, err := getSequenceIntegerBounds(existingType) | ||
if err != nil { | ||
return err | ||
} | ||
if (wasAscending && opts.MinValue == 1) || (!wasAscending && opts.MinValue == existingLowerIntBound) { | ||
setMinValue = true | ||
} | ||
if (wasAscending && opts.MaxValue == existingUpperIntBound) || (!wasAscending && opts.MaxValue == -1) { | ||
setMaxValue = true | ||
} | ||
} | ||
|
||
if err := setSequenceIntegerBounds( | ||
opts, | ||
integerType, | ||
isAscending, | ||
setMinValue, | ||
setMaxValue, | ||
); err != nil { | ||
return err | ||
} | ||
} | ||
|
||
// Fill in all other options. | ||
var restartVal *int64 | ||
optionsSeen := map[string]bool{} | ||
for _, option := range optsNode { | ||
// Error on duplicate options. | ||
_, seenBefore := optionsSeen[option.Name] | ||
if seenBefore { | ||
return errors.New("conflicting or redundant options") | ||
} | ||
optionsSeen[option.Name] = true | ||
|
||
switch option.Name { | ||
case tree.SeqOptCycle: | ||
return unimplemented.NewWithIssue(20961, | ||
"CYCLE option is not supported") | ||
case tree.SeqOptNoCycle: | ||
// Do nothing; this is the default. | ||
case tree.SeqOptCache: | ||
if v := *option.IntVal; v >= 1 { | ||
opts.CacheSize = v | ||
} else { | ||
return errors.Newf( | ||
"CACHE (%d) must be greater than zero", v) | ||
} | ||
case tree.SeqOptIncrement: | ||
// Do nothing; this has already been set. | ||
case tree.SeqOptMinValue: | ||
// A value of nil represents the user explicitly saying `NO MINVALUE`. | ||
if option.IntVal != nil { | ||
opts.MinValue = *option.IntVal | ||
} | ||
case tree.SeqOptMaxValue: | ||
// A value of nil represents the user explicitly saying `NO MAXVALUE`. | ||
if option.IntVal != nil { | ||
opts.MaxValue = *option.IntVal | ||
} | ||
case tree.SeqOptStart: | ||
opts.Start = *option.IntVal | ||
case tree.SeqOptRestart: | ||
// The RESTART option does not get saved, but still gets validated below. | ||
restartVal = option.IntVal | ||
case tree.SeqOptVirtual: | ||
opts.Virtual = true | ||
} | ||
} | ||
|
||
if setDefaults || (wasAscending && opts.Start == 1) || (!wasAscending && opts.Start == -1) { | ||
// If start option not specified, set it to MinValue (for ascending sequences) | ||
// or MaxValue (for descending sequences). | ||
// We only do this if we're setting it for the first time, or the sequence was | ||
// ALTERed with the default original values. | ||
if _, startSeen := optionsSeen[tree.SeqOptStart]; !startSeen { | ||
if opts.Increment > 0 { | ||
opts.Start = opts.MinValue | ||
} else { | ||
opts.Start = opts.MaxValue | ||
} | ||
} | ||
} | ||
|
||
if opts.MinValue < lowerIntBound { | ||
return errors.Newf( | ||
"MINVALUE (%d) must be greater than (%d) for type %s", | ||
opts.MinValue, | ||
lowerIntBound, | ||
integerType.SQLString(), | ||
) | ||
} | ||
if opts.MaxValue < lowerIntBound { | ||
return errors.Newf( | ||
"MAXVALUE (%d) must be greater than (%d) for type %s", | ||
opts.MaxValue, | ||
lowerIntBound, | ||
integerType.SQLString(), | ||
) | ||
} | ||
if opts.MinValue > upperIntBound { | ||
return errors.Newf( | ||
"MINVALUE (%d) must be less than (%d) for type %s", | ||
opts.MinValue, | ||
upperIntBound, | ||
integerType.SQLString(), | ||
) | ||
} | ||
if opts.MaxValue > upperIntBound { | ||
return errors.Newf( | ||
"MAXVALUE (%d) must be less than (%d) for type %s", | ||
opts.MaxValue, | ||
upperIntBound, | ||
integerType.SQLString(), | ||
) | ||
} | ||
if opts.Start > opts.MaxValue { | ||
return errors.Newf( | ||
"START value (%d) cannot be greater than MAXVALUE (%d)", | ||
opts.Start, | ||
opts.MaxValue, | ||
) | ||
} | ||
if opts.Start < opts.MinValue { | ||
return errors.Newf( | ||
"START value (%d) cannot be less than MINVALUE (%d)", | ||
opts.Start, | ||
opts.MinValue, | ||
) | ||
} | ||
if restartVal != nil { | ||
if *restartVal > opts.MaxValue { | ||
return errors.Newf( | ||
"RESTART value (%d) cannot be greater than MAXVALUE (%d)", | ||
*restartVal, | ||
opts.MaxValue, | ||
) | ||
} | ||
if *restartVal < opts.MinValue { | ||
return errors.Newf( | ||
"RESTART value (%d) cannot be less than MINVALUE (%d)", | ||
*restartVal, | ||
opts.MinValue, | ||
) | ||
} | ||
} | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.