Skip to content

Commit ea22964

Browse files
authored
Merge pull request #2223 from dolthub/zachmu/regclass
put pg_catalog implicitly on the search_path when it isn't there already
2 parents f499587 + fa280fb commit ea22964

6 files changed

Lines changed: 58 additions & 17 deletions

File tree

core/context.go

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ func GetSqlTableFromContext(ctx *sql.Context, databaseName string, tableName dol
199199
var searchPath []string
200200
if len(tableName.Schema) == 0 {
201201
// If a schema was not provided, then we'll use the search path
202-
searchPath, err = resolve.SearchPath(ctx)
202+
searchPath, err = SearchPath(ctx)
203203
if err != nil {
204204
return nil, err
205205
}
@@ -228,6 +228,30 @@ func GetSqlTableFromContext(ctx *sql.Context, databaseName string, tableName dol
228228
return nil, nil
229229
}
230230

231+
// SearchPath returns the effective schema search path for the current session
232+
func SearchPath(ctx *sql.Context) ([]string, error) {
233+
path, err := resolve.SearchPath(ctx)
234+
if err != nil {
235+
return nil, err
236+
}
237+
238+
// pg_catalog is *always* implicitly part of the search path as the first element, unless it's specifically
239+
// included later. This allows users to override built-in names with user-defined names, but they have to
240+
// opt in to that behavior.
241+
hasPgCatalog := false
242+
for _, schema := range path {
243+
if schema == "pg_catalog" {
244+
hasPgCatalog = true
245+
break
246+
}
247+
}
248+
249+
if !hasPgCatalog {
250+
path = append([]string{"pg_catalog"}, path...)
251+
}
252+
return path, nil
253+
}
254+
231255
// GetExtensionsCollectionFromContext returns the extensions collection from the given context. Will always return a
232256
// collection if no error is returned.
233257
func GetExtensionsCollectionFromContext(ctx *sql.Context, database string) (*extensions.Collection, error) {

server/functions/pg_table_is_visible.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,10 @@
1515
package functions
1616

1717
import (
18-
"github.com/dolthub/dolt/go/libraries/doltcore/sqle/resolve"
1918
"github.com/dolthub/go-mysql-server/sql"
2019

20+
"github.com/dolthub/doltgresql/core"
2121
"github.com/dolthub/doltgresql/core/id"
22-
2322
"github.com/dolthub/doltgresql/server/functions/framework"
2423
pgtypes "github.com/dolthub/doltgresql/server/types"
2524
)
@@ -38,7 +37,7 @@ var pg_table_is_visible_oid = framework.Function1{
3837
Strict: true,
3938
Callable: func(ctx *sql.Context, _ [2]*pgtypes.DoltgresType, val any) (any, error) {
4039
oidVal := val.(id.Id)
41-
paths, err := resolve.SearchPath(ctx)
40+
paths, err := core.SearchPath(ctx)
4241
if err != nil {
4342
return false, err
4443
}

server/functions/pg_type_is_visible.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,10 @@
1515
package functions
1616

1717
import (
18-
"github.com/dolthub/dolt/go/libraries/doltcore/sqle/resolve"
1918
"github.com/dolthub/go-mysql-server/sql"
2019

20+
"github.com/dolthub/doltgresql/core"
21+
2122
"github.com/dolthub/doltgresql/core/id"
2223
"github.com/dolthub/doltgresql/server/functions/framework"
2324
pgtypes "github.com/dolthub/doltgresql/server/types"
@@ -48,7 +49,7 @@ var pg_type_is_visible = framework.Function1{
4849
schemaName := oidVal.Segment(0)
4950

5051
// Get the current search path
51-
searchPath, err := resolve.SearchPath(ctx)
52+
searchPath, err := core.SearchPath(ctx)
5253
if err != nil {
5354
return false, err
5455
}

server/functions/regclass.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ import (
1919
"strconv"
2020

2121
"github.com/cockroachdb/errors"
22-
"github.com/dolthub/dolt/go/libraries/doltcore/sqle/resolve"
2322
"github.com/dolthub/go-mysql-server/sql"
2423

24+
"github.com/dolthub/doltgresql/core"
2525
"github.com/dolthub/doltgresql/core/id"
2626
"github.com/dolthub/doltgresql/server/functions/framework"
2727
"github.com/dolthub/doltgresql/server/settings"
@@ -65,7 +65,7 @@ var regclassin = framework.Function1{
6565
switch len(sections) {
6666
case 1:
6767
database = ctx.GetCurrentDatabase()
68-
searchSchemas, err = resolve.SearchPath(ctx)
68+
searchSchemas, err = core.SearchPath(ctx)
6969
if err != nil {
7070
return id.Null, err
7171
}
@@ -79,7 +79,7 @@ var regclassin = framework.Function1{
7979
searchSchemas = []string{sections[2]}
8080
relationName = sections[4]
8181
default:
82-
return id.Null, errors.Errorf("regclass failed validation")
82+
return id.Null, errors.Errorf("unexpected input for regclass: %s", input)
8383
}
8484

8585
// Iterate over all of the items to find which relation matches.

server/node/create_trigger.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ package node
1616

1717
import (
1818
"github.com/cockroachdb/errors"
19-
"github.com/dolthub/dolt/go/libraries/doltcore/sqle/resolve"
2019
"github.com/dolthub/go-mysql-server/sql"
2120
"github.com/dolthub/go-mysql-server/sql/plan"
2221
vitess "github.com/dolthub/vitess/go/vt/sqlparser"
@@ -180,11 +179,10 @@ func loadFunction(ctx *sql.Context, funcCollection *functions.Collection, funcID
180179
return functions.Function{}, err
181180
}
182181
} else {
183-
searchPaths, err := resolve.SearchPath(ctx)
182+
searchPaths, err := core.SearchPath(ctx)
184183
if err != nil {
185184
return functions.Function{}, err
186185
}
187-
searchPaths = append(searchPaths, "pg_catalog") // This isn't included in the search path but functions use it
188186
for _, searchPath := range searchPaths {
189187
function, err = funcCollection.GetFunction(ctx, id.NewFunction(searchPath, funcID.FunctionName()))
190188
if err != nil {

testing/go/prepared_statement_test.go

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1341,8 +1341,29 @@ var pgCatalogTests = []ScriptTest{
13411341
},
13421342
Assertions: []ScriptTestAssertion{
13431343
{
1344-
// https://github.com/dolthub/doltgresql/issues/2217
1345-
Skip: true,
1344+
Query: "select distinct relnamespace from pg_catalog.pg_class c INNER JOIN pg_catalog.pg_namespace n ON c.relnamespace = n.oid WHERE n.nspname=$1;",
1345+
BindVars: []any{"testschema"},
1346+
Expected: []sql.Row{{2638679668}},
1347+
},
1348+
// TODO: when this test is run in isolation without the query above, the below query returns no rows. This is
1349+
// because the process of converting an OID to its internal ID can only proceed in one direction: from internal
1350+
// to OID. When the above query runs, it causes the internal ID for the testschema namespace to be cached,
1351+
// allowing the reverse lookup to succeed in subsequent queries. For OIDs that have not yet been cached in this
1352+
// manner, lookups by their OID will fail. This doesn't impact all queries since many of them get an index
1353+
// lookup on OID, which has the side effect of converting everything to numeric IDs anyway. But for queries
1354+
// that use a normal comparison function for an OID literal value, the conversion to an internal ID of the
1355+
// appropriate type (e.g. id.Namespace) cannot happen in the |oidin| function in some cases because the internal
1356+
// to OID mapping hasn't yet been established for that schema element, so the comparison fails, yielding
1357+
// incorrect results.
1358+
// To fix this, we need to correctly seed the internal ID cache with all schema elements in the database.
1359+
{
1360+
Query: `SELECT c.oid,pg_catalog.pg_get_expr(c.relpartbound, c.oid) as partition_expr, pg_catalog.pg_get_partkeydef(c.oid) as partition_key
1361+
FROM pg_catalog.pg_class c
1362+
WHERE c.relnamespace=$1 AND c.relkind not in ('i','I','c') and c.oid not in (select oid from pg_catalog.pg_class where left(relname, 5) = 'dolt_');`,
1363+
BindVars: []any{2638679668},
1364+
Expected: []sql.Row{{1712283605, nil, ""}},
1365+
},
1366+
{
13461367
Query: `SELECT c.oid,d.description,pg_catalog.pg_get_expr(c.relpartbound, c.oid) as partition_expr, pg_catalog.pg_get_partkeydef(c.oid) as partition_key
13471368
FROM pg_catalog.pg_class c
13481369
LEFT OUTER JOIN pg_catalog.pg_description d ON d.objoid=c.oid AND d.objsubid=0 AND d.classoid='pg_class'::regclass
@@ -1351,10 +1372,8 @@ WHERE c.relnamespace=$1 AND c.relkind not in ('i','I','c') and c.oid not in (sel
13511372
Expected: []sql.Row{{1712283605, nil, nil, ""}},
13521373
},
13531374
{
1354-
// https://github.com/dolthub/doltgresql/issues/2217
1355-
Skip: true,
13561375
Query: `SELECT d.description from pg_catalog.pg_description d WHERE d.classoid='pg_class'::regclass`,
1357-
// TODO: add expected values
1376+
// TODO: add expected values (pg_description not yet implemented)
13581377
},
13591378
{
13601379
Query: `select c.oid,pg_catalog.pg_total_relation_size(c.oid) as total_rel_size,pg_catalog.pg_relation_size(c.oid) as rel_size FROM pg_class c WHERE c.relnamespace=$1 and c.oid not in (select oid from pg_catalog.pg_class where left(relname, 5) = 'dolt_');`,

0 commit comments

Comments
 (0)