当尝试创建新用户时,Golang出现了SQL错误。

huangapple go评论87阅读模式
英文:

Golang error for SQL when trying to create a new user

问题

我在使用Golang的vipercobra包创建用户时,在我的new_user.go文件中遇到了以下错误:

cannot use result (variable of type sql.Result) as error value in return statement: sql.Result does not implement error (missing method Error)

我的代码分为两个文件,它们彼此通信,以下是文件的层次结构:

.
├── Makefile
├── README.md
├── cli
│   ├── config.go
│   ├── db-creds.yaml
│   ├── go.mod
│   ├── go.sum
│   ├── new_user.go
│   └── root.go
├── docker-compose.yaml
├── go.work
└── main.go

为了连接到数据库,我创建了一个YAML文件db-creds.yaml,用于在config.go中获取凭据。这里没有出现错误:

config.go文件:

package cli

import (
	"database/sql"
	"fmt"

	_ "github.com/go-sql-driver/mysql"
	_ "github.com/lib/pq"
	"github.com/spf13/viper"
)

// var dialects = map[string]gorp.Dialect{
// 	"postgres": gorp.PostgresDialect{},
// 	"mysql":    gorp.MySQLDialect{Engine: "InnoDB", Encoding: "UTF8"},
// }

// initConfig reads in config file and ENV variables if set
func initConfig() {
	if cfgFile != "" {
		viper.SetConfigFile(cfgFile)
	} else {
		viper.AddConfigPath("./")
		viper.SetConfigName("db-creds")
		viper.SetConfigType("yaml")
	}

	// If a config file is found, read it in:
	err := viper.ReadInConfig()
	if err == nil {
		fmt.Println("Fatal error config file: ", viper.ConfigFileUsed())
	}
	return
}

func getConnection() *sql.DB {

	// Make sure we only accept dialects that were compiled in.
	// dialect := viper.GetString("database.dialect")
	// _, exists := dialects[dialect]
	// if !exists {
	// 	return nil, "", fmt.Errorf("Unsupported dialect: %s", dialect)
	// }

	// Will want to create another command that will use a mapping
	// to connect to a preset db in the yaml file.
	dsn := fmt.Sprintf("%s:%s@%s(%s)?parseTime=true",
		viper.GetString("mysql-5.7-dev.user"),
		viper.GetString("mysql-5.7-dev.password"),
		viper.GetString("mysql-5.7-dev.protocol"),
		viper.GetString("mysql-5.7-dev.address"),
	)
	viper.Set("database.datasource", dsn)

	db, err := sql.Open("msyql", viper.GetString("database.datasource"))
	if err != nil {
		fmt.Errorf("Cannot connect to database: %s", err)
	}

	return db
}

我在顶部放置的错误是当我返回我的result时出现的错误。我正在为cobra实现flag选项,使用-n后跟name来表示要添加的新用户。

new_user.go文件:

package cli

import (
	"log"

	"github.com/sethvargo/go-password/password"
	"github.com/spf13/cobra"
)

var name string

// newCmd represents the new command
var newCmd = &cobra.Command{
	Use:   "new",
	Short: "Create a new a user which will accommodate the individuals user name",
	Long:  `Create a new a user that will randomize a password to the specified user`,
	RunE: func(cmd *cobra.Command, args []string) error {

		db := getConnection()

		superSecretPassword, err := password.Generate(64, 10, 10, false, false)

		result, err := db.Exec("CREATE USER" + name + "'@'" + "IDENTIFIED BY" + superSecretPassword)
		if err != nil {
			log.Fatal(err)
		}

		// Will output the secret password combined with the user.
		log.Printf(superSecretPassword)

		return result // <---- 错误在这里
	},
}

func init() {
	rootCmd.AddCommand(newCmd)

	newCmd.Flags().StringVarP(&name, "name", "n", "", "The name of user to be added")
	_ = newCmd.MarkFlagRequired("name")
}

