Can I get EXPLAIN ANALYZE output through the lib/pq Go SQL driver? - sql

I'd like to be able to evaluate my queries inside my app, which is in Go and using the github.com/lib/pq driver. Unfortunately, neither the [lib/pq docs][1] nor the [database/sql][2] docs seem to say anything about this, and nothing in the database/sql interfaces suggests this is possible.
Has anyone found a way to get this output?

Typical EXPLAIN ANALYZE returns several rows, so you can do it with simple sql.Query. Here is an example:
package main
import (
"database/sql"
"fmt"
_ "github.com/lib/pq"
"log"
)
func main() {
db, err := sql.Open("postgres", "user=test dbname=test sslmode=disable")
if err != nil {
log.Fatal(err)
}
defer db.Close()
rows, err := db.Query("EXPLAIN ANALYZE SELECT * FROM accounts ORDER BY slug")
if err != nil {
log.Fatal(err)
}
for rows.Next() {
var s string
if err := rows.Scan(&s); err != nil {
log.Fatal(err)
}
fmt.Println(s)
}
if err := rows.Err(); err != nil {
log.Fatal(err)
}
}

Related

Can I return rows result from db without scan it first in Golang func?

I have mini project using Golang, my plan is make a base function which it will be called from Model to execute sql query, then return the rows result without Scan it first. I'm using this way to prevent forget write defer rows.Close() and the code for execute the Query in model more simple. I had tried this way, but when try to print the result, I got nil without any error. here my screenshoot. The result exists when the query executed and the rows result scanned are in same function. Maybe I miss something? This is my first question, sorry it's too long. Thank you
The base model where the SQL query will be executed and return the result
package model
import "database/sql"
import "hb-backend-v1/config/database"
import "fmt"
func Query(query string) (*sql.Rows, error){
connect, err := database.Connect()
if err != nil{
fmt.Println("Connection Failed")
return nil, err
}
fmt.Println("Connection Success")
defer connect.Close()
rows, err := connect.Query(query)
defer rows.Close()
if err != nil{
return nil, err
}
return rows, nil
}
This is where the base model will be called and give the result
package product
import "database/sql"
import _"fmt"
import "hb-backend=v1/model"
type Hasil struct{
Id_alamat_store int
Id_tk int
Alamat string
Id_wil int
Latitude sql.NullString
Longitude sql.NullString
}
func ProductList() ([]Hasil, error){
rows, err := model.Query("SELECT * FROM alamat_store")
if err != nil{
return nil, err
}
var result []Hasil
for rows.Next(){
var each = Hasil{}
var err = rows.Scan(&each.Id_alamat_store, &each.Id_tk, &each.Alamat, &each.Id_wil, &each.Latitude, &each.Longitude)
if err != nil{
return nil, err
}
result = append(result, each)
}
return result, nil
}
Both connection and rows will be closed once Query exits, after those two are closed you can't use rows anymore.
One approach to get around that would be to pass a closure to Query and have Query execute it before closing the two resources:
func Query(query string, scan func(*sql.Rows) error) error {
connect, err := database.Connect()
if err != nil{
return err
}
defer connect.Close()
rows, err := connect.Query(query)
if err != nil{
return err
}
defer rows.Close()
return scan(rows)
}
func ProductList() ([]Hasil, error) {
var result []Hasil
err := model.Query("SELECT * FROM alamat_store", func(rows *sql.Rows) error {
for rows.Next() {
var each = Hasil{}
var err = rows.Scan(&each.Id_alamat_store, &each.Id_tk, &each.Alamat, &each.Id_wil, &each.Latitude, &each.Longitude)
if err != nil {
return err
}
result = append(result, each)
}
return nil
})
if err != nil {
return nil, err
}
return result, nil
}

How to find an item

