Skip to content

Commit

Permalink
Merge pull request #8581 from dolthub/taylor/ignore-schemas
Browse files Browse the repository at this point in the history
Support per-schema dolt_ignore for doltgres
  • Loading branch information
tbantle22 authored Nov 22, 2024
2 parents 9c1cc4c + cdc32be commit 068a8f4
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 52 deletions.
20 changes: 19 additions & 1 deletion go/libraries/doltcore/diff/table_deltas.go
Original file line number Diff line number Diff line change
Expand Up @@ -625,6 +625,21 @@ func (td TableDelta) GetRowData(ctx context.Context) (from, to durable.Index, er
return from, to, nil
}

// GetUniqueSchemaNamesFromTableNames returns a list of unique schema names from a list of table names
func GetUniqueSchemaNamesFromTableDeltas(deltas []TableDelta) []string {
schemaMap := make(map[string]struct{})
var schemas []string

for _, td := range deltas {
if _, exists := schemaMap[td.ToName.Schema]; !exists {
schemaMap[td.ToName.Schema] = struct{}{}
schemas = append(schemas, td.ToName.Schema)
}
}

return schemas
}

// WorkingSetContainsOnlyIgnoredTables returns true if all changes in working set are ignored tables.
// Otherwise, if there are any non-ignored changes, returns false.
// Note that only unstaged tables are subject to dolt_ignore (this is consistent with what git does.)
Expand All @@ -638,7 +653,8 @@ func WorkingSetContainsOnlyIgnoredTables(ctx context.Context, roots doltdb.Roots
return false, nil
}

