Search code examples
postgresqlgogorp

Transaction stays in pg_stat_activity state after execution


I'm quite new to both PostgreSQL and golang. Mainly, I am trying to understand the following:

  • Why did I need the Commit statement to close the connection and the other two Close calls didn't do the trick?
  • Would also appreciate pointers regarding the right/wrong way in which I'm going about working with cursors.

In the following function, I'm using gorp to make a CURSOR, query my Postgres DB row by row and write each row to a writer function:

func(txn *gorp.Transaction, 
     q string,
     params []interface{}, 
     myWriter func([]byte, error)) {

    cursor := "DECLARE GRABDATA NO SCROLL CURSOR FOR " + q
    _, err := txn.Exec(cursor, params...)
    if err != nil {
        myWriter(nil, err)
        return
    }

    rows, err := txn.Query("FETCH ALL in GRABDATA")
    if err != nil {
        myWriter(nil, err)
        return
    }

    defer func() {
        if _, err := txn.Exec("CLOSE GRABDATA"); err != nil {
            fmt.Println("Error while closing cursor:", err)
        }
        if err = rows.Close(); err != nil {
            fmt.Println("Error while closing rows:", err)
        } else {
            fmt.Println("\n\n\n Closed rows without error", "\n\n\n")
        }
        if err = txn.Commit(); err != nil {
            fmt.Println("Error on commit:", err)
        }
    }()

    pointers := make([]interface{}, len(cols))
    container := make([]sql.NullString, len(cols))
    values := make([]string, len(cols))
    for i := range pointers {
        pointers[i] = &container[i]
    }

    for rows.Next() {
        if err = rows.Scan(pointers...); err != nil {
            myWriter(nil, err)
            return
        }

        stringLine := strings.Join(values, ",") + "\n"
        myWriter([]byte(stringLine), nil)
    }
}

In the defer section, I would initially, only Close the rows, but then I saw that pg_stat_activity stay open in idle in transaction state, with the FETCH ALL in GRABDATA query.

Calling txn.Exec("CLOSE <cursor_name>") didn't help. After that, I had a CLOSE GRABDATA query in idle in transaction state...

Only when I started calling Commit() did the connection actually close. I thought that maybe I need to call Commit to execute anything on the transation, but if that's the case - how come I got the result of my queries without calling it?


Solution

  • you want to end transaction, not close a declared cursor. commit does it. you can run multiple queries in one transaction - this is why you see the result without committing.

    the pg_stat_activity.state values are: active when you run the statement (eg, begin transaction; or fetch cursos), idle in transaction when you don't currently run statements, but the transaction remains begun and lastly idle, after you run end or commit, so the transaction is over. After you disconnect the session ends and there's no row in pg_stat_activity at all...