package ormimport ()// Placeholder that is replaced with count(*).constplaceholder = `'_go_pg_placeholder'`// https://wiki.postgresql.org/wiki/Count_estimate//nolintvarpgCountEstimateFunc = fmt.Sprintf(`CREATE OR REPLACE FUNCTION _go_pg_count_estimate_v2(query text, threshold int)RETURNS int AS $$DECLARE rec record; nrows int;BEGIN FOR rec IN EXECUTE 'EXPLAIN ' || query LOOP nrows := substring(rec."QUERY PLAN" FROM ' rows=(\d+)'); EXIT WHEN nrows IS NOT NULL; END LOOP; -- Return the estimation if there are too many rows. IF nrows > threshold THEN RETURN nrows; END IF; -- Otherwise execute real count query. query := replace(query, 'SELECT '%s'', 'SELECT count(*)'); EXECUTE query INTO nrows; IF nrows IS NULL THEN nrows := 0; END IF; RETURN nrows;END;$$ LANGUAGE plpgsql;`, placeholder)// CountEstimate uses EXPLAIN to get estimated number of rows returned the query.// If that number is bigger than the threshold it returns the estimation.// Otherwise it executes another query using count aggregate function and// returns the result.//// Based on https://wiki.postgresql.org/wiki/Count_estimatefunc ( *Query) ( int) (int, error) {if .stickyErr != nil {return0, .stickyErr } , := .countSelectQuery(placeholder).AppendQuery(.db.Formatter(), nil)if != nil {return0, }for := 0; < 3; ++ {varint _, = .db.QueryOneContext( .ctx,Scan(&),"SELECT _go_pg_count_estimate_v2(?, ?)",string(), , )if != nil {if , := .(internal.PGError); && .Field('C') == "42883" {// undefined_function = .createCountEstimateFunc()if != nil { , := .(internal.PGError)if ! || !.IntegrityViolation() {return0, } }continue } }return , }return0, }func ( *Query) () error { , := .db.ExecContext(.ctx, pgCountEstimateFunc)return}
The pages are generated with Goldsv0.4.9. (GOOS=linux GOARCH=amd64)