这个项目的主要目的有三个:
1)创建一个新用户,
2)为任何用户分配特定权限
3)删除它们。
这是我的最终目标。一步一步进行,刚刚遇到了这个错误。希望有人能帮助我。我刚开始学习Golang,大约两周前开始的。

英文:

I am receiving this error in my new_user.go when creating a user using Golang packages viper and cobra. The error is as follows:

cannot use result (variable of type sql.Result) as error value in return statement: sql.Result does not implement error (missing method Error)

My code is broken into 2 files which talk to each other, here is the tree hierarchy:

.
├── Makefile
├── README.md
├── cli
│&#160;&#160; ├── config.go
│&#160;&#160; ├── db-creds.yaml
│&#160;&#160; ├── go.mod
│&#160;&#160; ├── go.sum
│&#160;&#160; ├── new_user.go
│&#160;&#160; └── root.go
├── docker-compose.yaml
├── go.work
└── main.go

To connect to the database, I created a YAML file db-creds.yaml to pull the creds for config.go. No errors are popping up here:

config.go file

package cli
import (
&quot;database/sql&quot;
&quot;fmt&quot;
_ &quot;github.com/go-sql-driver/mysql&quot;
_ &quot;github.com/lib/pq&quot;
&quot;github.com/spf13/viper&quot;
)
// var dialects = map[string]gorp.Dialect{
// 	&quot;postgres&quot;: gorp.PostgresDialect{},
// 	&quot;mysql&quot;:    gorp.MySQLDialect{Engine: &quot;InnoDB&quot;, Encoding: &quot;UTF8&quot;},
// }
// initConfig reads in config file and ENV variables if set
func initConfig() {
if cfgFile != &quot;&quot; {
viper.SetConfigFile(cfgFile)
} else {
viper.AddConfigPath(&quot;./&quot;)
viper.SetConfigName(&quot;db-creds&quot;)
viper.SetConfigType(&quot;yaml&quot;)
}
// If a config file is found, read it in:
err := viper.ReadInConfig()
if err == nil {
fmt.Println(&quot;Fatal error config file: &quot;, viper.ConfigFileUsed())
}
return
}
func getConnection() *sql.DB {
// Make sure we only accept dialects that were compiled in.
// dialect := viper.GetString(&quot;database.dialect&quot;)
// _, exists := dialects[dialect]
// if !exists {
// 	return nil, &quot;&quot;, fmt.Errorf(&quot;Unsupported dialect: %s&quot;, dialect)
// }
// Will want to create another command that will use a mapping
// to connect to a preset db in the yaml file.
dsn := fmt.Sprintf(&quot;%s:%s@%s(%s)?parseTime=true&quot;,
viper.GetString(&quot;mysql-5.7-dev.user&quot;),
viper.GetString(&quot;mysql-5.7-dev.password&quot;),
viper.GetString(&quot;mysql-5.7-dev.protocol&quot;),
viper.GetString(&quot;mysql-5.7-dev.address&quot;),
)
viper.Set(&quot;database.datasource&quot;, dsn)
db, err := sql.Open(&quot;msyql&quot;, viper.GetString(&quot;database.datasource&quot;))
if err != nil {
fmt.Errorf(&quot;Cannot connect to database: %s&quot;, err)
}
return db
}

