github.com/dolthub/dolt/go@v0.40.5-0.20240520175717-68db7794bea6/libraries/doltcore/sqle/dtables/merge_status_table.go (about)

     1  // Copyright 2022 Dolthub, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package dtables
    16  
    17  import (
    18  	"context"
    19  	"io"
    20  	"strings"
    21  
    22  	"github.com/dolthub/go-mysql-server/sql"
    23  	"github.com/dolthub/go-mysql-server/sql/types"
    24  
    25  	"github.com/dolthub/dolt/go/libraries/doltcore/doltdb"
    26  	"github.com/dolthub/dolt/go/libraries/doltcore/sqle/dsess"
    27  	"github.com/dolthub/dolt/go/libraries/doltcore/sqle/index"
    28  	"github.com/dolthub/dolt/go/libraries/utils/set"
    29  )
    30  
    31  // MergeStatusTable is a sql.Table implementation that implements a system table
    32  // which shows information about an active merge.
    33  type MergeStatusTable struct {
    34  	dbName string
    35  }
    36  
    37  func (s MergeStatusTable) Name() string {
    38  	return doltdb.MergeStatusTableName
    39  }
    40  
    41  func (s MergeStatusTable) String() string {
    42  	return doltdb.MergeStatusTableName
    43  }
    44  
    45  func (s MergeStatusTable) Schema() sql.Schema {
    46  	return []*sql.Column{
    47  		{Name: "is_merging", Type: types.Boolean, Source: doltdb.MergeStatusTableName, PrimaryKey: false, Nullable: false, DatabaseSource: s.dbName},
    48  		{Name: "source", Type: types.Text, Source: doltdb.MergeStatusTableName, PrimaryKey: false, Nullable: true, DatabaseSource: s.dbName},
    49  		{Name: "source_commit", Type: types.Text, Source: doltdb.MergeStatusTableName, PrimaryKey: false, Nullable: true, DatabaseSource: s.dbName},
    50  		{Name: "target", Type: types.Text, Source: doltdb.MergeStatusTableName, PrimaryKey: false, Nullable: true, DatabaseSource: s.dbName},
    51  		{Name: "unmerged_tables", Type: types.Text, Source: doltdb.MergeStatusTableName, PrimaryKey: false, Nullable: true, DatabaseSource: s.dbName},
    52  	}
    53  }
    54  
    55  func (s MergeStatusTable) Collation() sql.CollationID {
    56  	return sql.Collation_Default
    57  }
    58  
    59  func (s MergeStatusTable) Partitions(*sql.Context) (sql.PartitionIter, error) {
    60  	return index.SinglePartitionIterFromNomsMap(nil), nil
    61  }
    62  
    63  func (s MergeStatusTable) PartitionRows(ctx *sql.Context, _ sql.Partition) (sql.RowIter, error) {
    64  	sesh := dsess.DSessFromSess(ctx.Session)
    65  	ws, err := sesh.WorkingSet(ctx, s.dbName)
    66  	if err != nil {
    67  		return nil, err
    68  	}
    69  
    70  	return newMergeStatusItr(ctx, ws)
    71  }
    72  
    73  // NewMergeStatusTable creates a StatusTable
    74  func NewMergeStatusTable(dbName string) sql.Table {
    75  	return &MergeStatusTable{dbName}
    76  }
    77  
    78  // MergeStatusIter is a sql.RowItr implementation which iterates over each commit as if it's a row in the table.
    79  type MergeStatusIter struct {
    80  	idx            int
    81  	isMerging      bool
    82  	sourceCommit   *string
    83  	source         *string
    84  	target         *string
    85  	unmergedTables *string
    86  }
    87  
    88  func newMergeStatusItr(ctx context.Context, ws *doltdb.WorkingSet) (*MergeStatusIter, error) {
    89  	wr := ws.WorkingRoot()
    90  
    91  	inConflict, err := doltdb.TablesWithDataConflicts(ctx, wr)
    92  	if err != nil {
    93  		return nil, err
    94  	}
    95  
    96  	tblsWithViolations, err := doltdb.TablesWithConstraintViolations(ctx, wr)
    97  	if err != nil {
    98  		return nil, err
    99  	}
   100  
   101  	var schConflicts []string
   102  	if ws.MergeActive() {
   103  		schConflicts = ws.MergeState().TablesWithSchemaConflicts()
   104  	}
   105  
   106  	unmergedTblNames := set.NewStrSet(inConflict)
   107  	unmergedTblNames.Add(tblsWithViolations...)
   108  	unmergedTblNames.Add(schConflicts...)
   109  
   110  	var sourceCommitSpecStr *string
   111  	var sourceCommitHash *string
   112  	var target *string
   113  	var unmergedTables *string
   114  	if ws.MergeActive() {
   115  		state := ws.MergeState()
   116  
   117  		s := state.CommitSpecStr()
   118  		sourceCommitSpecStr = &s
   119  
   120  		cmHash, err := state.Commit().HashOf()
   121  		if err != nil {
   122  			return nil, err
   123  		}
   124  		s2 := cmHash.String()
   125  		sourceCommitHash = &s2
   126  
   127  		curr, err := ws.Ref().ToHeadRef()
   128  		if err != nil {
   129  			return nil, err
   130  		}
   131  		s3 := curr.String()
   132  		target = &s3
   133  
   134  		s4 := strings.Join(unmergedTblNames.AsSlice(), ", ")
   135  		unmergedTables = &s4
   136  	}
   137  
   138  	return &MergeStatusIter{
   139  		idx:            0,
   140  		isMerging:      ws.MergeActive(),
   141  		source:         sourceCommitSpecStr,
   142  		sourceCommit:   sourceCommitHash,
   143  		target:         target,
   144  		unmergedTables: unmergedTables,
   145  	}, nil
   146  }
   147  
   148  // Next retrieves the next row.
   149  func (itr *MergeStatusIter) Next(*sql.Context) (sql.Row, error) {
   150  	if itr.idx >= 1 {
   151  		return nil, io.EOF
   152  	}
   153  
   154  	defer func() {
   155  		itr.idx++
   156  	}()
   157  
   158  	return sql.NewRow(itr.isMerging, unwrapString(itr.source), unwrapString(itr.sourceCommit), unwrapString(itr.target), unwrapString(itr.unmergedTables)), nil
   159  }
   160  
   161  func unwrapString(s *string) interface{} {
   162  	if s == nil {
   163  		return nil
   164  	}
   165  	return *s
   166  }
   167  
   168  // Close closes the iterator.
   169  func (itr *MergeStatusIter) Close(*sql.Context) error {
   170  	return nil
   171  }