- 
          
- 
                Notifications
    You must be signed in to change notification settings 
- Fork 415
Open
Description
Expected Behavior
CountEstimate(threshold int) should be safely called from any context, including transaction.
Current Behavior
If a transaction is run containing a CountEstimate() instruction without preliminary run of other query using this function, the transaction will fail.
It is due to the fact that CountEstimate() use an error-based lazy loading in count_estimate.go
if err != nil {
  if pgerr, ok := err.(internal.PGError); ok && pgerr.Field('C') == "42883" {
    // undefined_function
    err = q.createCountEstimateFunc()
    // ...
}This lazy-loading cause a rollback of the transaction, which fails.
Possible Solution
Several possible solutions:
- Change the "lazy init" of this function by checking it's existence whenever we use the function CountEstimate()... But can lead to performance issue...
- Handle the specific case of transaction whenever we fails to create this function
- Don't create the pgCountEstimateFunc from the query db whenever it's a transaction, but from the baseDB of the transaction...
- Make it a feature, add some docs to the function with the workaround ^^
Steps to Reproduce
(Error handling is omitted)
func main(){
  dbh, _ := getDBHandler() // return a db handler (*pg.DB) on a "clean" db (without _go_pg_count_estimate_v2 function)
  
  tx, _ := db.Begin()
  _, err := tx.Model(&SomeModel{}).CountEstimate(10)
  if err != nil {
     return panic(fmt.Sprintf("countEstimate failure. %s", err))
  }
}This code will panic with message:
panic: countEstimate failure. ERROR #25P02 current transaction is aborted, commands ignored until end of transaction block
The code below will succeed, since the first query will create the _go_pg_count_estimate_v2, and avoid the error in the transaction
func main(){
  dbh, _ := getDBHandler() // return a db handler (*pg.DB) on a "clean" db (without _go_pg_count_estimate_v2 function)
  // This will create the _go_pg_count_estimate_v2 function, which will make it available in above transaction
  db.Model(&SomeModel{}).CountEstimate(10)
  
  tx, _ := db.Begin()
  _, err := tx.Model(&SomeModel{}).CountEstimate(10)
  if err != nil {
     return panic(fmt.Sprintf("countEstimate failure. %s", err))
  }
}Context (Environment)
- Posgresql version : 14.1
- go-pg version : v10.10.6
thecampagnards
Metadata
Metadata
Assignees
Labels
No labels