ignorePatterns, err := doltdb.GetIgnoredTablePatterns(ctx, roots)
schemas := GetUniqueSchemaNamesFromTableDeltas(unstaged)
ignorePatternMap, err := doltdb.GetIgnoredTablePatterns(ctx, roots, schemas)
if err != nil {
return false, err
}
Expand All @@ -647,6 +663,8 @@ func WorkingSetContainsOnlyIgnoredTables(ctx context.Context, roots doltdb.Roots
if !(tableDelta.IsAdd()) {
return false, nil
}

ignorePatterns := ignorePatternMap[tableDelta.ToName.Schema]
isIgnored, err := ignorePatterns.IsTableNameIgnored(tableDelta.ToName)
if err != nil {
return false, err
Expand Down
92 changes: 51 additions & 41 deletions go/libraries/doltcore/doltdb/ignore.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,72 +68,82 @@ func convertTupleToIgnoreBoolean(valueDesc val.TupleDesc, valueTuple val.Tuple)
return ignore, nil
}

func GetIgnoredTablePatterns(ctx context.Context, roots Roots) (IgnorePatterns, error) {
var ignorePatterns []IgnorePattern
func GetIgnoredTablePatterns(ctx context.Context, roots Roots, schemas []string) (map[string]IgnorePatterns, error) {
ignorePatternsForSchemas := make(map[string]IgnorePatterns)
workingSet := roots.Working
table, found, err := workingSet.GetTable(ctx, TableName{Name: IgnoreTableName})
if err != nil {
return nil, err
}
if !found {
// dolt_ignore doesn't exist, so don't filter any tables.
return ignorePatterns, nil
}
index, err := table.GetRowData(ctx)
if table.Format() == types.Format_LD_1 {
// dolt_ignore is not supported for the legacy storage format.
return ignorePatterns, nil
}
if err != nil {
return nil, err
}
ignoreTableSchema, err := table.GetSchema(ctx)
if err != nil {
return nil, err
}
keyDesc, valueDesc := ignoreTableSchema.GetMapDescriptors()

if !keyDesc.Equals(val.NewTupleDescriptor(val.Type{Enc: val.StringEnc})) {
return nil, fmt.Errorf("dolt_ignore had unexpected key type, this should never happen")
}
for _, schemaName := range schemas {
var ignorePatterns []IgnorePattern

ignoreTableMap, err := durable.ProllyMapFromIndex(index).IterAll(ctx)
if err != nil {
return nil, err
}
for {
keyTuple, valueTuple, err := ignoreTableMap.Next(ctx)
if err == io.EOF {
break
tname := TableName{Name: IgnoreTableName, Schema: schemaName}
table, found, err := workingSet.GetTable(ctx, tname)
if err != nil {
return nil, err
}
if !found {
// dolt_ignore doesn't exist, so don't filter any tables.
continue
}
index, err := table.GetRowData(ctx)
if table.Format() == types.Format_LD_1 {
// dolt_ignore is not supported for the legacy storage format.
continue
}
if err != nil {
return nil, err
}
ignoreTableSchema, err := table.GetSchema(ctx)
if err != nil {
return nil, err
}
keyDesc, valueDesc := ignoreTableSchema.GetMapDescriptors()

pattern, ok := keyDesc.GetString(0, keyTuple)
if !ok {
return nil, fmt.Errorf("could not read pattern")
if !keyDesc.Equals(val.NewTupleDescriptor(val.Type{Enc: val.StringEnc})) {
return nil, fmt.Errorf("dolt_ignore had unexpected key type, this should never happen")
}
ignore, err := ConvertTupleToIgnoreBoolean(valueDesc, valueTuple)

ignoreTableMap, err := durable.ProllyMapFromIndex(index).IterAll(ctx)
if err != nil {
return nil, err
}
for {
keyTuple, valueTuple, err := ignoreTableMap.Next(ctx)
if err == io.EOF {
break
}
if err != nil {
return nil, err
}

pattern, ok := keyDesc.GetString(0, keyTuple)
if !ok {
return nil, fmt.Errorf("could not read pattern")
}
ignore, err := ConvertTupleToIgnoreBoolean(valueDesc, valueTuple)
if err != nil {
return nil, err
}
ignorePatterns = append(ignorePatterns, NewIgnorePattern(pattern, ignore))
}

ignorePatterns = append(ignorePatterns, NewIgnorePattern(pattern, ignore))
ignorePatternsForSchemas[schemaName] = ignorePatterns
}
return ignorePatterns, nil

return ignorePatternsForSchemas, nil
}

// ExcludeIgnoredTables takes a list of table names and removes any tables that should be ignored,
// as determined by the patterns in the dolt_ignore table.
// The ignore patterns are read from the dolt_ignore table in the working set.
func ExcludeIgnoredTables(ctx context.Context, roots Roots, tables []TableName) ([]TableName, error) {
ignorePatterns, err := GetIgnoredTablePatterns(ctx, roots)
schemas := GetUniqueSchemaNamesFromTableNames(tables)
ignorePatternMap, err := GetIgnoredTablePatterns(ctx, roots, schemas)
if err != nil {
return nil, err
}
filteredTables := []TableName{}
for _, tbl := range tables {
ignorePatterns := ignorePatternMap[tbl.Schema]
ignored, err := ignorePatterns.IsTableNameIgnored(tbl)
if err != nil {
return nil, err
Expand Down
19 changes: 18 additions & 1 deletion go/libraries/doltcore/doltdb/root_val.go
Original file line number Diff line number Diff line change
Expand Up @@ -835,6 +835,21 @@ func UnqualifiedTableNamesAsString(names []TableName) string {
return sb.String()
}

// GetUniqueSchemaNamesFromTableNames returns a list of unique schema names from a list of table names
func GetUniqueSchemaNamesFromTableNames(names []TableName) []string {
schemaMap := make(map[string]struct{})
var schemas []string

for _, t := range names {
if _, exists := schemaMap[t.Schema]; !exists {
schemaMap[t.Schema] = struct{}{}
schemas = append(schemas, t.Schema)
}
}

return schemas
}

// DefaultSchemaName is the name of the default schema. Tables with this schema name will be stored in the
// primary (unnamed) table store in a root.
var DefaultSchemaName = ""
Expand Down Expand Up @@ -1205,11 +1220,13 @@ func schemaNames(ctx context.Context, root RootValue) ([]string, error) {

// FilterIgnoredTables takes a slice of table names and divides it into new slices based on whether the table is ignored, not ignored, or matches conflicting ignore patterns.
func FilterIgnoredTables(ctx context.Context, tables []TableName, roots Roots) (ignoredTables IgnoredTables, err error) {
ignorePatterns, err := GetIgnoredTablePatterns(ctx, roots)
schemas := GetUniqueSchemaNamesFromTableNames(tables)
ignorePatternMap, err := GetIgnoredTablePatterns(ctx, roots, schemas)
if err != nil {
return ignoredTables, err
}
for _, tableName := range tables {
ignorePatterns := ignorePatternMap[tableName.Schema]
ignored, err := ignorePatterns.IsTableNameIgnored(tableName)
if conflict := AsDoltIgnoreInConflict(err); conflict != nil {
ignoredTables.Conflicts = append(ignoredTables.Conflicts, *conflict)
Expand Down
12 changes: 10 additions & 2 deletions go/libraries/doltcore/sqle/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -636,15 +636,23 @@ func (db Database) getTableInsensitive(ctx *sql.Context, head *doltdb.Commit, ds
}
}
case doltdb.IgnoreTableName:
if resolve.UseSearchPath && db.schemaName == "" {
schemaName, err := resolve.FirstExistingSchemaOnSearchPath(ctx, root)
if err != nil {
return nil, false, err
}
db.schemaName = schemaName
}

backingTable, _, err := db.getTable(ctx, root, doltdb.IgnoreTableName)
if err != nil {
return nil, false, err
}
if backingTable == nil {
dt, found = dtables.NewEmptyIgnoreTable(ctx), true
dt, found = dtables.NewEmptyIgnoreTable(ctx, db.schemaName), true
} else {
versionableTable := backingTable.(dtables.VersionableTable)
dt, found = dtables.NewIgnoreTable(ctx, versionableTable), true
dt, found = dtables.NewIgnoreTable(ctx, versionableTable, db.schemaName), true
}
case doltdb.GetDocTableName(), doltdb.DocTableName:
isDoltgresSystemTable, err := resolve.IsDoltgresSystemTable(ctx, tname, root)
Expand Down
5 changes: 4 additions & 1 deletion go/libraries/doltcore/sqle/dprocedures/dolt_rebase.go
Original file line number Diff line number Diff line change
Expand Up @@ -513,12 +513,15 @@ func filterIgnoredTables(ctx *sql.Context, unstagedTableDeltas []diff.TableDelta
}

filteredTableDeltas := make([]diff.TableDelta, 0, len(unstagedTableDeltas))
ignorePatterns, err := doltdb.GetIgnoredTablePatterns(ctx, roots)

schemas := diff.GetUniqueSchemaNamesFromTableDeltas(unstagedTableDeltas)
ignorePatternMap, err := doltdb.GetIgnoredTablePatterns(ctx, roots, schemas)
if err != nil {
return nil, err
}

for _, tableDelta := range unstagedTableDeltas {
ignorePatterns := ignorePatternMap[tableDelta.ToName.Schema]
isIgnored, err := ignorePatterns.IsTableNameIgnored(tableDelta.ToName)
if err != nil {
return nil, err
Expand Down
12 changes: 6 additions & 6 deletions go/libraries/doltcore/sqle/dtables/ignore_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ var _ sql.IndexAddressableTable = (*IgnoreTable)(nil)
// IgnoreTable is the system table that stores patterns for table names that should not be committed.
type IgnoreTable struct {
backingTable VersionableTable
schemaName string
}

func (i *IgnoreTable) Name() string {
Expand Down Expand Up @@ -86,13 +87,13 @@ func (i *IgnoreTable) PartitionRows(context *sql.Context, partition sql.Partitio
}

// NewIgnoreTable creates an IgnoreTable
func NewIgnoreTable(_ *sql.Context, backingTable VersionableTable) sql.Table {
return &IgnoreTable{backingTable: backingTable}
func NewIgnoreTable(_ *sql.Context, backingTable VersionableTable, schemaName string) sql.Table {
return &IgnoreTable{backingTable: backingTable, schemaName: schemaName}
}

// NewEmptyIgnoreTable creates an IgnoreTable
func NewEmptyIgnoreTable(_ *sql.Context) sql.Table {
return &IgnoreTable{}
func NewEmptyIgnoreTable(_ *sql.Context, schemaName string) sql.Table {
return &IgnoreTable{schemaName: schemaName}
}

// Replacer returns a RowReplacer for this table. The RowReplacer will have Insert and optionally Delete called once
Expand Down Expand Up @@ -211,9 +212,8 @@ func (iw *ignoreWriter) StatementBegin(ctx *sql.Context) {

iw.prevHash = &prevHash

tname := doltdb.TableName{Name: doltdb.IgnoreTableName}
tname := doltdb.TableName{Name: doltdb.IgnoreTableName, Schema: iw.it.schemaName}
found, err := roots.Working.HasTable(ctx, tname)

if err != nil {
iw.errDuringStatementBegin = err
return
Expand Down

0 comments on commit 068a8f4

Please sign in to comment.