I'm trying to find an element on the page, but it doesn't work out what could be the reason?
package main
import (
"github.com/tebeka/selenium"
"log"
"time"
)
func main() {
caps := selenium.Capabilities{
"browserName": "chrome",
}
wd, err := selenium.NewRemote(caps, "http://localhost:4444/wd/hub")
if err != nil{
log.Fatal(err)
}
defer func() {
if err := wd.Quit(); err != nil {
log.Fatal(err)
}
}()
if err := wd.SetPageLoadTimeout(time.Second * 10); err != nil {
log.Fatal(err)
}
if err = wd.SetImplicitWaitTimeout(time.Second * 10); err != nil {
log.Fatal(err)
}
if err = wd.Get("https://www.facebook.com/ads/library/?active_status=all&ad_type=political_and_issue_ads&country=ALL&sort_data[direction]=desc&sort_data[mode]=relevancy_monthly_grouped"); err != nil {
log.Fatal(err)
}
title, err := wd.Title()
if err != nil {
log.Fatalln(err)
}
log.Println(title)
elem, err := wd.FindElement(selenium.ByXPATH, "//*[#id=\"content\"]/div/div/div[3]/div/div[4]/div")
if err != nil {
log.Fatal(err)
}
log.Println(elem.Text())
}
gives an error message:
no such element: no such element: Unable to locate element: {"method":"xpath","selector":"//*[#id="content"]/div/div/div[3]/div/div[4]/div"}
The hub was raised in docker. Image https://hub.docker.com/r/selenium/standalone-chrome
Just try to not use XPATHs with Selenium if you can.
Search for it using .ByTag and look for a unique property of your element to find it. Never rely on XPATHs, classes or even IDs for famous websites since they often change.
Check my answer here: How to click on the Ask to join button within https://meet.google.com using Selenium and Python?

How to optimize database connections

In my Go application I use crontab package to run Tracker function every minute. As you can notice from the code I call PostgreSQL function. To interact with the PostgreSQL database, I use the gorm package. Application worked several days without any problem but now I notice an error in logs: pq: sorry, too many clients already. I know that same questions was asked several times in StackOverflow before. For example in this post people advice to use Exec or Scan methods. In my case as you can see I use Exec method but anyway I have error. As far as I understand, each database request makes a separate connection and does not close it. I can't figure out what I'm doing wrong.
main.go:
package main
import (
"github.com/mileusna/crontab"
)
func main() {
database.ConnectPostgreSQL()
defer database.DisconnectPostgreSQL()
err = crontab.New().AddJob("* * * * *", controllers.Tracker); if err != nil {
utils.Logger().Fatal(err)
return
}
}
tracker.go:
package controllers
import (
"questionnaire/database"
"time"
)
var Tracker = func() {
err := database.DBGORM.Exec("CALL tracker($1)", time.Now().Format("2006-01-02 15:04:05")).Error; if err != nil {
utils.Logger().Println(err) // ERROR: pq: sorry, too many clients already
return
}
}
PostgreSQL.go:
package database
import (
"fmt"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/postgres"
"github.com/joho/godotenv"
"questionnaire/utils"
)
var DBGORM *gorm.DB
func ConnectPostgreSQL() {
err := godotenv.Load(".env")
if err != nil {
utils.Logger().Println(err)
panic(err)
}
databaseUser := utils.CheckEnvironmentVariable("PostgreSQL_USER")
databasePassword := utils.CheckEnvironmentVariable("PostgreSQL_PASSWORD")
databaseHost := utils.CheckEnvironmentVariable("PostgreSQL_HOST")
databaseName := utils.CheckEnvironmentVariable("PostgreSQL_DATABASE_NAME")
databaseURL:= fmt.Sprintf("host=%s user=%s dbname=%s password=%s sslmode=disable", databaseHost, databaseUser, databaseName, databasePassword)
DBGORM, err = gorm.Open("postgres", databaseURL)
if err != nil {
utils.Logger().Println(err)
panic(err)
}
err = DBGORM.DB().Ping()
if err != nil {
utils.Logger().Println(err)
panic(err)
}
DBGORM.LogMode(true)
}
func DisconnectPostgreSQL() error {
return DBGORM.Close()
}

How to avoid using for next method in getting a row count

