From f069ca9bd328dc68ce9beefd0a92f9c4555097ce Mon Sep 17 00:00:00 2001 From: Raphael 'kena' Poss Date: Fri, 22 Feb 2019 15:46:01 +0100 Subject: [PATCH] sql: tolerate non-existent databases for plan cache invalidation Release note (bug fix): CockroachDB again properly reports when a database used during PREPARE does not exist any more when EXECUTE is used. --- pkg/sql/logictest/testdata/logic_test/prepare | 52 +++++++++++++++++++ pkg/sql/opt_catalog.go | 21 ++++++-- 2 files changed, 68 insertions(+), 5 deletions(-) diff --git a/pkg/sql/logictest/testdata/logic_test/prepare b/pkg/sql/logictest/testdata/logic_test/prepare index ef1290774605..bcc8ff773be7 100644 --- a/pkg/sql/logictest/testdata/logic_test/prepare +++ b/pkg/sql/logictest/testdata/logic_test/prepare @@ -954,3 +954,55 @@ query T EXECUTE foobar(NULL, NULL) ---- NULL + +subtest regression_35145 + +# Verify db-independent query behaves properly even when db does not exist + +statement ok +SET application_name = ap35145 + +# Prepare in custom db + +statement ok +CREATE DATABASE d35145; SET database = d35145; + +statement ok +PREPARE display_appname AS SELECT setting FROM pg_settings WHERE name = 'application_name' + +query T +EXECUTE display_appname +---- +ap35145 + +# Check what happens when the db where the stmt was prepared disappears "underneath". + +statement ok +DROP DATABASE d35145 + +query error database "d35145" does not exist +EXECUTE display_appname + +statement ok +CREATE DATABASE d35145 + +query T +EXECUTE display_appname +---- +ap35145 + +# Check what happens when the stmt is executed over a non-existent, unrelated db. + +statement ok +CREATE DATABASE d35145_2; SET database = d35145_2; DROP DATABASE d35145_2 + +query error database "d35145_2" does not exist +EXECUTE display_appname + +# Check what happens when the stmt is executed over no db whatsoever. + +statement ok +SET database = '' + +query error cannot access virtual schema in anonymous database +EXECUTE display_appname diff --git a/pkg/sql/opt_catalog.go b/pkg/sql/opt_catalog.go index 7bb4b645c4b4..ea0a07249d42 100644 --- a/pkg/sql/opt_catalog.go +++ b/pkg/sql/opt_catalog.go @@ -16,6 +16,7 @@ package sql import ( "context" + "math" "time" "github.com/cockroachdb/cockroach/pkg/sql/opt/cat" @@ -198,15 +199,25 @@ func (oc *optCatalog) newDataSource( // all databases. We treat the empty catalog as having database ID 0. if name.Catalog() != "" { // TODO(radu): it's unfortunate that we have to lookup the schema again. - found, dbDesc, err := oc.resolver.LookupSchema(ctx, name.Catalog(), name.Schema()) + _, dbDesc, err := oc.resolver.LookupSchema(ctx, name.Catalog(), name.Schema()) if err != nil { return nil, err } - if !found { - // The virtual table should be valid if we got this far. - return nil, pgerror.NewAssertionErrorf("schema for virtual table not found") + if dbDesc == nil { + // The database was not found. This can happen e.g. when + // accessing a virtual schema over a non-existent + // database. This is a common scenario when the current db + // in the session points to a database that was not created + // yet. + // + // In that case we use an invalid database ID. We + // distinguish this from the empty database case because the + // virtual tables do not "contain" the same information in + // both cases. + id |= cat.StableID(math.MaxUint32) << 32 + } else { + id |= cat.StableID(dbDesc.(*DatabaseDescriptor).ID) << 32 } - id |= cat.StableID(dbDesc.(*DatabaseDescriptor).ID) << 32 } }