I'm trying to connect Golang with an AS/400 DB2 Database, i have iSeries Access Driver Installed on the machine, this is the code by now:
package main
import (
"odbc"
)
func main() {
conn, _ := odbc.Connect("DSN=DSN/SCHEME;UID=USER;PWD=PASS")
stmt, _ := conn.Prepare("SELECT * FROM SCHEME.TABLE")
stmt.Execute()
rows, _ := stmt.FetchAll()
for i, row := range rows {
println(i, row)
}
stmt.Close()
conn.Close()
}
I was able to do this using Python with a DSN-Less configuration on the ODBC driver with something like this:
con = pyodbc.connect('DRIVER=iSeries Access ODBC Driver;SYSTEM=DSN;UID=USR;PWD=PASS;DBQ=PRUEBA')
I tried on Golang with odbc, mgodbc and db2cli, always getting an invalid memory address or nil pointer dereference error.
Any help is appreciated, Thanks!
Update –
bitbucket.org/phiggins/db2cli is now listed on https://github.com/golang/go/wiki/SQLDrivers
We're using bitbucket.org/phiggins/db2cli, which is based off of the greatcode.google.com/p/odbc library, and it's been working great!
package main
import (
"database/sql"
"log"
"time"
_ "bitbucket.org/phiggins/db2cli"
)
func main() {
db, err := sql.Open("db2-cli", "DATABASE=testdb; HOSTNAME=db2.domain.com; PORT=1234; PROTOCOL=TCPIP; UID=user1; PWD=password1;")
if err != nil {
log.Fatalln(err)
}
defer db.Close()
var t time.Time
row := db.QueryRow("SELECT current date FROM sysibm.sysdummy1;")
err = row.Scan(&t)
if err != nil {
log.Fatalln(err)
}
log.Println(t)
}
I managed to get it working, first, you need to install mgodbc go package:
go get bitbucket.org/miquella/mgodbc
To install this package you must have a working MinGW installation with gcc on your path (Windows), if you use Linux you should have gcc by installed by default.
Then, using this code i got it working:
package main
import (
_ "bitbucket.org/miquella/mgodbc"
"fmt"
"os"
"database/sql"
)
var (
db *sql.DB
checkError = func(err error, num int) {
if err != nil {
fmt.Println(err, num)
os.Exit(1)
}
}
)
func main() {
// Replace the DBQ value with the name of your ODBC data source.
db, err := sql.Open("mgodbc", "DRIVER=iSeries Access ODBC Driver;SYSTEM=HOSTNAME;UID=USER;PWD=PASS;DBQ=SCHEMA")
checkError(err,1)
rows, err := db.Query("SELECT * FROM TABLE")
checkError(err,2)
for rows.Next(){
fmt.Println(rows)
}
defer rows.Close()
defer db.Close()
}
The only thing missing here, is that sql Go package doesn't cast the Query to String, then you get weird codes when querying, now i'm looking to solve that.
I'm using Go + https://bitbucket.org/phiggins/db2cli.
This go lib for DB2 is using the DB2 CLI driver, that I found here and configured as described on phiggins page: http://public.dhe.ibm.com/ibmdl/export/pub/software/data/db2/drivers/odbc_cli/
Here is my code:
package main
import (
"fmt"
_ "bitbucket.org/phiggins/db2cli"
"database/sql"
"log"
"time"
)
func main() {
// JDBC conn string = jdbc:as400://127.0.0.1/;libraries=MYCUSTOM,hhpgm,trk35null,GX,TRK35B5ptf,TRK35B5PG,IFWMS,INTERTRK;user=MYUSER;password=MYPASS;naming=system;block criteria="0"
db, err := sql.Open("db2-cli", "DATABASE=MYCUSTOM; HOSTNAME=127.0.0.1; UID=MYUSER; PWD=MYPASS;")
if err != nil {
log.Fatalln(err)
}
defer db.Close()
var t time.Time
row := db.QueryRow("SELECT current date FROM SYSIBM.SYSDUMMY1;")
err = row.Scan(&t)
if err != nil {
log.Fatalln(err)
}
log.Println(t)
}
But I'm not being able to connect.
The error that I'm receiving is:
$ go run main.go
2016/10/27 18:07:46 SQLDriverConnect: {08001} [IBM][CLI Driver] SQL30081N A communication error has been detected. Communication protocol being used: "TCP/IP". Communication API being used: "SOCKETS". Location where the error was detected: "127.0.0.1". Communication function detecting the error: "connect". Protocol specific error code(s): "61", "*", "*". SQLSTATE=08001
exit status 1
I'm on mac, so I identified that the "protocol specific error code" 61 is "#define ECONNREFUSED 61 /* Connection refused */" according to:
http://opensource.apple.com//source/xnu/xnu-1456.1.26/bsd/sys/errno.h
However, I can connect using a SQL client and a JDBC driver.
So, the question is, how can I convert the JDBC connection string to the format expected by the DB2 CLI driver?
JDBC connection string: jdbc:as400://127.0.0.1/;libraries=MYCUSTOM,hhpgm,trk35null,GX,TRK35B5ptf,TRK35B5PG,IFWMS,INTERTRK;user=MYUSER;password=MYPASS;naming=system;block criteria="0"
CLI connection string: "HOSTNAME=127.0.0.1; UID=MYUSER; PWD=MYPASS;"
Vanessa, you might need to define the value of the port for your connection string. I not sure what is the default port value so just put it in there to be safe.
Have you tried the golang driver available for Db2?
https://github.com/ibmdb/go_ibm_db
Related
I have a Gorm delete with the returning result:
expirationDate := time.Now().UTC().Add(-(48 * time.hour))
var deletedUsers Users
res := gormDB.WithContext(ctx).
Table("my_users").
Clauses(clause.Returning{Columns: []clause.Column{{Name: "email"}}}).
Where("created_at < ?", expirationDate).
Delete(&deletedUsers)
Now the test with clauses always fails. e.g. :
sqlMock.ExpectExec(`DELETE`)
.WithArgs(expirationDate)
.WillReturnResult(sqlmock.NewResult(1, 1))
Receiving error:
"call to Query 'DELETE FROM "my_users" WHERE created_at < $1 RETURNING "email"' with args [{Name: Ordinal:1 Value:2023-01-18 06:15:34.694274 +0000 UTC}], was not expected, next expectation is: ExpectedExec => expecting Exec or ExecContext which:\n - matches sql: 'DELETE'\n - is with arguments:\n 0 - 2023-01-18 06:15:34.694274 +0000 UTC\n - should return Result having:\n LastInsertId: 1\n RowsAffected: 1"
I tried many other sqlMock expectations, but they have a similar issue.
Also, we don't have a return value in ExpectExec, only in ExpectQuery...
Any chance someone has to test the Gorm query with the Clauses?
I was able to successfully manage what you need. First, let me share the files I wrote, and then I'll walk you through all of the relevant changes. The files are repo.go for production and repo_test.go for the test code.
repo.go
package gormdelete
import (
"context"
"time"
"gorm.io/gorm"
"gorm.io/gorm/clause"
)
type Users struct {
Email string
}
func Delete(ctx context.Context, gormDB *gorm.DB) error {
expirationDate := time.Now().UTC().Add(-(48 * time.Hour))
var deletedUsers Users
res := gormDB.WithContext(ctx).Table("my_users").Clauses(clause.Returning{Columns: []clause.Column{{Name: "email"}}}).Where("created_at < ?", expirationDate).Delete(&deletedUsers)
if res.Error != nil {
return res.Error
}
return nil
}
As you didn't provide the full file I tried to guess what was missing.
repo_test.go
package gormdelete
import (
"context"
"database/sql/driver"
"testing"
"time"
"github.com/DATA-DOG/go-sqlmock"
"github.com/stretchr/testify/assert"
"gorm.io/driver/postgres"
"gorm.io/gorm"
)
// this is taken directly from the docs
// https://github.com/DATA-DOG/go-sqlmock#matching-arguments-like-timetime
type AnyTime struct{}
// Match satisfies sqlmock.Argument interface
func (a AnyTime) Match(v driver.Value) bool {
_, ok := v.(time.Time)
return ok
}
func TestDelete(t *testing.T) {
db, mock, err := sqlmock.New()
if err != nil {
t.Fatalf("an error was not expected: %v", err)
}
conn, _ := db.Conn(context.Background())
gormDb, err := gorm.Open(postgres.New(postgres.Config{
Conn: conn,
}))
row := sqlmock.NewRows([]string{"email"}).AddRow("test#example.com")
mock.ExpectBegin()
mock.ExpectQuery("DELETE FROM \"my_users\" WHERE created_at < ?").WithArgs(AnyTime{}).WillReturnRows(row)
mock.ExpectCommit()
err = Delete(context.Background(), gormDb)
assert.Nil(t, err)
if err = mock.ExpectationsWereMet(); err != nil {
t.Errorf("not all expectations were met: %v", err)
}
}
Here, there are more changes that it's worth mentioning:
I instantiated the AnyTime as per the documentation (you can see the link in the comment).
Again, I guessed the setup of the db, mock, and gormDb but I think it should be more or less the same.
I switch the usage of ExpectExec to ExpectQuery as we'll have back a result set as specified by the Clauses method in your repo.go file.
You've to wrap the ExpectQuery within an ExpectBegin and an ExpectCommit.
Finally, pay attention to the difference in how the driver expects the parameters in the SQL statement. In the production code, you can choose to use ? or $1. However, in the test code, you can only use the ? otherwise it won't match the expectations.
Hope to help a little bit, otherwise, let me know!
package main
import (
"database/sql"
"fmt"
"log"
"os"
_ "github.com/mattn/go-sqlite3"
)
type Users struct {
UserId, intUname string
}
func main() {
os.Remove("foo.db")
db, err := sql.Open("sqlite3", "foo.db")
if err != nil {
log.Fatal(err)
}
defer db.Close()
sql := `create table users (userId integer, uname text);`
db.Exec(sql)
sql = `insert into users(userId,uname) values(1,'Mike');`
db.Exec(sql)
sql = `insert into users(userId,uname) values(2,'John');`
db.Exec(sql)
rows, err := db.Query("select * from users")
if err != nil {
log.Fatal(err)
}
defer rows.Close()
var users []Users = make([]Users, 0)
for rows.Next() {
var u Users
rows.Scan(&u.UserId, &u.intUname)
users = append(users, u)
}
fmt.Println(users)
}
Above is my codes. Now I will run this file. Codes only connect to sqlite3 database, And execute some sql, No any else operate. I don't know why to happen this.
Met below error:
csccl25013> go run .
github.com/goproject/sqlite3
/nfs/site/disks/simcloud_zhoudo1x_002/go/go/pkg/tool/linux_amd64/link: running gcc failed: exit status 1
/nfs/site/itools/em64t_SLES12SP5/pkgs/gcc/4.7.2/.bin/../lib64/gcc/x86_64-suse-linux/4.7.2/../../../../x86_64-suse-linux/bin/ld: /tmp/go-link-322571714/000015.o(.text+0x63): unresolvable AWAVAUATUSH��h�*H�T$(���� relocation against symbol `stderr##GLIBC_2.2.5'
/nfs/site/itools/em64t_SLES12SP5/pkgs/gcc/4.7.2/.bin/../lib64/gcc/x86_64-suse-linux/4.7.2/../../../../x86_64-suse-linux/bin/ld: final link failed: Nonrepresentable section on output
collect2: error: ld returned 1 exit status
I don't know how to resolve this error. Please help me.
Expected Result:
Execute successful.
Connect sqlite3 normally.
The error indicates your Go toolchain is unable to build the CGO implementation for github.com/mattn/go-sqlite3 (eg, cross-compilation error).
If you are unable to troubleshoot your C compiler you could try importing modernc.org/sqlite and using the "sqlite" SQL driver instead. This is a pure Go conversion of Sqlite and avoids the need for the C compiler.
I'm trying to read data from some devices via telnet protocol and below is my simple code.
I just want to print some meaningful results.
package main
import (
"fmt"
"github.com/reiver/go-telnet"
)
func main() {
conn, _ := telnet.DialTo("10.253.102.41:23")
fmt.Println(conn)
}
but this is what I got by this way:
&{0xc000006028 0xc000004720 0xc000040640}
It's obvious that it gets you &{0xc000006028 0xc000004720 0xc000040640} cause you are printing the connection object and it's the pointer address of that. If you want to print the data, you have to read it through connection using the Read method of the connection. Something like this:
b := make([]byte, 100)
n, err := conn.Read(b)
if err != nil {
// handle error
}
fmt.Println(string(b))
This is a snippet of the first part of my code
package main
import (
"encoding/csv"
"fmt"
"os"
)
func main() {
file, err := os.Open("Account_balances.csv")
if err != nil {
fmt.Println("Error", err)
return
}
defer file.Close()
reader := csv.NewReader(file)
record, err := reader.ReadAll()
if err != nil {
fmt.Println("Error", err)
}
for value:= range record{ // for i:=0; i<len(record)
fmt.Println("", record[value])
}
}
I want to write code that saves the CSV file in any database (i.e SQL, SQLite or PostgreSQL).
The Go MySQL driver supports loading from file:
See https://github.com/go-sql-driver/mysql#load-data-local-infile-support and https://godoc.org/github.com/go-sql-driver/mysql#RegisterLocalFile.
RegisterLocalFile adds the given file to the file whitelist, so that
it can be used by "LOAD DATA LOCAL INFILE ". Alternatively
you can allow the use of all local files with the DSN parameter
'allowAllFiles=true'
filePath := "/home/gopher/data.csv" mysql.RegisterLocalFile(filePath)
err := db.Exec("LOAD DATA LOCAL INFILE '" + filePath + "' INTO TABLE
foo") if err != nil { ...
Each DB engine has different ways for importing CSVs in an optimized way. You should use them instead of writing you own methods for reading CSVs and mass inserting records.
Refs:
MySQL: https://dev.mysql.com/doc/refman/5.7/en/load-data.html
PgSQL: https://www.postgresql.org/docs/current/static/sql-copy.html
I'm trying to query a test keyspace like:
package main
import "fmt"
import _ "github.com/gocql/gocql"
var (
gocql string
)
func main() {
// connect to the cluster
cluster := gocql.NewCluster("127.0.0.1")
cluster.Keyspace = "dbaccess"
session, _ := cluster.CreateSession()
defer session.Close()
if err := session.Query("SELECT name, age FROM people WHERE name='doug'").Scan(&name, &age); err != nil {
log.Fatal(err)
}
fmt.Println(name, age)
}
But I get an error like:
12: gocql.NewCluster undefined (type string has no field or method NewCluster)
Does that mean it's trying to point to the method in the gocql/gocql folder but can't find it, or is the syntax wrong to import stuff or?
I think your problem is that you are declaring a gocql var as a string here:
var (
gocql string
)
You should just remove this and it should resolve that particular issue.
In addition your import statement:
import _ "github.com/gocql/gocql"
Shouldn't include an underscore (_) since you are explicitly using gocql and not just importing for its side effects.