In php, I can print rowcount where postid matches with the code below without passing the result in a while loop.
$status_query = "SELECT count(*) as postCount FROM postData WHERE postid=1";
$status_result = mysqli_query($con,$status_query);
$status_row = mysqli_fetch_array($status_result);
$postCount = $status_row['postCount'];
echo $postCount;
Now am re-writing the code to golang for the same row count. I leverage Stackoverflow solution found here.
source link
With that Stackoverflow solution link above, the golang code below is working great as I can get the row count.
rows1, err := db.Query("SELECT COUNT(*) as postCount FROM postData WHERE postid=1")
if err != nil {
log.Fatal(err)
}
defer rows1.Close()
var postCount int
for rows1.Next() {
if err := rows1.Scan(& postCount); err != nil {
log.Fatal(err)
}
}
fmt.Printf("Number of rows are %s\n", postCount)
Here is what I want modify:
The above code passed the row count result within
for rows1. Next(){
// result here.
}
My question is:
Please how do I avoid this for rows.next() function and just get my result straight since am retrieving the row count based on postid.
In php code above, I can get the result straight without passing it in a while loop.
In golang am thinking of something like the code below
rows1, err := db.Query("SELECT COUNT(*) as postCount FROM postData WHERE postid=1")
if err != nil {
log.Fatal(err)
}
defer rows1.Close()
var status_row = rows1.Next()
var postCount =rows1.Scan(& postCount)
fmt.Printf("Number of rows are %s\n", postCount)
Does anyone has a better way of getting this rowcount to display straight without passing the result within for rows1.Next() method
Here is the overall working code before I seek modification in the coding illustrations above.
package main
import "database/sql"
import _ "github.com/go-sql-driver/mysql"
import "net/http"
import "fmt"
import "log"
var db *sql.DB
var err error
func getRecordPage1(res http.ResponseWriter, req *http.Request) {
if req.Method != "POST" {
http.ServeFile(res, req, "getjsonRecord.html")
return
}
//The commented section below is the code I want to modify to avoid use of for rows.next function....
/*
rows1, err := db.Query("SELECT COUNT(*) as postCount FROM like_unlike WHERE postid=1")
if err != nil {
log.Fatal(err)
}
defer rows1.Close()
var postCount int
for rows1.Next() {
if err := rows1.Scan(& postCount); err != nil {
log.Fatal(err)
}
}
fmt.Printf("Number of rows are %s\n", postCount)
}
*/
func homePage(res http.ResponseWriter, req *http.Request) {
http.ServeFile(res, req, "index.html")
}
func main() {
db, err = sql.Open("mysql", "root:#/golang44")
if err != nil {
panic(err.Error())
}
defer db.Close()
err = db.Ping()
if err != nil {
panic(err.Error())
}
http.HandleFunc("/getjsonRecord", getRecordPage1)
http.HandleFunc("/", homePage)
fmt.Println("Listening on 127.0.0.1:8088")
http.ListenAndServe(":8088", nil)
}
Generally, if you know you are getting one row, use DB.QueryRow
It allows you to chain the query and scan together, so your example would look like:
var postCount int
err := db.QueryRow("SELECT COUNT(*) as postCount FROM postData WHERE postid=1").Scan(&postCount)
if err != nil {
log.Fatal(err)
}

how to query for multiples rows and parse to json?

I have this code:
func GetAll(c *gin.Context) {
var veiculos model.Veiculo
rows, err := db.Query("SELECT * FROM vei_veiculo")
if err != nil {
fmt.Println("[GetAll] erro ao abrir o query db inteiro")
}
defer rows.Close()
for rows.Next() {
err := rows.Scan(&veiculos)
if err != nil {
fmt.Println("[GetAll] erro ao scanear uma linha'")
}
}
fmt.Println(veiculos)}
My struct name is at model.Veiculo and I want to print it all once. It seems there is an error on scan the query rows. What did I do wrong?
Assuming you are using database/sql, the function signature is func (rs *Rows) Scan(dest ...interface{}) error.
You need to be doing scanning into each member of the struct, something more like:
err := rows.Scan(&veiculos.ID, &veiculos.Name, &veiculos.Description)
To scan each row to its own struct, I recommend an approach like so:
package main
import (
"database/sql"
"fmt"
"log"
_ "github.com/go-sql-driver/mysql"
)
type Person struct {
FirstName string
LastName string
Email string
}
func main() {
db, err := sql.Open("mysql", "dsn...")
if err != nil {
log.Fatalln(err)
}
defer db.Close()
people := []Person{}
rows, err := db.Query("SELECT * FROM people")
if err != nil {
log.Fatalln(err)
}
for rows.Next() {
person := Person{}
if err := rows.Scan(&person.FirstName, &person.LastName, &person.Email); err != nil {
log.Fatalln(err)
}
people = append(people, person)
}
fmt.Printf("%+v\n", people)
}
Alternatively, the library https://github.com/jmoiron/sqlx exists as one of the solutions to marshaling SQL query data to structs. I personally prefer this method, as it behaves more like an Unmarshal function:
package main
import (
"fmt"
"log"
_ "github.com/go-sql-driver/mysql"
"github.com/jmoiron/sqlx"
)
type Person struct {
FirstName string `db:"first_name"`
LastName string `db:"last_name"`
Email string `db:"email"`
}
func main() {
db, err := sqlx.Connect("mysql", "dsn...")
if err != nil {
log.Fatalln(err)
}
people := []Person{}
if err := db.Select(&people, "SELECT * FROM people"); err != nil {
log.Fataln(err)
}
fmt.Printf("%+v\n", people)
}
Following either of these approaches allows you to easily use the json.Marshal
method with the people variable, and viola!
Good luck!