blob: 5e16204b2b0c99908402968574b9a46a93cc2245 [file] [log] [blame]
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package postgres
import (
// getPackageSymbols returns all of the symbols for a given package path and module path.
func getPackageSymbols(ctx context.Context, ddb *database.DB, packagePath, modulePath string,
) (_ *internal.SymbolHistory, err error) {
defer derrors.Wrap(&err, "getPackageSymbols(ctx, ddb, %q, %q)", packagePath, modulePath)
defer middleware.ElapsedStat(ctx, "getPackageSymbols")()
query := packageSymbolQueryJoin(
" AS symbol_name",
" AS parent_symbol_name",
"d.goarch"), packagePath, modulePath).
OrderBy("CASE WHEN ps.type='Type' THEN 0 ELSE 1 END").
q, args, err := query.PlaceholderFormat(squirrel.Dollar).ToSql()
if err != nil {
return nil, err
sh, collect := collectSymbolHistory(func(sh *internal.SymbolHistory, sm internal.SymbolMeta, v string, build internal.BuildContext) error {
if sm.Section == internal.SymbolSectionTypes && sm.Kind != internal.SymbolKindType {
_, err := sh.GetSymbol(sm.ParentName, v, build)
if err != nil {
return fmt.Errorf("could not find parent for %q: %v", sm.Name, err)
return nil
return nil
if err := ddb.RunQuery(ctx, q, collect, args...); err != nil {
return nil, err
return sh, nil
func packageSymbolQueryJoin(query squirrel.SelectBuilder, pkgPath, modulePath string) squirrel.SelectBuilder {
return query.From("modules m").
Join("units u on u.module_id =").
Join("documentation d ON d.unit_id =").
Join("documentation_symbols ds ON ds.documentation_id =").
Join("package_symbols ps ON = ds.package_symbol_id").
Join("paths p1 ON u.path_id =").
Join("symbol_names s1 ON ps.symbol_name_id =").
Join("symbol_names s2 ON ps.parent_symbol_name_id =").
Where(squirrel.Eq{"p1.path": pkgPath}).
Where(squirrel.Eq{"m.module_path": modulePath}).
Where("NOT m.incompatible").
Where(squirrel.Eq{"m.version_type": "release"})
func collectSymbolHistory(check func(sh *internal.SymbolHistory, sm internal.SymbolMeta, v string, build internal.BuildContext) error) (*internal.SymbolHistory, func(rows *sql.Rows) error) {
sh := internal.NewSymbolHistory()
return sh, func(rows *sql.Rows) (err error) {
defer derrors.Wrap(&err, "collectSymbolHistory")
var (
sm internal.SymbolMeta
build internal.BuildContext
v string
if err := rows.Scan(
); err != nil {
return fmt.Errorf("row.Scan(): %v", err)
if err := check(sh, sm, v, build); err != nil {
return fmt.Errorf("check(): %v", err)
sh.AddSymbol(sm, v, build)
return nil