github.com/dolthub/dolt/go@v0.40.5-0.20240520175717-68db7794bea6/libraries/doltcore/sqle/dprocedures/dolt_commit.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 dprocedures 16 17 import ( 18 "errors" 19 "fmt" 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/cmd/dolt/cli" 25 "github.com/dolthub/dolt/go/libraries/doltcore/branch_control" 26 "github.com/dolthub/dolt/go/libraries/doltcore/dconfig" 27 "github.com/dolthub/dolt/go/libraries/doltcore/env/actions" 28 "github.com/dolthub/dolt/go/libraries/doltcore/sqle/dsess" 29 "github.com/dolthub/dolt/go/store/datas" 30 ) 31 32 // doltCommit is the stored procedure version for the CLI command `dolt commit`. 33 func doltCommit(ctx *sql.Context, args ...string) (sql.RowIter, error) { 34 commitHash, skipped, err := doDoltCommit(ctx, args) 35 if err != nil { 36 return nil, err 37 } 38 if skipped { 39 return nil, nil 40 } 41 return rowToIter(commitHash), nil 42 } 43 44 // doltCommitHashOut is the stored procedure version for the CLI function `commit`. The first parameter is the variable 45 // to set the hash of. 46 func doltCommitHashOut(ctx *sql.Context, outHash *string, args ...string) (sql.RowIter, error) { 47 commitHash, skipped, err := doDoltCommit(ctx, args) 48 if err != nil { 49 return nil, err 50 } 51 if skipped { 52 return nil, nil 53 } 54 55 *outHash = commitHash 56 return rowToIter(commitHash), nil 57 } 58 59 // doDoltCommit creates a dolt commit using the specified command line |args| provided. The response is the commit hash 60 // of the new commit (or the empty string if the commit was skipped), a boolean that indicates if creating the commit 61 // was skipped (e.g. due to --skip-empty), and an error describing any error encountered. 62 func doDoltCommit(ctx *sql.Context, args []string) (string, bool, error) { 63 if err := branch_control.CheckAccess(ctx, branch_control.Permissions_Write); err != nil { 64 return "", false, err 65 } 66 // Get the information for the sql context. 67 dbName := ctx.GetCurrentDatabase() 68 69 apr, err := cli.CreateCommitArgParser().Parse(args) 70 if err != nil { 71 return "", false, err 72 } 73 74 if err := cli.VerifyCommitArgs(apr); err != nil { 75 return "", false, err 76 } 77 78 dSess := dsess.DSessFromSess(ctx.Session) 79 roots, ok := dSess.GetRoots(ctx, dbName) 80 if !ok { 81 return "", false, fmt.Errorf("Could not load database %s", dbName) 82 } 83 84 if apr.Contains(cli.UpperCaseAllFlag) { 85 roots, err = actions.StageAllTables(ctx, roots, true) 86 if err != nil { 87 return "", false, fmt.Errorf(err.Error()) 88 } 89 roots, err = actions.StageDatabase(ctx, roots, true) 90 if err != nil { 91 return "", false, fmt.Errorf(err.Error()) 92 } 93 } else if apr.Contains(cli.AllFlag) { 94 roots, err = actions.StageModifiedAndDeletedTables(ctx, roots) 95 if err != nil { 96 return "", false, fmt.Errorf(err.Error()) 97 } 98 } 99 100 var name, email string 101 if authorStr, ok := apr.GetValue(cli.AuthorParam); ok { 102 name, email, err = cli.ParseAuthor(authorStr) 103 if err != nil { 104 return "", false, err 105 } 106 } else { 107 // In SQL mode, use the current SQL user as the commit author, instead of the `dolt config` configured values. 108 // We won't have an email address for the SQL user though, so instead use the MySQL user@address notation. 109 name = ctx.Client().User 110 email = fmt.Sprintf("%s@%s", ctx.Client().User, ctx.Client().Address) 111 } 112 113 amend := apr.Contains(cli.AmendFlag) 114 115 msg, msgOk := apr.GetValue(cli.MessageArg) 116 if !msgOk { 117 if amend { 118 commit, err := dSess.GetHeadCommit(ctx, dbName) 119 if err != nil { 120 return "", false, err 121 } 122 commitMeta, err := commit.GetCommitMeta(ctx) 123 if err != nil { 124 return "", false, err 125 } 126 msg = commitMeta.Description 127 } else { 128 return "", false, fmt.Errorf("Must provide commit message.") 129 } 130 } 131 132 t := ctx.QueryTime() 133 if commitTimeStr, ok := apr.GetValue(cli.DateParam); ok { 134 var err error 135 t, err = dconfig.ParseDate(commitTimeStr) 136 137 if err != nil { 138 return "", false, fmt.Errorf(err.Error()) 139 } 140 } else if datas.CustomAuthorDate { 141 t = datas.AuthorDate() 142 } 143 144 if apr.Contains(cli.ForceFlag) { 145 err = ctx.SetSessionVariable(ctx, "dolt_force_transaction_commit", 1) 146 if err != nil { 147 return "", false, fmt.Errorf(err.Error()) 148 } 149 } 150 151 pendingCommit, err := dSess.NewPendingCommit(ctx, dbName, roots, actions.CommitStagedProps{ 152 Message: msg, 153 Date: t, 154 AllowEmpty: apr.Contains(cli.AllowEmptyFlag), 155 SkipEmpty: apr.Contains(cli.SkipEmptyFlag), 156 Amend: amend, 157 Force: apr.Contains(cli.ForceFlag), 158 Name: name, 159 Email: email, 160 }) 161 if err != nil { 162 return "", false, err 163 } 164 165 // Nothing to commit, and we didn't pass --allowEmpty 166 if pendingCommit == nil && apr.Contains(cli.SkipEmptyFlag) { 167 return "", true, nil 168 } else if pendingCommit == nil { 169 return "", false, errors.New("nothing to commit") 170 } 171 172 newCommit, err := dSess.DoltCommit(ctx, dbName, dSess.GetTransaction(), pendingCommit) 173 if err != nil { 174 return "", false, err 175 } 176 177 h, err := newCommit.HashOf() 178 if err != nil { 179 return "", false, err 180 } 181 182 return h.String(), false, nil 183 } 184 185 func getDoltArgs(ctx *sql.Context, row sql.Row, children []sql.Expression) ([]string, error) { 186 args := make([]string, len(children)) 187 for i := range children { 188 childVal, err := children[i].Eval(ctx, row) 189 190 if err != nil { 191 return nil, err 192 } 193 194 text, _, err := types.Text.Convert(childVal) 195 196 if err != nil { 197 return nil, err 198 } 199 200 args[i] = text.(string) 201 } 202 203 return args, nil 204 }