github.com/dolthub/dolt/go@v0.40.5-0.20240520175717-68db7794bea6/libraries/doltcore/sqle/dtables/remotes_table.go (about) 1 // Copyright 2021 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/env" 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 remotesDefaultRowCount = 1 32 33 var _ sql.Table = (*RemotesTable)(nil) 34 var _ sql.UpdatableTable = (*RemotesTable)(nil) 35 var _ sql.DeletableTable = (*RemotesTable)(nil) 36 var _ sql.InsertableTable = (*RemotesTable)(nil) 37 var _ sql.ReplaceableTable = (*RemotesTable)(nil) 38 var _ sql.StatisticsTable = (*RemotesTable)(nil) 39 40 // RemotesTable is a sql.Table implementation that implements a system table which shows the dolt remotes 41 type RemotesTable struct { 42 ddb *doltdb.DoltDB 43 } 44 45 // NewRemotesTable creates a RemotesTable 46 func NewRemotesTable(_ *sql.Context, ddb *doltdb.DoltDB) sql.Table { 47 return &RemotesTable{ddb} 48 } 49 50 func (bt *RemotesTable) DataLength(ctx *sql.Context) (uint64, error) { 51 numBytesPerRow := schema.SchemaAvgLength(bt.Schema()) 52 numRows, _, err := bt.RowCount(ctx) 53 if err != nil { 54 return 0, err 55 } 56 return numBytesPerRow * numRows, nil 57 } 58 59 func (bt *RemotesTable) RowCount(_ *sql.Context) (uint64, bool, error) { 60 return remotesDefaultRowCount, false, nil 61 } 62 63 // Name is a sql.Table interface function which returns the name of the table which is defined by the constant 64 // RemotesTableName 65 func (bt *RemotesTable) Name() string { 66 return doltdb.RemotesTableName 67 } 68 69 // String is a sql.Table interface function which returns the name of the table which is defined by the constant 70 // RemotesTableName 71 func (bt *RemotesTable) String() string { 72 return doltdb.RemotesTableName 73 } 74 75 // Schema is a sql.Table interface function that gets the sql.Schema of the remotes system table 76 func (bt *RemotesTable) Schema() sql.Schema { 77 return []*sql.Column{ 78 {Name: "name", Type: types.Text, Source: doltdb.RemotesTableName, PrimaryKey: true, Nullable: false}, 79 {Name: "url", Type: types.Text, Source: doltdb.RemotesTableName, PrimaryKey: false, Nullable: false}, 80 {Name: "fetch_specs", Type: types.JSON, Source: doltdb.RemotesTableName, PrimaryKey: false, Nullable: true}, 81 {Name: "params", Type: types.JSON, Source: doltdb.RemotesTableName, PrimaryKey: false, Nullable: true}, 82 } 83 } 84 85 // Collation implements the sql.Table interface. 86 func (bt *RemotesTable) Collation() sql.CollationID { 87 return sql.Collation_Default 88 } 89 90 // Partitions is a sql.Table interface function that returns a partition of the data. Currently the data is unpartitioned. 91 func (bt *RemotesTable) Partitions(*sql.Context) (sql.PartitionIter, error) { 92 return index.SinglePartitionIterFromNomsMap(nil), nil 93 } 94 95 // PartitionRows is a sql.Table interface function that gets a row iterator for a partition 96 func (bt *RemotesTable) PartitionRows(ctx *sql.Context, part sql.Partition) (sql.RowIter, error) { 97 return NewRemoteItr(ctx, bt.ddb) 98 } 99 100 // RemoteItr is a sql.RowItr implementation which iterates over each commit as if it's a row in the table. 101 type RemoteItr struct { 102 remotes []env.Remote 103 idx int 104 } 105 106 // NewRemoteItr creates a RemoteItr from the current environment. 107 func NewRemoteItr(ctx *sql.Context, ddb *doltdb.DoltDB) (*RemoteItr, error) { 108 dbName := ctx.GetCurrentDatabase() 109 110 if len(dbName) == 0 { 111 return nil, fmt.Errorf("Empty database name.") 112 } 113 114 sess := dsess.DSessFromSess(ctx.Session) 115 dbData, ok := sess.GetDbData(ctx, dbName) 116 if !ok { 117 return nil, sql.ErrDatabaseNotFound.New(dbName) 118 } 119 120 remoteMap, err := dbData.Rsr.GetRemotes() 121 if err != nil { 122 return nil, err 123 } 124 remotes := []env.Remote{} 125 126 remoteMap.Iter(func(key string, val env.Remote) bool { 127 remotes = append(remotes, val) 128 return true 129 }) 130 131 return &RemoteItr{remotes, 0}, nil 132 } 133 134 // Next retrieves the next row. It will return io.EOF if it's the last row. 135 // After retrieving the last row, Close will be automatically closed. 136 func (itr *RemoteItr) Next(*sql.Context) (sql.Row, error) { 137 if itr.idx >= len(itr.remotes) { 138 return nil, io.EOF 139 } 140 141 defer func() { 142 itr.idx++ 143 }() 144 145 remote := itr.remotes[itr.idx] 146 147 fs, _, err := types.JSON.Convert(remote.FetchSpecs) 148 if err != nil { 149 return nil, err 150 } 151 params, _, err := types.JSON.Convert(remote.Params) 152 if err != nil { 153 return nil, err 154 } 155 156 return sql.NewRow(remote.Name, remote.Url, fs, params), nil 157 } 158 159 // Close closes the iterator. 160 func (itr *RemoteItr) Close(*sql.Context) error { 161 return nil 162 } 163 164 // Replacer returns a RowReplacer for this table. The RowReplacer will have Insert and optionally Delete called once 165 // for each row, followed by a call to Close() when all rows have been processed. 166 func (bt *RemotesTable) Replacer(ctx *sql.Context) sql.RowReplacer { 167 return remoteWriter{bt} 168 } 169 170 // Updater returns a RowUpdater for this table. The RowUpdater will have Update called once for each row to be 171 // updated, followed by a call to Close() when all rows have been processed. 172 func (bt *RemotesTable) Updater(ctx *sql.Context) sql.RowUpdater { 173 return remoteWriter{bt} 174 } 175 176 // Inserter returns an Inserter for this table. The Inserter will get one call to Insert() for each row to be 177 // inserted, and will end with a call to Close() to finalize the insert operation. 178 func (bt *RemotesTable) Inserter(*sql.Context) sql.RowInserter { 179 return remoteWriter{bt} 180 } 181 182 // Deleter returns a RowDeleter for this table. The RowDeleter will get one call to Delete for each row to be deleted, 183 // and will end with a call to Close() to finalize the delete operation. 184 func (bt *RemotesTable) Deleter(*sql.Context) sql.RowDeleter { 185 return remoteWriter{bt} 186 } 187 188 var _ sql.RowReplacer = remoteWriter{nil} 189 var _ sql.RowUpdater = remoteWriter{nil} 190 var _ sql.RowInserter = remoteWriter{nil} 191 var _ sql.RowDeleter = remoteWriter{nil} 192 193 type remoteWriter struct { 194 bt *RemotesTable 195 } 196 197 // Insert inserts the row given, returning an error if it cannot. Insert will be called once for each row to process 198 // for the insert operation, which may involve many rows. After all rows in an operation have been processed, Close 199 // is called. 200 func (bWr remoteWriter) Insert(ctx *sql.Context, r sql.Row) error { 201 return fmt.Errorf("the dolt_remotes table is read-only; use the dolt_remote stored procedure to edit remotes") 202 } 203 204 // Update the given row. Provides both the old and new rows. 205 func (bWr remoteWriter) Update(ctx *sql.Context, old sql.Row, new sql.Row) error { 206 return fmt.Errorf("the dolt_remotes table is read-only; use the dolt_remote stored procedure to edit remotes") 207 } 208 209 // Delete deletes the given row. Returns ErrDeleteRowNotFound if the row was not found. Delete will be called once for 210 // each row to process for the delete operation, which may involve many rows. After all rows have been processed, 211 // Close is called. 212 func (bWr remoteWriter) Delete(ctx *sql.Context, r sql.Row) error { 213 return fmt.Errorf("the dolt_remotes table is read-only; use the dolt_remote stored procedure to edit remotes") 214 } 215 216 // StatementBegin implements the interface sql.TableEditor. Currently a no-op. 217 func (bWr remoteWriter) StatementBegin(ctx *sql.Context) {} 218 219 // DiscardChanges implements the interface sql.TableEditor. Currently a no-op. 220 func (bWr remoteWriter) DiscardChanges(ctx *sql.Context, errorEncountered error) error { 221 return nil 222 } 223 224 // StatementComplete implements the interface sql.TableEditor. Currently a no-op. 225 func (bWr remoteWriter) StatementComplete(ctx *sql.Context) error { 226 return nil 227 } 228 229 // Close finalizes the delete operation, persisting the result. 230 func (bWr remoteWriter) Close(*sql.Context) error { 231 return nil 232 }