From 8c5959a5d3453cbb2b91eeba68f310beef9f6fd5 Mon Sep 17 00:00:00 2001 From: Rafi Shamim Date: Wed, 1 Feb 2023 17:09:22 -0500 Subject: [PATCH 1/4] importer: add deprecation notice for mysqldump/pgdump Release note (sql change): The PGDUMP and MYSQLDUMP formats for IMPORT were marked as deprecated. They are still present, but will be removed in a future release. The page at https://www.cockroachlabs.com/docs/v22.2/migration-overview shows alternatives. --- pkg/sql/importer/BUILD.bazel | 2 ++ pkg/sql/importer/import_planning.go | 9 ++++++++ pkg/sql/importer/import_stmt_test.go | 33 ++++++++++++++++++++++++++-- 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/pkg/sql/importer/BUILD.bazel b/pkg/sql/importer/BUILD.bazel index bfba28a6bb42..df61b5f80c58 100644 --- a/pkg/sql/importer/BUILD.bazel +++ b/pkg/sql/importer/BUILD.bazel @@ -35,6 +35,7 @@ go_library( "//pkg/cloud/cloudprivilege", "//pkg/clusterversion", "//pkg/col/coldata", + "//pkg/docs", "//pkg/featureflag", "//pkg/geo", "//pkg/geo/geopb", @@ -244,6 +245,7 @@ go_test( "@com_github_fraugster_parquet_go//parquet", "@com_github_go_sql_driver_mysql//:mysql", "@com_github_gogo_protobuf//proto", + "@com_github_jackc_pgconn//:pgconn", "@com_github_jackc_pgx_v4//:pgx", "@com_github_kr_pretty//:pretty", "@com_github_lib_pq//:pq", diff --git a/pkg/sql/importer/import_planning.go b/pkg/sql/importer/import_planning.go index 0de0cd2c75d9..cf76b9a1a9ec 100644 --- a/pkg/sql/importer/import_planning.go +++ b/pkg/sql/importer/import_planning.go @@ -23,6 +23,7 @@ import ( "github.com/cockroachdb/cockroach/pkg/cloud" "github.com/cockroachdb/cockroach/pkg/cloud/cloudprivilege" + "github.com/cockroachdb/cockroach/pkg/docs" "github.com/cockroachdb/cockroach/pkg/featureflag" "github.com/cockroachdb/cockroach/pkg/jobs" "github.com/cockroachdb/cockroach/pkg/jobs/jobspb" @@ -363,6 +364,14 @@ func importPlanHook( p.BufferClientNotice(ctx, pgnotice.Newf("IMPORT TABLE has been deprecated in 21.2, and will be removed in a future version."+ " Instead, use CREATE TABLE with the desired schema, and IMPORT INTO the newly created table.")) } + switch f := strings.ToUpper(importStmt.FileFormat); f { + case "PGDUMP", "MYSQLDUMP": + p.BufferClientNotice(ctx, pgnotice.Newf( + "IMPORT %s has been deprecated in 23.1, and will be removed in a future version. See %s for alternatives.", + redact.SafeString(f), + redact.SafeString(docs.URL("migration-overview")), + )) + } addToFileFormatTelemetry(importStmt.FileFormat, "attempted") diff --git a/pkg/sql/importer/import_stmt_test.go b/pkg/sql/importer/import_stmt_test.go index d07a6ebdbf6a..c685cdb092e2 100644 --- a/pkg/sql/importer/import_stmt_test.go +++ b/pkg/sql/importer/import_stmt_test.go @@ -78,6 +78,7 @@ import ( "github.com/cockroachdb/cockroach/pkg/util/syncutil" "github.com/cockroachdb/cockroach/pkg/util/timeutil" "github.com/cockroachdb/errors" + "github.com/jackc/pgconn" "github.com/jackc/pgx/v4" "github.com/linkedin/goavro/v2" "github.com/stretchr/testify/assert" @@ -1684,6 +1685,23 @@ func TestImportRowLimit(t *testing.T) { conn := tc.ServerConn(0) sqlDB := sqlutils.MakeSQLRunner(conn) + // Also create a pgx connection so we can check notices. + pgURL, cleanup := sqlutils.PGUrl( + t, + tc.Server(0).ServingSQLAddr(), + "TestImportRowLimit", + url.User(username.RootUser), + ) + defer cleanup() + config, err := pgx.ParseConfig(pgURL.String()) + require.NoError(t, err) + var noticeMsg string + config.OnNotice = func(_ *pgconn.PgConn, notice *pgconn.Notice) { + noticeMsg = notice.Message + } + pgxConn, err := pgx.ConnectConfig(ctx, config) + require.NoError(t, err) + avroField := []map[string]interface{}{ { "name": "a", @@ -1864,14 +1882,25 @@ func TestImportRowLimit(t *testing.T) { // Import table from dump format. importDumpQuery := fmt.Sprintf(`IMPORT TABLE t FROM %s ($1) %s`, test.typ, test.with) - sqlDB.Exec(t, importDumpQuery, srv.URL) + _, err := pgxConn.Exec(ctx, importDumpQuery, srv.URL) + require.NoError(t, err) + require.Regexp(t, fmt.Sprintf( + "IMPORT %s has been deprecated in 23.1.*See https://www.cockroachlabs.com/docs/.*/migration-overview for alternatives.", + test.typ, + ), noticeMsg) + sqlDB.CheckQueryResults(t, test.verifyQuery, test.expected) sqlDB.Exec(t, `DROP TABLE t`) // Import dump format directly. importDumpQuery = fmt.Sprintf(`IMPORT %s ($1) %s`, test.typ, test.with) - sqlDB.Exec(t, importDumpQuery, srv.URL) + _, err = pgxConn.Exec(ctx, importDumpQuery, srv.URL) + require.NoError(t, err) + require.Regexp(t, fmt.Sprintf( + "IMPORT %s has been deprecated in 23.1.*See https://www.cockroachlabs.com/docs/.*/migration-overview for alternatives.", + test.typ, + ), noticeMsg) sqlDB.CheckQueryResults(t, test.verifyQuery, test.expected) sqlDB.Exec(t, `DROP TABLE t`) From ef2f612d7f2a3c74d1bae26d879b9d5eaa32f606 Mon Sep 17 00:00:00 2001 From: Rafi Shamim Date: Mon, 6 Feb 2023 14:23:35 -0500 Subject: [PATCH 2/4] roachtest: fix sqlalchemy version pinning The test setup was wrong, and was always using the latest sqlalchemy. This fixes the pinning, and also updates to a newer version. Release note: None --- pkg/cmd/roachtest/tests/sqlalchemy.go | 31 ++++----------------------- 1 file changed, 4 insertions(+), 27 deletions(-) diff --git a/pkg/cmd/roachtest/tests/sqlalchemy.go b/pkg/cmd/roachtest/tests/sqlalchemy.go index c656faa51032..52ba71246c94 100644 --- a/pkg/cmd/roachtest/tests/sqlalchemy.go +++ b/pkg/cmd/roachtest/tests/sqlalchemy.go @@ -30,14 +30,10 @@ import ( var sqlAlchemyResultRegex = regexp.MustCompile(`^(?Ptest.*::.*::[^ \[\]]*(?:\[.*])?) (?P\w+)\s+\[.+]$`) var sqlAlchemyReleaseTagRegex = regexp.MustCompile(`^rel_(?P\d+)_(?P\d+)_(?P\d+)$`) -// TODO(arul): Investigate why we need this and can't install sql alchemy using -// -// pip. -var supportedSQLAlchemyTag = "rel_1_4_26" +var supportedSQLAlchemyTag = "1.4.46" // This test runs the SQLAlchemy dialect test suite against a single Cockroach // node. - func registerSQLAlchemy(r registry.Registry) { r.Add(registry.TestSpec{ Name: "sqlalchemy", @@ -98,10 +94,10 @@ func runSQLAlchemy(ctx context.Context, t test.Test, c cluster.Cluster) { t.Fatal(err) } - if err := repeatRunE(ctx, t, c, node, "install pytest", ` + if err := repeatRunE(ctx, t, c, node, "install pytest", fmt.Sprintf(` source venv/bin/activate && - pip3 install --upgrade --force-reinstall setuptools pytest==6.0.1 pytest-xdist psycopg2 alembic - `); err != nil { + pip3 install --upgrade --force-reinstall setuptools pytest==6.0.1 pytest-xdist psycopg2 alembic sqlalchemy==%s`, + supportedSQLAlchemyTag)); err != nil { t.Fatal(err) } @@ -124,25 +120,6 @@ func runSQLAlchemy(ctx context.Context, t test.Test, c cluster.Cluster) { t.Fatal(err) } - if err := repeatRunE(ctx, t, c, node, "remove old sqlalchemy", ` - sudo rm -rf /mnt/data1/sqlalchemy - `); err != nil { - t.Fatal(err) - } - - if err := repeatGitCloneE(ctx, t, c, - "https://github.com/sqlalchemy/sqlalchemy.git", "/mnt/data1/sqlalchemy", - supportedSQLAlchemyTag, node); err != nil { - t.Fatal(err) - } - - t.Status("building sqlalchemy") - if err := repeatRunE(ctx, t, c, node, "building sqlalchemy", ` - source venv/bin/activate && cd /mnt/data1/sqlalchemy && python3 setup.py build - `); err != nil { - t.Fatal(err) - } - // Phew, after having setup all that, let's actually run the test. t.Status("setting up cockroach") From 6b34dfbec2cf1dfaf3eeeff8a23895bb32467c79 Mon Sep 17 00:00:00 2001 From: Rafi Shamim Date: Tue, 7 Feb 2023 12:52:36 -0500 Subject: [PATCH 3/4] sql: use unimplemented error rather than syntax error for PL/pgSQL This change does not affect anything user-facing, but it allows us to parse CREATE FUNCTION statements that use `LANGUAGE plpgsql`. The plpgsql grammar is still not supported, so this will still show an error to the user. However, since parsing succeeds, the statement will be sent to telemetry logs, allowing us to analyze which parts of the plpgsql grammer that customers are trying to use. Release note: None --- pkg/sql/catalog/funcdesc/BUILD.bazel | 1 + pkg/sql/catalog/funcdesc/func_desc.go | 2 +- pkg/sql/catalog/funcdesc/helpers.go | 5 ++- pkg/sql/logictest/testdata/logic_test/udf | 18 ++++++++ pkg/sql/opt/optbuilder/BUILD.bazel | 1 + pkg/sql/opt/optbuilder/create_function.go | 5 +++ pkg/sql/opt/testutils/testcat/function.go | 4 +- pkg/sql/parser/testdata/create_function | 50 +++++++++++++++++++++++ pkg/sql/sem/tree/udf.go | 37 +++++++++-------- 9 files changed, 101 insertions(+), 22 deletions(-) diff --git a/pkg/sql/catalog/funcdesc/BUILD.bazel b/pkg/sql/catalog/funcdesc/BUILD.bazel index 60bd6388ea2d..2149fe5ff8d6 100644 --- a/pkg/sql/catalog/funcdesc/BUILD.bazel +++ b/pkg/sql/catalog/funcdesc/BUILD.bazel @@ -24,6 +24,7 @@ go_library( "//pkg/sql/sem/tree", "//pkg/sql/sem/volatility", "//pkg/sql/types", + "//pkg/util/errorutil/unimplemented", "//pkg/util/hlc", "//pkg/util/iterutil", "//pkg/util/protoutil", diff --git a/pkg/sql/catalog/funcdesc/func_desc.go b/pkg/sql/catalog/funcdesc/func_desc.go index d20b79e51ded..89b620df870d 100644 --- a/pkg/sql/catalog/funcdesc/func_desc.go +++ b/pkg/sql/catalog/funcdesc/func_desc.go @@ -635,7 +635,7 @@ func (desc *immutable) getCreateExprLang() tree.FunctionLanguage { case catpb.Function_SQL: return tree.FunctionLangSQL } - return 0 + return tree.FunctionLangUnknown } func (desc *immutable) getCreateExprVolatility() tree.FunctionVolatility { diff --git a/pkg/sql/catalog/funcdesc/helpers.go b/pkg/sql/catalog/funcdesc/helpers.go index 556eb92c6b2e..1a439fca02cb 100644 --- a/pkg/sql/catalog/funcdesc/helpers.go +++ b/pkg/sql/catalog/funcdesc/helpers.go @@ -15,6 +15,7 @@ import ( "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgcode" "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgerror" "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" + "github.com/cockroachdb/cockroach/pkg/util/errorutil/unimplemented" ) // VolatilityToProto converts sql statement input volatility to protobuf @@ -54,9 +55,11 @@ func FunctionLangToProto(v tree.FunctionLanguage) (catpb.Function_Language, erro switch v { case tree.FunctionLangSQL: return catpb.Function_SQL, nil + case tree.FunctionLangPlPgSQL: + return -1, unimplemented.NewWithIssue(91569, "PL/pgSQL is not yet supported") } - return -1, pgerror.Newf(pgcode.InvalidParameterValue, "Unknown function language %q", v) + return -1, pgerror.Newf(pgcode.UndefinedObject, "language %q does not exist", v) } // ParamClassToProto converts sql statement input argument class to protobuf diff --git a/pkg/sql/logictest/testdata/logic_test/udf b/pkg/sql/logictest/testdata/logic_test/udf index ba0809534d0d..ec378d4cc950 100644 --- a/pkg/sql/logictest/testdata/logic_test/udf +++ b/pkg/sql/logictest/testdata/logic_test/udf @@ -4,6 +4,24 @@ CREATE TABLE ab ( b INT ) +statement error pgcode 0A000 unimplemented: PL/pgSQL is not yet supported +CREATE FUNCTION populate() RETURNS integer AS $$ +DECLARE + -- declarations +BEGIN + PERFORM my_function(); +END; +$$ LANGUAGE plpgsql + +statement error pgcode 42704 language \"made_up_language\" does not exist +CREATE FUNCTION populate() RETURNS integer AS $$ +DECLARE + -- declarations +BEGIN + PERFORM my_function(); +END; +$$ LANGUAGE made_up_language + statement error pq: unimplemented: user-defined functions with SETOF return types are not supported CREATE FUNCTION f(a int) RETURNS SETOF INT LANGUAGE SQL AS 'SELECT 1' diff --git a/pkg/sql/opt/optbuilder/BUILD.bazel b/pkg/sql/opt/optbuilder/BUILD.bazel index 95b9945e1b7d..8ba8a26a96d8 100644 --- a/pkg/sql/opt/optbuilder/BUILD.bazel +++ b/pkg/sql/opt/optbuilder/BUILD.bazel @@ -52,6 +52,7 @@ go_library( "//pkg/settings", "//pkg/sql/catalog/colinfo", "//pkg/sql/catalog/descpb", + "//pkg/sql/catalog/funcdesc", "//pkg/sql/catalog/schemaexpr", "//pkg/sql/catalog/seqexpr", "//pkg/sql/catalog/tabledesc", diff --git a/pkg/sql/opt/optbuilder/create_function.go b/pkg/sql/opt/optbuilder/create_function.go index 482225cd4999..876f65c0c914 100644 --- a/pkg/sql/opt/optbuilder/create_function.go +++ b/pkg/sql/opt/optbuilder/create_function.go @@ -12,6 +12,7 @@ package optbuilder import ( "github.com/cockroachdb/cockroach/pkg/sql/catalog/descpb" + "github.com/cockroachdb/cockroach/pkg/sql/catalog/funcdesc" "github.com/cockroachdb/cockroach/pkg/sql/catalog/typedesc" "github.com/cockroachdb/cockroach/pkg/sql/opt" "github.com/cockroachdb/cockroach/pkg/sql/opt/memo" @@ -81,6 +82,10 @@ func (b *Builder) buildCreateFunction(cf *tree.CreateFunction, inScope *scope) ( funcBodyStr = string(opt) case tree.FunctionLanguage: languageFound = true + // Check the language here, before attempting to parse the function body. + if _, err := funcdesc.FunctionLangToProto(opt); err != nil { + panic(err) + } } } diff --git a/pkg/sql/opt/testutils/testcat/function.go b/pkg/sql/opt/testutils/testcat/function.go index a4424f33fff8..7adf8591c870 100644 --- a/pkg/sql/opt/testutils/testcat/function.go +++ b/pkg/sql/opt/testutils/testcat/function.go @@ -146,8 +146,8 @@ func collectFuncOptions( } case tree.FunctionLanguage: - if t != tree.FunctionLangSQL { - panic(fmt.Errorf("LANGUAGE must be SQL")) + if t != tree.FunctionLangSQL && t != tree.FunctionLangPlPgSQL { + panic(fmt.Errorf("LANGUAGE must be SQL or plpgsql")) } default: diff --git a/pkg/sql/parser/testdata/create_function b/pkg/sql/parser/testdata/create_function index 298181be6d62..e3793c5abf52 100644 --- a/pkg/sql/parser/testdata/create_function +++ b/pkg/sql/parser/testdata/create_function @@ -495,3 +495,53 @@ using the support form. We appreciate your feedback. ---- ---- + +parse +CREATE FUNCTION populate() RETURNS integer AS $$ +DECLARE + -- declarations +BEGIN + PERFORM my_function(); +END; +$$ LANGUAGE plpgsql +---- +CREATE FUNCTION populate() + RETURNS INT8 + LANGUAGE plpgsql + AS $$ +DECLARE + -- declarations +BEGIN + PERFORM my_function(); +END; +$$ -- normalized! +CREATE FUNCTION populate() + RETURNS INT8 + LANGUAGE plpgsql + AS $$ +DECLARE + -- declarations +BEGIN + PERFORM my_function(); +END; +$$ -- fully parenthesized +CREATE FUNCTION populate() + RETURNS INT8 + LANGUAGE plpgsql + AS $$ +DECLARE + -- declarations +BEGIN + PERFORM my_function(); +END; +$$ -- literals removed +CREATE FUNCTION _() + RETURNS INT8 + LANGUAGE plpgsql + AS $$ +DECLARE + -- declarations +BEGIN + PERFORM my_function(); +END; +$$ -- identifiers removed diff --git a/pkg/sql/sem/tree/udf.go b/pkg/sql/sem/tree/udf.go index c7978c38c558..e9bb0075380c 100644 --- a/pkg/sql/sem/tree/udf.go +++ b/pkg/sql/sem/tree/udf.go @@ -235,33 +235,34 @@ func (node FunctionLeakproof) Format(ctx *FmtCtx) { // FunctionLanguage indicates the language of the statements in the UDF function // body. -type FunctionLanguage int +type FunctionLanguage string const ( - _ FunctionLanguage = iota - // FunctionLangSQL represent SQL language. - FunctionLangSQL + // FunctionLangUnknown represents an unknown language. + FunctionLangUnknown FunctionLanguage = "unknown" + // FunctionLangSQL represents SQL language. + FunctionLangSQL FunctionLanguage = "SQL" + // FunctionLangPlPgSQL represents the PL/pgSQL procedural language. + FunctionLangPlPgSQL FunctionLanguage = "plpgsql" ) // Format implements the NodeFormatter interface. func (node FunctionLanguage) Format(ctx *FmtCtx) { ctx.WriteString("LANGUAGE ") - switch node { - case FunctionLangSQL: - ctx.WriteString("SQL") - default: - panic(pgerror.New(pgcode.InvalidParameterValue, "Unknown function option")) - } + ctx.WriteString(string(node)) } // AsFunctionLanguage converts a string to a FunctionLanguage if applicable. -// Error is returned if string does not represent a valid UDF language. +// No error is returned if string does not represent a valid UDF language; +// unknown languages result in an error later. func AsFunctionLanguage(lang string) (FunctionLanguage, error) { switch strings.ToLower(lang) { case "sql": return FunctionLangSQL, nil + case "plpgsql": + return FunctionLangPlPgSQL, nil } - return 0, errors.Newf("language %q does not exist", lang) + return FunctionLanguage(lang), nil } // FunctionBodyStr is a string containing all statements in a UDF body. @@ -523,34 +524,34 @@ func MaybeFailOnUDFUsage(expr TypedExpr) error { // function options in the given slice. func ValidateFuncOptions(options FunctionOptions) error { var hasLang, hasBody, hasLeakProof, hasVolatility, hasNullInputBehavior bool - err := func(opt FunctionOption) error { + conflictingErr := func(opt FunctionOption) error { return errors.Wrapf(ErrConflictingFunctionOption, "%s", AsString(opt)) } for _, option := range options { switch option.(type) { case FunctionLanguage: if hasLang { - return err(option) + return conflictingErr(option) } hasLang = true case FunctionBodyStr: if hasBody { - return err(option) + return conflictingErr(option) } hasBody = true case FunctionLeakproof: if hasLeakProof { - return err(option) + return conflictingErr(option) } hasLeakProof = true case FunctionVolatility: if hasVolatility { - return err(option) + return conflictingErr(option) } hasVolatility = true case FunctionNullInputBehavior: if hasNullInputBehavior { - return err(option) + return conflictingErr(option) } hasNullInputBehavior = true default: From 8e3c2fd451f87ec06d00f6dab374a427c9fbfcad Mon Sep 17 00:00:00 2001 From: Evan Wall Date: Tue, 7 Feb 2023 10:15:26 -0500 Subject: [PATCH 4/4] sql: fix r.end_key after comparison in show_range_for_row Fixes #96714 Flip the `<` to `>` in `show_range_for_row` to be consistent with `show_ranges.go`: ``` WHEN r.end_key < crdb_internal.table_span(%[1]d)[2] THEN '' ``` becomes ``` WHEN r.end_key > crdb_internal.table_span(%[1]d)[2] THEN '' ``` Release note: None --- .../logic_test/regional_by_row_query_behavior | 2 +- pkg/sql/delegate/show_range_for_row.go | 2 +- pkg/sql/logictest/testdata/logic_test/ranges | 37 +++++++++++++------ 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/pkg/ccl/logictestccl/testdata/logic_test/regional_by_row_query_behavior b/pkg/ccl/logictestccl/testdata/logic_test/regional_by_row_query_behavior index 7c9410615748..92bb67161b14 100644 --- a/pkg/ccl/logictestccl/testdata/logic_test/regional_by_row_query_behavior +++ b/pkg/ccl/logictestccl/testdata/logic_test/regional_by_row_query_behavior @@ -262,7 +262,7 @@ ap-southeast-2 23 query TT SELECT start_key, end_key FROM [SHOW RANGE FROM TABLE regional_by_row_table FOR ROW ('ap-southeast-2', 1)] ---- - + … query TIIII SELECT crdb_region, pk, pk2, a, b FROM regional_by_row_table diff --git a/pkg/sql/delegate/show_range_for_row.go b/pkg/sql/delegate/show_range_for_row.go index 4f28c3903526..49a435fd25b7 100644 --- a/pkg/sql/delegate/show_range_for_row.go +++ b/pkg/sql/delegate/show_range_for_row.go @@ -69,7 +69,7 @@ SELECT END AS start_key, CASE WHEN r.end_key = crdb_internal.table_span(%[1]d)[2] THEN '…/' - WHEN r.end_key < crdb_internal.table_span(%[1]d)[2] THEN '' + WHEN r.end_key > crdb_internal.table_span(%[1]d)[2] THEN '' ELSE '…'||crdb_internal.pretty_key(r.end_key, 2) END AS end_key, range_id, diff --git a/pkg/sql/logictest/testdata/logic_test/ranges b/pkg/sql/logictest/testdata/logic_test/ranges index 4dce2d6db6f5..22d315ab4cda 100644 --- a/pkg/sql/logictest/testdata/logic_test/ranges +++ b/pkg/sql/logictest/testdata/logic_test/ranges @@ -364,10 +364,23 @@ CREATE TABLE simple_range_for_row(x INT PRIMARY KEY) statement ok ALTER TABLE simple_range_for_row SPLIT AT VALUES (1), (2) +# Before split +query TT +SELECT start_key, end_key FROM [SHOW RANGE FROM TABLE simple_range_for_row FOR ROW (0)] +---- + …/1 + +# Between splits query TT SELECT start_key, end_key FROM [SHOW RANGE FROM TABLE simple_range_for_row FOR ROW (1)] ---- -…/1 +…/1 …/2 + +# After split +query TT retry +SELECT start_key, end_key FROM [SHOW RANGE FROM TABLE simple_range_for_row FOR ROW (2)] +---- +…/2 statement ok CREATE TABLE range_for_row(x INT, y INT, z INT, w INT, PRIMARY KEY (x, y), INDEX i (z, w)) @@ -381,32 +394,32 @@ ALTER INDEX range_for_row@i SPLIT AT VALUES (3, 4), (3, 5) query TT SELECT start_key, end_key FROM [SHOW RANGE FROM TABLE range_for_row FOR ROW (1, 2)] ---- -…/1/2 +…/1/2 …/1/3 query TT SELECT start_key, end_key FROM [SHOW RANGE FROM TABLE range_for_row FOR ROW (1, 3)] ---- -…/1/3 +…/1/3 …/3/4 query TT SELECT start_key, end_key FROM [SHOW RANGE FROM TABLE range_for_row FOR ROW (1, 1)] ---- - + …/1/2 query TT SELECT start_key, end_key FROM [SHOW RANGE FROM INDEX range_for_row@i FOR ROW (1, 2, 1, 2)] ---- -…/1/3 +…/1/3 …/3/4 query TT SELECT start_key, end_key FROM [SHOW RANGE FROM INDEX range_for_row@i FOR ROW (3, 4, 1, 2)] ---- -…/3/4 +…/3/4 …/3/5 query TT SELECT start_key, end_key FROM [SHOW RANGE FROM INDEX range_for_row@i FOR ROW (3, 5, 1, 2)] ---- -…/3/5 … +…/3/5 statement ok CREATE TABLE range_for_row_string(x STRING PRIMARY KEY) @@ -417,7 +430,7 @@ ALTER TABLE range_for_row_string SPLIT AT VALUES ('hello') query TT SELECT start_key, end_key FROM [SHOW RANGE FROM TABLE range_for_row_string FOR ROW ('he')] ---- - + …/"hello" statement ok CREATE TABLE range_for_row_decimal(x DECIMAL PRIMARY KEY) @@ -428,7 +441,7 @@ ALTER TABLE range_for_row_decimal SPLIT AT VALUES (1), (2) query TT SELECT start_key, end_key FROM [SHOW RANGE FROM TABLE range_for_row_decimal FOR ROW (1)] ---- -…/1 +…/1 …/2 statement ok CREATE TABLE range_for_row_nulls(x INT PRIMARY KEY, y INT, INDEX i (y)) @@ -439,7 +452,7 @@ ALTER INDEX range_for_row_nulls@i SPLIT AT VALUES (NULL) query TT SELECT start_key, end_key from [SHOW RANGE FROM INDEX range_for_row_nulls@i FOR ROW (NULL, 1)] ---- -…/NULL … +…/NULL subtest end @@ -529,12 +542,12 @@ ALTER TABLE t63646 SPLIT AT VALUES ('a'), ('b') query TT SELECT start_key, end_key FROM [SHOW RANGE FROM TABLE t63646 FOR ROW ('a')] ---- -…/"@" +…/"@" …/"\x80" query TT SELECT start_key, end_key FROM [SHOW RANGE FROM TABLE t63646 FOR ROW ('b')] ---- -…/"\x80" … +…/"\x80" # Test permissions for showing ranges with ZONECONFIG privilege