chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:32:25 +08:00
commit e014feafe1
2285 changed files with 1131979 additions and 0 deletions
+113
View File
@@ -0,0 +1,113 @@
// 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 objinterface
import (
"context"
"github.com/dolthub/dolt/go/libraries/doltcore/doltdb"
"github.com/dolthub/dolt/go/libraries/doltcore/merge"
"github.com/dolthub/dolt/go/store/hash"
"github.com/dolthub/doltgresql/core/id"
"github.com/dolthub/doltgresql/core/storage"
pgtypes "github.com/dolthub/doltgresql/server/types"
)
// RootObjectID is an ID that distinguishes names and root objects from one another.
type RootObjectID int64
const (
RootObjectID_None RootObjectID = iota
RootObjectID_Sequences
RootObjectID_Types
RootObjectID_Functions
RootObjectID_Triggers
RootObjectID_Extensions
RootObjectID_Conflicts
RootObjectID_Procedures
RootObjectID_Casts
)
const (
FIELD_NAME_ROOT_OBJECT = "root_object"
FIELD_NAME_ANCESTOR = "ancestor"
FIELD_NAME_OURS = "ours"
FIELD_NAME_THEIRS = "theirs"
)
// Collection is a collection of root objects.
type Collection interface {
// DeserializeRootObject deserializes a root object's data.
DeserializeRootObject(ctx context.Context, data []byte) (RootObject, error)
// DiffRootObjects returns a RootObjectDiff for each change made from the ancestor that is not reflected on both
// "ours" and "theirs".
DiffRootObjects(ctx context.Context, fromHash string, ours RootObject, theirs RootObject, ancestor RootObject) ([]RootObjectDiff, RootObject, error)
// DropRootObject removes the given root object from the collection.
DropRootObject(ctx context.Context, identifier id.Id) error
// GetFieldType returns the type associated with the given diff field name. Returns nil if the name is invalid.
GetFieldType(ctx context.Context, fieldName string) *pgtypes.DoltgresType
// GetID returns the identifying ID for the Collection.
GetID() RootObjectID
// GetRootObject returns the root object matching the given ID. Returns false if it cannot be found.
GetRootObject(ctx context.Context, identifier id.Id) (RootObject, bool, error)
// HasRootObject returns whether a root object exactly matching the given ID was found.
HasRootObject(ctx context.Context, identifier id.Id) (bool, error)
// IDToTableName converts the given ID to a table name. The table name will be empty for invalid IDs.
IDToTableName(identifier id.Id) doltdb.TableName
// IterAll iterates over all root objects in the Collection.
IterAll(ctx context.Context, callback func(rootObj RootObject) (stop bool, err error)) error
// IterIDs iterates over all IDs in the Collection.
IterIDs(ctx context.Context, callback func(identifier id.Id) (stop bool, err error)) error
// PutRootObject updates the Collection with the given root object. This may error if the root object already exists.
PutRootObject(ctx context.Context, rootObj RootObject) error
// RenameRootObject changes the ID for a root object matching the old ID.
RenameRootObject(ctx context.Context, oldID id.Id, newID id.Id) error
// ResolveName 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.
ResolveName(ctx context.Context, name doltdb.TableName) (doltdb.TableName, id.Id, error)
// TableNameToID converts the given name to an ID. The ID will be invalid for empty/malformed names.
TableNameToID(name doltdb.TableName) id.Id
// UpdateField updates the field on the given root object with the new value. Returns a new root object with the
// updated field.
UpdateField(ctx context.Context, rootObject RootObject, fieldName string, newValue any) (RootObject, error)
// HandleMerge handles merging of two objects. It is guaranteed that "ours" and "theirs" will not be nil, however
// "ancestor" may or may not be nil.
HandleMerge(ctx context.Context, mro merge.MergeRootObject) (doltdb.RootObject, *merge.MergeStats, error)
// LoadCollection loads the Collection from the given root.
LoadCollection(ctx context.Context, root RootValue) (Collection, error)
// 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.
UpdateRoot(ctx context.Context, root RootValue) (RootValue, error)
}
// RootValue is an interface to get around import cycles, since the core package references this package (and is where
// RootValue is defined).
type RootValue interface {
doltdb.RootValue
// GetStorage returns the storage contained in the root.
GetStorage(context.Context) storage.RootStorage
// WithStorage returns an updated RootValue with the given storage.
WithStorage(context.Context, storage.RootStorage) RootValue
}
+208
View File
@@ -0,0 +1,208 @@
// 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 objinterface
import (
"cmp"
"context"
"github.com/cockroachdb/errors"
"github.com/dolthub/dolt/go/libraries/doltcore/doltdb"
"github.com/dolthub/go-mysql-server/sql"
"github.com/dolthub/doltgresql/core/id"
pgtypes "github.com/dolthub/doltgresql/server/types"
)
// RootObject is an expanded interface on Dolt's root objects.
type RootObject interface {
doltdb.RootObject
// GetID returns the root object ID.
GetID() id.Id
// GetRootObjectID returns the root object ID.
GetRootObjectID() RootObjectID
// Serialize returns the byte representation of the root object.
Serialize(ctx context.Context) ([]byte, error)
}
// Conflict is an expanded interface on Dolt's conflict root object.
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.
FieldType(ctx context.Context, name string) *pgtypes.DoltgresType
}
// RootObjectDiffChange specifies the type of change that occurred from the ancestor value.
type RootObjectDiffChange uint8
const (
RootObjectDiffChange_Added RootObjectDiffChange = iota
RootObjectDiffChange_Deleted
RootObjectDiffChange_Modified
RootObjectDiffChange_NoChange
)
// RootObjectDiffSchema is the baseline schema that is returned for root object diffs.
var RootObjectDiffSchema = sql.Schema{
{Name: "from_root_ish", Type: pgtypes.Text, Default: nil, Nullable: false},
{Name: "base_value", Type: pgtypes.Text, Default: nil, Nullable: true},
{Name: "our_value", Type: pgtypes.Text, Default: nil, Nullable: true},
{Name: "our_diff_type", Type: pgtypes.Text, Default: nil, Nullable: false},
{Name: "their_value", Type: pgtypes.Text, Default: nil, Nullable: true},
{Name: "their_diff_type", Type: pgtypes.Text, Default: nil, Nullable: false},
{Name: "dolt_conflict_id", Type: pgtypes.Text, Default: nil, Nullable: false},
}
// RootObjectDiff represents a diff between the ancestor value and our/their values. The field name uniquely identifies
// which part of a root object that this diff covers.
type RootObjectDiff struct {
Type *pgtypes.DoltgresType
FromHash string
FieldName string
AncestorValue any
OurValue any
TheirValue any
OurChange RootObjectDiffChange
TheirChange RootObjectDiffChange
}
var _ doltdb.RootObjectDiff = RootObjectDiff{}
// CompareIds implements the interface doltdb.RootObjectDiff.
func (diff RootObjectDiff) CompareIds(ctx context.Context, o doltdb.RootObjectDiff) (int, error) {
other, ok := o.(RootObjectDiff)
if !ok {
return 0, errors.Errorf("root object diff cannot compare with diff of type %T", o)
}
return cmp.Compare(diff.FieldName, other.FieldName), nil
}
// ToRow implements the interface doltdb.RootObjectDiff.
func (diff RootObjectDiff) ToRow(ctx *sql.Context) (_ sql.Row, err error) {
var baseValue any
var ourValue any
var theirValue any
var ourChange any
var theirChange any
if diff.AncestorValue != nil {
baseValue, err = diff.Type.IoOutput(ctx, diff.AncestorValue)
if err != nil {
return nil, err
}
}
if diff.OurValue != nil {
ourValue, err = diff.Type.IoOutput(ctx, diff.OurValue)
if err != nil {
return nil, err
}
}
if diff.TheirValue != nil {
theirValue, err = diff.Type.IoOutput(ctx, diff.TheirValue)
if err != nil {
return nil, err
}
}
switch diff.OurChange {
case RootObjectDiffChange_Added:
ourChange = "added"
case RootObjectDiffChange_Deleted:
ourChange = "deleted"
case RootObjectDiffChange_Modified:
ourChange = "modified"
case RootObjectDiffChange_NoChange:
ourChange = "no_change"
}
switch diff.TheirChange {
case RootObjectDiffChange_Added:
theirChange = "added"
case RootObjectDiffChange_Deleted:
theirChange = "deleted"
case RootObjectDiffChange_Modified:
theirChange = "modified"
case RootObjectDiffChange_NoChange:
ourChange = "no_change"
}
return sql.Row{diff.FromHash, baseValue, ourValue, ourChange, theirValue, theirChange, diff.FieldName}, nil
}
// DiffFromRow converts a row to a conflict diff.
func DiffFromRow(ctx *sql.Context, conflict doltdb.ConflictRootObject, row sql.Row) (_ doltdb.RootObjectDiff, err error) {
if len(row) != len(RootObjectDiffSchema) {
return nil, errors.Newf("expected root object row diff to have %d columns but had %d", len(RootObjectDiffSchema), len(row))
}
fieldName := row[6].(string)
typ := conflict.(Conflict).FieldType(ctx, fieldName)
if typ == nil {
return nil, errors.Newf("cannot find a field named `%s`", fieldName)
}
var baseValue any
var ourValue any
var theirValue any
var ourChange RootObjectDiffChange
var theirChange RootObjectDiffChange
if row[1] != nil {
baseValue, err = typ.IoInput(ctx, row[1].(string))
if err != nil {
return nil, err
}
}
if row[2] != nil {
ourValue, err = typ.IoInput(ctx, row[2].(string))
if err != nil {
return nil, err
}
}
if row[4] != nil {
theirValue, err = typ.IoInput(ctx, row[4].(string))
if err != nil {
return nil, err
}
}
switch row[3].(string) {
case "added":
ourChange = RootObjectDiffChange_Added
case "deleted":
ourChange = RootObjectDiffChange_Deleted
case "modified":
ourChange = RootObjectDiffChange_Modified
case "no_change":
ourChange = RootObjectDiffChange_NoChange
}
switch row[5].(string) {
case "added":
theirChange = RootObjectDiffChange_Added
case "deleted":
theirChange = RootObjectDiffChange_Deleted
case "modified":
theirChange = RootObjectDiffChange_Modified
case "no_change":
ourChange = RootObjectDiffChange_NoChange
}
return RootObjectDiff{
Type: typ,
FromHash: row[0].(string),
FieldName: fieldName,
AncestorValue: baseValue,
OurValue: ourValue,
TheirValue: theirValue,
OurChange: ourChange,
TheirChange: theirChange,
}, nil
}
+102
View File
@@ -0,0 +1,102 @@
// 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 objinterface
import (
"context"
"fmt"
doltserial "github.com/dolthub/dolt/go/gen/fb/serial"
"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/dolt/go/store/types"
flatbuffers "github.com/dolthub/flatbuffers/v23/go"
"github.com/dolthub/doltgresql/core/storage"
"github.com/dolthub/doltgresql/flatbuffers/gen/serial"
)
// RootObjectSerializer holds function pointers for the serialization of root objects.
type RootObjectSerializer struct {
Bytes func(*serial.RootValue) []byte
RootValueAdd func(builder *flatbuffers.Builder, sequences flatbuffers.UOffsetT)
}
// CreateProllyMap creates and returns a new, empty Prolly map.
func (serializer RootObjectSerializer) CreateProllyMap(ctx context.Context, root RootValue) (prolly.AddressMap, error) {
return prolly.NewEmptyAddressMap(root.NodeStore())
}
// GetProllyMap loads the Prolly map from the given root, using the internal serialization functions.
func (serializer RootObjectSerializer) GetProllyMap(ctx context.Context, root RootValue) (prolly.AddressMap, bool, error) {
val, ok, err := serializer.getValue(ctx, root)
if err != nil || !ok {
return prolly.AddressMap{}, ok, err
}
serialMessage := val.(types.SerialMessage)
node, fileId, err := tree.NodeFromBytes(serialMessage)
if err != nil {
return prolly.AddressMap{}, false, err
}
if fileId != doltserial.AddressMapFileID {
return prolly.AddressMap{}, false, fmt.Errorf("invalid address map identifier, expected %s, got %s", doltserial.AddressMapFileID, fileId)
}
addressMap, err := prolly.NewAddressMap(node, root.NodeStore())
return addressMap, err == nil, err
}
// WriteProllyMap writes the given Prolly map to the root, returning the updated root.
func (serializer RootObjectSerializer) WriteProllyMap(ctx context.Context, root RootValue, val prolly.AddressMap) (RootValue, error) {
return serializer.writeValue(ctx, root, tree.ValueFromNode(val.Node()))
}
// getValue loads the value from the given root, using the internal serialization functions.
func (serializer RootObjectSerializer) getValue(ctx context.Context, root RootValue) (types.Value, bool, error) {
hashBytes := serializer.Bytes(root.GetStorage(ctx).SRV)
if len(hashBytes) == 0 {
return nil, false, nil
}
h := hash.New(hashBytes)
if h.IsEmpty() {
return nil, false, nil
}
val, err := root.VRW().ReadValue(ctx, h)
return val, err == nil && val != nil, err
}
// setHash writes the given hash to storage, returning the updated storage.
func (serializer RootObjectSerializer) setHash(ctx context.Context, st storage.RootStorage, h hash.Hash) (storage.RootStorage, error) {
if len(serializer.Bytes(st.SRV)) > 0 {
ret := st.Clone()
copy(serializer.Bytes(ret.SRV), h[:])
return ret, nil
} else {
return st.Clone(), nil
}
}
// writeValue writes the given value to the root, returning the updated root.
func (serializer RootObjectSerializer) writeValue(ctx context.Context, root RootValue, val types.Value) (RootValue, error) {
ref, err := root.VRW().WriteValue(ctx, val)
if err != nil {
return nil, err
}
newStorage, err := serializer.setHash(ctx, root.GetStorage(ctx), ref.TargetHash())
if err != nil {
return nil, err
}
return root.WithStorage(ctx, newStorage), nil
}