I am trying to create prepared statements using the Snowflake driver for Go: https://github.com/snowflakedb/gosnowflake
However, every time I try to prepare a statement that requires strings, it fails to bind them to the overall query.
Here is an example:
import (
"database/sql"
_ "github.com/snowflakedb/gosnowflake"
)
func getData(db *sql.DB) error {
tbl := "DATASET"
s := "Bob"
stmt := "INSERT INTO ? SELECT * FROM OTHER_TBL WHERE name = ?"
_, err := db.Exec(stmt, dataset, s)
if err != nil {
return err
}
return nil
}
The query always fails with a Syntax error stating it didn't recognize the ?. I've also tried the .Prepare() method and I get the same result.
I've also tried single quoting the ? placeholder, but in my actual query, I have several ? and it doesn't bind any of them.
I'm left with only having success if I use fmt.Sprintf() but I'd like to avoid that method.
In your snippet code, you are parameterized the table name.
Snowflake implements database/sql interfaces. as my experience with this library, parameterization table or column names are not allowed.
Related
I am developing an API using Go which connects to MySQL database for some query execution. Am using GORM for database operations. But am stuck at printing the SELECT query output for the tables which I don't have the column names.
My use case is that, I need to run the query on multiple tables where I don't have an idea about what their column names and types are. And so I cannot pre-define a struct for all the current and future tables which might get added.
Is there a way to print/save the SELECT query output without a pre-defined struct ?
I tried do some using empty struct but it didn't help me.
P.S: Am a beginner in Go
type Testing struct{}
var test Testing
dsn := fmt.Sprintf("%v:%v#tcp(%v:%v)/%v", myds.DBuser, myds.DBpassword, myds.DBhost, myds.DBport, myds.DBname)
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
fmt.Println(err)
}
tx := db.Raw(query).Scan(&test)
if tx.Error != nil {
fmt.Println(tx.Error)
}
fmt.Println(test)
You can use an anonymous struct
Let's say you have a struct:
type User struct{
FirstName string
LastName string
}
Query:
SELECT CONCAT(first_name,last_name) AS full_name from users;
Notice the new column full_name
you can simply do
var fullName = struct{FullName string}{}
Notice how I use pascal case & FullName has to be the field name
A capital letter in between will represent a _
Field is public so it can be accessed outside.
full_name(query) = FullName(field)
pass this fullName object as a bucket to your Scan and it should work.
db.Raw(query).Scan(&fullName)
EDIT:
Your query will have some result right?
Let me assume that you have
column_one,column_two... column_n
Now, to get the data from all the columns or selected ones if you want, you simply have to define fields (in anonymous struct) with specific names. In our case:
struct{ColumnOne,ColumnTwo,..ColumnN interface{}}{}
P.S. I have used interface{}, you can use types depending on the data your column returns.
It worked for me by using a map type with interface. This helped me to save the SELECT query results without pre-defined struct or the column names.
dsn := fmt.Sprintf("%v:%v#tcp(%v:%v)/%v", myds.DBuser, myds.DBpassword, myds.DBhost, myds.DBport, myds.DBname)
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
fmt.Println(err)
}
var result []map[string]interface{}
tx := db.Raw(query).Scan(&result)
if tx.Error != nil {
fmt.Println(tx.Error)
return
}
bytes, _ := json.Marshal(result)
fmt.Println(string(bytes))
I am using Go to open a file with multiple JSON entries, parse the file into a slice with a custom type, then insert the slice data into an Oracle database. According to the godror documentation at https://godror.github.io/godror/doc/tuning.html, I should be able to feed a slice into the insert command, and have the database/sql Exec method iterate thru the struct for me. I am at a loss for how to do this. I am sure there is a simple solution to this.
To slightly complicate things, I have a database column that is not in the struct for the host name of the computer the app is running on. This column should be filled in for every row the app inserts. In other words, every row of this table needs to have a column filled in with the host name of the machine is running on. Is there a more elegant way to do this than to just add a 'hostname' field to my struct that has the running system's host name, over and over again?
What follows is a simplified version of my code.
package main
import (
"database/sql"
_ "github.com/godror/godror"
)
type MyType struct {
var1 string `json:"var1"`
var2 string `json:"var2"`
}
func main() {
hostname, err := os.Hostname()
if err != nil {
//log.Println("Error when getting host name")
log.Fatal(err)
}
mySlice := parseFile("/path/to/file", false)
db, err := sql.Open("godror", "user/pass#oraHost/oraDb")
sql := `INSERT INTO mytable (var1, var2, host) values (:1 :2 :3)`
// this is the line where everything breaks down, and i am not sure
// what should go here.
_, err = db.Exec(sql, mySlice[var1], mySlice[var2], hostname)
}
func parseFile(filePath string, deleteFile bool) []MyType {
// a few lines of code that opens a text file, parses it into a slice
// of type MyType, and returns it
}
not sure, if you already went through, does this test case, TestExecuteMany help ? mentioned in https://github.com/godror/godror/blob/master/z_test.go has example usage for array insert.
res, err := tx.ExecContext(ctx,
`INSERT INTO `+tbl+ //nolint:gas
` (f_id, f_int, f_num, f_num_6, F_num_5_2, F_vc, F_dt)
VALUES
(:1, :2, :3, :4, :5, :6, :7)`,
ids, ints, nums, int32s, floats, strs, dates)
for batch insert of structs:
https://github.com/jmoiron/sqlx
I am using database/sql package with oracle driver (“gopkg.in/rana/ora.v4”), when I am inserting the data, it’s LastInsertId Method is returning 0, while data is successfully inserted.
Attaching code.
package main
import (
“database/sql”
“fmt”
_ "gopkg.in/rana/ora.v4"
)
func main() {
conn, err = sql.Open(“ora”,
username+"/"+password+"#"+host+":"+port+"/"+sid)
query := “INSERT INTO Table (C2) VALUES (:C2)”
result, err := conn.Exec(query, “Test”)
if err!= nil {
panic(err)
}
lastId := result.LastInsertId() // returning 0
fmt.Println(lastId)
}
Please tell me why this is happening?
From the documentation (emphasis added):
LastInsertId
The database/sql package provides a LastInsertId method to return the last inserted row's id. Oracle does not provide such functionality, but if you append ... RETURNING col /*LastInsertId*/ to your SQL, then it will be presented as LastInsertId. Note that you have to mark with a /*LastInsertId*/ (case insensitive) your RETURNING part, to allow ora to return the last column as LastInsertId(). That column must fit in int64, though!
Hi I don't understand what I'm doing wrong here.
_, err = db.Exec("CREATE TABLE $1", "books")
if err != nil {
log.Fatal(err)
}
I'm failing to see what is syntactically wrong here.
I have also done:
_, err = db.Exec("CREATE TABLE books")
if err != nil {
log.Fatal(err)
}
Gives the syntax error as well
Identifiers cannot be used as placeholders. Only values can be used there. (it's not a Go or its db drivers limitations, it's relational databases themselves that have such a "limitation").
In case of hardcoded identifiers - use the exact query
CREATE TABLE books
In case of dynamic placeholders - ensure you're using white lists of what values are allowed there.
UPD
Just this query
CREATE TABLE books
is invalid because it's missing any column definitions. It must be at least one column in a table.
is invalid because it's missing parentheses:
CREATE TABLE books()
in which you define columns.
TIL: you can have a table with zero columns in postgresql.
References:
https://www.postgresql.org/docs/current/static/sql-createtable.html
I use this driver to communicate with psql from Go. Now when I issue an update query, I have no possibility to know whether it actually updated anything (it can update 0 rows if such id is not present).
_, err := Db.Query("UPDATE tags SET name=$1 WHERE id=1", name)
I tried to investigate err variable (in the way the doc suggests for Insert statement):
if err == sql.ErrNoRows {
...
}
But even with non-existent id, err is still null.
I also tried to use QueryRow with returning clause:
id := 0
err := Db.QueryRow("UPDATE tags SET name=$1 WHERE id=1 RETURNING id", name).Scan(&id)
But this one fails to scan &id when id=1 is not present in the database.
So what is the canonical way to check whether my update updated anything?
Try using db.Exec() instead of db.Query() for queries that do not return results. Instead of returning a sql.Rows object (which doesn't have a way to check how many rows were affected), it returns a sql.Result object, which has a method RowsAffected() (int64, error). This returns the number of rows affected (inserted, deleted, updated) by any write operations in the query fed to the Exec() call.
res, err := db.Exec(query, args...)
if err != nil {
return err
}
n, err := res.RowsAffected()
if err != nil {
return err
}
// do something with n
Note that if your query doesn't affect any rows directly, but only does so via a subquery, the rows affected by the subquery will not be counted as rows affected for that method call.
Also, as the method comment notes, this doesn't work for all database types, but I know for a fact it works with pq, as we're using that driver ourselves (and using the RowsAffected() method).
Reference links:
https://golang.org/pkg/database/sql/#DB.Exec
https://golang.org/pkg/database/sql/#Result