Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sql: initial support for virtual columns #57803

Merged
merged 1 commit into from
Dec 12, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/generated/settings/settings.html
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,6 @@
<tr><td><code>trace.debug.enable</code></td><td>boolean</td><td><code>false</code></td><td>if set, traces for recent requests can be seen in the /debug page</td></tr>
<tr><td><code>trace.lightstep.token</code></td><td>string</td><td><code></code></td><td>if set, traces go to Lightstep using this token</td></tr>
<tr><td><code>trace.zipkin.collector</code></td><td>string</td><td><code></code></td><td>if set, traces go to the given Zipkin instance (example: '127.0.0.1:9411'); ignored if trace.lightstep.token is set</td></tr>
<tr><td><code>version</code></td><td>version</td><td><code>20.2-6</code></td><td>set the active cluster version in the format '<major>.<minor>'</td></tr>
<tr><td><code>version</code></td><td>version</td><td><code>20.2-8</code></td><td>set the active cluster version in the format '<major>.<minor>'</td></tr>
</tbody>
</table>
6 changes: 6 additions & 0 deletions pkg/clusterversion/cockroach_versions.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,8 @@ const (
// UniqueWithoutIndexConstraints is when adding UNIQUE WITHOUT INDEX
// constraints is supported.
UniqueWithoutIndexConstraints
// VirtualComputedColumns is when virtual computed columns are supported.
VirtualComputedColumns

// Step (1): Add new versions here.
)
Expand Down Expand Up @@ -328,6 +330,10 @@ var versionsSingleton = keyedVersions([]keyedVersion{
Key: UniqueWithoutIndexConstraints,
Version: roachpb.Version{Major: 20, Minor: 2, Internal: 6},
},
{
Key: VirtualComputedColumns,
Version: roachpb.Version{Major: 20, Minor: 2, Internal: 8},
},

// Step (2): Add new versions here.
})
Expand Down
5 changes: 3 additions & 2 deletions pkg/clusterversion/key_string.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

715 changes: 376 additions & 339 deletions pkg/sql/catalog/descpb/structured.pb.go

Large diffs are not rendered by default.

8 changes: 7 additions & 1 deletion pkg/sql/catalog/descpb/structured.proto
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,8 @@ message ColumnDescriptor {
option (gogoproto.equal) = true;
optional string name = 1 [(gogoproto.nullable) = false];
optional uint32 id = 2 [(gogoproto.nullable) = false,
(gogoproto.customname) = "ID", (gogoproto.casttype) = "ColumnID"];
(gogoproto.customname) = "ID",
(gogoproto.casttype) = "ColumnID"];
optional sql.sem.types.T type = 3;
optional bool nullable = 4 [(gogoproto.nullable) = false];
reserved 8;
Expand All @@ -142,6 +143,11 @@ message ColumnDescriptor {
// have been serialized in a internal format. Instead, use one of the
// schemaexpr.FormatExpr* functions.
optional string compute_expr = 11;

// A computed column can be stored or virtual.
// Virtual can only be true if there is a compute expression.
optional bool virtual = 16 [(gogoproto.nullable) = false];

// PGAttributeNum must be accessed through the accessor, since it is set
// lazily, it is incorrect to access it directly.
// PGAttributeNum represents a column's number in catalog tables.
Expand Down
6 changes: 5 additions & 1 deletion pkg/sql/catalog/schemaexpr/column.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,11 @@ func FormatColumnForDisplay(
return "", err
}
f.WriteString(compExpr)
f.WriteString(") STORED")
if desc.Virtual {
f.WriteString(") VIRTUAL")
} else {
f.WriteString(") STORED")
}
}
return f.CloseAndGetString(), nil
}
Expand Down
48 changes: 33 additions & 15 deletions pkg/sql/catalog/tabledesc/structured.go
Original file line number Diff line number Diff line change
Expand Up @@ -1316,6 +1316,10 @@ func (desc *Mutable) allocateColumnFamilyIDs(columnNames map[string]descpb.Colum
}

