diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c2b89d..e3c7290 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Go Library +# [v1.9.2 - 2023-08-08] +### New +- add Cobra Command helper +- add more sql functions and tests +### Changed +- use github.com/jmoiron/sqlx instead of database/sql + # [v1.9.1 - 2023-07-22] ### New - add line number to location diff --git a/dblib/db.go b/dblib/db.go index 2bda766..cf35761 100644 --- a/dblib/db.go +++ b/dblib/db.go @@ -4,8 +4,10 @@ package dblib import ( "context" "database/sql" + "fmt" "time" + "github.com/jmoiron/sqlx" log "github.com/sirupsen/logrus" ) @@ -13,7 +15,7 @@ import ( // https://github.com/sijms/go-ora/#version-241-add-support-for-connection-time-out--context-read-and-write // DBConnect connect to a database using connect string -func DBConnect(driver string, source string, timeout int) (db *sql.DB, err error) { +func DBConnect(driver string, source string, timeout int) (dbh *sqlx.DB, err error) { const defaultTimeout = 5 // Create a new child context with a 5-second timeout, using the // provided ctx parameter as the parent. @@ -22,7 +24,7 @@ func DBConnect(driver string, source string, timeout int) (db *sql.DB, err error timeout = defaultTimeout } log.Debugf("try to connect, timeout %d", timeout) - db, err = sql.Open(driver, source) + dbh, err = sqlx.Open(driver, source) if err != nil { return nil, err } @@ -33,23 +35,204 @@ func DBConnect(driver string, source string, timeout int) (db *sql.DB, err error defer cancel() // Use this when testing the connection pool. - if err = db.PingContext(ctx); err != nil { + if err = dbh.PingContext(ctx); err != nil { log.Debugf("DB Connect returned error= %s", err) return nil, err } log.Debugf("DB Connect success") - return db, err + return dbh, err +} + +func checkType(t interface{}, expected string) (ok bool, haveType string) { + ok = false + haveType = fmt.Sprintf("%T", t) + if haveType == expected { + ok = true + } + return } // SelectOneStringValue Select a single string -func SelectOneStringValue(db *sql.DB, sql string) (queryResult string, err error) { - row := db.QueryRow(sql) - err = row.Scan(&queryResult) +func SelectOneStringValue(dbh *sqlx.DB, mySQL string, args ...any) (resultString string, err error) { + log.Debugf("SelectOneStringValue entered") + err = SelectOneRow(dbh, mySQL, &resultString, args...) + if err != nil { + if isOerr, _, msg := HaveOerr(err); isOerr { + err = fmt.Errorf("oracle rrror %s", msg) + } + } + return +} + +// SelectOneInt64Value Select a int64 string +func SelectOneInt64Value(dbh *sqlx.DB, mySQL string, args ...any) (resultInt int64, err error) { + log.Debugf("SelectOneStringValue entered") + err = SelectOneRow(dbh, mySQL, &resultInt, args...) + if err != nil { + if isOerr, _, msg := HaveOerr(err); isOerr { + err = fmt.Errorf("oracle error %s", msg) + } + } + return +} + +// PrepareSQL parses a sql for a given connection and returns statement handler +func PrepareSQL(dbh *sqlx.DB, mySQL string) (stmt *sqlx.Stmt, err error) { + log.Debugf("PrepareSql entered") + ok, t := checkType(dbh, "*sqlx.DB") + if dbh == nil { + err = fmt.Errorf("dbh is nil") + return + } + if !ok { + err = fmt.Errorf("invalid dbh type: %s", t) + return + } + stmt, err = dbh.Preparex(mySQL) + if err != nil { + if isOerr, _, msg := HaveOerr(err); isOerr { + err = fmt.Errorf("prepare error: %s (%s) ", msg, mySQL) + return + } + err = fmt.Errorf("prepare failed:%s (%s)", err, mySQL) + } + return +} + +// PrepareSQLTx parses a sql for a given transaction and returns statement handler +func PrepareSQLTx(tx *sqlx.Tx, mySQL string) (stmt *sqlx.Stmt, err error) { + log.Debugf("PrepareSql entered") + ok, t := checkType(tx, "*sqlx.Tx") + if tx == nil { + err = fmt.Errorf("TX is nil") + return + } + if !ok { + err = fmt.Errorf("invalid transaction type %s", t) + return + } + stmt, err = tx.Preparex(mySQL) + if err != nil { + if isOerr, _, msg := HaveOerr(err); isOerr { + err = fmt.Errorf("prepare error: %s (%s) ", msg, mySQL) + return + } + err = fmt.Errorf("prepare failed:%s (%s)", err, mySQL) + } + return +} + +// SelectOneRow combines preparing a statement, add bind variables and returns results +func SelectOneRow(dbh *sqlx.DB, mySQL string, result interface{}, args ...any) (err error) { + log.Debugf("QueryOnRow entered") + ok, t := checkType(dbh, "*sqlx.DB") + if dbh == nil { + err = fmt.Errorf("dbh is nil") + return + } + if !ok { + err = fmt.Errorf("invalid dbh type: %s", t) + return + } + log.Debugf("SQL: %s", mySQL) + err = dbh.Get(result, mySQL, args...) + return +} + +// SelectAllRows combines preparing a statement, add bind variables and returns results struct +func SelectAllRows(dbh *sqlx.DB, mySQL string, result interface{}, args ...any) (err error) { + log.Debugf("QuerySql entered") + ok, t := checkType(dbh, "*sqlx.DB") + if dbh == nil { + err = fmt.Errorf("dbh is nil") + return + } + if !ok { + err = fmt.Errorf("invalid dbh type: %s", t) + return + } + log.Debugf("SQL: %s", mySQL) + err = dbh.Select(result, mySQL, args...) + return +} + +// SelectSQL runs a query, add bind variables and returns a cursor +func SelectSQL(dbh *sqlx.DB, mySQL string, args ...any) (rows *sqlx.Rows, err error) { + log.Debugf("QuerySql entered") + ok, t := checkType(dbh, "*sqlx.DB") + if dbh == nil { + err = fmt.Errorf("TX is nil") + return + } + if !ok { + err = fmt.Errorf("invalid dbh type: %s", t) + return + } + log.Debugf("SQL: %s", mySQL) + rows, err = dbh.Queryx(mySQL, args...) + if err != nil { + if isOerr, _, msg := HaveOerr(err); isOerr { + err = fmt.Errorf("%s", msg) + return + } + } + return +} + +// SelectStmt runs a query on a prepared statement, add bind variables and returns a cursor +func SelectStmt(stmt *sqlx.Stmt, args ...any) (rows *sqlx.Rows, err error) { + log.Debugf("QueryStmt entered") + ok, t := checkType(stmt, "*sqlx.Stmt") + if stmt == nil { + err = fmt.Errorf("stmt is nil") + return + } + if !ok { + err = fmt.Errorf("invalid stmt type: %s", t) + return + } + log.Debugf("Parameter values: %v", args...) + rows, err = stmt.Queryx(args...) + if err != nil { + if isOerr, _, msg := HaveOerr(err); isOerr { + err = fmt.Errorf("%s", msg) + return + } + } + return +} + +// MakeRowMap returns rows as a slice of map field->value +func MakeRowMap(rows *sqlx.Rows) (result []map[string]interface{}, err error) { + log.Debugf("MakeRowMap entered") + for rows.Next() { + row := make(map[string]interface{}) + err = rows.MapScan(row) + if err != nil { + return + } + result = append(result, row) + } + return +} + +// ExecSQL executes a sql on a open transaction and returns result handler +func ExecSQL(tx *sqlx.Tx, mySQL string, args ...any) (result sql.Result, err error) { + log.Debugf("ExecSQL: %s", mySQL) + ok, t := checkType(tx, "*sqlx.Tx") + if tx == nil { + err = fmt.Errorf("TX is nil") + return + } + if !ok { + err = fmt.Errorf("invalid transaction type %s", t) + return + } + result, err = tx.Exec(mySQL, args...) if err != nil { if isOerr, _, msg := HaveOerr(err); isOerr { - log.Warnf("Oracle Error %s", msg) - } else { - log.Warnf("got error %s", err) + err = fmt.Errorf("prepare error: %s (%s) ", msg, mySQL) + return } } return diff --git a/dblib/db_test.go b/dblib/db_test.go index 88c5653..10a041d 100644 --- a/dblib/db_test.go +++ b/dblib/db_test.go @@ -5,6 +5,8 @@ import ( "os" "testing" + "github.com/jmoiron/sqlx" + ora "github.com/sijms/go-ora/v2" _ "github.com/glebarez/go-sqlite" @@ -30,12 +32,12 @@ func newTestfile(filename string) error { func TestDBConnect(t *testing.T) { t.Run("Test DB Connect Memory", func(t *testing.T) { - db, err := DBConnect("sqlite", ":memory:", 5) - defer func(db *sql.DB) { - _ = db.Close() - }(db) + dbh, err := DBConnect("sqlite", ":memory:", 5) + defer func(dbh *sqlx.DB) { + _ = dbh.Close() + }(dbh) require.NoError(t, err, "DB Open sqlite memory failed") - assert.NotEmpty(t, db, "DB Handle missed") + assert.NotEmpty(t, dbh, "DB Handle missed") }) t.Run("Test DB Connect noexisting oracle", func(t *testing.T) { @@ -51,48 +53,200 @@ func TestDBConnect(t *testing.T) { if err != nil { t.Fatalf("Cannot create sqlite file") } - db, err := DBConnect("sqlite", filename, 5) + dbh, err := DBConnect("sqlite", filename, 5) require.NoError(t, err, "DB Open sqlite %s failed") - assert.NotEmpty(t, db, "DB Handle missed") - e := db.Close() + assert.NotEmpty(t, dbh, "DB Handle missed") + e := dbh.Close() if e == nil { _ = os.Remove(filename) } }) } - -func TestSelectOneStringValue(t *testing.T) { - var actual string +func TestSQL(t *testing.T) { + var actualString string + var actualInt int64 var err error + var actualRows int64 + var rows *sqlx.Rows + var res sql.Result + var dbh *sqlx.DB + var stmt *sqlx.Stmt + type testTab struct { + ID int64 `db:"id"` + Name string `db:"name"` + } filename := "test3.db" err = newTestfile(filename) if err != nil { t.Fatalf("Cannot create sqlite file") } - db, err := DBConnect("sqlite", filename, 5) - defer func(db *sql.DB) { - e := db.Close() + dbh, err = DBConnect("sqlite", filename, 5) + defer func(dbh *sqlx.DB) { + e := dbh.Close() if e == nil { _ = os.Remove(filename) } - }(db) + }(dbh) if err != nil { t.Fatalf("DB Open sqlite %s failed", filename) } - if db == nil { + if dbh == nil { t.Fatalf("DB Handle missed") } - - t.Run("Test Select Singlerow", func(t *testing.T) { - mysql := "select sqlite_version()" - actual, err = SelectOneStringValue(db, mysql) - assert.NoErrorf(t, err, "Querry returned error %s", err) - assert.NotEmpty(t, actual, "Select value empty") - t.Logf("Version %s", actual) + tx := dbh.MustBegin() + t.Run("Test DoSql Create", func(t *testing.T) { + mysql := "create table test (id int, name varchar(20))" + res, err = ExecSQL(tx, mysql) + assert.NoErrorf(t, err, "Query returned error %s", err) + }) + t.Run("Test DoSql insert", func(t *testing.T) { + mysql := "insert into test (id, name) values (1, 'test')" + res, err = ExecSQL(tx, mysql) + assert.NoErrorf(t, err, "Query returned error %s", err) + require.NotNil(t, res, "Result is nil") + actualRows, err = res.RowsAffected() + assert.Equal(t, int64(1), actualRows, "Rows not as expected") }) + t.Run("Test DoSql insert parameter", func(t *testing.T) { + mysql := "insert into test (id, name) values (2, 'test2')" + res, err = ExecSQL(tx, mysql, 2, "test2") + assert.NoErrorf(t, err, "Query returned error %s", err) + require.NotNil(t, res, "Result is nil") + actualRows, err = res.RowsAffected() + assert.Equal(t, int64(1), actualRows, "Rows not as expected") + t.Logf("Value %d", actualRows) + }) + _ = tx.Commit() t.Run("Test wrong sql", func(t *testing.T) { mysql := "seleccct sqlite_version()" - _, err = SelectOneStringValue(db, mysql) + _, err = SelectOneStringValue(dbh, mysql) + assert.Error(t, err, "Query returned no error, but should") + }) + t.Run("Test Select Singlerow String", func(t *testing.T) { + mysql := "select name from test where id = ?" + actualString, err = SelectOneStringValue(dbh, mysql, 1) + assert.NoErrorf(t, err, "Query returned error %s", err) + assert.NotEmpty(t, actualString, "Select value empty") + assert.Equal(t, "test", actualString, "Select value not as expected") + t.Logf("Version %s", actualString) + }) + + t.Run("Test Select Singlerow Int64", func(t *testing.T) { + mysql := "select id from test where name = 'test'" + actualInt, err = SelectOneInt64Value(dbh, mysql) + assert.NoErrorf(t, err, "Query returned error %s", err) + assert.Equal(t, int64(1), actualInt, "Select value empty") + t.Logf("Value %d", actualInt) + }) + t.Run("Test wrong result type", func(t *testing.T) { + mysql := "select name from test where id = 1" + _, err = SelectOneInt64Value(dbh, mysql) + assert.Error(t, err, "Query returned no error, but should") + }) + t.Run("test wrong dbh", func(t *testing.T) { + mysql := "select sqlite_version()" + _, err = SelectOneInt64Value(nil, mysql) assert.Error(t, err, "Query returned no error, but should") }) + t.Run("test checkType", func(t *testing.T) { + actual, e := checkType(dbh, "test") + assert.False(t, actual, "type returned true, but should not") + assert.NotEmpty(t, e, "actual is empty, but should not") + }) + t.Run("Test query one row", func(t *testing.T) { + var row testTab + mysql := "select id, name from test where id = ?" + err = SelectOneRow(dbh, mysql, &row, 1) + assert.NoErrorf(t, err, "Query returned error %s", err) + assert.Equal(t, int64(1), row.ID, "id value not expected") + assert.Equal(t, "test", row.Name, "name value not expected") + }) + t.Run("Test query all rows", func(t *testing.T) { + var result []testTab + mysql := "select id,name from test" + err = SelectAllRows(dbh, mysql, &result) + c := len(result) + assert.NoErrorf(t, err, "Query returned error %s", err) + assert.Equal(t, 2, c, "number of rows not expected") + if c > 1 { + row := result[1] + assert.Equal(t, int64(2), row.ID, "id value not expected") + assert.Equal(t, "test2", row.Name, "name value not expected") + } + }) + t.Run("Test prepare with transaction", func(t *testing.T) { + tx = dbh.MustBegin() + mysql := "insert into test (id, name) values (?, ?)" + stmt, err = PrepareSQLTx(tx, mysql) + assert.NoErrorf(t, err, "Query returned error %s", err) + assert.NotNil(t, stmt, "Statement is nil") + if stmt != nil { + res, err = stmt.Exec(3, "test3") + assert.NoErrorf(t, err, "Query returned error %s", err) + require.NotNil(t, res, "Result is nil") + actualRows, err = res.RowsAffected() + assert.Equal(t, int64(1), actualRows, "Rows not as expected") + } + _ = tx.Commit() + }) + t.Run("Test prepare without transaction", func(t *testing.T) { + mysql := "select * from test where id > ?" + stmt, err = PrepareSQL(dbh, mysql) + assert.NoErrorf(t, err, "Query returned error %s", err) + assert.NotNil(t, stmt, "Statement is nil") + if stmt != nil { + err = stmt.QueryRow(2).Scan(&actualInt, &actualString) + assert.NoErrorf(t, err, "Query returned error %s", err) + assert.Equal(t, int64(3), actualInt, "id value not expected") + assert.Equal(t, "test3", actualString, "name value not expected") + } + }) + t.Run("Test Select SQL with stmt return struct", func(t *testing.T) { + rows, err = SelectStmt(stmt, 1) + assert.NoErrorf(t, err, "Query should not return error:%s", err) + assert.NotNil(t, rows, "Rows is nil") + var result []testTab + for rows.Next() { + var record testTab + err = rows.StructScan(&record) + assert.NoErrorf(t, err, "Query returned error %s", err) + result = append(result, record) + } + assert.Equal(t, 2, len(result), "number of rows not expected") + t.Logf("Rows %v", result) + _ = rows.Close() + }) + t.Run("Test Select SQL returning map", func(t *testing.T) { + mysql := "select * from test" + rows, err = SelectSQL(dbh, mysql) + assert.NoErrorf(t, err, "Query should not return error:%s", err) + assert.NotNil(t, rows, "Rows is nil") + var result []map[string]interface{} + result, err = MakeRowMap(rows) + assert.NoErrorf(t, err, "Mapping returned error %s", err) + assert.Equal(t, 3, len(result), "number of rows not expected") + t.Logf("Rows %v", result) + _ = rows.Close() + }) + t.Run("Test Select SQL with stmt and no rows", func(t *testing.T) { + rows, err = SelectStmt(stmt, 3) + assert.NoErrorf(t, err, "Query should not return error:%s", err) + assert.NotNil(t, rows, "Rows is nil") + var result []testTab + for rows.Next() { + var record testTab + err = rows.StructScan(&record) + assert.NoErrorf(t, err, "Query returned error %s", err) + result = append(result, record) + } + assert.Equal(t, 0, len(result), "number of rows not expected") + t.Logf("Rows %v", result) + _ = rows.Close() + }) + t.Run("Test Select with wrong sql", func(t *testing.T) { + mysql := "select * from test where idxx > ?" + rows, err = SelectSQL(dbh, mysql) + assert.Error(t, err, "Query should return error") + assert.Nil(t, rows, "Rows is not nil") + }) } diff --git a/dblib/oracle_docker_test.go b/dblib/oracle_docker_test.go index a9b3999..c456839 100644 --- a/dblib/oracle_docker_test.go +++ b/dblib/oracle_docker_test.go @@ -26,7 +26,7 @@ func prepareContainer() (container *dockertest.Resource, err error) { } containerName = os.Getenv("CONTAINER_NAME") if containerName == "" { - containerName = "tnscli-oracledb" + containerName = "dblib-oracledb" } var pool *dockertest.Pool pool, err = common.GetDockerPool() diff --git a/dblib/oracle_test.go b/dblib/oracle_test.go index 7ca7929..0cc8134 100644 --- a/dblib/oracle_test.go +++ b/dblib/oracle_test.go @@ -7,11 +7,11 @@ import ( "os" "testing" + "github.com/jmoiron/sqlx" "github.com/tommi2day/gomodules/common" - "github.com/tommi2day/gomodules/test" - "github.com/ory/dockertest/v3" + "github.com/tommi2day/gomodules/test" ora "github.com/sijms/go-ora/v2" "github.com/sijms/go-ora/v2/network" @@ -84,32 +84,32 @@ func TestWithOracle(t *testing.T) { assert.NoErrorf(t, err, "Connect failed: %s", err) }) t.Run("connect with function", func(t *testing.T) { - var db *sql.DB + var db *sqlx.DB connect := target t.Logf("connect with %s\n", connect) db, err = DBConnect("oracle", connect, TIMEOUT) assert.NoErrorf(t, err, "Connect failed: %v", err) - assert.IsType(t, &sql.DB{}, db, "Returned wrong type") + assert.IsType(t, &sqlx.DB{}, db, "Returned wrong type") result, err := SelectOneStringValue(db, "select to_char(sysdate,'YYYY-MM-DD HH24:MI:SS') from dual") assert.NoErrorf(t, err, "Select returned error::%v", err) assert.NotEmpty(t, result) t.Logf("Sysdate: %s", result) }) t.Run("Check tns connect", func(t *testing.T) { - var db *sql.DB + var db *sqlx.DB connect := ora.BuildJDBC(DBUSER, DBPASSWORD, desc, urlOptions) t.Logf("connect with %s\n", connect) db, err = DBConnect("oracle", connect, TIMEOUT) assert.NoErrorf(t, err, "Connect failed: %s", err) - assert.IsType(t, &sql.DB{}, db, "Returned wrong type") + assert.IsType(t, &sqlx.DB{}, db, "Returned wrong type") }) t.Run("Check dummy connect", func(t *testing.T) { - var db *sql.DB + var db *sqlx.DB connect := ora.BuildJDBC("dummy", "dummy", desc, urlOptions) t.Logf("connect with dummy user to %s\n", desc) db, err = DBConnect("oracle", connect, TIMEOUT) assert.ErrorContainsf(t, err, "ORA-01017", "returned unexpected error: %v", err) - assert.IsType(t, &sql.DB{}, db, "Returned wrong type") + assert.IsType(t, &sqlx.DB{}, db, "Returned wrong type") }) } diff --git a/go.mod b/go.mod index 9bd4ca6..f511c4e 100644 --- a/go.mod +++ b/go.mod @@ -11,14 +11,16 @@ require ( github.com/go-ldap/ldap/v3 v3.4.5 github.com/golangci/golangci-lint v1.53.3 github.com/hashicorp/vault/api v1.9.2 + github.com/jmoiron/sqlx v1.3.5 github.com/jstemmer/go-junit-report/v2 v2.0.0 github.com/ory/dockertest/v3 v3.10.0 - github.com/sijms/go-ora/v2 v2.7.9 + github.com/sijms/go-ora/v2 v2.7.11 github.com/sirupsen/logrus v1.9.3 + github.com/spf13/cobra v1.7.0 github.com/stretchr/testify v1.8.4 github.com/wneessen/go-mail v0.4.0 github.com/xlzd/gotp v0.1.0 - golang.org/x/net v0.10.0 + golang.org/x/net v0.14.0 gopkg.in/ini.v1 v1.67.0 ) @@ -186,7 +188,6 @@ require ( github.com/sourcegraph/go-diff v0.7.0 // indirect github.com/spf13/afero v1.8.2 // indirect github.com/spf13/cast v1.5.0 // indirect - github.com/spf13/cobra v1.7.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/viper v1.12.0 // indirect @@ -216,13 +217,13 @@ require ( go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.6.0 // indirect go.uber.org/zap v1.24.0 // indirect - golang.org/x/crypto v0.9.0 // indirect + golang.org/x/crypto v0.12.0 // indirect golang.org/x/exp v0.0.0-20230510235704-dd950f8aeaea // indirect golang.org/x/exp/typeparams v0.0.0-20230224173230-c95f2b4c22f2 // indirect golang.org/x/mod v0.10.0 // indirect golang.org/x/sync v0.2.0 // indirect - golang.org/x/sys v0.8.0 // indirect - golang.org/x/text v0.9.0 // indirect + golang.org/x/sys v0.11.0 // indirect + golang.org/x/text v0.12.0 // indirect golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 // indirect golang.org/x/tools v0.9.3 // indirect google.golang.org/protobuf v1.28.0 // indirect diff --git a/go.sum b/go.sum index 8eea25f..8fee2bc 100644 --- a/go.sum +++ b/go.sum @@ -211,6 +211,7 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= +github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= @@ -389,6 +390,8 @@ github.com/jingyugao/rowserrcheck v1.1.1 h1:zibz55j/MJtLsjP1OF4bSdgXxwL1b+Vn7Tjz github.com/jingyugao/rowserrcheck v1.1.1/go.mod h1:4yvlZSDb3IyDTUZJUmpZfm2Hwok+Dtp+nu2qOq+er9c= github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af h1:KA9BjwUk7KlCh6S9EAGWBt1oExIUv9WyNCiRz5amv48= github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af/go.mod h1:HEWGJkRDzjJY2sqdDwxccsGicWEf9BQOZsq2tV+xzM0= +github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= +github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -431,6 +434,7 @@ github.com/ldez/tagliatelle v0.5.0 h1:epgfuYt9v0CG3fms0pEgIMNPuFf/LpPIfjk4kyqSio github.com/ldez/tagliatelle v0.5.0/go.mod h1:rj1HmWiL1MiKQuOONhd09iySTEkUuE/8+5jtPYz9xa4= github.com/leonklingele/grouper v1.1.1 h1:suWXRU57D4/Enn6pXR0QVqqWWrnJ9Osrz+5rjt8ivzU= github.com/leonklingele/grouper v1.1.1/go.mod h1:uk3I3uDfi9B6PeUjsCKi6ndcf63Uy7snXgR4yDYQVDY= +github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lufeee/execinquery v1.2.1 h1:hf0Ems4SHcUGBxpGN7Jz78z1ppVkP/837ZlETPCEtOM= github.com/lufeee/execinquery v1.2.1/go.mod h1:EC7DrEKView09ocscGHC+apXMIaorh4xqSxS/dy8SbM= @@ -453,6 +457,8 @@ github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPn github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mbilski/exhaustivestruct v1.2.0 h1:wCBmUnSYufAHO6J4AVWY6ff+oxWxsVFrwgOdMUQePUo= @@ -582,8 +588,8 @@ github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c/go.mod h1:/PevMnwAx github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/sijms/go-ora/v2 v2.7.9 h1:FvPwsyNtAOywDKlgjrgCpGkL0s49ZA/ShTBgEAfYKE0= -github.com/sijms/go-ora/v2 v2.7.9/go.mod h1:EHxlY6x7y9HAsdfumurRfTd+v8NrEOTR3Xl4FWlH6xk= +github.com/sijms/go-ora/v2 v2.7.11 h1:RqyIXtTyIavMfQWAB/pRPbCo3m9daS4ks7sHzWSweaA= +github.com/sijms/go-ora/v2 v2.7.11/go.mod h1:EHxlY6x7y9HAsdfumurRfTd+v8NrEOTR3Xl4FWlH6xk= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= @@ -720,8 +726,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= -golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= +golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -812,8 +818,8 @@ golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -906,8 +912,8 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -927,8 +933,8 @@ golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=