Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions core/conflicts/collection.go
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,11 @@ func (conflict Conflict) FieldType(ctx context.Context, name string) *pgtypes.Do
return GetFieldType(ctx, conflict.RootObjectID, name)
}

// GetContainedRootObjectID implements the interface objinterface.RootObject.
func (conflict Conflict) GetContainedRootObjectID() objinterface.RootObjectID {
return conflict.RootObjectID
}

// GetID implements the interface objinterface.RootObject.
func (conflict Conflict) GetID() id.Id {
return conflict.ID
Expand Down Expand Up @@ -383,6 +388,12 @@ var GetFieldType = func(ctx context.Context, rootObjID objinterface.RootObjectID
panic("GetFieldType was never initialized")
}

// ResolveNameExternal handles name resolution across all collection types, and is declared in a different package. It
// is assigned here by an Init function to get around import cycles.
var ResolveNameExternal = func(ctx context.Context, name doltdb.TableName, rootObjects []objinterface.RootObject) (doltdb.TableName, id.Id, error) {
panic("ResolveNameExternal was never initialized")
}

// UpdateField handles updating fields in a root object, and is declared in a different package. It is assigned here by
// an Init function to get around import cycles.
var UpdateField = func(ctx context.Context, rootObjID objinterface.RootObjectID, rootObject objinterface.RootObject, fieldName string, newValue any) (objinterface.RootObject, error) {
Expand Down
7 changes: 7 additions & 0 deletions core/conflicts/collection_funcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"github.com/dolthub/dolt/go/store/hash"
"github.com/dolthub/dolt/go/store/prolly"

"github.com/dolthub/doltgresql/core/id"
"github.com/dolthub/doltgresql/core/rootobject/objinterface"
"github.com/dolthub/doltgresql/flatbuffers/gen/serial"
)
Expand Down Expand Up @@ -95,6 +96,12 @@ func LoadConflicts(ctx context.Context, root objinterface.RootValue) (*Collectio
return NewCollection(ctx, m, root.NodeStore())
}

// ResolveNameFromObjects implements the interface objinterface.Collection.
func (*Collection) ResolveNameFromObjects(ctx context.Context, name doltdb.TableName, rootObjects []objinterface.RootObject) (doltdb.TableName, id.Id, error) {
// Conflicts make use of this interface function, so we must return nil to prevent infinite recursion
return doltdb.TableName{}, id.Null, nil
}

// Serializer implements the interface objinterface.Collection.
func (*Collection) Serializer() objinterface.RootObjectSerializer {
return storage
Expand Down
16 changes: 13 additions & 3 deletions core/conflicts/root_object.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,20 @@ func (pgc *Collection) RenameRootObject(ctx context.Context, oldName id.Id, newN

// ResolveName implements the interface objinterface.Collection.
func (pgc *Collection) ResolveName(ctx context.Context, name doltdb.TableName) (doltdb.TableName, id.Id, error) {
if resolvedId, ok := pgc.nameCache[name]; ok {
return name, resolvedId, nil
if len(pgc.idCache) == 0 {
return doltdb.TableName{}, id.Null, nil
}
objs := make([]objinterface.RootObject, 0, len(pgc.idCache))
for _, conflict := range pgc.accessCache {
if conflict.Ours != nil {
objs = append(objs, conflict.Ours)
} else if conflict.Theirs != nil {
objs = append(objs, conflict.Theirs)
} else if conflict.Ancestor != nil {
objs = append(objs, conflict.Ancestor)
}
}
return doltdb.TableName{}, id.Null, nil
return ResolveNameExternal(ctx, name, objs)
}

// TableNameToID implements the interface objinterface.Collection.
Expand Down
57 changes: 38 additions & 19 deletions core/conflicts/serialization.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import (
)

// Serialize returns the Conflict as a byte slice. If the Conflict is invalid, then this returns a nil slice.
func (conflict Conflict) Serialize(ctx context.Context) ([]byte, error) {
func (conflict Conflict) Serialize(ctx context.Context) (_ []byte, err error) {
if !conflict.ID.IsValid() {
return nil, nil
}
Expand All @@ -33,22 +33,32 @@ func (conflict Conflict) Serialize(ctx context.Context) ([]byte, error) {
writer := utils.NewWriter(512)
writer.VariableUint(0) // Version
// Serialize "ours", "theirs", and "ancestor"
ours, err := conflict.Ours.Serialize(ctx)
if err != nil {
return nil, err
var ours, theirs, ancestor []byte
if conflict.Ours != nil {
ours, err = conflict.Ours.Serialize(ctx)
if err != nil {
return nil, err
}
}
theirs, err := conflict.Theirs.Serialize(ctx)
if err != nil {
return nil, err
if conflict.Theirs != nil {
theirs, err = conflict.Theirs.Serialize(ctx)
if err != nil {
return nil, err
}
}
ancestor, err := conflict.Ancestor.Serialize(ctx)
if err != nil {
return nil, err
if conflict.Ancestor != nil {
ancestor, err = conflict.Ancestor.Serialize(ctx)
if err != nil {
return nil, err
}
}
// Write the conflict data
writer.Id(conflict.ID)
writer.String(conflict.FromHash)
writer.Int64(int64(conflict.RootObjectID))
writer.Bool(conflict.Ours != nil)
writer.Bool(conflict.Theirs != nil)
writer.Bool(conflict.Ancestor != nil)
writer.ByteSlice(ours)
writer.ByteSlice(theirs)
writer.ByteSlice(ancestor)
Expand All @@ -73,21 +83,30 @@ func DeserializeConflict(ctx context.Context, data []byte) (_ Conflict, err erro
conflict.ID = reader.Id()
conflict.FromHash = reader.String()
conflict.RootObjectID = objinterface.RootObjectID(reader.Int64())
hasOurs := reader.Bool()
hasTheirs := reader.Bool()
hasAncestor := reader.Bool()
ours := reader.ByteSlice()
theirs := reader.ByteSlice()
ancestor := reader.ByteSlice()
// Deserialize "ours", "theirs", and "ancestor"
conflict.Ours, err = DeserializeRootObject(ctx, conflict.RootObjectID, ours)
if err != nil {
return Conflict{}, err
if hasOurs {
conflict.Ours, err = DeserializeRootObject(ctx, conflict.RootObjectID, ours)
if err != nil {
return Conflict{}, err
}
}
conflict.Theirs, err = DeserializeRootObject(ctx, conflict.RootObjectID, theirs)
if err != nil {
return Conflict{}, err
if hasTheirs {
conflict.Theirs, err = DeserializeRootObject(ctx, conflict.RootObjectID, theirs)
if err != nil {
return Conflict{}, err
}
}
conflict.Ancestor, err = DeserializeRootObject(ctx, conflict.RootObjectID, ancestor)
if err != nil {
return Conflict{}, err
if hasAncestor {
conflict.Ancestor, err = DeserializeRootObject(ctx, conflict.RootObjectID, ancestor)
if err != nil {
return Conflict{}, err
}
}
if !reader.IsEmpty() {
return Conflict{}, errors.Errorf("extra data found while deserializing a conflict")
Expand Down
14 changes: 14 additions & 0 deletions core/extensions/collection_funcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"github.com/dolthub/dolt/go/store/hash"
"github.com/dolthub/dolt/go/store/prolly"

"github.com/dolthub/doltgresql/core/id"
"github.com/dolthub/doltgresql/core/rootobject/objinterface"
"github.com/dolthub/doltgresql/flatbuffers/gen/serial"
)
Expand Down Expand Up @@ -105,6 +106,19 @@ func LoadExtensions(ctx context.Context, root objinterface.RootValue) (*Collecti
return NewCollection(ctx, m, root.NodeStore())
}

// ResolveNameFromObjects implements the interface objinterface.Collection.
func (*Collection) ResolveNameFromObjects(ctx context.Context, name doltdb.TableName, rootObjects []objinterface.RootObject) (doltdb.TableName, id.Id, error) {
tempCollection := Collection{
accessCache: make(map[id.Extension]Extension),
}
for _, rootObject := range rootObjects {
if obj, ok := rootObject.(Extension); ok {
tempCollection.accessCache[obj.ExtName] = obj
}
}
return tempCollection.ResolveName(ctx, name)
}

// Serializer implements the interface objinterface.Collection.
func (*Collection) Serializer() objinterface.RootObjectSerializer {
return storage
Expand Down
16 changes: 16 additions & 0 deletions core/functions/collection_funcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"github.com/dolthub/dolt/go/store/hash"
"github.com/dolthub/dolt/go/store/prolly"

"github.com/dolthub/doltgresql/core/id"
pgmerge "github.com/dolthub/doltgresql/core/merge"
"github.com/dolthub/doltgresql/core/rootobject/objinterface"
"github.com/dolthub/doltgresql/flatbuffers/gen/serial"
Expand Down Expand Up @@ -95,6 +96,21 @@ func LoadFunctions(ctx context.Context, root objinterface.RootValue) (*Collectio
return NewCollection(ctx, m, root.NodeStore())
}

// ResolveNameFromObjects implements the interface objinterface.Collection.
func (*Collection) ResolveNameFromObjects(ctx context.Context, name doltdb.TableName, rootObjects []objinterface.RootObject) (doltdb.TableName, id.Id, error) {
tempCollection := Collection{
accessCache: make(map[id.Function]Function),
idCache: make([]id.Function, 0, len(rootObjects)),
}
for _, rootObject := range rootObjects {
if obj, ok := rootObject.(Function); ok {
tempCollection.accessCache[obj.ID] = obj
tempCollection.idCache = append(tempCollection.idCache, obj.ID)
}
}
return tempCollection.ResolveName(ctx, name)
}

// Serializer implements the interface objinterface.Collection.
func (*Collection) Serializer() objinterface.RootObjectSerializer {
return storage
Expand Down
56 changes: 51 additions & 5 deletions core/rootobject/collection.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,11 +215,14 @@ func GetRootObject(ctx context.Context, root objinterface.RootValue, tName doltd

// GetRootObjectConflicts returns the conflict root object that matches the given name.
func GetRootObjectConflicts(ctx context.Context, root objinterface.RootValue, tName doltdb.TableName) (conflicts.Conflict, bool, error) {
_, rawID, objID, err := ResolveName(ctx, root, tName)
if err != nil || objID == objinterface.RootObjectID_None {
coll, err := globalCollections[objinterface.RootObjectID_Conflicts].LoadCollection(ctx, root)
if err != nil {
return conflicts.Conflict{}, false, err
}
_, rawID, err := coll.ResolveName(ctx, tName)
if err != nil {
return conflicts.Conflict{}, false, err
}
coll, _ := globalCollections[objinterface.RootObjectID_Conflicts].LoadCollection(ctx, root)
ro, ok, err := coll.GetRootObject(ctx, rawID)
if err != nil || !ok {
return conflicts.Conflict{}, false, err
Expand Down Expand Up @@ -455,13 +458,13 @@ func PutRootObject(ctx context.Context, root objinterface.RootValue, tName doltd
}
}
if merged == nil {
return RemoveRootObject(ctx, root, conflict.GetID(), conflict.GetRootObjectID())
return RemoveRootObjectIfExists(ctx, root, conflict.GetID(), conflict.GetContainedRootObjectID())
} else {
return PutRootObject(ctx, root, tName, merged)
}
} else {
if merged == nil {
root, err = RemoveRootObject(ctx, root, conflict.GetID(), conflict.GetRootObjectID())
root, err = RemoveRootObjectIfExists(ctx, root, conflict.GetID(), conflict.GetContainedRootObjectID())
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -491,6 +494,25 @@ func RemoveRootObject(ctx context.Context, root objinterface.RootValue, identifi
return coll.UpdateRoot(ctx, root)
}

// RemoveRootObjectIfExists removes the matching root object from its respective Collection, returning the updated root.
// If the root object does not exist, then this will not attempt the deletion.
func RemoveRootObjectIfExists(ctx context.Context, root objinterface.RootValue, identifier id.Id, rootObjectID objinterface.RootObjectID) (objinterface.RootValue, error) {
coll, err := LoadCollection(ctx, root, rootObjectID)
if err != nil {
return nil, err
}
exists, err := coll.HasRootObject(ctx, identifier)
if err != nil {
return nil, err
}
if exists {
if err = coll.DropRootObject(ctx, identifier); err != nil {
return nil, err
}
}
return coll.UpdateRoot(ctx, root)
}

// ResolveName returns the fully resolved name of the given item (if the item exists). Also returns the type of the item.
func ResolveName(ctx context.Context, root objinterface.RootValue, name doltdb.TableName) (doltdb.TableName, id.Id, objinterface.RootObjectID, error) {
var resolvedName doltdb.TableName
Expand Down Expand Up @@ -524,3 +546,27 @@ func ResolveName(ctx context.Context, root objinterface.RootValue, name doltdb.T

return resolvedName, resolvedRawID, resolvedObjID, nil
}

// resolveNameFromObjects resolves the given name on all given objects on all global collections (except for conflicts).
func resolveNameFromObjects(ctx context.Context, name doltdb.TableName, rootObjects []objinterface.RootObject) (doltdb.TableName, id.Id, error) {
var resolvedName doltdb.TableName
resolvedRawID := id.Null

for i, emptyColl := range globalCollections {
if emptyColl == nil || i == int(objinterface.RootObjectID_Conflicts) {
continue
}
rName, rID, err := emptyColl.ResolveNameFromObjects(ctx, name, rootObjects)
if err != nil {
return doltdb.TableName{}, id.Null, err
}
if rID.IsValid() {
if resolvedRawID != id.Null {
return doltdb.TableName{}, id.Null, fmt.Errorf(`"%s" is ambiguous`, name.String())
}
resolvedName = rName
resolvedRawID = rID
}
}
return resolvedName, resolvedRawID, nil
}
1 change: 1 addition & 0 deletions core/rootobject/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ func Init() {
conflicts.DeserializeRootObject = DeserializeRootObject
conflicts.DiffRootObjects = DiffRootObjects
conflicts.GetFieldType = GetFieldType
conflicts.ResolveNameExternal = resolveNameFromObjects
conflicts.UpdateField = UpdateField
doltdb.RootObjectDiffFromRow = objinterface.DiffFromRow
for _, collFuncs := range globalCollections {
Expand Down
4 changes: 4 additions & 0 deletions core/rootobject/objinterface/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ type Collection interface {
// LoadCollectionHash loads the Collection hash from the given root. This does not load the entire collection from
// the root, and is therefore a bit more performant if only the hash is needed.
LoadCollectionHash(ctx context.Context, root RootValue) (hash.Hash, error)
// ResolveNameFromObjects finds the closest matching (or exact) ID for the given name. If an exact match is not
// found, then this may error if the name is ambiguous. This searches through the given root objects rather than the
// ones stored in the collection itself.
ResolveNameFromObjects(ctx context.Context, name doltdb.TableName, rootObjects []RootObject) (doltdb.TableName, id.Id, error)
// Serializer returns the serializer associated with this Collection.
Serializer() RootObjectSerializer
// UpdateRoot updates the Collection in the given root, returning the updated root.
Expand Down
2 changes: 2 additions & 0 deletions core/rootobject/objinterface/root_object.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ type RootObject interface {
type Conflict interface {
RootObject
doltdb.ConflictRootObject
// GetContainedRootObjectID returns the root object ID of the contained items.
GetContainedRootObjectID() RootObjectID
// Diffs returns the diffs for the conflict, along with the merged root object if there are no diffs.
Diffs(ctx context.Context) ([]RootObjectDiff, RootObject, error)
// FieldType returns the type associated with the given field name. Returns nil if the name does not match a field.
Expand Down
27 changes: 27 additions & 0 deletions core/sequences/collection_funcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"github.com/dolthub/dolt/go/libraries/doltcore/merge"
"github.com/dolthub/dolt/go/store/hash"
"github.com/dolthub/dolt/go/store/prolly"
"github.com/dolthub/dolt/go/store/prolly/tree"

"github.com/dolthub/doltgresql/core/id"
merge2 "github.com/dolthub/doltgresql/core/merge"
Expand Down Expand Up @@ -145,6 +146,32 @@ func LoadSequences(ctx context.Context, root objinterface.RootValue) (*Collectio
}, nil
}

// ResolveNameFromObjects implements the interface objinterface.Collection.
func (*Collection) ResolveNameFromObjects(ctx context.Context, name doltdb.TableName, rootObjects []objinterface.RootObject) (doltdb.TableName, id.Id, error) {
// First we'll check if there are any objects to search through in the first place
accessedMap := make(map[id.Sequence]*Sequence)
for _, rootObject := range rootObjects {
if obj, ok := rootObject.(*Sequence); ok {
accessedMap[obj.Id] = obj
}
}
if len(accessedMap) == 0 {
return doltdb.TableName{}, id.Null, nil
}
// There are root objects to search through, so we'll create a temporary store
ns := tree.NewTestNodeStore()
addressMap, err := prolly.NewEmptyAddressMap(ns)
if err != nil {
return doltdb.TableName{}, id.Null, err
}
tempCollection := Collection{
accessedMap: accessedMap,
underlyingMap: addressMap,
ns: ns,
}
return tempCollection.ResolveName(ctx, name)
}

// Serializer implements the interface objinterface.Collection.
func (*Collection) Serializer() objinterface.RootObjectSerializer {
return storage
Expand Down
Loading
Loading