ensureColumnInFamily := func(col *descpb.ColumnDescriptor) {
if col.Virtual {
// Virtual columns don't need to be part of families.
return
}
if columnsInFamilies.Contains(col.ID) {
return
}
Expand Down Expand Up @@ -1944,7 +1948,7 @@ func (desc *Immutable) ValidateTable(ctx context.Context) error {
}

columnNames := make(map[string]descpb.ColumnID, len(desc.Columns))
columnIDs := make(map[descpb.ColumnID]string, len(desc.Columns))
columnIDs := make(map[descpb.ColumnID]*descpb.ColumnDescriptor, len(desc.Columns))
if err := desc.validateColumns(columnNames, columnIDs); err != nil {
return err
}
Expand All @@ -1959,7 +1963,7 @@ func (desc *Immutable) ValidateTable(ctx context.Context) error {
"mutation in state %s, direction %s, col %q, id %v",
errors.Safe(m.State), errors.Safe(m.Direction), col.Name, errors.Safe(col.ID))
}
columnIDs[col.ID] = col.Name
columnIDs[col.ID] = col
case *descpb.DescriptorMutation_Index:
if unSetEnums {
idx := desc.Index
Expand Down Expand Up @@ -2080,9 +2084,12 @@ func (desc *Immutable) ValidateTable(ctx context.Context) error {
}

func (desc *Immutable) validateColumns(
columnNames map[string]descpb.ColumnID, columnIDs map[descpb.ColumnID]string,
columnNames map[string]descpb.ColumnID, columnIDs map[descpb.ColumnID]*descpb.ColumnDescriptor,
) error {
for _, column := range desc.AllNonDropColumns() {
colDescs := desc.AllNonDropColumns()
for colIdx := range colDescs {
column := &colDescs[colIdx]

if err := catalog.ValidateName(column.Name, "column"); err != nil {
return err
}
Expand All @@ -2108,9 +2115,9 @@ func (desc *Immutable) validateColumns(

if other, ok := columnIDs[column.ID]; ok {
return fmt.Errorf("column %q duplicate ID of column %q: %d",
column.Name, other, column.ID)
column.Name, other.Name, column.ID)
}
columnIDs[column.ID] = column.Name
columnIDs[column.ID] = column

if column.ID >= desc.NextColumnID {
return errors.AssertionFailedf("column %q invalid ID (%d) >= next column ID (%d)",
Expand All @@ -2131,12 +2138,16 @@ func (desc *Immutable) validateColumns(
return fmt.Errorf("computed column %q refers to unknown columns in expression: %s",
column.Name, *column.ComputeExpr)
}
} else if column.Virtual {
return fmt.Errorf("virtual column %q is not computed", column.Name)
}
}
return nil
}

func (desc *Immutable) validateColumnFamilies(columnIDs map[descpb.ColumnID]string) error {
func (desc *Immutable) validateColumnFamilies(
columnIDs map[descpb.ColumnID]*descpb.ColumnDescriptor,
) error {
if len(desc.Families) < 1 {
return fmt.Errorf("at least 1 column family must be specified")
}
Expand Down Expand Up @@ -2184,13 +2195,16 @@ func (desc *Immutable) validateColumnFamilies(columnIDs map[descpb.ColumnID]stri
}

for i, colID := range family.ColumnIDs {
name, ok := columnIDs[colID]
col, ok := columnIDs[colID]
if !ok {
return fmt.Errorf("family %q contains unknown column \"%d\"", family.Name, colID)
}
if name != family.ColumnNames[i] {
if col.Name != family.ColumnNames[i] {
return fmt.Errorf("family %q column %d should have name %q, but found name %q",
family.Name, colID, name, family.ColumnNames[i])
family.Name, colID, col.Name, family.ColumnNames[i])
}
if col.Virtual {
return fmt.Errorf("virtual computed column %q cannot be part of a family", col.Name)
}
}

Expand All @@ -2201,9 +2215,11 @@ func (desc *Immutable) validateColumnFamilies(columnIDs map[descpb.ColumnID]stri
colIDToFamilyID[colID] = family.ID
}
}
for colID := range columnIDs {
if _, ok := colIDToFamilyID[colID]; !ok {
return fmt.Errorf("column %d is not in any column family", colID)
for colID, colDesc := range columnIDs {
if !colDesc.Virtual {
if _, ok := colIDToFamilyID[colID]; !ok {
return fmt.Errorf("column %q is not in any column family", colDesc.Name)
}
}
}
return nil
Expand All @@ -2212,7 +2228,9 @@ func (desc *Immutable) validateColumnFamilies(columnIDs map[descpb.ColumnID]stri
// validateCheckConstraints validates that check constraints are well formed.
// Checks include validating the column IDs and verifying that check expressions
// do not reference non-existent columns.
func (desc *Immutable) validateCheckConstraints(columnIDs map[descpb.ColumnID]string) error {
func (desc *Immutable) validateCheckConstraints(
columnIDs map[descpb.ColumnID]*descpb.ColumnDescriptor,
) error {
for _, chk := range desc.AllActiveAndInactiveChecks() {
// Verify that the check's column IDs are valid.
for _, colID := range chk.ColumnIDs {
Expand Down Expand Up @@ -2243,7 +2261,7 @@ func (desc *Immutable) validateCheckConstraints(columnIDs map[descpb.ColumnID]st
// constraints are well formed. Checks include validating the column IDs and
// column names.
func (desc *Immutable) validateUniqueWithoutIndexConstraints(
columnIDs map[descpb.ColumnID]string,
columnIDs map[descpb.ColumnID]*descpb.ColumnDescriptor,
) error {
for _, c := range desc.AllActiveAndInactiveUniqueWithoutIndexConstraints() {
if err := catalog.ValidateName(c.Name, "unique without index constraint"); err != nil {
Expand Down
33 changes: 32 additions & 1 deletion pkg/sql/catalog/tabledesc/structured_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,8 @@ func TestValidateTableDesc(t *testing.T) {

ctx := context.Background()

computedExpr := "1 + 1"

testData := []struct {
err string
desc descpb.TableDescriptor
Expand Down Expand Up @@ -232,6 +234,18 @@ func TestValidateTableDesc(t *testing.T) {
},
NextColumnID: 2,
}},
{`virtual column "virt" is not computed`,
descpb.TableDescriptor{
ID: 2,
ParentID: 1,
Name: "foo",
FormatVersion: descpb.FamilyFormatVersion,
Columns: []descpb.ColumnDescriptor{
{ID: 1, Name: "bar"},
{ID: 2, Name: "virt", Virtual: true},
},
NextColumnID: 3,
}},
{`invalid column ID 0`,
descpb.TableDescriptor{
ID: 2,
Expand Down Expand Up @@ -400,7 +414,7 @@ func TestValidateTableDesc(t *testing.T) {
NextColumnID: 2,
NextFamilyID: 1,
}},
{`column 1 is not in any column family`,
{`column "bar" is not in any column family`,
descpb.TableDescriptor{
ID: 2,
ParentID: 1,
Expand Down Expand Up @@ -431,6 +445,23 @@ func TestValidateTableDesc(t *testing.T) {
NextColumnID: 2,
NextFamilyID: 2,
}},
{`virtual computed column "virt" cannot be part of a family`,
descpb.TableDescriptor{
ID: 2,
ParentID: 1,
Name: "foo",
FormatVersion: descpb.FamilyFormatVersion,
Columns: []descpb.ColumnDescriptor{
{ID: 1, Name: "bar"},
{ID: 2, Name: "virt", ComputeExpr: &computedExpr, Virtual: true},
},
Families: []descpb.ColumnFamilyDescriptor{
{ID: 0, Name: "fam1", ColumnIDs: []descpb.ColumnID{1}, ColumnNames: []string{"bar"}},
{ID: 1, Name: "fam2", ColumnIDs: []descpb.ColumnID{2}, ColumnNames: []string{"virt"}},
},
NextColumnID: 3,
NextFamilyID: 2,
}},
{`table must contain a primary key`,
descpb.TableDescriptor{
ID: 2,
Expand Down
1 change: 1 addition & 0 deletions pkg/sql/catalog/tabledesc/table.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ func MakeColumnDefDescs(
col := &descpb.ColumnDescriptor{
Name: string(d.Name),
Nullable: d.Nullable.Nullability != tree.NotNull && !d.PrimaryKey.IsPrimaryKey,
Virtual: d.IsVirtual(),
}

// Validate and assign column type.
Expand Down
1 change: 1 addition & 0 deletions pkg/sql/catalog/tabledesc/validate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ var validationMap = []struct {
status: todoIAmKnowinglyAddingTechDebt,
reason: "initial import: TODO(features): add validation"},
"ComputeExpr": {status: iSolemnlySwearThisFieldIsValidated},
"Virtual": {status: iSolemnlySwearThisFieldIsValidated},
"PGAttributeNum": {
status: todoIAmKnowinglyAddingTechDebt,
reason: "initial import: TODO(features): add validation"},
Expand Down
18 changes: 16 additions & 2 deletions pkg/sql/create_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -1399,7 +1399,17 @@ func NewTableDesc(
columnDefaultExprs = append(columnDefaultExprs, nil)
}
if d.IsVirtual() {
return nil, unimplemented.NewWithIssue(57608, "virtual computed columns")
if !sessionData.VirtualColumnsEnabled {
return nil, unimplemented.NewWithIssue(57608, "virtual computed columns")
}
if !evalCtx.Settings.Version.IsActive(ctx, clusterversion.VirtualComputedColumns) {
return nil, pgerror.Newf(pgcode.FeatureNotSupported,
"version %v must be finalized to use virtual columns",
clusterversion.VirtualComputedColumns)
}
if d.HasColumnFamily() {
return nil, pgerror.Newf(pgcode.Syntax, "virtual columns cannot have family specifications")
}
}

col, idx, expr, err := tabledesc.MakeColumnDefDescs(ctx, d, semaCtx, evalCtx)
Expand Down Expand Up @@ -2279,7 +2289,11 @@ func incTelemetryForNewColumn(def *tree.ColumnTableDef, desc *descpb.ColumnDescr
telemetry.Inc(sqltelemetry.SchemaNewTypeCounter(desc.Type.TelemetryName()))
}
if desc.IsComputed() {
telemetry.Inc(sqltelemetry.SchemaNewColumnTypeQualificationCounter("computed"))
if desc.Virtual {
telemetry.Inc(sqltelemetry.SchemaNewColumnTypeQualificationCounter("virtual"))
} else {
telemetry.Inc(sqltelemetry.SchemaNewColumnTypeQualificationCounter("computed"))
}
}
if desc.HasDefault() {
telemetry.Inc(sqltelemetry.SchemaNewColumnTypeQualificationCounter("default_expr"))
Expand Down
5 changes: 5 additions & 0 deletions pkg/sql/exec_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -2188,6 +2188,11 @@ func (m *sessionDataMutator) SetMutliColumnInvertedIndexes(val bool) {
m.data.EnableMultiColumnInvertedIndexes = val
}

// TODO(radu): remove this once the feature is stable.
func (m *sessionDataMutator) SetVirtualColumnsEnabled(val bool) {
m.data.VirtualColumnsEnabled = val
}

// TODO(rytaft): remove this once unique without index constraints are fully
// supported.
func (m *sessionDataMutator) SetUniqueWithoutIndexConstraints(val bool) {
Expand Down
3 changes: 3 additions & 0 deletions pkg/sql/logictest/testdata/logic_test/pg_catalog
Original file line number Diff line number Diff line change
Expand Up @@ -1894,6 +1894,7 @@ experimental_enable_hash_sharded_indexes off NULL
experimental_enable_multi_column_inverted_indexes off NULL NULL NULL string
experimental_enable_temp_tables off NULL NULL NULL string
experimental_enable_unique_without_index_constraints off NULL NULL NULL string
experimental_enable_virtual_columns off NULL NULL NULL string
extra_float_digits 0 NULL NULL NULL string
force_savepoint_restart off NULL NULL NULL string
foreign_key_cascades_limit 10000 NULL NULL NULL string
Expand Down Expand Up @@ -1967,6 +1968,7 @@ experimental_enable_hash_sharded_indexes off NULL
experimental_enable_multi_column_inverted_indexes off NULL user NULL off off
experimental_enable_temp_tables off NULL user NULL off off
experimental_enable_unique_without_index_constraints off NULL user NULL off off
experimental_enable_virtual_columns off NULL user NULL off off
extra_float_digits 0 NULL user NULL 0 2
force_savepoint_restart off NULL user NULL off off
foreign_key_cascades_limit 10000 NULL user NULL 10000 10000
Expand Down Expand Up @@ -2036,6 +2038,7 @@ experimental_enable_hash_sharded_indexes NULL NULL NULL
experimental_enable_multi_column_inverted_indexes NULL NULL NULL NULL NULL
experimental_enable_temp_tables NULL NULL NULL NULL NULL
experimental_enable_unique_without_index_constraints NULL NULL NULL NULL NULL
experimental_enable_virtual_columns NULL NULL NULL NULL NULL
extra_float_digits NULL NULL NULL NULL NULL
force_savepoint_restart NULL NULL NULL NULL NULL
foreign_key_cascades_limit NULL NULL NULL NULL NULL
Expand Down
1 change: 1 addition & 0 deletions pkg/sql/logictest/testdata/logic_test/show_source
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ experimental_enable_hash_sharded_indexes off
experimental_enable_multi_column_inverted_indexes off
experimental_enable_temp_tables off
experimental_enable_unique_without_index_constraints off
experimental_enable_virtual_columns off
extra_float_digits 0
force_savepoint_restart off
foreign_key_cascades_limit 10000
Expand Down
Loading