The error that I put at the top is where the error appears when I return my result. I am implementing the flag option for cobra to use -n follow by the name to represent the new user being added`.

new_user.go file

package cli
import (
&quot;log&quot;
&quot;github.com/sethvargo/go-password/password&quot;
&quot;github.com/spf13/cobra&quot;
)
var name string
// newCmd represents the new command
var newCmd = &amp;cobra.Command{
Use:   &quot;new&quot;,
Short: &quot;Create a new a user which will accommodate the individuals user name&quot;,
Long:  `Create a new a user that will randomize a password to the specified user`,
RunE: func(cmd *cobra.Command, args []string) error {
db := getConnection()
superSecretPassword, err := password.Generate(64, 10, 10, false, false)
result, err := db.Exec(&quot;CREATE USER&quot; + name + &quot;&#39;@&#39;%&#39;&quot; + &quot;IDENTIFIED BY&quot; + superSecretPassword)
if err != nil {
log.Fatal(err)
}
// Will output the secret password combined with the user.
log.Printf(superSecretPassword)
return result &lt;---- Error is here
},
}
func init() {
rootCmd.AddCommand(newCmd)
newCmd.Flags().StringVarP(&amp;name, &quot;name&quot;, &quot;n&quot;, &quot;&quot;, &quot;The name of user to be added&quot;)
_ = newCmd.MarkFlagRequired(&quot;name&quot;)
}

The main purpose of this project are three things:
1.) Create a new user,
2.) Give any user specific permissions
3.) Delete them.
That is my end goal. Going one step at a time and just ran into this error. Hope anyone can help me. Golang is new to me and started about 2 weeks ago.

答案1

得分: 1

Go语言可以清楚地指示发生了什么。cobraRunE成员期望其回调函数返回一个错误(或者在成功的情况下返回nil)。

在你的代码中,你返回了一个结果result,而不是一个错误,这是你的SQL查询返回的特定类型。以下是你的函数应该如何编写:

RunE: func(cmd *cobra.Command, args []string) error {

    db := getConnection()

    superSecretPassword, err := password.Generate(64, 10, 10, false, false)

    _, err := db.Exec("CREATE USER" + name + "'@'%'" + "IDENTIFIED BY" + superSecretPassword)
    if err != nil {
        // 不要无谓地使用Fatal,让cobra以设计好的方式处理错误。
        return err
    }

    // 输出与用户组合的秘密密码。
    log.Printf(superSecretPassword)

    // 这是你应该指示回调成功终止的方式。
    // 错误是一个接口,所以它接受nil值。
    return nil
}

如果你需要db.Exec命令的结果(似乎不是你的情况),你需要在cobra回调函数中完成所有必需的处理,因为它不设计将值返回给主线程。

错误处理

我在你的代码中注意到了一些处理错误的不良实践:

  • 如果一个Go函数有一个错误返回值,在发生意外情况时不要恐慌或终止程序(就像你在log.Fatal中所做的那样)。相反,使用该错误返回值将错误传播到主线程,并让主线程决定如何处理。

  • 另一方面,如果出现错误,不要返回结果。你的getConnection函数应该能够在失败时返回一个错误:func getConnection() (*sql.DB, error)。然后,在你的RunE函数中处理这个错误,而不仅仅是记录它并正常处理。

英文:

Go gives you a pretty clear indication about what's going on. The RunE member of cobra expects its callback to return an error (or nil, in case of success).

Here, you are returning result, which is not an error, but a specific type returned by your sql query. This is what your function should look like.

RunE: func(cmd *cobra.Command, args []string) error {

    db := getConnection()

    superSecretPassword, err := password.Generate(64, 10, 10, false, false)

    _, err := db.Exec(&quot;CREATE USER&quot; + name + &quot;&#39;@&#39;%&#39;&quot; + &quot;IDENTIFIED BY&quot; + superSecretPassword)
    if err != nil {
        // Don&#39;t Fatal uselessly, let cobra handle your error the way it
        // was designed to do it.
        return err
    }

    // Will output the secret password combined with the user.
    log.Printf(superSecretPassword)

    // Here is how you should indicate your callback terminated successfully.
    // Error is an interface, so it accepts nil values.
    return nil
}

If you need the result of the db.Exec command (which does not seem to be the case), you'll need to do all the required processing within your cobra callback, as it is not designed to return values to the main thread.

Error handling

A few bad practices about handling error I noticed in your code:

  • If a go function has an error return, don't panic or kill the program if something unexpected occurs (like you did with log.Fatal). Instead, use that error return to propagate the error to the main thread, and let it decide what to do.

  • On the other hand, don't return results if something went wrong. Your getConnection function should be able to return an error if it fails: func getConnection() (*sql.DB, error). You should then handle this error in your RunE function, instead of just logging it and processing normally.

huangapple
  • 本文由 发表于 2022年12月13日 08:28:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/74778760.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定