diff --git a/go/libraries/doltcore/doltdb/system_table.go b/go/libraries/doltcore/doltdb/system_table.go index 65c1c9d6aec..d0ffc6e1e77 100644 --- a/go/libraries/doltcore/doltdb/system_table.go +++ b/go/libraries/doltcore/doltdb/system_table.go @@ -137,50 +137,6 @@ func GetNonSystemTableNames(ctx context.Context, root RootValue) ([]string, erro return tn, nil } -// GetSystemTableNames gets system table names -func GetSystemTableNames(ctx context.Context, root RootValue) ([]string, error) { - p, err := GetPersistedSystemTables(ctx, root) - if err != nil { - return nil, err - } - - g, err := GetGeneratedSystemTables(ctx, root) - if err != nil { - - } - - s := append(p, g...) - sort.Strings(s) - - return s, nil -} - -// GetPersistedSystemTables returns table names of all persisted system tables. -func GetPersistedSystemTables(ctx context.Context, root RootValue) ([]string, error) { - tn, err := root.GetTableNames(ctx, DefaultSchemaName) - if err != nil { - return nil, err - } - sort.Strings(tn) - return funcitr.FilterStrings(tn, HasDoltPrefix), nil -} - -// GetGeneratedSystemTables returns table names of all generated system tables. -func GetGeneratedSystemTables(ctx context.Context, root RootValue) ([]string, error) { - s := set.NewStrSet(getGeneratedSystemTables()) - - tn, err := root.GetTableNames(ctx, DefaultSchemaName) - if err != nil { - return nil, err - } - - for _, pre := range generatedSystemTablePrefixes { - s.Add(funcitr.MapStrings(tn, func(s string) string { return pre + s })...) - } - - return s.AsSlice(), nil -} - // The set of reserved dolt_ tables that should be considered part of user space, like any other user-created table, // for the purposes of the dolt command line. These tables cannot be created or altered explicitly, but can be updated // like normal SQL tables. @@ -206,9 +162,9 @@ var getWriteableSystemTables = func() []string { } } -// getGeneratedSystemTables is a function which returns the names of all generated system tables. This is not +// GeneratedSystemTableNames returns the names of all generated system tables. This is not // simply a list of constants because doltgres swaps out the functions used to generate different names. -var getGeneratedSystemTables = func() []string { +func GeneratedSystemTableNames() []string { return []string{ GetBranchesTableName(), GetRemoteBranchesTableName(), @@ -225,7 +181,9 @@ var getGeneratedSystemTables = func() []string { } } -var generatedSystemTablePrefixes = []string{ +// GeneratedSystemTablePrefixes returns the prefixes of all generated system tables, the ones that exist for every +// user table. +var GeneratedSystemTablePrefixes = []string{ DoltDiffTablePrefix, DoltCommitDiffTablePrefix, DoltHistoryTablePrefix, @@ -454,6 +412,27 @@ const ( StashesTableName = "dolt_stashes" ) +// DoltGeneratedTableNames is a list of all the generated dolt system tables that are not specific to a user table. +// It does not include tables in the dolt_ prefix namespace that are user-populated, such as dolt_ignore or dolt_docs. +// These tables are addressable by these names in both Dolt and Doltgres. In doltgres they are additionally addressable +// in the `dolt.` schema, e.g. `dolt.branches` +var DoltGeneratedTableNames = []string{ + LogTableName, + DiffTableName, + ColumnDiffTableName, + TableOfTablesInConflictName, + TableOfTablesWithViolationsName, + SchemaConflictsTableName, + BranchesTableName, + RemoteBranchesTableName, + RemotesTableName, + CommitsTableName, + CommitAncestorsTableName, + StatusTableName, + MergeStatusTableName, + TagsTableName, +} + const ( // WorkflowsTableName is the dolt CI workflows system table name WorkflowsTableName = "dolt_ci_workflows" diff --git a/go/libraries/doltcore/sqle/database.go b/go/libraries/doltcore/sqle/database.go index 37a18079deb..37faffcbc0b 100644 --- a/go/libraries/doltcore/sqle/database.go +++ b/go/libraries/doltcore/sqle/database.go @@ -1050,8 +1050,12 @@ func (db Database) tableInsensitive(ctx *sql.Context, root doltdb.RootValue, tab return doltdb.TableName{}, nil, false, fmt.Errorf("no state for database %s", db.RevisionQualifiedName()) } - if tableListKey := root.TableListHash(); tableListKey != 0 { - tableList, ok := dbState.SessionCache().GetCachedTableMap(tableListKey) + // TODO: this logic is broken in the presence of schemas. It's set on a root value but always uses a single schema. + // It needs to use the values of every table in every schema when computing the cache. It's also only set on a + // call to GetTableNames, and is unset before such a call. This also means that doltgres cannot make use of this + // caching, because the getAllTableNames below switches to different logic for doltgres. + if root.TableListHash() != 0 { + tableList, ok := dbState.SessionCache().GetTableNameMap(root.TableListHash()) if ok { tname, ok := tableList[strings.ToLower(tableName)] if ok { @@ -1067,17 +1071,17 @@ func (db Database) tableInsensitive(ctx *sql.Context, root doltdb.RootValue, tab } } - tableNames, err := db.getAllTableNames(ctx, root, true) + tableNames, err := db.getAllTableNames(ctx, root, false) if err != nil { return doltdb.TableName{}, nil, false, err } - if tableListKey := root.TableListHash(); tableListKey != 0 { + if root.TableListHash() != 0 { tableMap := make(map[string]string) for _, table := range tableNames { tableMap[strings.ToLower(table)] = table } - dbState.SessionCache().CacheTableMap(tableListKey, tableMap) + dbState.SessionCache().CacheTableNameMap(root.TableListHash(), tableMap) } tableName, ok = sql.GetTableNameInsensitive(tableName, tableNames) @@ -1158,7 +1162,7 @@ func (db Database) GetAllTableNames(ctx *sql.Context, showSystemTables bool) ([] return db.getAllTableNames(ctx, root, showSystemTables) } -func (db Database) getAllTableNames(ctx *sql.Context, root doltdb.RootValue, showSystemTables bool) ([]string, error) { +func (db Database) getAllTableNames(ctx *sql.Context, root doltdb.RootValue, includeGeneratedSystemTables bool) ([]string, error) { var err error var result []string // If we are in a schema-enabled session and the schema name is not set, we need to union all table names in all @@ -1178,12 +1182,14 @@ func (db Database) getAllTableNames(ctx *sql.Context, root doltdb.RootValue, sho } } - if showSystemTables { - systemTables, err := doltdb.GetGeneratedSystemTables(ctx, root) + if includeGeneratedSystemTables { + // TODO: this should work on the current schema only, if there is one + // TODO: this is getting called with showSystemTables = true, which seems wrong in most cases + systemTables, err := resolve.GetGeneratedSystemTables(ctx, root) if err != nil { return nil, err } - result = append(result, systemTables...) + result = append(result, doltdb.FlattenTableNames(systemTables)...) } return result, nil diff --git a/go/libraries/doltcore/sqle/dsess/session_cache.go b/go/libraries/doltcore/sqle/dsess/session_cache.go index e681f651134..11f0380f63c 100644 --- a/go/libraries/doltcore/sqle/dsess/session_cache.go +++ b/go/libraries/doltcore/sqle/dsess/session_cache.go @@ -261,13 +261,16 @@ func (c *SessionCache) CacheTableChecks(key doltdb.DataCacheKey, checks []sql.Ch c.checks[key] = checks } -func (c *SessionCache) GetCachedTableMap(key uint64) (map[string]string, bool) { +// GetTableNameMap returns the cached names of tables in a given root, keyed by their lower-case name, to their +// case-sensitive name +func (c *SessionCache) GetTableNameMap(key uint64) (map[string]string, bool) { tables, ok := c.tableMaps[key] return tables, ok } -// CacheTableChecks caches sql.CheckConstraints for the table named -func (c *SessionCache) CacheTableMap(key uint64, tables map[string]string) { +// CacheTableNameMap caches the names of tables in a given root, keyed by their lower-case name, to their +// case-sensitive name +func (c *SessionCache) CacheTableNameMap(key uint64, tables map[string]string) { c.mu.Lock() defer c.mu.Unlock() diff --git a/go/libraries/doltcore/sqle/resolve/system_tables.go b/go/libraries/doltcore/sqle/resolve/system_tables.go new file mode 100755 index 00000000000..47de3ed807c --- /dev/null +++ b/go/libraries/doltcore/sqle/resolve/system_tables.go @@ -0,0 +1,77 @@ +// Copyright 2025 Dolthub, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package resolve + +import ( + "context" + + "github.com/dolthub/dolt/go/libraries/doltcore/doltdb" + "github.com/dolthub/dolt/go/libraries/doltcore/schema" +) + +// GetGeneratedSystemTables returns table names of all generated system tables. +func GetGeneratedSystemTables(ctx context.Context, root doltdb.RootValue) ([]doltdb.TableName, error) { + s := doltdb.NewTableNameSet(nil) + + // Depending on whether the search path is used, the generated system tables will either be in the dolt namespace + // or the empty (default) namespace + if !UseSearchPath { + for _, t := range doltdb.GeneratedSystemTableNames() { + s.Add(doltdb.TableName{Name: t}) + } + } else { + for _, t := range doltdb.GeneratedSystemTableNames() { + s.Add(doltdb.TableName{Name: t, Schema: doltdb.DoltNamespace}) + } + } + + schemas, err := root.GetDatabaseSchemas(ctx) + if err != nil { + return nil, err + } + + // For dolt there are no stored schemas, search the default (empty string) schema + if len(schemas) == 0 { + schemas = append(schemas, schema.DatabaseSchema{Name: doltdb.DefaultSchemaName}) + } + + for _, schema := range schemas { + tableNames, err := root.GetTableNames(ctx, schema.Name) + if err != nil { + return nil, err + } + + for _, pre := range doltdb.GeneratedSystemTablePrefixes { + for _, tableName := range tableNames { + s.Add(doltdb.TableName{ + Name: pre + tableName, + Schema: schema.Name, + }) + } + } + + // For doltgres, we also support the legacy dolt_ table names, addressable in any user schema + if UseSearchPath && schema.Name != "pg_catalog" && schema.Name != doltdb.DoltNamespace { + for _, name := range doltdb.DoltGeneratedTableNames { + s.Add(doltdb.TableName{ + Name: name, + Schema: schema.Name, + }) + } + } + } + + return s.AsSlice(), nil +} diff --git a/go/libraries/doltcore/sqle/tables.go b/go/libraries/doltcore/sqle/tables.go index 7ad57f5dd32..8a8382180f4 100644 --- a/go/libraries/doltcore/sqle/tables.go +++ b/go/libraries/doltcore/sqle/tables.go @@ -79,7 +79,6 @@ func init() { } } -var _ dtables.VersionableTable = (*DoltTable)(nil) var _ dtables.VersionableTable = (*DoltTable)(nil) // DoltTable implements the sql.Table interface and gives access to dolt table rows and schema.