diff --git a/pkg/sql/catalog/catconstants/constants.go b/pkg/sql/catalog/catconstants/constants.go index 0b04fa57f7c7..2125afca2ace 100644 --- a/pkg/sql/catalog/catconstants/constants.go +++ b/pkg/sql/catalog/catconstants/constants.go @@ -10,14 +10,7 @@ package catconstants -import ( - "math" - - "github.com/cockroachdb/cockroach/pkg/sql/sessiondata" -) - -// DefaultSearchPath is the search path used by virgin sessions. -var DefaultSearchPath = sessiondata.MakeSearchPath([]string{"public"}) +import "math" // ReportableAppNamePrefix indicates that the application name can be // reported in telemetry without scrubbing. (Note this only applies to diff --git a/pkg/sql/conn_executor.go b/pkg/sql/conn_executor.go index dd9e0bba4f89..e9f5f591e2de 100644 --- a/pkg/sql/conn_executor.go +++ b/pkg/sql/conn_executor.go @@ -29,7 +29,6 @@ import ( "github.com/cockroachdb/cockroach/pkg/server/serverpb" "github.com/cockroachdb/cockroach/pkg/server/telemetry" "github.com/cockroachdb/cockroach/pkg/settings" - "github.com/cockroachdb/cockroach/pkg/sql/catalog/catconstants" "github.com/cockroachdb/cockroach/pkg/sql/catalog/colinfo" "github.com/cockroachdb/cockroach/pkg/sql/catalog/database" "github.com/cockroachdb/cockroach/pkg/sql/catalog/descpb" @@ -545,7 +544,7 @@ func (s *Server) populateMinimalSessionData(sd *sessiondata.SessionData) { } } if len(sd.SearchPath.GetPathArray()) == 0 { - sd.SearchPath = catconstants.DefaultSearchPath + sd.SearchPath = sessiondata.DefaultSearchPathForUser(sd.User) } } diff --git a/pkg/sql/distsql/server.go b/pkg/sql/distsql/server.go index 540a9777c328..da2a91fc109e 100644 --- a/pkg/sql/distsql/server.go +++ b/pkg/sql/distsql/server.go @@ -284,8 +284,12 @@ func (ds *ServerImpl) setupFlow( ApplicationName: req.EvalContext.ApplicationName, Database: req.EvalContext.Database, User: req.EvalContext.User, - SearchPath: sessiondata.MakeSearchPath(req.EvalContext.SearchPath).WithTemporarySchemaName(req.EvalContext.TemporarySchemaName), - SequenceState: sessiondata.NewSequenceState(), + SearchPath: sessiondata.MakeSearchPath( + req.EvalContext.SearchPath, + ).WithTemporarySchemaName( + req.EvalContext.TemporarySchemaName, + ).WithUserSchemaName(req.EvalContext.User), + SequenceState: sessiondata.NewSequenceState(), DataConversion: sessiondata.DataConversionConfig{ Location: location, BytesEncodeFormat: be, diff --git a/pkg/sql/logictest/testdata/logic_test/discard b/pkg/sql/logictest/testdata/logic_test/discard index afa6ad74b253..a980b87e68ea 100644 --- a/pkg/sql/logictest/testdata/logic_test/discard +++ b/pkg/sql/logictest/testdata/logic_test/discard @@ -12,7 +12,7 @@ DISCARD ALL query T SHOW SEARCH_PATH ---- -public +$user,public query T SET timezone = 'Europe/Amsterdam'; SHOW TIMEZONE diff --git a/pkg/sql/logictest/testdata/logic_test/pg_catalog b/pkg/sql/logictest/testdata/logic_test/pg_catalog index 70a8dc7eb1ec..74654dba84b1 100644 --- a/pkg/sql/logictest/testdata/logic_test/pg_catalog +++ b/pkg/sql/logictest/testdata/logic_test/pg_catalog @@ -1854,7 +1854,7 @@ reorder_joins_limit 8 NULL NUL require_explicit_primary_keys off NULL NULL NULL string results_buffer_size 16384 NULL NULL NULL string row_security off NULL NULL NULL string -search_path public NULL NULL NULL string +search_path $user,public NULL NULL NULL string serial_normalization rowid NULL NULL NULL string server_encoding UTF8 NULL NULL NULL string server_version 9.5.0 NULL NULL NULL string @@ -1924,7 +1924,7 @@ reorder_joins_limit 8 NULL user require_explicit_primary_keys off NULL user NULL off off results_buffer_size 16384 NULL user NULL 16384 16384 row_security off NULL user NULL off off -search_path public NULL user NULL public public +search_path $user,public NULL user NULL $user,public $user,public serial_normalization rowid NULL user NULL rowid rowid server_encoding UTF8 NULL user NULL UTF8 UTF8 server_version 9.5.0 NULL user NULL 9.5.0 9.5.0 diff --git a/pkg/sql/logictest/testdata/logic_test/reset b/pkg/sql/logictest/testdata/logic_test/reset index ac0441a4ff5e..263427309a11 100644 --- a/pkg/sql/logictest/testdata/logic_test/reset +++ b/pkg/sql/logictest/testdata/logic_test/reset @@ -15,7 +15,7 @@ RESET SEARCH_PATH query T SHOW SEARCH_PATH ---- -public +$user,public statement error parameter "server_version" cannot be changed RESET SERVER_VERSION @@ -39,7 +39,7 @@ RESET search_path query T SHOW search_path ---- -public +$user,public statement ok RESET client_encoding; RESET NAMES diff --git a/pkg/sql/logictest/testdata/logic_test/schema b/pkg/sql/logictest/testdata/logic_test/schema index 48a5ad848040..3a6bbfe136be 100644 --- a/pkg/sql/logictest/testdata/logic_test/schema +++ b/pkg/sql/logictest/testdata/logic_test/schema @@ -459,3 +459,77 @@ CREATE TABLE new_db.public.bar() statement ok CREATE TABLE new_db.testuser.bar() + +# cleanup the testuser schema created as part of the CREATE SCHEMA AUTHORIZATION +# command above +statement ok +DROP SCHEMA testuser CASCADE + +# If a schema with a username exists, then that should be the first entry in +# the search path. +subtest user_schema_search_path + +# Test setup +user root + +statement ok +CREATE SCHEMA testuser + +statement ok +GRANT ALL ON SCHEMA testuser TO testuser + +statement ok +CREATE TABLE public.public_table(a INT) + +statement ok +GRANT SELECT ON public.public_table TO testuser + +user testuser + +statement ok +CREATE TABLE test_table(a INT); + +statement error pq: relation "public.test_table" does not exist +SELECT * FROM public.test_table + +statement ok +SELECT * FROM testuser.test_table + +# Only root has privs to create inside public +user root + +statement ok +CREATE TABLE public.test_table(a INT, b INT) + +statement ok +GRANT SELECT ON public.test_table TO testuser + +user testuser + +query I colnames +SELECT * FROM test_table +---- +a + +query II colnames +SELECT * FROM public.test_table +---- +a b + +query I colnames +SELECT * FROM public_table +---- +a + +# The search path is configured to be user specific. +user root + +query II colnames +SELECT * FROM test_table +---- +a b + +query I colnames +SELECT * FROM testuser.test_table +---- +a diff --git a/pkg/sql/logictest/testdata/logic_test/show_source b/pkg/sql/logictest/testdata/logic_test/show_source index ef38e1edaba4..404aade86a9c 100644 --- a/pkg/sql/logictest/testdata/logic_test/show_source +++ b/pkg/sql/logictest/testdata/logic_test/show_source @@ -67,7 +67,7 @@ reorder_joins_limit 8 require_explicit_primary_keys off results_buffer_size 16384 row_security off -search_path public +search_path $user,public serial_normalization rowid server_encoding UTF8 server_version 9.5.0 diff --git a/pkg/sql/planner.go b/pkg/sql/planner.go index f727c0d9c138..81a2738c661e 100644 --- a/pkg/sql/planner.go +++ b/pkg/sql/planner.go @@ -19,7 +19,6 @@ import ( "github.com/cockroachdb/cockroach/pkg/kv" "github.com/cockroachdb/cockroach/pkg/server/serverpb" "github.com/cockroachdb/cockroach/pkg/sql/catalog" - "github.com/cockroachdb/cockroach/pkg/sql/catalog/catconstants" "github.com/cockroachdb/cockroach/pkg/sql/catalog/descpb" "github.com/cockroachdb/cockroach/pkg/sql/catalog/descs" "github.com/cockroachdb/cockroach/pkg/sql/catalog/lease" @@ -263,7 +262,7 @@ func newInternalPlanner( ctx := logtags.AddTag(context.Background(), opName, "") sd := &sessiondata.SessionData{ - SearchPath: catconstants.DefaultSearchPath, + SearchPath: sessiondata.DefaultSearchPathForUser(user), User: user, Database: "system", SequenceState: sessiondata.NewSequenceState(), diff --git a/pkg/sql/schema_changer.go b/pkg/sql/schema_changer.go index 60c35911ed8e..293aee27e1e5 100644 --- a/pkg/sql/schema_changer.go +++ b/pkg/sql/schema_changer.go @@ -30,7 +30,6 @@ import ( "github.com/cockroachdb/cockroach/pkg/sql/catalog" "github.com/cockroachdb/cockroach/pkg/sql/catalog/catalogkeys" "github.com/cockroachdb/cockroach/pkg/sql/catalog/catalogkv" - "github.com/cockroachdb/cockroach/pkg/sql/catalog/catconstants" "github.com/cockroachdb/cockroach/pkg/sql/catalog/dbdesc" "github.com/cockroachdb/cockroach/pkg/sql/catalog/descpb" "github.com/cockroachdb/cockroach/pkg/sql/catalog/descs" @@ -1972,7 +1971,7 @@ func createSchemaChangeEvalCtx( func newFakeSessionData() *sessiondata.SessionData { sd := &sessiondata.SessionData{ - SearchPath: catconstants.DefaultSearchPath, + SearchPath: sessiondata.DefaultSearchPathForUser(security.NodeUser), // The database is not supposed to be needed in schema changes, as there // shouldn't be unqualified identifiers in backfills, and the pure functions // that need it should have already been evaluated. diff --git a/pkg/sql/sessiondata/search_path.go b/pkg/sql/sessiondata/search_path.go index 38fe294bc956..e4de19f1961d 100644 --- a/pkg/sql/sessiondata/search_path.go +++ b/pkg/sql/sessiondata/search_path.go @@ -23,6 +23,9 @@ const PgCatalogName = "pg_catalog" // PublicSchemaName is the name of the pg_catalog system schema. const PublicSchemaName = "public" +// UserSchemaName is the alias for schema names for users. +const UserSchemaName = "$user" + // InformationSchemaName is the name of the information_schema system schema. const InformationSchemaName = "information_schema" @@ -40,6 +43,11 @@ const PgTempSchemaName = "pg_temp" // when installing an extension, but must be stored as a separate schema in CRDB. const PgExtensionSchemaName = "pg_extension" +// DefaultSearchPath is the search path used by virgin sessions. +var DefaultSearchPath = MakeSearchPath( + []string{UserSchemaName, PublicSchemaName}, +) + // SearchPath represents a list of namespaces to search builtins in. // The names must be normalized (as per Name.Normalize) already. type SearchPath struct { @@ -48,11 +56,18 @@ type SearchPath struct { containsPgExtension bool containsPgTempSchema bool tempSchemaName string + userSchemaName string } // EmptySearchPath is a SearchPath with no schema names in it. var EmptySearchPath = SearchPath{} +// DefaultSearchPathForUser returns the default search path with the user +// specific schema name set so that it can be expanded during resolution. +func DefaultSearchPathForUser(username string) SearchPath { + return DefaultSearchPath.WithUserSchemaName(username) +} + // MakeSearchPath returns a new immutable SearchPath struct. The paths slice // must not be modified after hand-off to MakeSearchPath. func MakeSearchPath(paths []string) SearchPath { @@ -87,14 +102,28 @@ func (s SearchPath) WithTemporarySchemaName(tempSchemaName string) SearchPath { containsPgCatalog: s.containsPgCatalog, containsPgTempSchema: s.containsPgTempSchema, containsPgExtension: s.containsPgExtension, + userSchemaName: s.userSchemaName, tempSchemaName: tempSchemaName, } } +// WithUserSchemaName returns a new immutable SearchPath struct with the +// userSchemaName populated and the same values for all other fields as before. +func (s SearchPath) WithUserSchemaName(userSchemaName string) SearchPath { + return SearchPath{ + paths: s.paths, + containsPgCatalog: s.containsPgCatalog, + containsPgTempSchema: s.containsPgTempSchema, + containsPgExtension: s.containsPgExtension, + userSchemaName: userSchemaName, + tempSchemaName: s.tempSchemaName, + } +} + // UpdatePaths returns a new immutable SearchPath struct with the paths supplied -// and the same tempSchemaName as before. +// and the same tempSchemaName and userSchemaName as before. func (s SearchPath) UpdatePaths(paths []string) SearchPath { - return MakeSearchPath(paths).WithTemporarySchemaName(s.tempSchemaName) + return MakeSearchPath(paths).WithTemporarySchemaName(s.tempSchemaName).WithUserSchemaName(s.userSchemaName) } // MaybeResolveTemporarySchema returns the session specific temporary schema @@ -135,6 +164,7 @@ func (s SearchPath) Iter() SearchPathIter { implicitPgExtension: !s.containsPgExtension, implicitPgTempSchema: implicitPgTempSchema, tempSchemaName: s.tempSchemaName, + userSchemaName: s.userSchemaName, } return sp } @@ -147,6 +177,7 @@ func (s SearchPath) IterWithoutImplicitPGSchemas() SearchPathIter { implicitPgCatalog: false, implicitPgTempSchema: false, tempSchemaName: s.tempSchemaName, + userSchemaName: s.userSchemaName, } return sp } @@ -202,7 +233,7 @@ func (s SearchPath) Equals(other *SearchPath) bool { } func (s SearchPath) String() string { - return strings.Join(s.paths, ", ") + return strings.Join(s.paths, ",") } // SearchPathIter enables iteration over the search paths without triggering an @@ -216,6 +247,7 @@ type SearchPathIter struct { implicitPgExtension bool implicitPgTempSchema bool tempSchemaName string + userSchemaName string i int } @@ -245,6 +277,14 @@ func (iter *SearchPathIter) Next() (path string, ok bool) { } return iter.tempSchemaName, true } + if iter.paths[iter.i-1] == UserSchemaName { + // In case the user schema name is unset, we simply iterate to the next + // entry. + if iter.userSchemaName == "" { + return iter.Next() + } + return iter.userSchemaName, true + } // pg_extension should be read before delving into the schema. if iter.paths[iter.i-1] == PublicSchemaName && iter.implicitPgExtension { iter.implicitPgExtension = false diff --git a/pkg/sql/temporary_schema.go b/pkg/sql/temporary_schema.go index 2a3ba7742baa..02cc7bf6425f 100644 --- a/pkg/sql/temporary_schema.go +++ b/pkg/sql/temporary_schema.go @@ -28,7 +28,6 @@ import ( "github.com/cockroachdb/cockroach/pkg/sql/catalog" "github.com/cockroachdb/cockroach/pkg/sql/catalog/catalogkeys" "github.com/cockroachdb/cockroach/pkg/sql/catalog/catalogkv" - "github.com/cockroachdb/cockroach/pkg/sql/catalog/catconstants" "github.com/cockroachdb/cockroach/pkg/sql/catalog/descpb" "github.com/cockroachdb/cockroach/pkg/sql/catalog/resolver" "github.com/cockroachdb/cockroach/pkg/sql/catalog/tabledesc" @@ -229,7 +228,7 @@ func cleanupSchemaObjects( } a := catalogkv.UncachedPhysicalAccessor{} - searchPath := catconstants.DefaultSearchPath.WithTemporarySchemaName(schemaName) + searchPath := sessiondata.DefaultSearchPathForUser(security.RootUser).WithTemporarySchemaName(schemaName) override := sessiondata.InternalExecutorOverride{ SearchPath: &searchPath, User: security.RootUser, diff --git a/pkg/sql/vars.go b/pkg/sql/vars.go index 8484c78545c2..0d4b5bb3db20 100644 --- a/pkg/sql/vars.go +++ b/pkg/sql/vars.go @@ -22,7 +22,6 @@ import ( "github.com/cockroachdb/cockroach/pkg/build" "github.com/cockroachdb/cockroach/pkg/server/telemetry" "github.com/cockroachdb/cockroach/pkg/settings" - "github.com/cockroachdb/cockroach/pkg/sql/catalog/catconstants" "github.com/cockroachdb/cockroach/pkg/sql/delegate" "github.com/cockroachdb/cockroach/pkg/sql/lex" "github.com/cockroachdb/cockroach/pkg/sql/paramparse" @@ -827,7 +826,7 @@ var varGen = map[string]sessionVar{ return evalCtx.SessionData.SearchPath.String() }, GlobalDefault: func(sv *settings.Values) string { - return catconstants.DefaultSearchPath.String() + return sessiondata.DefaultSearchPath.String() }, },