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: adding version gates for changes related to JSON forward indexes #101932

Merged
merged 1 commit into from
May 22, 2023
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
34 changes: 32 additions & 2 deletions pkg/sql/create_index.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ func makeIndexDescriptor(
return nil, pgerror.Newf(pgcode.DuplicateRelation, "index with name %q already exists", n.Name)
}

if err := checkIndexColumns(tableDesc, columns, n.Storing, n.Inverted); err != nil {
if err := checkIndexColumns(tableDesc, columns, n.Storing, n.Inverted, params.ExecCfg().Settings.Version.ActiveVersion(params.ctx)); err != nil {
return nil, err
}

Expand Down Expand Up @@ -319,7 +319,11 @@ func makeIndexDescriptor(
}

func checkIndexColumns(
desc catalog.TableDescriptor, columns tree.IndexElemList, storing tree.NameList, inverted bool,
desc catalog.TableDescriptor,
columns tree.IndexElemList,
storing tree.NameList,
inverted bool,
version clusterversion.ClusterVersion,
) error {
for i, colDef := range columns {
col, err := catalog.MustFindColumnByTreeName(desc, colDef.Column)
Expand All @@ -336,6 +340,20 @@ func checkIndexColumns(
return pgerror.New(pgcode.DatatypeMismatch,
"operator classes are only allowed for the last column of an inverted index")
}

// Checking if JSON Columns can be forward indexed for a given cluster version.
if col.GetType().Family() == types.JsonFamily && !inverted && !version.IsActive(clusterversion.V23_2) {
return errors.WithHint(
pgerror.Newf(
pgcode.InvalidTableDefinition,
"index element %s of type %s is not indexable in a non-inverted index",
col.GetName(),
col.GetType().Name(),
),
"you may want to create an inverted index instead. See the documentation for inverted indexes: "+docs.URL("inverted-indexes.html"),
)
}

}
for i, colName := range storing {
col, err := catalog.MustFindColumnByTreeName(desc, colName)
Expand Down Expand Up @@ -544,6 +562,18 @@ func replaceExpressionElemsWithVirtualCols(
)
}

if typ.Family() == types.JsonFamily && !version.IsActive(clusterversion.V23_2) {
return errors.WithHint(
pgerror.Newf(
pgcode.InvalidTableDefinition,
"index element %s of type %s is not indexable in a non-inverted index",
elem.Expr.String(),
typ.Name(),
),
"you may want to create an inverted index instead. See the documentation for inverted indexes: "+docs.URL("inverted-indexes.html"),
)
}

if !isInverted && !colinfo.ColumnTypeIsIndexable(typ) {
if colinfo.ColumnTypeIsInvertedIndexable(typ) {
return errors.WithHint(
Expand Down
15 changes: 14 additions & 1 deletion pkg/sql/create_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -1602,6 +1602,19 @@ func NewTableDesc(
incTelemetryForNewColumn(d, col)
}

// Version gates for enabling primary keys for JSONB columns
if col.Type.Family() == types.JsonFamily && d.PrimaryKey.IsPrimaryKey && !version.IsActive(clusterversion.V23_2) {
return nil, errors.WithHint(
pgerror.Newf(
pgcode.InvalidTableDefinition,
"index element %s of type %s is not indexable in a non-inverted index",
col.Name,
col.Type.Name(),
),
"you may want to create an inverted index instead. See the documentation for inverted indexes: "+docs.URL("inverted-indexes.html"),
)
}

desc.AddColumn(col)

if idx != nil {
Expand Down Expand Up @@ -1786,7 +1799,7 @@ func NewTableDesc(
); err != nil {
return nil, err
}
if err := checkIndexColumns(&desc, d.Columns, d.Storing, d.Inverted); err != nil {
if err := checkIndexColumns(&desc, d.Columns, d.Storing, d.Inverted, version); err != nil {
return nil, err
}
if !version.IsActive(clusterversion.V23_2_PartiallyVisibleIndexes) &&
Expand Down
2 changes: 2 additions & 0 deletions pkg/sql/logictest/testdata/logic_test/expression_index
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# LogicTest: default-configs !local-mixed-22.2-23.1

statement ok
CREATE TABLE t (
k INT PRIMARY KEY,
Expand Down
1 change: 1 addition & 0 deletions pkg/sql/logictest/testdata/logic_test/json
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ SELECT bar FROM foo WHERE bar->'a' = '"b"'::JSON
statement ok
SELECT bar FROM foo ORDER BY bar

skipif config local-mixed-22.2-23.1
statement ok
CREATE TABLE pk (k JSON PRIMARY KEY)

Expand Down
2 changes: 2 additions & 0 deletions pkg/sql/logictest/testdata/logic_test/json_index
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# LogicTest: default-configs !local-mixed-22.2-23.1

# Add JSON columns as primary index.
statement ok
CREATE TABLE t (x JSONB PRIMARY KEY)
Expand Down
14 changes: 0 additions & 14 deletions pkg/sql/logictest/tests/local-mixed-22.2-23.1/generated_test.go

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

Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,7 @@ func processColNodeType(
})
}
// Only certain column types are supported for inverted indexes.
version := b.EvalCtx().Settings.Version.ActiveVersion(b)
if n.Inverted && lastColIdx &&
!colinfo.ColumnTypeIsInvertedIndexable(columnType.Type) {
colNameForErr := colName
Expand All @@ -385,7 +386,8 @@ func processColNodeType(
panic(tabledesc.NewInvalidInvertedColumnError(colNameForErr,
columnType.Type.String()))
} else if (!n.Inverted || !lastColIdx) &&
!colinfo.ColumnTypeIsIndexable(columnType.Type) {
(!colinfo.ColumnTypeIsIndexable(columnType.Type) ||
(columnType.Type.Family() == types.JsonFamily && !version.IsActive(clusterversion.V23_2))) {
// Otherwise, check if the column type is indexable.
panic(unimplemented.NewWithIssueDetailf(35730,
columnType.Type.DebugString(),
Expand Down
1 change: 1 addition & 0 deletions pkg/upgrade/upgrades/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ go_test(
"ensure_sql_schema_telemetry_schedule_test.go",
"external_connections_table_user_id_migration_test.go",
"helpers_test.go",
"json_forward_indexes_test.go",
"key_visualizer_migration_test.go",
"main_test.go",
"role_members_ids_migration_test.go",
Expand Down
147 changes: 147 additions & 0 deletions pkg/upgrade/upgrades/json_forward_indexes_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
// Copyright 2023 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 upgrades_test

import (
"context"
"testing"

"github.com/cockroachdb/cockroach/pkg/base"
"github.com/cockroachdb/cockroach/pkg/clusterversion"
"github.com/cockroachdb/cockroach/pkg/server"
"github.com/cockroachdb/cockroach/pkg/settings/cluster"
"github.com/cockroachdb/cockroach/pkg/testutils/skip"
"github.com/cockroachdb/cockroach/pkg/testutils/testcluster"
"github.com/cockroachdb/cockroach/pkg/util/leaktest"
"github.com/stretchr/testify/require"
)

func TestJSONForwardingIndexes(t *testing.T) {
var err error
skip.UnderStressRace(t)
defer leaktest.AfterTest(t)()
ctx := context.Background()

settings := cluster.MakeTestingClusterSettingsWithVersions(
clusterversion.TestingBinaryVersion,
clusterversion.TestingBinaryMinSupportedVersion,
false,
)

tc := testcluster.StartTestCluster(t, 1, base.TestClusterArgs{
ServerArgs: base.TestServerArgs{
Settings: settings,
Knobs: base.TestingKnobs{
Server: &server.TestingKnobs{
DisableAutomaticVersionUpgrade: make(chan struct{}),
BinaryVersionOverride: clusterversion.TestingBinaryMinSupportedVersion,
},
},
},
})
defer tc.Stopper().Stop(ctx)

db := tc.ServerConn(0)
defer db.Close()

// Set the cluster version to 22.2 to test that with the legacy schema changer
// we cannot create forward indexes on JSON columns.
_, err = tc.Conns[0].ExecContext(ctx, `SET CLUSTER SETTING version = $1`,
clusterversion.ByKey(clusterversion.V22_2).String())
require.NoError(t, err)

_, err = db.Exec(`CREATE DATABASE test`)
require.NoError(t, err)

_, err = db.Exec(`CREATE TABLE test.hello (
key INT PRIMARY KEY,
j JSONB
)`)
require.NoError(t, err)

_, err = db.Exec(`INSERT INTO test.hello VALUES (1, '[{"a":"b"}]'::JSONB)`)
require.NoError(t, err)

// Creating an index on the JSON column should result in an error.
_, err = db.Exec(`CREATE INDEX testidx_col on test.hello (j)`)
require.Error(t, err)

// Creating an JSON expression index should result in an error.
_, err = db.Exec(`CREATE INDEX testidx_expr on test.hello ((j->'a'))`)
require.Error(t, err)

// Creating a table with an index on the JSON column should result in an error.
_, err = db.Exec(`CREATE TABLE test.tbl_json_secondary(
j JSONB,
INDEX tbl_json_secondary_idx (j)
)`)
require.Error(t, err)

// Creating a primary key on a JSON column should result in an error.
_, err = db.Exec(`CREATE TABLE test.tbl_json_primary (
key JSONB PRIMARY KEY
)`)
require.Error(t, err)

// Set the cluster version to 23.1 to test that with the declarative schema
// changer we cannot create forward indexes on JSON columns.
_, err = tc.Conns[0].ExecContext(ctx, `SET CLUSTER SETTING version = $1`,
clusterversion.ByKey(clusterversion.V23_1).String())
require.NoError(t, err)

// Creating an index on the JSON column should result in an error.
_, err = db.Exec(`CREATE INDEX on test.hello (j)`)
require.Error(t, err)

// Creating an JSON expression index should result in an error.
_, err = db.Exec(`CREATE INDEX on test.hello ((j->'a'))`)
require.Error(t, err)

// Creating a table with an index on the JSON column should result in an error.
_, err = db.Exec(`CREATE TABLE test.tbl_json_secondary(
j JSONB,
INDEX tbl_json_secondary_idx (j)
)`)
require.Error(t, err)

// Creating a primary key on a JSON column should result in an error.
_, err = db.Exec(`CREATE TABLE test.tbl_json_primary (
key JSONB PRIMARY KEY
)`)
require.Error(t, err)

// Setting a cluster version that supports forward indexes on JSON
// columns and expecting success when creating forward indexes.
_, err = tc.Conns[0].ExecContext(ctx, `SET CLUSTER SETTING version = $1`,
clusterversion.ByKey(clusterversion.V23_2).String())
require.NoError(t, err)

// Creating an index on the JSON column should not result in an error.
_, err = db.Exec(`CREATE INDEX on test.hello (j)`)
require.NoError(t, err)

// Creating an JSON expression index should not result in an error.
_, err = db.Exec(`CREATE INDEX on test.hello ((j->'a'))`)
require.NoError(t, err)

// Creating a table with an index on the JSON column should result in an error.
_, err = db.Exec(`CREATE TABLE test.tbl_json_secondary(
j JSONB,
INDEX tbl_json_secondary_idx (j)
)`)
require.NoError(t, err)

// Creating a primary key on a JSON column should result in an error.
_, err = db.Exec(`CREATE TABLE test.tbl_json_primary (
key JSONB PRIMARY KEY
)`)
require.NoError(t, err)
}