github.com/dolthub/dolt/go@v0.40.5-0.20240520175717-68db7794bea6/libraries/doltcore/sqle/dtables/branches_table.go (about) 1 // Copyright 2020 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 "fmt" 19 "io" 20 21 "github.com/dolthub/go-mysql-server/sql" 22 "github.com/dolthub/go-mysql-server/sql/types" 23 24 "github.com/dolthub/dolt/go/libraries/doltcore/doltdb" 25 "github.com/dolthub/dolt/go/libraries/doltcore/ref" 26 "github.com/dolthub/dolt/go/libraries/doltcore/schema" 27 "github.com/dolthub/dolt/go/libraries/doltcore/sqle/dsess" 28 "github.com/dolthub/dolt/go/libraries/doltcore/sqle/index" 29 ) 30 31 const branchesDefaultRowCount = 10 32 33 var _ sql.Table = (*BranchesTable)(nil) 34 var _ sql.StatisticsTable = (*BranchesTable)(nil) 35 var _ sql.UpdatableTable = (*BranchesTable)(nil) 36 var _ sql.DeletableTable = (*BranchesTable)(nil) 37 var _ sql.InsertableTable = (*BranchesTable)(nil) 38 var _ sql.ReplaceableTable = (*BranchesTable)(nil) 39 40 // BranchesTable is the system table that accesses branches 41 type BranchesTable struct { 42 db dsess.SqlDatabase 43 remote bool 44 } 45 46 // NewBranchesTable creates a BranchesTable 47 func NewBranchesTable(_ *sql.Context, db dsess.SqlDatabase) sql.Table { 48 return &BranchesTable{db: db} 49 } 50 51 // NewRemoteBranchesTable creates a BranchesTable with only remote refs 52 func NewRemoteBranchesTable(_ *sql.Context, ddb dsess.SqlDatabase) sql.Table { 53 return &BranchesTable{ddb, true} 54 } 55 56 func (bt *BranchesTable) DataLength(ctx *sql.Context) (uint64, error) { 57 numBytesPerRow := schema.SchemaAvgLength(bt.Schema()) 58 numRows, _, err := bt.RowCount(ctx) 59 if err != nil { 60 return 0, err 61 } 62 return numBytesPerRow * numRows, nil 63 } 64 65 func (bt *BranchesTable) RowCount(_ *sql.Context) (uint64, bool, error) { 66 return branchesDefaultRowCount, false, nil 67 } 68 69 // Name is a sql.Table interface function which returns the name of the table which is defined by the constant 70 // BranchesTableName 71 func (bt *BranchesTable) Name() string { 72 if bt.remote { 73 return doltdb.RemoteBranchesTableName 74 } 75 return doltdb.BranchesTableName 76 } 77 78 // String is a sql.Table interface function which returns the name of the table which is defined by the constant 79 // BranchesTableName 80 func (bt *BranchesTable) String() string { 81 if bt.remote { 82 return doltdb.RemoteBranchesTableName 83 } 84 return doltdb.BranchesTableName 85 } 86 87 // Schema is a sql.Table interface function that gets the sql.Schema of the branches system table 88 func (bt *BranchesTable) Schema() sql.Schema { 89 tableName := doltdb.BranchesTableName 90 if bt.remote { 91 tableName = doltdb.RemoteBranchesTableName 92 } 93 94 columns := []*sql.Column{ 95 {Name: "name", Type: types.Text, Source: tableName, PrimaryKey: true, Nullable: false, DatabaseSource: bt.db.Name()}, 96 {Name: "hash", Type: types.Text, Source: tableName, PrimaryKey: false, Nullable: false, DatabaseSource: bt.db.Name()}, 97 {Name: "latest_committer", Type: types.Text, Source: tableName, PrimaryKey: false, Nullable: true, DatabaseSource: bt.db.Name()}, 98 {Name: "latest_committer_email", Type: types.Text, Source: tableName, PrimaryKey: false, Nullable: true, DatabaseSource: bt.db.Name()}, 99 {Name: "latest_commit_date", Type: types.Datetime, Source: tableName, PrimaryKey: false, Nullable: true, DatabaseSource: bt.db.Name()}, 100 {Name: "latest_commit_message", Type: types.Text, Source: tableName, PrimaryKey: false, Nullable: true, DatabaseSource: bt.db.Name()}, 101 } 102 if !bt.remote { 103 columns = append(columns, &sql.Column{Name: "remote", Type: types.Text, Source: tableName, PrimaryKey: false, Nullable: true}) 104 columns = append(columns, &sql.Column{Name: "branch", Type: types.Text, Source: tableName, PrimaryKey: false, Nullable: true}) 105 } 106 return columns 107 } 108 109 // Collation implements the sql.Table interface. 110 func (bt *BranchesTable) Collation() sql.CollationID { 111 return sql.Collation_Default 112 } 113 114 // Partitions is a sql.Table interface function that returns a partition of the data. Currently the data is unpartitioned. 115 func (bt *BranchesTable) Partitions(*sql.Context) (sql.PartitionIter, error) { 116 return index.SinglePartitionIterFromNomsMap(nil), nil 117 } 118 119 // PartitionRows is a sql.Table interface function that gets a row iterator for a partition 120 func (bt *BranchesTable) PartitionRows(sqlCtx *sql.Context, part sql.Partition) (sql.RowIter, error) { 121 return NewBranchItr(sqlCtx, bt) 122 } 123 124 // BranchItr is a sql.RowItr implementation which iterates over each commit as if it's a row in the table. 125 type BranchItr struct { 126 table *BranchesTable 127 branches []string 128 commits []*doltdb.Commit 129 idx int 130 } 131 132 // NewBranchItr creates a BranchItr from the current environment. 133 func NewBranchItr(ctx *sql.Context, table *BranchesTable) (*BranchItr, error) { 134 var branchRefs []ref.DoltRef 135 var err error 136 db := table.db 137 remote := table.remote 138 139 txRoot, err := dsess.TransactionRoot(ctx, db) 140 if err != nil { 141 return nil, err 142 } 143 144 ddb := db.DbData().Ddb 145 146 if remote { 147 branchRefs, err = ddb.GetRefsOfTypeByNomsRoot(ctx, map[ref.RefType]struct{}{ref.RemoteRefType: {}}, txRoot) 148 if err != nil { 149 return nil, err 150 } 151 } else { 152 branchRefs, err = ddb.GetBranchesByNomsRoot(ctx, txRoot) 153 if err != nil { 154 return nil, err 155 } 156 } 157 158 branchNames := make([]string, len(branchRefs)) 159 commits := make([]*doltdb.Commit, len(branchRefs)) 160 for i, branch := range branchRefs { 161 commit, err := ddb.ResolveCommitRefAtRoot(ctx, branch, txRoot) 162 163 if err != nil { 164 return nil, err 165 } 166 167 if branch.GetType() == ref.RemoteRefType { 168 branchNames[i] = "remotes/" + branch.GetPath() 169 } else { 170 branchNames[i] = branch.GetPath() 171 } 172 173 commits[i] = commit 174 } 175 176 return &BranchItr{ 177 table: table, 178 branches: branchNames, 179 commits: commits, 180 idx: 0, 181 }, nil 182 } 183 184 // Next retrieves the next row. It will return io.EOF if it's the last row. 185 // After retrieving the last row, Close will be automatically closed. 186 func (itr *BranchItr) Next(ctx *sql.Context) (sql.Row, error) { 187 if itr.idx >= len(itr.commits) { 188 return nil, io.EOF 189 } 190 191 defer func() { 192 itr.idx++ 193 }() 194 195 name := itr.branches[itr.idx] 196 cm := itr.commits[itr.idx] 197 meta, err := cm.GetCommitMeta(ctx) 198 199 if err != nil { 200 return nil, err 201 } 202 203 h, err := cm.HashOf() 204 205 if err != nil { 206 return nil, err 207 } 208 209 remoteBranches := itr.table.remote 210 if remoteBranches { 211 return sql.NewRow(name, h.String(), meta.Name, meta.Email, meta.Time(), meta.Description), nil 212 } else { 213 branches, err := itr.table.db.DbData().Rsr.GetBranches() 214 215 if err != nil { 216 return nil, err 217 } 218 219 remoteName := "" 220 branchName := "" 221 branch, ok := branches.Get(name) 222 if ok { 223 remoteName = branch.Remote 224 branchName = branch.Merge.Ref.GetPath() 225 } 226 return sql.NewRow(name, h.String(), meta.Name, meta.Email, meta.Time(), meta.Description, remoteName, branchName), nil 227 } 228 } 229 230 // Close closes the iterator. 231 func (itr *BranchItr) Close(*sql.Context) error { 232 return nil 233 } 234 235 // Replacer returns a RowReplacer for this table. The RowReplacer will have Insert and optionally Delete called once 236 // for each row, followed by a call to Close() when all rows have been processed. 237 func (bt *BranchesTable) Replacer(ctx *sql.Context) sql.RowReplacer { 238 return branchWriter{bt} 239 } 240 241 // Updater returns a RowUpdater for this table. The RowUpdater will have Update called once for each row to be 242 // updated, followed by a call to Close() when all rows have been processed. 243 func (bt *BranchesTable) Updater(ctx *sql.Context) sql.RowUpdater { 244 return branchWriter{bt} 245 } 246 247 // Inserter returns an Inserter for this table. The Inserter will get one call to Insert() for each row to be 248 // inserted, and will end with a call to Close() to finalize the insert operation. 249 func (bt *BranchesTable) Inserter(*sql.Context) sql.RowInserter { 250 return branchWriter{bt} 251 } 252 253 // Deleter returns a RowDeleter for this table. The RowDeleter will get one call to Delete for each row to be deleted, 254 // and will end with a call to Close() to finalize the delete operation. 255 func (bt *BranchesTable) Deleter(*sql.Context) sql.RowDeleter { 256 return branchWriter{bt} 257 } 258 259 var _ sql.RowReplacer = branchWriter{nil} 260 var _ sql.RowUpdater = branchWriter{nil} 261 var _ sql.RowInserter = branchWriter{nil} 262 var _ sql.RowDeleter = branchWriter{nil} 263 264 type branchWriter struct { 265 bt *BranchesTable 266 } 267 268 // Insert inserts the row given, returning an error if it cannot. Insert will be called once for each row to process 269 // for the insert operation, which may involve many rows. After all rows in an operation have been processed, Close 270 // is called. 271 func (bWr branchWriter) Insert(ctx *sql.Context, r sql.Row) error { 272 return fmt.Errorf("the dolt_branches table is read-only; use the dolt_branch stored procedure to edit remotes") 273 } 274 275 // Update the given row. Provides both the old and new rows. 276 func (bWr branchWriter) Update(ctx *sql.Context, old sql.Row, new sql.Row) error { 277 return fmt.Errorf("the dolt_branches table is read-only; use the dolt_branch stored procedure to edit remotes") 278 } 279 280 // Delete deletes the given row. Returns ErrDeleteRowNotFound if the row was not found. Delete will be called once for 281 // each row to process for the delete operation, which may involve many rows. After all rows have been processed, 282 // Close is called. 283 func (bWr branchWriter) Delete(ctx *sql.Context, r sql.Row) error { 284 return fmt.Errorf("the dolt_branches table is read-only; use the dolt_branch stored procedure to edit remotes") 285 } 286 287 // StatementBegin implements the interface sql.TableEditor. Currently a no-op. 288 func (bWr branchWriter) StatementBegin(ctx *sql.Context) {} 289 290 // DiscardChanges implements the interface sql.TableEditor. Currently a no-op. 291 func (bWr branchWriter) DiscardChanges(ctx *sql.Context, errorEncountered error) error { 292 return nil 293 } 294 295 // StatementComplete implements the interface sql.TableEditor. Currently a no-op. 296 func (bWr branchWriter) StatementComplete(ctx *sql.Context) error { 297 return nil 298 } 299 300 // Close finalizes the delete operation, persisting the result. 301 func (bWr branchWriter) Close(*sql.Context) error { 302 return nil 303 }