diff --git a/DEPS.bzl b/DEPS.bzl index 55b442956afe..9c38712ebf8c 100644 --- a/DEPS.bzl +++ b/DEPS.bzl @@ -1485,10 +1485,10 @@ def go_deps(): patches = [ "@com_github_cockroachdb_cockroach//build/patches:com_github_cockroachdb_pebble.patch", ], - sha256 = "1b070e4908697f78b0842d165521695413c7bac40b6f7e374d63b9748ee2ed83", - strip_prefix = "github.com/cockroachdb/pebble@v0.0.0-20230110150502-a80169845786", + sha256 = "dcef948c71b6b6f6e83c41a8c6b9f6bc3df953216534ac4bc7a817d54bcd3515", + strip_prefix = "github.com/cockroachdb/pebble@v0.0.0-20230112184329-90c810757fe6", urls = [ - "https://storage.googleapis.com/cockroach-godeps/gomod/github.com/cockroachdb/pebble/com_github_cockroachdb_pebble-v0.0.0-20230110150502-a80169845786.zip", + "https://storage.googleapis.com/cockroach-godeps/gomod/github.com/cockroachdb/pebble/com_github_cockroachdb_pebble-v0.0.0-20230112184329-90c810757fe6.zip", ], ) go_repository( diff --git a/build/bazelutil/distdir_files.bzl b/build/bazelutil/distdir_files.bzl index c9e6b4d7756a..ac2a8c10c04a 100644 --- a/build/bazelutil/distdir_files.bzl +++ b/build/bazelutil/distdir_files.bzl @@ -193,7 +193,7 @@ DISTDIR_FILES = { "https://storage.googleapis.com/cockroach-godeps/gomod/github.com/cockroachdb/google-api-go-client/com_github_cockroachdb_google_api_go_client-v0.80.1-0.20221117193156-6a9f7150cb93.zip": "b3378c579f4f4340403038305907d672c86f615f8233118a8873ebe4229c4f39", "https://storage.googleapis.com/cockroach-godeps/gomod/github.com/cockroachdb/gostdlib/com_github_cockroachdb_gostdlib-v1.19.0.zip": "c4d516bcfe8c07b6fc09b8a9a07a95065b36c2855627cb3514e40c98f872b69e", "https://storage.googleapis.com/cockroach-godeps/gomod/github.com/cockroachdb/logtags/com_github_cockroachdb_logtags-v0.0.0-20211118104740-dabe8e521a4f.zip": "1972c3f171f118add3fd9e64bcea6cbb9959a3b7fa0ada308e8a7310813fea74", - "https://storage.googleapis.com/cockroach-godeps/gomod/github.com/cockroachdb/pebble/com_github_cockroachdb_pebble-v0.0.0-20230110150502-a80169845786.zip": "1b070e4908697f78b0842d165521695413c7bac40b6f7e374d63b9748ee2ed83", + "https://storage.googleapis.com/cockroach-godeps/gomod/github.com/cockroachdb/pebble/com_github_cockroachdb_pebble-v0.0.0-20230112184329-90c810757fe6.zip": "dcef948c71b6b6f6e83c41a8c6b9f6bc3df953216534ac4bc7a817d54bcd3515", "https://storage.googleapis.com/cockroach-godeps/gomod/github.com/cockroachdb/redact/com_github_cockroachdb_redact-v1.1.3.zip": "7778b1e4485e4f17f35e5e592d87eb99c29e173ac9507801d000ad76dd0c261e", "https://storage.googleapis.com/cockroach-godeps/gomod/github.com/cockroachdb/returncheck/com_github_cockroachdb_returncheck-v0.0.0-20200612231554-92cdbca611dd.zip": "ce92ba4352deec995b1f2eecf16eba7f5d51f5aa245a1c362dfe24c83d31f82b", "https://storage.googleapis.com/cockroach-godeps/gomod/github.com/cockroachdb/sentry-go/com_github_cockroachdb_sentry_go-v0.6.1-cockroachdb.2.zip": "fbb2207d02aecfdd411b1357efe1192dbb827959e36b7cab7491731ac55935c9", diff --git a/go.mod b/go.mod index b1e7bf343f59..43f751bc7ffa 100644 --- a/go.mod +++ b/go.mod @@ -111,7 +111,7 @@ require ( github.com/cockroachdb/go-test-teamcity v0.0.0-20191211140407-cff980ad0a55 github.com/cockroachdb/gostdlib v1.19.0 github.com/cockroachdb/logtags v0.0.0-20211118104740-dabe8e521a4f - github.com/cockroachdb/pebble v0.0.0-20230110150502-a80169845786 + github.com/cockroachdb/pebble v0.0.0-20230112184329-90c810757fe6 github.com/cockroachdb/redact v1.1.3 github.com/cockroachdb/returncheck v0.0.0-20200612231554-92cdbca611dd github.com/cockroachdb/stress v0.0.0-20220803192808-1806698b1b7b diff --git a/go.sum b/go.sum index e952b7245d71..a4e0ca453ac5 100644 --- a/go.sum +++ b/go.sum @@ -474,8 +474,8 @@ github.com/cockroachdb/gostdlib v1.19.0/go.mod h1:+dqqpARXbE/gRDEhCak6dm0l14AaTy github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= github.com/cockroachdb/logtags v0.0.0-20211118104740-dabe8e521a4f h1:6jduT9Hfc0njg5jJ1DdKCFPdMBrp/mdZfCpa5h+WM74= github.com/cockroachdb/logtags v0.0.0-20211118104740-dabe8e521a4f/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= -github.com/cockroachdb/pebble v0.0.0-20230110150502-a80169845786 h1:avnVz2lzx0gNPoStePsmGgK4mJLu/UTmaXJD1W2tTDs= -github.com/cockroachdb/pebble v0.0.0-20230110150502-a80169845786/go.mod h1:rWEpkT1ud5qGG2m1HqTBRWbLgi+oodC4+BWC46uVPjw= +github.com/cockroachdb/pebble v0.0.0-20230112184329-90c810757fe6 h1:g4/xNt1/chUSHly60rbkoMxUrzL4DhzJvL9UktSq9Fs= +github.com/cockroachdb/pebble v0.0.0-20230112184329-90c810757fe6/go.mod h1:rWEpkT1ud5qGG2m1HqTBRWbLgi+oodC4+BWC46uVPjw= github.com/cockroachdb/redact v1.1.3 h1:AKZds10rFSIj7qADf0g46UixK8NNLwWTNdCIGS5wfSQ= github.com/cockroachdb/redact v1.1.3/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= github.com/cockroachdb/returncheck v0.0.0-20200612231554-92cdbca611dd h1:KFOt5I9nEKZgCnOSmy8r4Oykh8BYQO8bFOTgHDS8YZA= diff --git a/pkg/ccl/logictestccl/testdata/logic_test/crdb_internal_tenant b/pkg/ccl/logictestccl/testdata/logic_test/crdb_internal_tenant index ce0ab01e4e7f..a3b3fd72ddfe 100644 --- a/pkg/ccl/logictestccl/testdata/logic_test/crdb_internal_tenant +++ b/pkg/ccl/logictestccl/testdata/logic_test/crdb_internal_tenant @@ -261,10 +261,10 @@ SELECT * FROM crdb_internal.cluster_contention_events WHERE table_id < 0 ---- table_id index_id num_contention_events cumulative_contention_time key txn_id count -query TTTT colnames +query TTTTT colnames SELECT * FROM crdb_internal.builtin_functions WHERE function = '' ---- -function signature category details +function signature category details schema query ITTITTTTTTTBBBB colnames SELECT * FROM crdb_internal.create_statements WHERE database_name = '' diff --git a/pkg/cli/clisqlshell/sql.go b/pkg/cli/clisqlshell/sql.go index 0a98a5c1f3d0..7321c7f25412 100644 --- a/pkg/cli/clisqlshell/sql.go +++ b/pkg/cli/clisqlshell/sql.go @@ -1326,7 +1326,22 @@ func (c *cliState) doHandleCliCmd(loopState, nextState cliStateEnum) cliStateEnu case `\hf`: if len(cmd) == 1 { - c.concatLines = `SELECT DISTINCT proname AS function FROM pg_proc ORDER BY 1` + // The following query lists all functions. It prefixes + // functions with their schema but only if the schema is not in + // the search path. This ensures that "common" functions + // are not prefixed by "pg_catalog", but crdb_internal functions + // get prefixed with "crdb_internal." + // + // TODO(knz): Replace this by the \df logic when that is implemented; + // see: https://github.com/cockroachdb/cockroach/pull/88061 + c.concatLines = ` +SELECT DISTINCT + IF(n.nspname = ANY current_schemas(TRUE), '', + pg_catalog.quote_ident(n.nspname) || '.') || + pg_catalog.quote_ident(p.proname) AS function + FROM pg_catalog.pg_proc p + JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace +ORDER BY 1` return cliRunStatement } return c.handleFunctionHelp(cmd[1:], loopState, errState) diff --git a/pkg/cli/clisqlshell/testdata/complete/composite_names b/pkg/cli/clisqlshell/testdata/complete/composite_names index 091ec32b7aac..5ee569001043 100644 --- a/pkg/cli/clisqlshell/testdata/complete/composite_names +++ b/pkg/cli/clisqlshell/testdata/complete/composite_names @@ -11,3 +11,55 @@ msg: "" completions: - "functions": "crdb_internal.force_error(" (This function is used only by CockroachDB's developers for testing purposes.) -> "crdb_internal.force_error(" (0, 25) + +sql +create schema my_schema +---- +ok + +sql +CREATE FUNCTION my_func(i INT) RETURNS INT LANGUAGE SQL AS 'SELECT i' +---- +ok + +sql +CREATE FUNCTION my_schema.my_other_func(i INT) RETURNS INT LANGUAGE SQL AS 'SELECT i' +---- +ok + +complete +select my@ +---- +complete 0 9 +msg: "" +completions: +- "functions": + "my_func(" () -> "my_func(" (0, 2) +- "schema": + "my_schema" () -> "my_schema" (0, 2) + +complete +select my_schema.@ +---- +complete 0 17 +msg: "" +completions: +- "functions": + "my_schema.my_other_func(" () -> "my_schema.my_other_func(" (0, 10) + +complete +select pg_catalog.array_l@ +---- +complete 0 25 +msg: "" +completions: +- "functions": + "pg_catalog.array_length(" (Calculates the length of `input` on the provided `array_dimension`. However, bec) -> "pg_catalog.array_length(" (0, 18) + "pg_catalog.array_lower(" (Calculates the minimum value of `input` on the provided `array_dimension`. Howev) -> "pg_catalog.array_lower(" (0, 18) + +complete +select "PG_CATALOG".@ +---- +complete 0 20 +msg: "" +(no completions generated) diff --git a/pkg/cli/clisqlshell/testdata/complete/sql b/pkg/cli/clisqlshell/testdata/complete/sql index d1d22046527f..805af1ed4b93 100644 --- a/pkg/cli/clisqlshell/testdata/complete/sql +++ b/pkg/cli/clisqlshell/testdata/complete/sql @@ -102,3 +102,13 @@ msg: "" completions: - "relation": "mytable" () -> "mytable" (0, 0) + +complete +select array_l@ +---- +complete 0 14 +msg: "" +completions: +- "functions": + "array_length(" (Calculates the length of `input` on the provided `array_dimension`. However, bec) -> "array_length(" (0, 7) + "array_lower(" (Calculates the minimum value of `input` on the provided `array_dimension`. Howev) -> "array_lower(" (0, 7) diff --git a/pkg/sql/comprules/rules.go b/pkg/sql/comprules/rules.go index 01f3b536d135..1552a78c0721 100644 --- a/pkg/sql/comprules/rules.go +++ b/pkg/sql/comprules/rules.go @@ -25,7 +25,7 @@ import ( func GetCompMethods() []compengine.Method { return []compengine.Method{ method("keywords", completeKeyword), - method("builtins", completeBuiltin), + method("functions", completeFunction), method("objects", completeObjectInCurrentDatabase), method("schemas", completeSchemaInCurrentDatabase), method("dbs", completeDatabase), @@ -96,41 +96,27 @@ var compNotQualProcRe = regexp.MustCompile(`[^.](i'|_)`) // A qualified possible builtin name. var compMaybeQualProcRe = regexp.MustCompile(`i\.['_]|i\.i'`) -var compVSchemaRe = regexp.MustCompile(`pg_catalog|crdb_internal|information_schema`) - -func completeBuiltin(ctx context.Context, c compengine.Context) (compengine.Rows, error) { - // Complete builtin names: +func completeFunction(ctx context.Context, c compengine.Context) (compengine.Rows, error) { + // Complete function names: // // - at whitespace after keywords. - // - after a period, if the identifier before the period is a vschema. + // - after a period. // var prefix string var start, end int - var extraPrefix string + var schemaName string atWord := c.AtWord() sketch := c.Sketch() switch { - case compMaybeQualProcRe.MatchString(sketch) && - ((!atWord && compVSchemaRe.MatchString(c.RelToken(-1).Str)) || - (atWord && compVSchemaRe.MatchString(c.RelToken(-2).Str))): + case compMaybeQualProcRe.MatchString(sketch): start = int(c.RelToken(-1).Start) - prefix = c.RelToken(-1).Str + "." + schemaName = c.RelToken(-1).Str if atWord { start = int(c.RelToken(-2).Start) - prefix = c.RelToken(-2).Str + "." - } - // crdb has this weird thing where every unqualified built-in "X" - // also exists as "pg_catalog.X". So when we search for - // completions after "pg_catalog.", we can strip that prefix from - // the search. However, we must be careful to add it back in the - // completion results, so that the prefix does not get stripped - // when the completion occurs. - if prefix == "pg_catalog." { - prefix = "" - extraPrefix = "pg_catalog." + schemaName = c.RelToken(-2).Str } if atWord { - prefix += c.RelToken(0).Str + prefix = c.RelToken(0).Str } end = int(c.RelToken(0).End) @@ -152,23 +138,31 @@ func completeBuiltin(ctx context.Context, c compengine.Context) (compengine.Rows return nil, nil } - c.Trace("completing for %q (%d,%d)", prefix, start, end) + c.Trace("completing for %q (%d,%d) with schema %q", prefix, start, end, schemaName) // TODO(knz): use the comment extraction functions from pg_catalog // instead of crdb_internal. This requires exposing comments for // built-in functions through pg_catalog. const query = ` -WITH p AS (SELECT DISTINCT proname FROM pg_catalog.pg_proc) -SELECT $4:::STRING || proname || '(' AS completion, +WITH p AS ( +SELECT DISTINCT + proname, nspname + FROM pg_catalog.pg_proc + JOIN pg_catalog.pg_namespace n ON n.oid = pronamespace) +SELECT IF(length($4) > 0, pg_catalog.quote_ident($4:::STRING) || '.', '') || + pg_catalog.quote_ident(proname) || '(' AS completion, 'functions' AS category, - substr(COALESCE((SELECT details + substr(COALESCE(( + SELECT details FROM "".crdb_internal.builtin_functions f2 - WHERE f2.function = p.proname + WHERE f2.function = p.proname AND f2.schema = p.nspname LIMIT 1), ''), e'[^\n]{0,80}') AS description, $2:::INT AS start, $3:::INT AS end FROM p - WHERE left(proname, length($1:::STRING)) = $1:::STRING` - iter, err := c.Query(ctx, query, prefix, start, end, extraPrefix) + WHERE left(proname, length($1:::STRING)) = $1:::STRING + AND ((length($4) > 0 AND $4 = nspname) + OR (length($4) = 0 AND nspname = ANY current_schemas(true)))` + iter, err := c.Query(ctx, query, prefix, start, end, schemaName) return iter, err } diff --git a/pkg/sql/comprules/testdata/completion_patterns/builtins b/pkg/sql/comprules/testdata/completion_patterns/builtins index 3695dc829a93..43a3e36cee69 100644 --- a/pkg/sql/comprules/testdata/completion_patterns/builtins +++ b/pkg/sql/comprules/testdata/completion_patterns/builtins @@ -1,5 +1,5 @@ filter -builtins: +functions: ---- subtest at_ident @@ -10,19 +10,27 @@ select xor ii' ^ -- -builtins: completing for "xor" (7,10) +functions: completing for "xor" (7,10) with schema "" --sql: -WITH p AS (SELECT DISTINCT proname FROM pg_catalog.pg_proc) -SELECT $4:::STRING || proname || '(' AS completion, +WITH p AS ( +SELECT DISTINCT + proname, nspname + FROM pg_catalog.pg_proc + JOIN pg_catalog.pg_namespace n ON n.oid = pronamespace) +SELECT IF(length($4) > 0, pg_catalog.quote_ident($4:::STRING) || '.', '') || + pg_catalog.quote_ident(proname) || '(' AS completion, 'functions' AS category, - substr(COALESCE((SELECT details + substr(COALESCE(( + SELECT details FROM "".crdb_internal.builtin_functions f2 - WHERE f2.function = p.proname + WHERE f2.function = p.proname AND f2.schema = p.nspname LIMIT 1), ''), e'[^\n]{0,80}') AS description, $2:::INT AS start, $3:::INT AS end FROM p WHERE left(proname, length($1:::STRING)) = $1:::STRING + AND ((length($4) > 0 AND $4 = nspname) + OR (length($4) = 0 AND nspname = ANY current_schemas(true))) --placeholders: []interface {}{"xor", 7, 10, ""} comp at=12 @@ -31,19 +39,27 @@ select xor ii_ ^ -- -builtins: completing for "" (12,12) +functions: completing for "" (12,12) with schema "" --sql: -WITH p AS (SELECT DISTINCT proname FROM pg_catalog.pg_proc) -SELECT $4:::STRING || proname || '(' AS completion, +WITH p AS ( +SELECT DISTINCT + proname, nspname + FROM pg_catalog.pg_proc + JOIN pg_catalog.pg_namespace n ON n.oid = pronamespace) +SELECT IF(length($4) > 0, pg_catalog.quote_ident($4:::STRING) || '.', '') || + pg_catalog.quote_ident(proname) || '(' AS completion, 'functions' AS category, - substr(COALESCE((SELECT details + substr(COALESCE(( + SELECT details FROM "".crdb_internal.builtin_functions f2 - WHERE f2.function = p.proname + WHERE f2.function = p.proname AND f2.schema = p.nspname LIMIT 1), ''), e'[^\n]{0,80}') AS description, $2:::INT AS start, $3:::INT AS end FROM p WHERE left(proname, length($1:::STRING)) = $1:::STRING + AND ((length($4) > 0 AND $4 = nspname) + OR (length($4) = 0 AND nspname = ANY current_schemas(true))) --placeholders: []interface {}{"", 12, 12, ""} subtest end @@ -56,7 +72,28 @@ select a.xor ii.i' ^ -- -builtins: not completing +functions: completing for "xor" (7,12) with schema "a" +--sql: +WITH p AS ( +SELECT DISTINCT + proname, nspname + FROM pg_catalog.pg_proc + JOIN pg_catalog.pg_namespace n ON n.oid = pronamespace) +SELECT IF(length($4) > 0, pg_catalog.quote_ident($4:::STRING) || '.', '') || + pg_catalog.quote_ident(proname) || '(' AS completion, + 'functions' AS category, + substr(COALESCE(( + SELECT details + FROM "".crdb_internal.builtin_functions f2 + WHERE f2.function = p.proname AND f2.schema = p.nspname + LIMIT 1), ''), e'[^\n]{0,80}') AS description, + $2:::INT AS start, + $3:::INT AS end + FROM p + WHERE left(proname, length($1:::STRING)) = $1:::STRING + AND ((length($4) > 0 AND $4 = nspname) + OR (length($4) = 0 AND nspname = ANY current_schemas(true))) +--placeholders: []interface {}{"xor", 7, 12, "a"} comp at=10 select a. @@ -64,7 +101,28 @@ select a. ii._ ^ -- -builtins: not completing +functions: completing for "" (7,9) with schema "a" +--sql: +WITH p AS ( +SELECT DISTINCT + proname, nspname + FROM pg_catalog.pg_proc + JOIN pg_catalog.pg_namespace n ON n.oid = pronamespace) +SELECT IF(length($4) > 0, pg_catalog.quote_ident($4:::STRING) || '.', '') || + pg_catalog.quote_ident(proname) || '(' AS completion, + 'functions' AS category, + substr(COALESCE(( + SELECT details + FROM "".crdb_internal.builtin_functions f2 + WHERE f2.function = p.proname AND f2.schema = p.nspname + LIMIT 1), ''), e'[^\n]{0,80}') AS description, + $2:::INT AS start, + $3:::INT AS end + FROM p + WHERE left(proname, length($1:::STRING)) = $1:::STRING + AND ((length($4) > 0 AND $4 = nspname) + OR (length($4) = 0 AND nspname = ANY current_schemas(true))) +--placeholders: []interface {}{"", 7, 9, "a"} subtest end @@ -76,20 +134,28 @@ select crdb_internal.xor ii.i' ^ -- -builtins: completing for "crdb_internal.xor" (7,24) +functions: completing for "xor" (7,24) with schema "crdb_internal" --sql: -WITH p AS (SELECT DISTINCT proname FROM pg_catalog.pg_proc) -SELECT $4:::STRING || proname || '(' AS completion, +WITH p AS ( +SELECT DISTINCT + proname, nspname + FROM pg_catalog.pg_proc + JOIN pg_catalog.pg_namespace n ON n.oid = pronamespace) +SELECT IF(length($4) > 0, pg_catalog.quote_ident($4:::STRING) || '.', '') || + pg_catalog.quote_ident(proname) || '(' AS completion, 'functions' AS category, - substr(COALESCE((SELECT details + substr(COALESCE(( + SELECT details FROM "".crdb_internal.builtin_functions f2 - WHERE f2.function = p.proname + WHERE f2.function = p.proname AND f2.schema = p.nspname LIMIT 1), ''), e'[^\n]{0,80}') AS description, $2:::INT AS start, $3:::INT AS end FROM p WHERE left(proname, length($1:::STRING)) = $1:::STRING ---placeholders: []interface {}{"crdb_internal.xor", 7, 24, ""} + AND ((length($4) > 0 AND $4 = nspname) + OR (length($4) = 0 AND nspname = ANY current_schemas(true))) +--placeholders: []interface {}{"xor", 7, 24, "crdb_internal"} comp at=21 select crdb_internal. @@ -97,20 +163,28 @@ select crdb_internal. ii.' ^ -- -builtins: completing for "crdb_internal." (7,21) +functions: completing for "" (7,21) with schema "crdb_internal" --sql: -WITH p AS (SELECT DISTINCT proname FROM pg_catalog.pg_proc) -SELECT $4:::STRING || proname || '(' AS completion, +WITH p AS ( +SELECT DISTINCT + proname, nspname + FROM pg_catalog.pg_proc + JOIN pg_catalog.pg_namespace n ON n.oid = pronamespace) +SELECT IF(length($4) > 0, pg_catalog.quote_ident($4:::STRING) || '.', '') || + pg_catalog.quote_ident(proname) || '(' AS completion, 'functions' AS category, - substr(COALESCE((SELECT details + substr(COALESCE(( + SELECT details FROM "".crdb_internal.builtin_functions f2 - WHERE f2.function = p.proname + WHERE f2.function = p.proname AND f2.schema = p.nspname LIMIT 1), ''), e'[^\n]{0,80}') AS description, $2:::INT AS start, $3:::INT AS end FROM p WHERE left(proname, length($1:::STRING)) = $1:::STRING ---placeholders: []interface {}{"crdb_internal.", 7, 21, ""} + AND ((length($4) > 0 AND $4 = nspname) + OR (length($4) = 0 AND nspname = ANY current_schemas(true))) +--placeholders: []interface {}{"", 7, 21, "crdb_internal"} comp at=20 @@ -119,20 +193,28 @@ select pg_catalog.xor ii.i' ^ -- -builtins: completing for "xor" (7,21) +functions: completing for "xor" (7,21) with schema "pg_catalog" --sql: -WITH p AS (SELECT DISTINCT proname FROM pg_catalog.pg_proc) -SELECT $4:::STRING || proname || '(' AS completion, +WITH p AS ( +SELECT DISTINCT + proname, nspname + FROM pg_catalog.pg_proc + JOIN pg_catalog.pg_namespace n ON n.oid = pronamespace) +SELECT IF(length($4) > 0, pg_catalog.quote_ident($4:::STRING) || '.', '') || + pg_catalog.quote_ident(proname) || '(' AS completion, 'functions' AS category, - substr(COALESCE((SELECT details + substr(COALESCE(( + SELECT details FROM "".crdb_internal.builtin_functions f2 - WHERE f2.function = p.proname + WHERE f2.function = p.proname AND f2.schema = p.nspname LIMIT 1), ''), e'[^\n]{0,80}') AS description, $2:::INT AS start, $3:::INT AS end FROM p WHERE left(proname, length($1:::STRING)) = $1:::STRING ---placeholders: []interface {}{"xor", 7, 21, "pg_catalog."} + AND ((length($4) > 0 AND $4 = nspname) + OR (length($4) = 0 AND nspname = ANY current_schemas(true))) +--placeholders: []interface {}{"xor", 7, 21, "pg_catalog"} comp at=18 select pg_catalog. @@ -140,20 +222,28 @@ select pg_catalog. ii.' ^ -- -builtins: completing for "" (7,18) +functions: completing for "" (7,18) with schema "pg_catalog" --sql: -WITH p AS (SELECT DISTINCT proname FROM pg_catalog.pg_proc) -SELECT $4:::STRING || proname || '(' AS completion, +WITH p AS ( +SELECT DISTINCT + proname, nspname + FROM pg_catalog.pg_proc + JOIN pg_catalog.pg_namespace n ON n.oid = pronamespace) +SELECT IF(length($4) > 0, pg_catalog.quote_ident($4:::STRING) || '.', '') || + pg_catalog.quote_ident(proname) || '(' AS completion, 'functions' AS category, - substr(COALESCE((SELECT details + substr(COALESCE(( + SELECT details FROM "".crdb_internal.builtin_functions f2 - WHERE f2.function = p.proname + WHERE f2.function = p.proname AND f2.schema = p.nspname LIMIT 1), ''), e'[^\n]{0,80}') AS description, $2:::INT AS start, $3:::INT AS end FROM p WHERE left(proname, length($1:::STRING)) = $1:::STRING ---placeholders: []interface {}{"", 7, 18, "pg_catalog."} + AND ((length($4) > 0 AND $4 = nspname) + OR (length($4) = 0 AND nspname = ANY current_schemas(true))) +--placeholders: []interface {}{"", 7, 18, "pg_catalog"} comp at=27 @@ -162,20 +252,28 @@ select information_schema.xor ii.i' ^ -- -builtins: completing for "information_schema.xor" (7,29) +functions: completing for "xor" (7,29) with schema "information_schema" --sql: -WITH p AS (SELECT DISTINCT proname FROM pg_catalog.pg_proc) -SELECT $4:::STRING || proname || '(' AS completion, +WITH p AS ( +SELECT DISTINCT + proname, nspname + FROM pg_catalog.pg_proc + JOIN pg_catalog.pg_namespace n ON n.oid = pronamespace) +SELECT IF(length($4) > 0, pg_catalog.quote_ident($4:::STRING) || '.', '') || + pg_catalog.quote_ident(proname) || '(' AS completion, 'functions' AS category, - substr(COALESCE((SELECT details + substr(COALESCE(( + SELECT details FROM "".crdb_internal.builtin_functions f2 - WHERE f2.function = p.proname + WHERE f2.function = p.proname AND f2.schema = p.nspname LIMIT 1), ''), e'[^\n]{0,80}') AS description, $2:::INT AS start, $3:::INT AS end FROM p WHERE left(proname, length($1:::STRING)) = $1:::STRING ---placeholders: []interface {}{"information_schema.xor", 7, 29, ""} + AND ((length($4) > 0 AND $4 = nspname) + OR (length($4) = 0 AND nspname = ANY current_schemas(true))) +--placeholders: []interface {}{"xor", 7, 29, "information_schema"} comp at=26 select information_schema. @@ -183,20 +281,28 @@ select information_schema. ii.' ^ -- -builtins: completing for "information_schema." (7,26) +functions: completing for "" (7,26) with schema "information_schema" --sql: -WITH p AS (SELECT DISTINCT proname FROM pg_catalog.pg_proc) -SELECT $4:::STRING || proname || '(' AS completion, +WITH p AS ( +SELECT DISTINCT + proname, nspname + FROM pg_catalog.pg_proc + JOIN pg_catalog.pg_namespace n ON n.oid = pronamespace) +SELECT IF(length($4) > 0, pg_catalog.quote_ident($4:::STRING) || '.', '') || + pg_catalog.quote_ident(proname) || '(' AS completion, 'functions' AS category, - substr(COALESCE((SELECT details + substr(COALESCE(( + SELECT details FROM "".crdb_internal.builtin_functions f2 - WHERE f2.function = p.proname + WHERE f2.function = p.proname AND f2.schema = p.nspname LIMIT 1), ''), e'[^\n]{0,80}') AS description, $2:::INT AS start, $3:::INT AS end FROM p WHERE left(proname, length($1:::STRING)) = $1:::STRING ---placeholders: []interface {}{"information_schema.", 7, 26, ""} + AND ((length($4) > 0 AND $4 = nspname) + OR (length($4) = 0 AND nspname = ANY current_schemas(true))) +--placeholders: []interface {}{"", 7, 26, "information_schema"} subtest end @@ -208,30 +314,58 @@ select "pg_catalog".xor ii.i' ^ -- -builtins: completing for "xor" (7,23) +functions: completing for "xor" (7,23) with schema "pg_catalog" --sql: -WITH p AS (SELECT DISTINCT proname FROM pg_catalog.pg_proc) -SELECT $4:::STRING || proname || '(' AS completion, +WITH p AS ( +SELECT DISTINCT + proname, nspname + FROM pg_catalog.pg_proc + JOIN pg_catalog.pg_namespace n ON n.oid = pronamespace) +SELECT IF(length($4) > 0, pg_catalog.quote_ident($4:::STRING) || '.', '') || + pg_catalog.quote_ident(proname) || '(' AS completion, 'functions' AS category, - substr(COALESCE((SELECT details + substr(COALESCE(( + SELECT details FROM "".crdb_internal.builtin_functions f2 - WHERE f2.function = p.proname + WHERE f2.function = p.proname AND f2.schema = p.nspname LIMIT 1), ''), e'[^\n]{0,80}') AS description, $2:::INT AS start, $3:::INT AS end FROM p WHERE left(proname, length($1:::STRING)) = $1:::STRING ---placeholders: []interface {}{"xor", 7, 23, "pg_catalog."} + AND ((length($4) > 0 AND $4 = nspname) + OR (length($4) = 0 AND nspname = ANY current_schemas(true))) +--placeholders: []interface {}{"xor", 7, 23, "pg_catalog"} # Quoted uppercase is an entire schema entirely. -# Not completing in that case. comp at=22 select "PG_CATALOG".xor ---- ii.i' ^ -- -builtins: not completing +functions: completing for "xor" (7,23) with schema "PG_CATALOG" +--sql: +WITH p AS ( +SELECT DISTINCT + proname, nspname + FROM pg_catalog.pg_proc + JOIN pg_catalog.pg_namespace n ON n.oid = pronamespace) +SELECT IF(length($4) > 0, pg_catalog.quote_ident($4:::STRING) || '.', '') || + pg_catalog.quote_ident(proname) || '(' AS completion, + 'functions' AS category, + substr(COALESCE(( + SELECT details + FROM "".crdb_internal.builtin_functions f2 + WHERE f2.function = p.proname AND f2.schema = p.nspname + LIMIT 1), ''), e'[^\n]{0,80}') AS description, + $2:::INT AS start, + $3:::INT AS end + FROM p + WHERE left(proname, length($1:::STRING)) = $1:::STRING + AND ((length($4) > 0 AND $4 = nspname) + OR (length($4) = 0 AND nspname = ANY current_schemas(true))) +--placeholders: []interface {}{"xor", 7, 23, "PG_CATALOG"} subtest end diff --git a/pkg/sql/crdb_internal.go b/pkg/sql/crdb_internal.go index 7acc6f5add92..a058817240b8 100644 --- a/pkg/sql/crdb_internal.go +++ b/pkg/sql/crdb_internal.go @@ -2721,17 +2721,25 @@ CREATE TABLE crdb_internal.builtin_functions ( function STRING NOT NULL, signature STRING NOT NULL, category STRING NOT NULL, - details STRING NOT NULL + details STRING NOT NULL, + schema STRING NOT NULL )`, populate: func(ctx context.Context, _ *planner, _ catalog.DatabaseDescriptor, addRow func(...tree.Datum) error) error { for _, name := range builtins.AllBuiltinNames() { props, overloads := builtinsregistry.GetBuiltinProperties(name) + schema := catconstants.PgCatalogName + const crdbInternal = catconstants.CRDBInternalSchemaName + "." + if strings.HasPrefix(name, crdbInternal) { + name = name[len(crdbInternal):] + schema = catconstants.CRDBInternalSchemaName + } for _, f := range overloads { if err := addRow( tree.NewDString(name), tree.NewDString(f.Signature(false /* simplify */)), tree.NewDString(props.Category), tree.NewDString(f.Info), + tree.NewDString(schema), ); err != nil { return err } diff --git a/pkg/sql/logictest/testdata/logic_test/crdb_internal b/pkg/sql/logictest/testdata/logic_test/crdb_internal index e1c410ff6a3b..da0dc9e514f9 100644 --- a/pkg/sql/logictest/testdata/logic_test/crdb_internal +++ b/pkg/sql/logictest/testdata/logic_test/crdb_internal @@ -393,10 +393,10 @@ SELECT * FROM crdb_internal.cluster_contention_events WHERE table_id < 0 ---- table_id index_id num_contention_events cumulative_contention_time key txn_id count -query TTTT colnames +query TTTTT colnames SELECT * FROM crdb_internal.builtin_functions WHERE function = '' ---- -function signature category details +function signature category details schema query ITTITTTTTTTBBBB colnames SELECT * FROM crdb_internal.create_statements WHERE database_name = '' diff --git a/pkg/sql/logictest/testdata/logic_test/crdb_internal_catalog b/pkg/sql/logictest/testdata/logic_test/crdb_internal_catalog index dcec9c93c1e7..44d5fe16effb 100644 --- a/pkg/sql/logictest/testdata/logic_test/crdb_internal_catalog +++ b/pkg/sql/logictest/testdata/logic_test/crdb_internal_catalog @@ -457,7 +457,7 @@ SELECT id, strip_volatile(descriptor) FROM crdb_internal.kv_catalog_descriptor 4294967289 {"table": {"columns": [{"id": 1, "name": "parent_id", "type": {"family": "IntFamily", "oid": 20, "width": 64}}, {"id": 2, "name": "parent_schema_id", "type": {"family": "IntFamily", "oid": 20, "width": 64}}, {"id": 3, "name": "name", "type": {"family": "StringFamily", "oid": 25}}, {"id": 4, "name": "id", "type": {"family": "IntFamily", "oid": 20, "width": 64}}], "formatVersion": 3, "id": 4294967289, "name": "kv_catalog_namespace", "nextColumnId": 5, "nextConstraintId": 2, "nextIndexId": 2, "nextMutationId": 1, "primaryIndex": {"constraintId": 1, "foreignKey": {}, "geoConfig": {}, "id": 1, "interleave": {}, "partitioning": {}, "sharded": {}}, "privileges": {"ownerProto": "node", "users": [{"privileges": "32", "userProto": "public"}], "version": 2}, "replacementOf": {"time": {}}, "unexposedParentSchemaId": 4294967295, "version": "1"}} 4294967290 {"table": {"columns": [{"id": 1, "name": "id", "type": {"family": "IntFamily", "oid": 20, "width": 64}}, {"id": 2, "name": "descriptor", "type": {"family": "JsonFamily", "oid": 3802}}], "formatVersion": 3, "id": 4294967290, "name": "kv_catalog_descriptor", "nextColumnId": 3, "nextConstraintId": 2, "nextIndexId": 2, "nextMutationId": 1, "primaryIndex": {"constraintId": 1, "foreignKey": {}, "geoConfig": {}, "id": 1, "interleave": {}, "partitioning": {}, "sharded": {}}, "privileges": {"ownerProto": "node", "users": [{"privileges": "32", "userProto": "public"}], "version": 2}, "replacementOf": {"time": {}}, "unexposedParentSchemaId": 4294967295, "version": "1"}} 4294967291 {"table": {"columns": [{"id": 1, "name": "type", "type": {"family": "StringFamily", "oid": 25}}, {"id": 2, "name": "object_id", "type": {"family": "IntFamily", "oid": 20, "width": 64}}, {"id": 3, "name": "sub_id", "type": {"family": "IntFamily", "oid": 20, "width": 64}}, {"id": 4, "name": "comment", "type": {"family": "StringFamily", "oid": 25}}], "formatVersion": 3, "id": 4294967291, "name": "kv_catalog_comments", "nextColumnId": 5, "nextConstraintId": 2, "nextIndexId": 2, "nextMutationId": 1, "primaryIndex": {"constraintId": 1, "foreignKey": {}, "geoConfig": {}, "id": 1, "interleave": {}, "partitioning": {}, "sharded": {}}, "privileges": {"ownerProto": "node", "users": [{"privileges": "32", "userProto": "public"}], "version": 2}, "replacementOf": {"time": {}}, "unexposedParentSchemaId": 4294967295, "version": "1"}} -4294967292 {"table": {"columns": [{"id": 1, "name": "function", "type": {"family": "StringFamily", "oid": 25}}, {"id": 2, "name": "signature", "type": {"family": "StringFamily", "oid": 25}}, {"id": 3, "name": "category", "type": {"family": "StringFamily", "oid": 25}}, {"id": 4, "name": "details", "type": {"family": "StringFamily", "oid": 25}}], "formatVersion": 3, "id": 4294967292, "name": "builtin_functions", "nextColumnId": 5, "nextConstraintId": 2, "nextIndexId": 2, "nextMutationId": 1, "primaryIndex": {"constraintId": 1, "foreignKey": {}, "geoConfig": {}, "id": 1, "interleave": {}, "partitioning": {}, "sharded": {}}, "privileges": {"ownerProto": "node", "users": [{"privileges": "32", "userProto": "public"}], "version": 2}, "replacementOf": {"time": {}}, "unexposedParentSchemaId": 4294967295, "version": "1"}} +4294967292 {"table": {"columns": [{"id": 1, "name": "function", "type": {"family": "StringFamily", "oid": 25}}, {"id": 2, "name": "signature", "type": {"family": "StringFamily", "oid": 25}}, {"id": 3, "name": "category", "type": {"family": "StringFamily", "oid": 25}}, {"id": 4, "name": "details", "type": {"family": "StringFamily", "oid": 25}}, {"id": 5, "name": "schema", "type": {"family": "StringFamily", "oid": 25}}], "formatVersion": 3, "id": 4294967292, "name": "builtin_functions", "nextColumnId": 6, "nextConstraintId": 2, "nextIndexId": 2, "nextMutationId": 1, "primaryIndex": {"constraintId": 1, "foreignKey": {}, "geoConfig": {}, "id": 1, "interleave": {}, "partitioning": {}, "sharded": {}}, "privileges": {"ownerProto": "node", "users": [{"privileges": "32", "userProto": "public"}], "version": 2}, "replacementOf": {"time": {}}, "unexposedParentSchemaId": 4294967295, "version": "1"}} 4294967293 {"table": {"columns": [{"id": 1, "name": "node_id", "type": {"family": "IntFamily", "oid": 20, "width": 64}}, {"id": 2, "name": "field", "type": {"family": "StringFamily", "oid": 25}}, {"id": 3, "name": "value", "type": {"family": "StringFamily", "oid": 25}}], "formatVersion": 3, "id": 4294967293, "name": "node_build_info", "nextColumnId": 4, "nextConstraintId": 2, "nextIndexId": 2, "nextMutationId": 1, "primaryIndex": {"constraintId": 1, "foreignKey": {}, "geoConfig": {}, "id": 1, "interleave": {}, "partitioning": {}, "sharded": {}}, "privileges": {"ownerProto": "node", "users": [{"privileges": "32", "userProto": "public"}], "version": 2}, "replacementOf": {"time": {}}, "unexposedParentSchemaId": 4294967295, "version": "1"}} 4294967294 {"table": {"columns": [{"id": 1, "name": "descriptor_id", "nullable": true, "type": {"family": "IntFamily", "oid": 20, "width": 64}}, {"id": 2, "name": "descriptor_name", "type": {"family": "StringFamily", "oid": 25}}, {"id": 3, "name": "index_id", "nullable": true, "type": {"family": "IntFamily", "oid": 20, "width": 64}}, {"id": 4, "name": "column_id", "nullable": true, "type": {"family": "IntFamily", "oid": 20, "width": 64}}, {"id": 5, "name": "dependson_id", "type": {"family": "IntFamily", "oid": 20, "width": 64}}, {"id": 6, "name": "dependson_type", "type": {"family": "StringFamily", "oid": 25}}, {"id": 7, "name": "dependson_index_id", "nullable": true, "type": {"family": "IntFamily", "oid": 20, "width": 64}}, {"id": 8, "name": "dependson_name", "nullable": true, "type": {"family": "StringFamily", "oid": 25}}, {"id": 9, "name": "dependson_details", "nullable": true, "type": {"family": "StringFamily", "oid": 25}}], "formatVersion": 3, "id": 4294967294, "name": "backward_dependencies", "nextColumnId": 10, "nextConstraintId": 2, "nextIndexId": 2, "nextMutationId": 1, "primaryIndex": {"constraintId": 1, "foreignKey": {}, "geoConfig": {}, "id": 1, "interleave": {}, "partitioning": {}, "sharded": {}}, "privileges": {"ownerProto": "node", "users": [{"privileges": "32", "userProto": "public"}], "version": 2}, "replacementOf": {"time": {}}, "unexposedParentSchemaId": 4294967295, "version": "1"}} 4294967295 {"schema": {"defaultPrivileges": {"type": "SCHEMA"}, "id": 4294967295, "name": "crdb_internal", "privileges": {"ownerProto": "node", "users": [{"privileges": "512", "userProto": "public"}], "version": 2}, "version": "1"}} diff --git a/pkg/sql/logictest/testdata/logic_test/pg_catalog b/pkg/sql/logictest/testdata/logic_test/pg_catalog index b5dff20428db..d1146a7033c0 100644 --- a/pkg/sql/logictest/testdata/logic_test/pg_catalog +++ b/pkg/sql/logictest/testdata/logic_test/pg_catalog @@ -2242,20 +2242,21 @@ oid typname typnamespace typowner typlen typbyval typtype ## pg_catalog.pg_proc -query TOOOTTO colnames -SELECT proname, pronamespace, proowner, prolang, procost, prorows, provariadic -FROM pg_catalog.pg_proc +query TOTOOTTO colnames +SELECT proname, pronamespace, nspname, proowner, prolang, procost, prorows, provariadic +FROM pg_catalog.pg_proc p +JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace WHERE proname='substring' ---- -proname pronamespace proowner prolang procost prorows provariadic -substring 4294967129 NULL 0 NULL NULL 0 -substring 4294967129 NULL 0 NULL NULL 0 -substring 4294967129 NULL 0 NULL NULL 0 -substring 4294967129 NULL 0 NULL NULL 0 -substring 4294967129 NULL 0 NULL NULL 0 -substring 4294967129 NULL 0 NULL NULL 0 -substring 4294967129 NULL 0 NULL NULL 0 -substring 4294967129 NULL 0 NULL NULL 0 +proname pronamespace nspname proowner prolang procost prorows provariadic +substring 4294967129 pg_catalog NULL 0 NULL NULL 0 +substring 4294967129 pg_catalog NULL 0 NULL NULL 0 +substring 4294967129 pg_catalog NULL 0 NULL NULL 0 +substring 4294967129 pg_catalog NULL 0 NULL NULL 0 +substring 4294967129 pg_catalog NULL 0 NULL NULL 0 +substring 4294967129 pg_catalog NULL 0 NULL NULL 0 +substring 4294967129 pg_catalog NULL 0 NULL NULL 0 +substring 4294967129 pg_catalog NULL 0 NULL NULL 0 query TTBBBB colnames SELECT proname, protransform, proisagg, proiswindow, prosecdef, proleakproof @@ -2317,6 +2318,18 @@ substring NULL substring NULL NULL NULL substring NULL substring NULL NULL NULL substring NULL substring NULL NULL NULL +query TTOTOT colnames +SELECT proname, prosrc, pronamespace, nspname, prorettype, proargtypes +FROM pg_catalog.pg_proc p +JOIN pg_catalog.pg_namespace n ON p.pronamespace = n.oid +WHERE proname='pb_to_json' +ORDER BY p.oid +---- +proname prosrc pronamespace nspname prorettype proargtypes +pb_to_json pb_to_json 4294967295 crdb_internal 3802 25 17 +pb_to_json pb_to_json 4294967295 crdb_internal 3802 25 17 16 +pb_to_json pb_to_json 4294967295 crdb_internal 3802 25 17 16 16 + query TOIOTTB colnames SELECT proname, provariadic, pronargs, prorettype, proargtypes, proargmodes, proisstrict FROM pg_catalog.pg_proc diff --git a/pkg/sql/pg_catalog.go b/pkg/sql/pg_catalog.go index db05c9d2fefa..8cf136da083b 100644 --- a/pkg/sql/pg_catalog.go +++ b/pkg/sql/pg_catalog.go @@ -2328,10 +2328,17 @@ https://www.postgresql.org/docs/9.6/view-pg-prepared-statements.html`, }, } -func addPgProcBuiltinRow(nspOid *tree.DOid, name string, addRow func(...tree.Datum) error) error { +func addPgProcBuiltinRow(name string, addRow func(...tree.Datum) error) error { props, overloads := builtinsregistry.GetBuiltinProperties(name) isAggregate := props.Class == tree.AggregateClass isWindow := props.Class == tree.WindowClass + nspOid := tree.NewDOid(catconstants.PgCatalogID) + const crdbInternal = catconstants.CRDBInternalSchemaName + "." + if strings.HasPrefix(name, crdbInternal) { + nspOid = tree.NewDOid(catconstants.CrdbInternalID) + name = name[len(crdbInternal):] + } + for _, builtin := range overloads { dName := tree.NewDName(name) dSrc := tree.NewDString(name) @@ -2524,7 +2531,6 @@ https://www.postgresql.org/docs/9.5/catalog-pg-proc.html`, err := forEachDatabaseDesc(ctx, p, dbContext, false, /* requiresPrivileges */ func(db catalog.DatabaseDescriptor) error { - nspOid := tree.NewDOid(catconstants.PgCatalogID) for _, name := range builtins.AllBuiltinNames() { // parser.Builtins contains duplicate uppercase and lowercase keys. // Only return the lowercase ones for compatibility with postgres. @@ -2536,7 +2542,7 @@ https://www.postgresql.org/docs/9.5/catalog-pg-proc.html`, if unicode.IsUpper(first) { continue } - err := addPgProcBuiltinRow(nspOid, name, addRow) + err := addPgProcBuiltinRow(name, addRow) if err != nil { return err } @@ -2598,7 +2604,7 @@ https://www.postgresql.org/docs/9.5/catalog-pg-proc.html`, return true, nil } else { - err := addPgProcBuiltinRow(tree.NewDOid(catconstants.PgCatalogID), name, addRow) + err := addPgProcBuiltinRow(name, addRow) if err != nil { return false, err } diff --git a/pkg/ui/workspaces/db-console/src/redux/cachedDataReducer.ts b/pkg/ui/workspaces/db-console/src/redux/cachedDataReducer.ts index 34804c700d3b..63ae0611081d 100644 --- a/pkg/ui/workspaces/db-console/src/redux/cachedDataReducer.ts +++ b/pkg/ui/workspaces/db-console/src/redux/cachedDataReducer.ts @@ -26,6 +26,7 @@ import { getLoginPage } from "src/redux/login"; import { APIRequestFn } from "src/util/api"; import { PayloadAction, WithRequest } from "src/interfaces/action"; +import { maybeClearTenantCookie } from "./cookies"; export interface WithPaginationRequest { page_size: number; @@ -278,6 +279,7 @@ export class CachedDataReducer< // codes. However, at the moment that's all that the underlying // timeoutFetch offers. Major changes to this plumbing are warranted. if (error.message === "Unauthorized") { + maybeClearTenantCookie(); // TODO(couchand): This is an unpleasant dependency snuck in here... const { location } = createHashHistory(); if (location && !location.pathname.startsWith("/login")) { diff --git a/pkg/ui/workspaces/db-console/src/redux/cookies.ts b/pkg/ui/workspaces/db-console/src/redux/cookies.ts index 39a88e74726d..d29a12f5dd0e 100644 --- a/pkg/ui/workspaces/db-console/src/redux/cookies.ts +++ b/pkg/ui/workspaces/db-console/src/redux/cookies.ts @@ -39,6 +39,17 @@ export const selectTenantsFromMultitenantSessionCookie = (): string[] => { : []; }; +// maybeClearTenantCookie clears the tenant cookie if there are multiple tenants +// found in the multitenant-session cookie. +export const maybeClearTenantCookie = () => { + const tenants = selectTenantsFromMultitenantSessionCookie(); + // If in multi-tenant environment, we need to clear the tenant cookie so that + // we can do a multi-tenant logout. + if (tenants.length > 1) { + setCookie("tenant", ""); + } +}; + export const setCookie = ( key: string, val: string, diff --git a/pkg/ui/workspaces/db-console/src/redux/login.ts b/pkg/ui/workspaces/db-console/src/redux/login.ts index d2d83165f603..d0b494d44538 100644 --- a/pkg/ui/workspaces/db-console/src/redux/login.ts +++ b/pkg/ui/workspaces/db-console/src/redux/login.ts @@ -20,10 +20,7 @@ import { cockroach } from "src/js/protos"; import { getDataFromServer } from "src/util/dataFromServer"; import UserLoginRequest = cockroach.server.serverpb.UserLoginRequest; -import { - selectTenantsFromMultitenantSessionCookie, - setCookie, -} from "./cookies"; +import { maybeClearTenantCookie } from "./cookies"; const dataFromServer = getDataFromServer(); @@ -217,12 +214,7 @@ export function doLogout(): ThunkAction< > { return dispatch => { dispatch(logoutBeginAction); - const tenants = selectTenantsFromMultitenantSessionCookie(); - // If in multi-tenant environment, we need to clear the tenant cookie so that - // we can do a multi-tenant logout. - if (tenants.length > 1) { - setCookie("tenant", ""); - } + maybeClearTenantCookie(); // Make request to log out, reloading the page whether it succeeds or not. // If there was a successful log out but the network dropped the response somehow, // you'll get the login page on reload. If The logout actually didn't work, you'll