~vcs-imports/mammoth-replicator/trunk

« back to all changes in this revision

Viewing changes to src/backend/catalog/namespace.c

  • Committer: alvherre
  • Date: 2005-12-16 21:24:52 UTC
  • Revision ID: svn-v4:db760fc0-0f08-0410-9d63-cc6633f64896:trunk:1
Initial import of the REL8_0_3 sources from the Pgsql CVS repository.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-------------------------------------------------------------------------
 
2
 *
 
3
 * namespace.c
 
4
 *        code to support accessing and searching namespaces
 
5
 *
 
6
 * This is separate from pg_namespace.c, which contains the routines that
 
7
 * directly manipulate the pg_namespace system catalog.  This module
 
8
 * provides routines associated with defining a "namespace search path"
 
9
 * and implementing search-path-controlled searches.
 
10
 *
 
11
 *
 
12
 * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
 
13
 * Portions Copyright (c) 1994, Regents of the University of California
 
14
 *
 
15
 * IDENTIFICATION
 
16
 *        $PostgreSQL: pgsql/src/backend/catalog/namespace.c,v 1.73 2004-12-31 21:59:38 pgsql Exp $
 
17
 *
 
18
 *-------------------------------------------------------------------------
 
19
 */
 
20
#include "postgres.h"
 
21
 
 
22
#include "access/xact.h"
 
23
#include "catalog/catname.h"
 
24
#include "catalog/dependency.h"
 
25
#include "catalog/namespace.h"
 
26
#include "catalog/pg_conversion.h"
 
27
#include "catalog/pg_namespace.h"
 
28
#include "catalog/pg_opclass.h"
 
29
#include "catalog/pg_operator.h"
 
30
#include "catalog/pg_proc.h"
 
31
#include "catalog/pg_shadow.h"
 
32
#include "catalog/pg_type.h"
 
33
#include "commands/dbcommands.h"
 
34
#include "lib/stringinfo.h"
 
35
#include "miscadmin.h"
 
36
#include "nodes/makefuncs.h"
 
37
#include "storage/backendid.h"
 
38
#include "storage/ipc.h"
 
39
#include "utils/acl.h"
 
40
#include "utils/builtins.h"
 
41
#include "utils/catcache.h"
 
42
#include "utils/guc.h"
 
43
#include "utils/inval.h"
 
44
#include "utils/lsyscache.h"
 
45
#include "utils/memutils.h"
 
46
#include "utils/syscache.h"
 
47
 
 
48
 
 
49
/*
 
50
 * The namespace search path is a possibly-empty list of namespace OIDs.
 
51
 * In addition to the explicit list, several implicitly-searched namespaces
 
52
 * may be included:
 
53
 *
 
54
 * 1. If a "special" namespace has been set by PushSpecialNamespace, it is
 
55
 * always searched first.  (This is a hack for CREATE SCHEMA.)
 
56
 *
 
57
 * 2. If a TEMP table namespace has been initialized in this session, it
 
58
 * is always searched just after any special namespace.
 
59
 *
 
60
 * 3. The system catalog namespace is always searched.  If the system
 
61
 * namespace is present in the explicit path then it will be searched in
 
62
 * the specified order; otherwise it will be searched after TEMP tables and
 
63
 * *before* the explicit list.  (It might seem that the system namespace
 
64
 * should be implicitly last, but this behavior appears to be required by
 
65
 * SQL99.  Also, this provides a way to search the system namespace first
 
66
 * without thereby making it the default creation target namespace.)
 
67
 *
 
68
 * The default creation target namespace is normally equal to the first
 
69
 * element of the explicit list, but is the "special" namespace when one
 
70
 * has been set.  If the explicit list is empty and there is no special
 
71
 * namespace, there is no default target.
 
72
 *
 
73
 * In bootstrap mode, the search path is set equal to 'pg_catalog', so that
 
74
 * the system namespace is the only one searched or inserted into.
 
75
 * The initdb script is also careful to set search_path to 'pg_catalog' for
 
76
 * its post-bootstrap standalone backend runs.  Otherwise the default search
 
77
 * path is determined by GUC.  The factory default path contains the PUBLIC
 
78
 * namespace (if it exists), preceded by the user's personal namespace
 
79
 * (if one exists).
 
80
 *
 
81
 * If namespaceSearchPathValid is false, then namespaceSearchPath (and other
 
82
 * derived variables) need to be recomputed from namespace_search_path.
 
83
 * We mark it invalid upon an assignment to namespace_search_path or receipt
 
84
 * of a syscache invalidation event for pg_namespace.  The recomputation
 
85
 * is done during the next lookup attempt.
 
86
 *
 
87
 * Any namespaces mentioned in namespace_search_path that are not readable
 
88
 * by the current user ID are simply left out of namespaceSearchPath; so
 
89
 * we have to be willing to recompute the path when current userid changes.
 
90
 * namespaceUser is the userid the path has been computed for.
 
91
 */
 
92
 
 
93
static List *namespaceSearchPath = NIL;
 
94
 
 
95
static Oid      namespaceUser = InvalidOid;
 
96
 
 
97
/* default place to create stuff; if InvalidOid, no default */
 
98
static Oid      defaultCreationNamespace = InvalidOid;
 
99
 
 
100
/* first explicit member of list; usually same as defaultCreationNamespace */
 
101
static Oid      firstExplicitNamespace = InvalidOid;
 
102
 
 
103
/* The above four values are valid only if namespaceSearchPathValid */
 
104
static bool namespaceSearchPathValid = true;
 
105
 
 
106
/*
 
107
 * myTempNamespace is InvalidOid until and unless a TEMP namespace is set up
 
108
 * in a particular backend session (this happens when a CREATE TEMP TABLE
 
109
 * command is first executed).  Thereafter it's the OID of the temp namespace.
 
110
 *
 
111
 * myTempNamespaceSubID shows whether we've created the TEMP namespace in the
 
112
 * current subtransaction.  The flag propagates up the subtransaction tree,
 
113
 * so the main transaction will correctly recognize the flag if all
 
114
 * intermediate subtransactions commit.  When it is InvalidSubTransactionId,
 
115
 * we either haven't made the TEMP namespace yet, or have successfully
 
116
 * committed its creation, depending on whether myTempNamespace is valid.
 
117
 */
 
118
static Oid      myTempNamespace = InvalidOid;
 
119
 
 
120
static SubTransactionId myTempNamespaceSubID = InvalidSubTransactionId;
 
121
 
 
122
/*
 
123
 * "Special" namespace for CREATE SCHEMA.  If set, it's the first search
 
124
 * path element, and also the default creation namespace.
 
125
 */
 
126
static Oid      mySpecialNamespace = InvalidOid;
 
127
 
 
128
/*
 
129
 * This is the text equivalent of the search path --- it's the value
 
130
 * of the GUC variable 'search_path'.
 
131
 */
 
132
char       *namespace_search_path = NULL;
 
133
 
 
134
 
 
135
/* Local functions */
 
136
static void recomputeNamespacePath(void);
 
137
static void InitTempTableNamespace(void);
 
138
static void RemoveTempRelations(Oid tempNamespaceId);
 
139
static void RemoveTempRelationsCallback(int code, Datum arg);
 
140
static void NamespaceCallback(Datum arg, Oid relid);
 
141
 
 
142
/* These don't really need to appear in any header file */
 
143
Datum           pg_table_is_visible(PG_FUNCTION_ARGS);
 
144
Datum           pg_type_is_visible(PG_FUNCTION_ARGS);
 
145
Datum           pg_function_is_visible(PG_FUNCTION_ARGS);
 
146
Datum           pg_operator_is_visible(PG_FUNCTION_ARGS);
 
147
Datum           pg_opclass_is_visible(PG_FUNCTION_ARGS);
 
148
Datum           pg_conversion_is_visible(PG_FUNCTION_ARGS);
 
149
 
 
150
 
 
151
/*
 
152
 * RangeVarGetRelid
 
153
 *              Given a RangeVar describing an existing relation,
 
154
 *              select the proper namespace and look up the relation OID.
 
155
 *
 
156
 * If the relation is not found, return InvalidOid if failOK = true,
 
157
 * otherwise raise an error.
 
158
 */
 
159
Oid
 
160
RangeVarGetRelid(const RangeVar *relation, bool failOK)
 
161
{
 
162
        Oid                     namespaceId;
 
163
        Oid                     relId;
 
164
 
 
165
        /*
 
166
         * We check the catalog name and then ignore it.
 
167
         */
 
168
        if (relation->catalogname)
 
169
        {
 
170
                if (strcmp(relation->catalogname, get_database_name(MyDatabaseId)) != 0)
 
171
                        ereport(ERROR,
 
172
                                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 
173
                                         errmsg("cross-database references are not implemented: \"%s.%s.%s\"",
 
174
                                                        relation->catalogname, relation->schemaname,
 
175
                                                        relation->relname)));
 
176
        }
 
177
 
 
178
        if (relation->schemaname)
 
179
        {
 
180
                /* use exact schema given */
 
181
                namespaceId = LookupExplicitNamespace(relation->schemaname);
 
182
                relId = get_relname_relid(relation->relname, namespaceId);
 
183
        }
 
184
        else
 
185
        {
 
186
                /* search the namespace path */
 
187
                relId = RelnameGetRelid(relation->relname);
 
188
        }
 
189
 
 
190
        if (!OidIsValid(relId) && !failOK)
 
191
        {
 
192
                if (relation->schemaname)
 
193
                        ereport(ERROR,
 
194
                                        (errcode(ERRCODE_UNDEFINED_TABLE),
 
195
                                         errmsg("relation \"%s.%s\" does not exist",
 
196
                                                        relation->schemaname, relation->relname)));
 
197
                else
 
198
                        ereport(ERROR,
 
199
                                        (errcode(ERRCODE_UNDEFINED_TABLE),
 
200
                                         errmsg("relation \"%s\" does not exist",
 
201
                                                        relation->relname)));
 
202
        }
 
203
        return relId;
 
204
}
 
205
 
 
206
/*
 
207
 * RangeVarGetCreationNamespace
 
208
 *              Given a RangeVar describing a to-be-created relation,
 
209
 *              choose which namespace to create it in.
 
210
 *
 
211
 * Note: calling this may result in a CommandCounterIncrement operation.
 
212
 * That will happen on the first request for a temp table in any particular
 
213
 * backend run; we will need to either create or clean out the temp schema.
 
214
 */
 
215
Oid
 
216
RangeVarGetCreationNamespace(const RangeVar *newRelation)
 
217
{
 
218
        Oid                     namespaceId;
 
219
 
 
220
        /*
 
221
         * We check the catalog name and then ignore it.
 
222
         */
 
223
        if (newRelation->catalogname)
 
224
        {
 
225
                if (strcmp(newRelation->catalogname, get_database_name(MyDatabaseId)) != 0)
 
226
                        ereport(ERROR,
 
227
                                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 
228
                                         errmsg("cross-database references are not implemented: \"%s.%s.%s\"",
 
229
                                           newRelation->catalogname, newRelation->schemaname,
 
230
                                                        newRelation->relname)));
 
231
        }
 
232
 
 
233
        if (newRelation->istemp)
 
234
        {
 
235
                /* TEMP tables are created in our backend-local temp namespace */
 
236
                if (newRelation->schemaname)
 
237
                        ereport(ERROR,
 
238
                                        (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
 
239
                          errmsg("temporary tables may not specify a schema name")));
 
240
                /* Initialize temp namespace if first time through */
 
241
                if (!OidIsValid(myTempNamespace))
 
242
                        InitTempTableNamespace();
 
243
                return myTempNamespace;
 
244
        }
 
245
 
 
246
        if (newRelation->schemaname)
 
247
        {
 
248
                /* use exact schema given */
 
249
                namespaceId = GetSysCacheOid(NAMESPACENAME,
 
250
                                                                CStringGetDatum(newRelation->schemaname),
 
251
                                                                         0, 0, 0);
 
252
                if (!OidIsValid(namespaceId))
 
253
                        ereport(ERROR,
 
254
                                        (errcode(ERRCODE_UNDEFINED_SCHEMA),
 
255
                                         errmsg("schema \"%s\" does not exist",
 
256
                                                        newRelation->schemaname)));
 
257
                /* we do not check for USAGE rights here! */
 
258
        }
 
259
        else
 
260
        {
 
261
                /* use the default creation namespace */
 
262
                recomputeNamespacePath();
 
263
                namespaceId = defaultCreationNamespace;
 
264
                if (!OidIsValid(namespaceId))
 
265
                        ereport(ERROR,
 
266
                                        (errcode(ERRCODE_UNDEFINED_SCHEMA),
 
267
                                         errmsg("no schema has been selected to create in")));
 
268
        }
 
269
 
 
270
        /* Note: callers will check for CREATE rights when appropriate */
 
271
 
 
272
        return namespaceId;
 
273
}
 
274
 
 
275
/*
 
276
 * RelnameGetRelid
 
277
 *              Try to resolve an unqualified relation name.
 
278
 *              Returns OID if relation found in search path, else InvalidOid.
 
279
 */
 
280
Oid
 
281
RelnameGetRelid(const char *relname)
 
282
{
 
283
        Oid                     relid;
 
284
        ListCell   *l;
 
285
 
 
286
        recomputeNamespacePath();
 
287
 
 
288
        foreach(l, namespaceSearchPath)
 
289
        {
 
290
                Oid                     namespaceId = lfirst_oid(l);
 
291
 
 
292
                relid = get_relname_relid(relname, namespaceId);
 
293
                if (OidIsValid(relid))
 
294
                        return relid;
 
295
        }
 
296
 
 
297
        /* Not found in path */
 
298
        return InvalidOid;
 
299
}
 
300
 
 
301
 
 
302
/*
 
303
 * RelationIsVisible
 
304
 *              Determine whether a relation (identified by OID) is visible in the
 
305
 *              current search path.  Visible means "would be found by searching
 
306
 *              for the unqualified relation name".
 
307
 */
 
308
bool
 
309
RelationIsVisible(Oid relid)
 
310
{
 
311
        HeapTuple       reltup;
 
312
        Form_pg_class relform;
 
313
        Oid                     relnamespace;
 
314
        bool            visible;
 
315
 
 
316
        reltup = SearchSysCache(RELOID,
 
317
                                                        ObjectIdGetDatum(relid),
 
318
                                                        0, 0, 0);
 
319
        if (!HeapTupleIsValid(reltup))
 
320
                elog(ERROR, "cache lookup failed for relation %u", relid);
 
321
        relform = (Form_pg_class) GETSTRUCT(reltup);
 
322
 
 
323
        recomputeNamespacePath();
 
324
 
 
325
        /*
 
326
         * Quick check: if it ain't in the path at all, it ain't visible.
 
327
         * Items in the system namespace are surely in the path and so we
 
328
         * needn't even do list_member_oid() for them.
 
329
         */
 
330
        relnamespace = relform->relnamespace;
 
331
        if (relnamespace != PG_CATALOG_NAMESPACE &&
 
332
                !list_member_oid(namespaceSearchPath, relnamespace))
 
333
                visible = false;
 
334
        else
 
335
        {
 
336
                /*
 
337
                 * If it is in the path, it might still not be visible; it could
 
338
                 * be hidden by another relation of the same name earlier in the
 
339
                 * path. So we must do a slow check to see if this rel would be
 
340
                 * found by RelnameGetRelid.
 
341
                 */
 
342
                char       *relname = NameStr(relform->relname);
 
343
 
 
344
                visible = (RelnameGetRelid(relname) == relid);
 
345
        }
 
346
 
 
347
        ReleaseSysCache(reltup);
 
348
 
 
349
        return visible;
 
350
}
 
351
 
 
352
 
 
353
/*
 
354
 * TypenameGetTypid
 
355
 *              Try to resolve an unqualified datatype name.
 
356
 *              Returns OID if type found in search path, else InvalidOid.
 
357
 *
 
358
 * This is essentially the same as RelnameGetRelid.
 
359
 */
 
360
Oid
 
361
TypenameGetTypid(const char *typname)
 
362
{
 
363
        Oid                     typid;
 
364
        ListCell   *l;
 
365
 
 
366
        recomputeNamespacePath();
 
367
 
 
368
        foreach(l, namespaceSearchPath)
 
369
        {
 
370
                Oid                     namespaceId = lfirst_oid(l);
 
371
 
 
372
                typid = GetSysCacheOid(TYPENAMENSP,
 
373
                                                           PointerGetDatum(typname),
 
374
                                                           ObjectIdGetDatum(namespaceId),
 
375
                                                           0, 0);
 
376
                if (OidIsValid(typid))
 
377
                        return typid;
 
378
        }
 
379
 
 
380
        /* Not found in path */
 
381
        return InvalidOid;
 
382
}
 
383
 
 
384
/*
 
385
 * TypeIsVisible
 
386
 *              Determine whether a type (identified by OID) is visible in the
 
387
 *              current search path.  Visible means "would be found by searching
 
388
 *              for the unqualified type name".
 
389
 */
 
390
bool
 
391
TypeIsVisible(Oid typid)
 
392
{
 
393
        HeapTuple       typtup;
 
394
        Form_pg_type typform;
 
395
        Oid                     typnamespace;
 
396
        bool            visible;
 
397
 
 
398
        typtup = SearchSysCache(TYPEOID,
 
399
                                                        ObjectIdGetDatum(typid),
 
400
                                                        0, 0, 0);
 
401
        if (!HeapTupleIsValid(typtup))
 
402
                elog(ERROR, "cache lookup failed for type %u", typid);
 
403
        typform = (Form_pg_type) GETSTRUCT(typtup);
 
404
 
 
405
        recomputeNamespacePath();
 
406
 
 
407
        /*
 
408
         * Quick check: if it ain't in the path at all, it ain't visible.
 
409
         * Items in the system namespace are surely in the path and so we
 
410
         * needn't even do list_member_oid() for them.
 
411
         */
 
412
        typnamespace = typform->typnamespace;
 
413
        if (typnamespace != PG_CATALOG_NAMESPACE &&
 
414
                !list_member_oid(namespaceSearchPath, typnamespace))
 
415
                visible = false;
 
416
        else
 
417
        {
 
418
                /*
 
419
                 * If it is in the path, it might still not be visible; it could
 
420
                 * be hidden by another type of the same name earlier in the path.
 
421
                 * So we must do a slow check to see if this type would be found
 
422
                 * by TypenameGetTypid.
 
423
                 */
 
424
                char       *typname = NameStr(typform->typname);
 
425
 
 
426
                visible = (TypenameGetTypid(typname) == typid);
 
427
        }
 
428
 
 
429
        ReleaseSysCache(typtup);
 
430
 
 
431
        return visible;
 
432
}
 
433
 
 
434
 
 
435
/*
 
436
 * FuncnameGetCandidates
 
437
 *              Given a possibly-qualified function name and argument count,
 
438
 *              retrieve a list of the possible matches.
 
439
 *
 
440
 * If nargs is -1, we return all functions matching the given name,
 
441
 * regardless of argument count.
 
442
 *
 
443
 * We search a single namespace if the function name is qualified, else
 
444
 * all namespaces in the search path.  The return list will never contain
 
445
 * multiple entries with identical argument lists --- in the multiple-
 
446
 * namespace case, we arrange for entries in earlier namespaces to mask
 
447
 * identical entries in later namespaces.
 
448
 */
 
449
FuncCandidateList
 
450
FuncnameGetCandidates(List *names, int nargs)
 
451
{
 
452
        FuncCandidateList resultList = NULL;
 
453
        char       *schemaname;
 
454
        char       *funcname;
 
455
        Oid                     namespaceId;
 
456
        CatCList   *catlist;
 
457
        int                     i;
 
458
 
 
459
        /* deconstruct the name list */
 
460
        DeconstructQualifiedName(names, &schemaname, &funcname);
 
461
 
 
462
        if (schemaname)
 
463
        {
 
464
                /* use exact schema given */
 
465
                namespaceId = LookupExplicitNamespace(schemaname);
 
466
        }
 
467
        else
 
468
        {
 
469
                /* flag to indicate we need namespace search */
 
470
                namespaceId = InvalidOid;
 
471
                recomputeNamespacePath();
 
472
        }
 
473
 
 
474
        /* Search syscache by name and (optionally) nargs only */
 
475
        if (nargs >= 0)
 
476
                catlist = SearchSysCacheList(PROCNAMENSP, 2,
 
477
                                                                         CStringGetDatum(funcname),
 
478
                                                                         Int16GetDatum(nargs),
 
479
                                                                         0, 0);
 
480
        else
 
481
                catlist = SearchSysCacheList(PROCNAMENSP, 1,
 
482
                                                                         CStringGetDatum(funcname),
 
483
                                                                         0, 0, 0);
 
484
 
 
485
        for (i = 0; i < catlist->n_members; i++)
 
486
        {
 
487
                HeapTuple       proctup = &catlist->members[i]->tuple;
 
488
                Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup);
 
489
                int                     pathpos = 0;
 
490
                FuncCandidateList newResult;
 
491
 
 
492
                nargs = procform->pronargs;
 
493
 
 
494
                if (OidIsValid(namespaceId))
 
495
                {
 
496
                        /* Consider only procs in specified namespace */
 
497
                        if (procform->pronamespace != namespaceId)
 
498
                                continue;
 
499
                        /* No need to check args, they must all be different */
 
500
                }
 
501
                else
 
502
                {
 
503
                        /* Consider only procs that are in the search path */
 
504
                        ListCell   *nsp;
 
505
 
 
506
                        foreach(nsp, namespaceSearchPath)
 
507
                        {
 
508
                                if (procform->pronamespace == lfirst_oid(nsp))
 
509
                                        break;
 
510
                                pathpos++;
 
511
                        }
 
512
                        if (nsp == NULL)
 
513
                                continue;               /* proc is not in search path */
 
514
 
 
515
                        /*
 
516
                         * Okay, it's in the search path, but does it have the same
 
517
                         * arguments as something we already accepted?  If so, keep
 
518
                         * only the one that appears earlier in the search path.
 
519
                         *
 
520
                         * If we have an ordered list from SearchSysCacheList (the normal
 
521
                         * case), then any conflicting proc must immediately adjoin
 
522
                         * this one in the list, so we only need to look at the newest
 
523
                         * result item.  If we have an unordered list, we have to scan
 
524
                         * the whole result list.
 
525
                         */
 
526
                        if (resultList)
 
527
                        {
 
528
                                FuncCandidateList prevResult;
 
529
 
 
530
                                if (catlist->ordered)
 
531
                                {
 
532
                                        if (nargs == resultList->nargs &&
 
533
                                                memcmp(procform->proargtypes, resultList->args,
 
534
                                                           nargs * sizeof(Oid)) == 0)
 
535
                                                prevResult = resultList;
 
536
                                        else
 
537
                                                prevResult = NULL;
 
538
                                }
 
539
                                else
 
540
                                {
 
541
                                        for (prevResult = resultList;
 
542
                                                 prevResult;
 
543
                                                 prevResult = prevResult->next)
 
544
                                        {
 
545
                                                if (nargs == prevResult->nargs &&
 
546
                                                  memcmp(procform->proargtypes, prevResult->args,
 
547
                                                                 nargs * sizeof(Oid)) == 0)
 
548
                                                        break;
 
549
                                        }
 
550
                                }
 
551
                                if (prevResult)
 
552
                                {
 
553
                                        /* We have a match with a previous result */
 
554
                                        Assert(pathpos != prevResult->pathpos);
 
555
                                        if (pathpos > prevResult->pathpos)
 
556
                                                continue;               /* keep previous result */
 
557
                                        /* replace previous result */
 
558
                                        prevResult->pathpos = pathpos;
 
559
                                        prevResult->oid = HeapTupleGetOid(proctup);
 
560
                                        continue;       /* args are same, of course */
 
561
                                }
 
562
                        }
 
563
                }
 
564
 
 
565
                /*
 
566
                 * Okay to add it to result list
 
567
                 */
 
568
                newResult = (FuncCandidateList)
 
569
                        palloc(sizeof(struct _FuncCandidateList) - sizeof(Oid)
 
570
                                   + nargs * sizeof(Oid));
 
571
                newResult->pathpos = pathpos;
 
572
                newResult->oid = HeapTupleGetOid(proctup);
 
573
                newResult->nargs = nargs;
 
574
                memcpy(newResult->args, procform->proargtypes, nargs * sizeof(Oid));
 
575
 
 
576
                newResult->next = resultList;
 
577
                resultList = newResult;
 
578
        }
 
579
 
 
580
        ReleaseSysCacheList(catlist);
 
581
 
 
582
        return resultList;
 
583
}
 
584
 
 
585
/*
 
586
 * FunctionIsVisible
 
587
 *              Determine whether a function (identified by OID) is visible in the
 
588
 *              current search path.  Visible means "would be found by searching
 
589
 *              for the unqualified function name with exact argument matches".
 
590
 */
 
591
bool
 
592
FunctionIsVisible(Oid funcid)
 
593
{
 
594
        HeapTuple       proctup;
 
595
        Form_pg_proc procform;
 
596
        Oid                     pronamespace;
 
597
        bool            visible;
 
598
 
 
599
        proctup = SearchSysCache(PROCOID,
 
600
                                                         ObjectIdGetDatum(funcid),
 
601
                                                         0, 0, 0);
 
602
        if (!HeapTupleIsValid(proctup))
 
603
                elog(ERROR, "cache lookup failed for function %u", funcid);
 
604
        procform = (Form_pg_proc) GETSTRUCT(proctup);
 
605
 
 
606
        recomputeNamespacePath();
 
607
 
 
608
        /*
 
609
         * Quick check: if it ain't in the path at all, it ain't visible.
 
610
         * Items in the system namespace are surely in the path and so we
 
611
         * needn't even do list_member_oid() for them.
 
612
         */
 
613
        pronamespace = procform->pronamespace;
 
614
        if (pronamespace != PG_CATALOG_NAMESPACE &&
 
615
                !list_member_oid(namespaceSearchPath, pronamespace))
 
616
                visible = false;
 
617
        else
 
618
        {
 
619
                /*
 
620
                 * If it is in the path, it might still not be visible; it could
 
621
                 * be hidden by another proc of the same name and arguments
 
622
                 * earlier in the path.  So we must do a slow check to see if this
 
623
                 * is the same proc that would be found by FuncnameGetCandidates.
 
624
                 */
 
625
                char       *proname = NameStr(procform->proname);
 
626
                int                     nargs = procform->pronargs;
 
627
                FuncCandidateList clist;
 
628
 
 
629
                visible = false;
 
630
 
 
631
                clist = FuncnameGetCandidates(list_make1(makeString(proname)), nargs);
 
632
 
 
633
                for (; clist; clist = clist->next)
 
634
                {
 
635
                        if (memcmp(clist->args, procform->proargtypes,
 
636
                                           nargs * sizeof(Oid)) == 0)
 
637
                        {
 
638
                                /* Found the expected entry; is it the right proc? */
 
639
                                visible = (clist->oid == funcid);
 
640
                                break;
 
641
                        }
 
642
                }
 
643
        }
 
644
 
 
645
        ReleaseSysCache(proctup);
 
646
 
 
647
        return visible;
 
648
}
 
649
 
 
650
 
 
651
/*
 
652
 * OpernameGetCandidates
 
653
 *              Given a possibly-qualified operator name and operator kind,
 
654
 *              retrieve a list of the possible matches.
 
655
 *
 
656
 * If oprkind is '\0', we return all operators matching the given name,
 
657
 * regardless of arguments.
 
658
 *
 
659
 * We search a single namespace if the operator name is qualified, else
 
660
 * all namespaces in the search path.  The return list will never contain
 
661
 * multiple entries with identical argument lists --- in the multiple-
 
662
 * namespace case, we arrange for entries in earlier namespaces to mask
 
663
 * identical entries in later namespaces.
 
664
 *
 
665
 * The returned items always have two args[] entries --- one or the other
 
666
 * will be InvalidOid for a prefix or postfix oprkind.  nargs is 2, too.
 
667
 */
 
668
FuncCandidateList
 
669
OpernameGetCandidates(List *names, char oprkind)
 
670
{
 
671
        FuncCandidateList resultList = NULL;
 
672
        char       *resultSpace = NULL;
 
673
        int                     nextResult = 0;
 
674
        char       *schemaname;
 
675
        char       *opername;
 
676
        Oid                     namespaceId;
 
677
        CatCList   *catlist;
 
678
        int                     i;
 
679
 
 
680
        /* deconstruct the name list */
 
681
        DeconstructQualifiedName(names, &schemaname, &opername);
 
682
 
 
683
        if (schemaname)
 
684
        {
 
685
                /* use exact schema given */
 
686
                namespaceId = LookupExplicitNamespace(schemaname);
 
687
        }
 
688
        else
 
689
        {
 
690
                /* flag to indicate we need namespace search */
 
691
                namespaceId = InvalidOid;
 
692
                recomputeNamespacePath();
 
693
        }
 
694
 
 
695
        /* Search syscache by name only */
 
696
        catlist = SearchSysCacheList(OPERNAMENSP, 1,
 
697
                                                                 CStringGetDatum(opername),
 
698
                                                                 0, 0, 0);
 
699
 
 
700
        /*
 
701
         * In typical scenarios, most if not all of the operators found by the
 
702
         * catcache search will end up getting returned; and there can be
 
703
         * quite a few, for common operator names such as '=' or '+'.  To
 
704
         * reduce the time spent in palloc, we allocate the result space as an
 
705
         * array large enough to hold all the operators.  The original coding
 
706
         * of this routine did a separate palloc for each operator, but
 
707
         * profiling revealed that the pallocs used an unreasonably large
 
708
         * fraction of parsing time.
 
709
         */
 
710
#define SPACE_PER_OP MAXALIGN(sizeof(struct _FuncCandidateList) + sizeof(Oid))
 
711
 
 
712
        if (catlist->n_members > 0)
 
713
                resultSpace = palloc(catlist->n_members * SPACE_PER_OP);
 
714
 
 
715
        for (i = 0; i < catlist->n_members; i++)
 
716
        {
 
717
                HeapTuple       opertup = &catlist->members[i]->tuple;
 
718
                Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup);
 
719
                int                     pathpos = 0;
 
720
                FuncCandidateList newResult;
 
721
 
 
722
                /* Ignore operators of wrong kind, if specific kind requested */
 
723
                if (oprkind && operform->oprkind != oprkind)
 
724
                        continue;
 
725
 
 
726
                if (OidIsValid(namespaceId))
 
727
                {
 
728
                        /* Consider only opers in specified namespace */
 
729
                        if (operform->oprnamespace != namespaceId)
 
730
                                continue;
 
731
                        /* No need to check args, they must all be different */
 
732
                }
 
733
                else
 
734
                {
 
735
                        /* Consider only opers that are in the search path */
 
736
                        ListCell   *nsp;
 
737
 
 
738
                        foreach(nsp, namespaceSearchPath)
 
739
                        {
 
740
                                if (operform->oprnamespace == lfirst_oid(nsp))
 
741
                                        break;
 
742
                                pathpos++;
 
743
                        }
 
744
                        if (nsp == NULL)
 
745
                                continue;               /* oper is not in search path */
 
746
 
 
747
                        /*
 
748
                         * Okay, it's in the search path, but does it have the same
 
749
                         * arguments as something we already accepted?  If so, keep
 
750
                         * only the one that appears earlier in the search path.
 
751
                         *
 
752
                         * If we have an ordered list from SearchSysCacheList (the normal
 
753
                         * case), then any conflicting oper must immediately adjoin
 
754
                         * this one in the list, so we only need to look at the newest
 
755
                         * result item.  If we have an unordered list, we have to scan
 
756
                         * the whole result list.
 
757
                         */
 
758
                        if (resultList)
 
759
                        {
 
760
                                FuncCandidateList prevResult;
 
761
 
 
762
                                if (catlist->ordered)
 
763
                                {
 
764
                                        if (operform->oprleft == resultList->args[0] &&
 
765
                                                operform->oprright == resultList->args[1])
 
766
                                                prevResult = resultList;
 
767
                                        else
 
768
                                                prevResult = NULL;
 
769
                                }
 
770
                                else
 
771
                                {
 
772
                                        for (prevResult = resultList;
 
773
                                                 prevResult;
 
774
                                                 prevResult = prevResult->next)
 
775
                                        {
 
776
                                                if (operform->oprleft == prevResult->args[0] &&
 
777
                                                        operform->oprright == prevResult->args[1])
 
778
                                                        break;
 
779
                                        }
 
780
                                }
 
781
                                if (prevResult)
 
782
                                {
 
783
                                        /* We have a match with a previous result */
 
784
                                        Assert(pathpos != prevResult->pathpos);
 
785
                                        if (pathpos > prevResult->pathpos)
 
786
                                                continue;               /* keep previous result */
 
787
                                        /* replace previous result */
 
788
                                        prevResult->pathpos = pathpos;
 
789
                                        prevResult->oid = HeapTupleGetOid(opertup);
 
790
                                        continue;       /* args are same, of course */
 
791
                                }
 
792
                        }
 
793
                }
 
794
 
 
795
                /*
 
796
                 * Okay to add it to result list
 
797
                 */
 
798
                newResult = (FuncCandidateList) (resultSpace + nextResult);
 
799
                nextResult += SPACE_PER_OP;
 
800
 
 
801
                newResult->pathpos = pathpos;
 
802
                newResult->oid = HeapTupleGetOid(opertup);
 
803
                newResult->nargs = 2;
 
804
                newResult->args[0] = operform->oprleft;
 
805
                newResult->args[1] = operform->oprright;
 
806
                newResult->next = resultList;
 
807
                resultList = newResult;
 
808
        }
 
809
 
 
810
        ReleaseSysCacheList(catlist);
 
811
 
 
812
        return resultList;
 
813
}
 
814
 
 
815
/*
 
816
 * OperatorIsVisible
 
817
 *              Determine whether an operator (identified by OID) is visible in the
 
818
 *              current search path.  Visible means "would be found by searching
 
819
 *              for the unqualified operator name with exact argument matches".
 
820
 */
 
821
bool
 
822
OperatorIsVisible(Oid oprid)
 
823
{
 
824
        HeapTuple       oprtup;
 
825
        Form_pg_operator oprform;
 
826
        Oid                     oprnamespace;
 
827
        bool            visible;
 
828
 
 
829
        oprtup = SearchSysCache(OPEROID,
 
830
                                                        ObjectIdGetDatum(oprid),
 
831
                                                        0, 0, 0);
 
832
        if (!HeapTupleIsValid(oprtup))
 
833
                elog(ERROR, "cache lookup failed for operator %u", oprid);
 
834
        oprform = (Form_pg_operator) GETSTRUCT(oprtup);
 
835
 
 
836
        recomputeNamespacePath();
 
837
 
 
838
        /*
 
839
         * Quick check: if it ain't in the path at all, it ain't visible.
 
840
         * Items in the system namespace are surely in the path and so we
 
841
         * needn't even do list_member_oid() for them.
 
842
         */
 
843
        oprnamespace = oprform->oprnamespace;
 
844
        if (oprnamespace != PG_CATALOG_NAMESPACE &&
 
845
                !list_member_oid(namespaceSearchPath, oprnamespace))
 
846
                visible = false;
 
847
        else
 
848
        {
 
849
                /*
 
850
                 * If it is in the path, it might still not be visible; it could
 
851
                 * be hidden by another operator of the same name and arguments
 
852
                 * earlier in the path.  So we must do a slow check to see if this
 
853
                 * is the same operator that would be found by
 
854
                 * OpernameGetCandidates.
 
855
                 */
 
856
                char       *oprname = NameStr(oprform->oprname);
 
857
                FuncCandidateList clist;
 
858
 
 
859
                visible = false;
 
860
 
 
861
                clist = OpernameGetCandidates(list_make1(makeString(oprname)),
 
862
                                                                          oprform->oprkind);
 
863
 
 
864
                for (; clist; clist = clist->next)
 
865
                {
 
866
                        if (clist->args[0] == oprform->oprleft &&
 
867
                                clist->args[1] == oprform->oprright)
 
868
                        {
 
869
                                /* Found the expected entry; is it the right op? */
 
870
                                visible = (clist->oid == oprid);
 
871
                                break;
 
872
                        }
 
873
                }
 
874
        }
 
875
 
 
876
        ReleaseSysCache(oprtup);
 
877
 
 
878
        return visible;
 
879
}
 
880
 
 
881
 
 
882
/*
 
883
 * OpclassGetCandidates
 
884
 *              Given an index access method OID, retrieve a list of all the
 
885
 *              opclasses for that AM that are visible in the search path.
 
886
 *
 
887
 * NOTE: the opcname_tmp field in the returned structs should not be used
 
888
 * by callers, because it points at syscache entries that we release at
 
889
 * the end of this routine.  If any callers needed the name information,
 
890
 * we could pstrdup() the names ... but at present it'd be wasteful.
 
891
 */
 
892
OpclassCandidateList
 
893
OpclassGetCandidates(Oid amid)
 
894
{
 
895
        OpclassCandidateList resultList = NULL;
 
896
        CatCList   *catlist;
 
897
        int                     i;
 
898
 
 
899
        /* Search syscache by AM OID only */
 
900
        catlist = SearchSysCacheList(CLAAMNAMENSP, 1,
 
901
                                                                 ObjectIdGetDatum(amid),
 
902
                                                                 0, 0, 0);
 
903
 
 
904
        recomputeNamespacePath();
 
905
 
 
906
        for (i = 0; i < catlist->n_members; i++)
 
907
        {
 
908
                HeapTuple       opctup = &catlist->members[i]->tuple;
 
909
                Form_pg_opclass opcform = (Form_pg_opclass) GETSTRUCT(opctup);
 
910
                int                     pathpos = 0;
 
911
                OpclassCandidateList newResult;
 
912
                ListCell   *nsp;
 
913
 
 
914
                /* Consider only opclasses that are in the search path */
 
915
                foreach(nsp, namespaceSearchPath)
 
916
                {
 
917
                        if (opcform->opcnamespace == lfirst_oid(nsp))
 
918
                                break;
 
919
                        pathpos++;
 
920
                }
 
921
                if (nsp == NULL)
 
922
                        continue;                       /* opclass is not in search path */
 
923
 
 
924
                /*
 
925
                 * Okay, it's in the search path, but does it have the same name
 
926
                 * as something we already accepted?  If so, keep only the one
 
927
                 * that appears earlier in the search path.
 
928
                 *
 
929
                 * If we have an ordered list from SearchSysCacheList (the normal
 
930
                 * case), then any conflicting opclass must immediately adjoin
 
931
                 * this one in the list, so we only need to look at the newest
 
932
                 * result item.  If we have an unordered list, we have to scan the
 
933
                 * whole result list.
 
934
                 */
 
935
                if (resultList)
 
936
                {
 
937
                        OpclassCandidateList prevResult;
 
938
 
 
939
                        if (catlist->ordered)
 
940
                        {
 
941
                                if (strcmp(NameStr(opcform->opcname),
 
942
                                                   resultList->opcname_tmp) == 0)
 
943
                                        prevResult = resultList;
 
944
                                else
 
945
                                        prevResult = NULL;
 
946
                        }
 
947
                        else
 
948
                        {
 
949
                                for (prevResult = resultList;
 
950
                                         prevResult;
 
951
                                         prevResult = prevResult->next)
 
952
                                {
 
953
                                        if (strcmp(NameStr(opcform->opcname),
 
954
                                                           prevResult->opcname_tmp) == 0)
 
955
                                                break;
 
956
                                }
 
957
                        }
 
958
                        if (prevResult)
 
959
                        {
 
960
                                /* We have a match with a previous result */
 
961
                                Assert(pathpos != prevResult->pathpos);
 
962
                                if (pathpos > prevResult->pathpos)
 
963
                                        continue;       /* keep previous result */
 
964
                                /* replace previous result */
 
965
                                prevResult->opcname_tmp = NameStr(opcform->opcname);
 
966
                                prevResult->pathpos = pathpos;
 
967
                                prevResult->oid = HeapTupleGetOid(opctup);
 
968
                                prevResult->opcintype = opcform->opcintype;
 
969
                                prevResult->opcdefault = opcform->opcdefault;
 
970
                                prevResult->opckeytype = opcform->opckeytype;
 
971
                                continue;
 
972
                        }
 
973
                }
 
974
 
 
975
                /*
 
976
                 * Okay to add it to result list
 
977
                 */
 
978
                newResult = (OpclassCandidateList)
 
979
                        palloc(sizeof(struct _OpclassCandidateList));
 
980
                newResult->opcname_tmp = NameStr(opcform->opcname);
 
981
                newResult->pathpos = pathpos;
 
982
                newResult->oid = HeapTupleGetOid(opctup);
 
983
                newResult->opcintype = opcform->opcintype;
 
984
                newResult->opcdefault = opcform->opcdefault;
 
985
                newResult->opckeytype = opcform->opckeytype;
 
986
                newResult->next = resultList;
 
987
                resultList = newResult;
 
988
        }
 
989
 
 
990
        ReleaseSysCacheList(catlist);
 
991
 
 
992
        return resultList;
 
993
}
 
994
 
 
995
/*
 
996
 * OpclassnameGetOpcid
 
997
 *              Try to resolve an unqualified index opclass name.
 
998
 *              Returns OID if opclass found in search path, else InvalidOid.
 
999
 *
 
1000
 * This is essentially the same as TypenameGetTypid, but we have to have
 
1001
 * an extra argument for the index AM OID.
 
1002
 */
 
1003
Oid
 
1004
OpclassnameGetOpcid(Oid amid, const char *opcname)
 
1005
{
 
1006
        Oid                     opcid;
 
1007
        ListCell   *l;
 
1008
 
 
1009
        recomputeNamespacePath();
 
1010
 
 
1011
        foreach(l, namespaceSearchPath)
 
1012
        {
 
1013
                Oid                     namespaceId = lfirst_oid(l);
 
1014
 
 
1015
                opcid = GetSysCacheOid(CLAAMNAMENSP,
 
1016
                                                           ObjectIdGetDatum(amid),
 
1017
                                                           PointerGetDatum(opcname),
 
1018
                                                           ObjectIdGetDatum(namespaceId),
 
1019
                                                           0);
 
1020
                if (OidIsValid(opcid))
 
1021
                        return opcid;
 
1022
        }
 
1023
 
 
1024
        /* Not found in path */
 
1025
        return InvalidOid;
 
1026
}
 
1027
 
 
1028
/*
 
1029
 * OpclassIsVisible
 
1030
 *              Determine whether an opclass (identified by OID) is visible in the
 
1031
 *              current search path.  Visible means "would be found by searching
 
1032
 *              for the unqualified opclass name".
 
1033
 */
 
1034
bool
 
1035
OpclassIsVisible(Oid opcid)
 
1036
{
 
1037
        HeapTuple       opctup;
 
1038
        Form_pg_opclass opcform;
 
1039
        Oid                     opcnamespace;
 
1040
        bool            visible;
 
1041
 
 
1042
        opctup = SearchSysCache(CLAOID,
 
1043
                                                        ObjectIdGetDatum(opcid),
 
1044
                                                        0, 0, 0);
 
1045
        if (!HeapTupleIsValid(opctup))
 
1046
                elog(ERROR, "cache lookup failed for opclass %u", opcid);
 
1047
        opcform = (Form_pg_opclass) GETSTRUCT(opctup);
 
1048
 
 
1049
        recomputeNamespacePath();
 
1050
 
 
1051
        /*
 
1052
         * Quick check: if it ain't in the path at all, it ain't visible.
 
1053
         * Items in the system namespace are surely in the path and so we
 
1054
         * needn't even do list_member_oid() for them.
 
1055
         */
 
1056
        opcnamespace = opcform->opcnamespace;
 
1057
        if (opcnamespace != PG_CATALOG_NAMESPACE &&
 
1058
                !list_member_oid(namespaceSearchPath, opcnamespace))
 
1059
                visible = false;
 
1060
        else
 
1061
        {
 
1062
                /*
 
1063
                 * If it is in the path, it might still not be visible; it could
 
1064
                 * be hidden by another opclass of the same name earlier in the
 
1065
                 * path. So we must do a slow check to see if this opclass would
 
1066
                 * be found by OpclassnameGetOpcid.
 
1067
                 */
 
1068
                char       *opcname = NameStr(opcform->opcname);
 
1069
 
 
1070
                visible = (OpclassnameGetOpcid(opcform->opcamid, opcname) == opcid);
 
1071
        }
 
1072
 
 
1073
        ReleaseSysCache(opctup);
 
1074
 
 
1075
        return visible;
 
1076
}
 
1077
 
 
1078
/*
 
1079
 * ConversionGetConid
 
1080
 *              Try to resolve an unqualified conversion name.
 
1081
 *              Returns OID if conversion found in search path, else InvalidOid.
 
1082
 *
 
1083
 * This is essentially the same as RelnameGetRelid.
 
1084
 */
 
1085
Oid
 
1086
ConversionGetConid(const char *conname)
 
1087
{
 
1088
        Oid                     conid;
 
1089
        ListCell   *l;
 
1090
 
 
1091
        recomputeNamespacePath();
 
1092
 
 
1093
        foreach(l, namespaceSearchPath)
 
1094
        {
 
1095
                Oid                     namespaceId = lfirst_oid(l);
 
1096
 
 
1097
                conid = GetSysCacheOid(CONNAMENSP,
 
1098
                                                           PointerGetDatum(conname),
 
1099
                                                           ObjectIdGetDatum(namespaceId),
 
1100
                                                           0, 0);
 
1101
                if (OidIsValid(conid))
 
1102
                        return conid;
 
1103
        }
 
1104
 
 
1105
        /* Not found in path */
 
1106
        return InvalidOid;
 
1107
}
 
1108
 
 
1109
/*
 
1110
 * ConversionIsVisible
 
1111
 *              Determine whether a conversion (identified by OID) is visible in the
 
1112
 *              current search path.  Visible means "would be found by searching
 
1113
 *              for the unqualified conversion name".
 
1114
 */
 
1115
bool
 
1116
ConversionIsVisible(Oid conid)
 
1117
{
 
1118
        HeapTuple       contup;
 
1119
        Form_pg_conversion conform;
 
1120
        Oid                     connamespace;
 
1121
        bool            visible;
 
1122
 
 
1123
        contup = SearchSysCache(CONOID,
 
1124
                                                        ObjectIdGetDatum(conid),
 
1125
                                                        0, 0, 0);
 
1126
        if (!HeapTupleIsValid(contup))
 
1127
                elog(ERROR, "cache lookup failed for conversion %u", conid);
 
1128
        conform = (Form_pg_conversion) GETSTRUCT(contup);
 
1129
 
 
1130
        recomputeNamespacePath();
 
1131
 
 
1132
        /*
 
1133
         * Quick check: if it ain't in the path at all, it ain't visible.
 
1134
         * Items in the system namespace are surely in the path and so we
 
1135
         * needn't even do list_member_oid() for them.
 
1136
         */
 
1137
        connamespace = conform->connamespace;
 
1138
        if (connamespace != PG_CATALOG_NAMESPACE &&
 
1139
                !list_member_oid(namespaceSearchPath, connamespace))
 
1140
                visible = false;
 
1141
        else
 
1142
        {
 
1143
                /*
 
1144
                 * If it is in the path, it might still not be visible; it could
 
1145
                 * be hidden by another conversion of the same name earlier in the
 
1146
                 * path. So we must do a slow check to see if this conversion
 
1147
                 * would be found by ConversionGetConid.
 
1148
                 */
 
1149
                char       *conname = NameStr(conform->conname);
 
1150
 
 
1151
                visible = (ConversionGetConid(conname) == conid);
 
1152
        }
 
1153
 
 
1154
        ReleaseSysCache(contup);
 
1155
 
 
1156
        return visible;
 
1157
}
 
1158
 
 
1159
/*
 
1160
 * DeconstructQualifiedName
 
1161
 *              Given a possibly-qualified name expressed as a list of String nodes,
 
1162
 *              extract the schema name and object name.
 
1163
 *
 
1164
 * *nspname_p is set to NULL if there is no explicit schema name.
 
1165
 */
 
1166
void
 
1167
DeconstructQualifiedName(List *names,
 
1168
                                                 char **nspname_p,
 
1169
                                                 char **objname_p)
 
1170
{
 
1171
        char       *catalogname;
 
1172
        char       *schemaname = NULL;
 
1173
        char       *objname = NULL;
 
1174
 
 
1175
        switch (list_length(names))
 
1176
        {
 
1177
                case 1:
 
1178
                        objname = strVal(linitial(names));
 
1179
                        break;
 
1180
                case 2:
 
1181
                        schemaname = strVal(linitial(names));
 
1182
                        objname = strVal(lsecond(names));
 
1183
                        break;
 
1184
                case 3:
 
1185
                        catalogname = strVal(linitial(names));
 
1186
                        schemaname = strVal(lsecond(names));
 
1187
                        objname = strVal(lthird(names));
 
1188
 
 
1189
                        /*
 
1190
                         * We check the catalog name and then ignore it.
 
1191
                         */
 
1192
                        if (strcmp(catalogname, get_database_name(MyDatabaseId)) != 0)
 
1193
                                ereport(ERROR,
 
1194
                                                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 
1195
                                                 errmsg("cross-database references are not implemented: %s",
 
1196
                                                                NameListToString(names))));
 
1197
                        break;
 
1198
                default:
 
1199
                        ereport(ERROR,
 
1200
                                        (errcode(ERRCODE_SYNTAX_ERROR),
 
1201
                        errmsg("improper qualified name (too many dotted names): %s",
 
1202
                                   NameListToString(names))));
 
1203
                        break;
 
1204
        }
 
1205
 
 
1206
        *nspname_p = schemaname;
 
1207
        *objname_p = objname;
 
1208
}
 
1209
 
 
1210
/*
 
1211
 * LookupExplicitNamespace
 
1212
 *              Process an explicitly-specified schema name: look up the schema
 
1213
 *              and verify we have USAGE (lookup) rights in it.
 
1214
 *
 
1215
 * Returns the namespace OID.  Raises ereport if any problem.
 
1216
 */
 
1217
Oid
 
1218
LookupExplicitNamespace(const char *nspname)
 
1219
{
 
1220
        Oid                     namespaceId;
 
1221
        AclResult       aclresult;
 
1222
 
 
1223
        namespaceId = GetSysCacheOid(NAMESPACENAME,
 
1224
                                                                 CStringGetDatum(nspname),
 
1225
                                                                 0, 0, 0);
 
1226
        if (!OidIsValid(namespaceId))
 
1227
                ereport(ERROR,
 
1228
                                (errcode(ERRCODE_UNDEFINED_SCHEMA),
 
1229
                                 errmsg("schema \"%s\" does not exist", nspname)));
 
1230
 
 
1231
        aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_USAGE);
 
1232
        if (aclresult != ACLCHECK_OK)
 
1233
                aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
 
1234
                                           nspname);
 
1235
 
 
1236
        return namespaceId;
 
1237
}
 
1238
 
 
1239
/*
 
1240
 * QualifiedNameGetCreationNamespace
 
1241
 *              Given a possibly-qualified name for an object (in List-of-Values
 
1242
 *              format), determine what namespace the object should be created in.
 
1243
 *              Also extract and return the object name (last component of list).
 
1244
 *
 
1245
 * This is *not* used for tables.  Hence, the TEMP table namespace is
 
1246
 * never selected as the creation target.
 
1247
 */
 
1248
Oid
 
1249
QualifiedNameGetCreationNamespace(List *names, char **objname_p)
 
1250
{
 
1251
        char       *schemaname;
 
1252
        char       *objname;
 
1253
        Oid                     namespaceId;
 
1254
 
 
1255
        /* deconstruct the name list */
 
1256
        DeconstructQualifiedName(names, &schemaname, &objname);
 
1257
 
 
1258
        if (schemaname)
 
1259
        {
 
1260
                /* use exact schema given */
 
1261
                namespaceId = GetSysCacheOid(NAMESPACENAME,
 
1262
                                                                         CStringGetDatum(schemaname),
 
1263
                                                                         0, 0, 0);
 
1264
                if (!OidIsValid(namespaceId))
 
1265
                        ereport(ERROR,
 
1266
                                        (errcode(ERRCODE_UNDEFINED_SCHEMA),
 
1267
                                         errmsg("schema \"%s\" does not exist", schemaname)));
 
1268
                /* we do not check for USAGE rights here! */
 
1269
        }
 
1270
        else
 
1271
        {
 
1272
                /* use the default creation namespace */
 
1273
                recomputeNamespacePath();
 
1274
                namespaceId = defaultCreationNamespace;
 
1275
                if (!OidIsValid(namespaceId))
 
1276
                        ereport(ERROR,
 
1277
                                        (errcode(ERRCODE_UNDEFINED_SCHEMA),
 
1278
                                         errmsg("no schema has been selected to create in")));
 
1279
        }
 
1280
 
 
1281
        /* Note: callers will check for CREATE rights when appropriate */
 
1282
 
 
1283
        *objname_p = objname;
 
1284
        return namespaceId;
 
1285
}
 
1286
 
 
1287
/*
 
1288
 * makeRangeVarFromNameList
 
1289
 *              Utility routine to convert a qualified-name list into RangeVar form.
 
1290
 */
 
1291
RangeVar *
 
1292
makeRangeVarFromNameList(List *names)
 
1293
{
 
1294
        RangeVar   *rel = makeRangeVar(NULL, NULL);
 
1295
 
 
1296
        switch (list_length(names))
 
1297
        {
 
1298
                case 1:
 
1299
                        rel->relname = strVal(linitial(names));
 
1300
                        break;
 
1301
                case 2:
 
1302
                        rel->schemaname = strVal(linitial(names));
 
1303
                        rel->relname = strVal(lsecond(names));
 
1304
                        break;
 
1305
                case 3:
 
1306
                        rel->catalogname = strVal(linitial(names));
 
1307
                        rel->schemaname = strVal(lsecond(names));
 
1308
                        rel->relname = strVal(lthird(names));
 
1309
                        break;
 
1310
                default:
 
1311
                        ereport(ERROR,
 
1312
                                        (errcode(ERRCODE_SYNTAX_ERROR),
 
1313
                         errmsg("improper relation name (too many dotted names): %s",
 
1314
                                        NameListToString(names))));
 
1315
                        break;
 
1316
        }
 
1317
 
 
1318
        return rel;
 
1319
}
 
1320
 
 
1321
/*
 
1322
 * NameListToString
 
1323
 *              Utility routine to convert a qualified-name list into a string.
 
1324
 *
 
1325
 * This is used primarily to form error messages, and so we do not quote
 
1326
 * the list elements, for the sake of legibility.
 
1327
 */
 
1328
char *
 
1329
NameListToString(List *names)
 
1330
{
 
1331
        StringInfoData string;
 
1332
        ListCell   *l;
 
1333
 
 
1334
        initStringInfo(&string);
 
1335
 
 
1336
        foreach(l, names)
 
1337
        {
 
1338
                if (l != list_head(names))
 
1339
                        appendStringInfoChar(&string, '.');
 
1340
                appendStringInfoString(&string, strVal(lfirst(l)));
 
1341
        }
 
1342
 
 
1343
        return string.data;
 
1344
}
 
1345
 
 
1346
/*
 
1347
 * NameListToQuotedString
 
1348
 *              Utility routine to convert a qualified-name list into a string.
 
1349
 *
 
1350
 * Same as above except that names will be double-quoted where necessary,
 
1351
 * so the string could be re-parsed (eg, by textToQualifiedNameList).
 
1352
 */
 
1353
char *
 
1354
NameListToQuotedString(List *names)
 
1355
{
 
1356
        StringInfoData string;
 
1357
        ListCell   *l;
 
1358
 
 
1359
        initStringInfo(&string);
 
1360
 
 
1361
        foreach(l, names)
 
1362
        {
 
1363
                if (l != list_head(names))
 
1364
                        appendStringInfoChar(&string, '.');
 
1365
                appendStringInfoString(&string, quote_identifier(strVal(lfirst(l))));
 
1366
        }
 
1367
 
 
1368
        return string.data;
 
1369
}
 
1370
 
 
1371
/*
 
1372
 * isTempNamespace - is the given namespace my temporary-table namespace?
 
1373
 */
 
1374
bool
 
1375
isTempNamespace(Oid namespaceId)
 
1376
{
 
1377
        if (OidIsValid(myTempNamespace) && myTempNamespace == namespaceId)
 
1378
                return true;
 
1379
        return false;
 
1380
}
 
1381
 
 
1382
/*
 
1383
 * isOtherTempNamespace - is the given namespace some other backend's
 
1384
 * temporary-table namespace?
 
1385
 */
 
1386
bool
 
1387
isOtherTempNamespace(Oid namespaceId)
 
1388
{
 
1389
        bool            result;
 
1390
        char       *nspname;
 
1391
 
 
1392
        /* If it's my own temp namespace, say "false" */
 
1393
        if (isTempNamespace(namespaceId))
 
1394
                return false;
 
1395
        /* Else, if the namespace name starts with "pg_temp_", say "true" */
 
1396
        nspname = get_namespace_name(namespaceId);
 
1397
        if (!nspname)
 
1398
                return false;                   /* no such namespace? */
 
1399
        result = (strncmp(nspname, "pg_temp_", 8) == 0);
 
1400
        pfree(nspname);
 
1401
        return result;
 
1402
}
 
1403
 
 
1404
/*
 
1405
 * PushSpecialNamespace - push a "special" namespace onto the front of the
 
1406
 * search path.
 
1407
 *
 
1408
 * This is a slightly messy hack intended only for support of CREATE SCHEMA.
 
1409
 * Although the API is defined to allow a stack of pushed namespaces, we
 
1410
 * presently only support one at a time.
 
1411
 *
 
1412
 * The pushed namespace will be removed from the search path at end of
 
1413
 * transaction, whether commit or abort.
 
1414
 */
 
1415
void
 
1416
PushSpecialNamespace(Oid namespaceId)
 
1417
{
 
1418
        Assert(!OidIsValid(mySpecialNamespace));
 
1419
        mySpecialNamespace = namespaceId;
 
1420
        namespaceSearchPathValid = false;
 
1421
}
 
1422
 
 
1423
/*
 
1424
 * PopSpecialNamespace - remove previously pushed special namespace.
 
1425
 */
 
1426
void
 
1427
PopSpecialNamespace(Oid namespaceId)
 
1428
{
 
1429
        Assert(mySpecialNamespace == namespaceId);
 
1430
        mySpecialNamespace = InvalidOid;
 
1431
        namespaceSearchPathValid = false;
 
1432
}
 
1433
 
 
1434
/*
 
1435
 * FindConversionByName - find a conversion by possibly qualified name
 
1436
 */
 
1437
Oid
 
1438
FindConversionByName(List *name)
 
1439
{
 
1440
        char       *schemaname;
 
1441
        char       *conversion_name;
 
1442
        Oid                     namespaceId;
 
1443
        Oid                     conoid;
 
1444
        ListCell   *l;
 
1445
 
 
1446
        /* deconstruct the name list */
 
1447
        DeconstructQualifiedName(name, &schemaname, &conversion_name);
 
1448
 
 
1449
        if (schemaname)
 
1450
        {
 
1451
                /* use exact schema given */
 
1452
                namespaceId = LookupExplicitNamespace(schemaname);
 
1453
                return FindConversion(conversion_name, namespaceId);
 
1454
        }
 
1455
        else
 
1456
        {
 
1457
                /* search for it in search path */
 
1458
                recomputeNamespacePath();
 
1459
 
 
1460
                foreach(l, namespaceSearchPath)
 
1461
                {
 
1462
                        namespaceId = lfirst_oid(l);
 
1463
                        conoid = FindConversion(conversion_name, namespaceId);
 
1464
                        if (OidIsValid(conoid))
 
1465
                                return conoid;
 
1466
                }
 
1467
        }
 
1468
 
 
1469
        /* Not found in path */
 
1470
        return InvalidOid;
 
1471
}
 
1472
 
 
1473
/*
 
1474
 * FindDefaultConversionProc - find default encoding conversion proc
 
1475
 */
 
1476
Oid
 
1477
FindDefaultConversionProc(int4 for_encoding, int4 to_encoding)
 
1478
{
 
1479
        Oid                     proc;
 
1480
        ListCell   *l;
 
1481
 
 
1482
        recomputeNamespacePath();
 
1483
 
 
1484
        foreach(l, namespaceSearchPath)
 
1485
        {
 
1486
                Oid                     namespaceId = lfirst_oid(l);
 
1487
 
 
1488
                proc = FindDefaultConversion(namespaceId, for_encoding, to_encoding);
 
1489
                if (OidIsValid(proc))
 
1490
                        return proc;
 
1491
        }
 
1492
 
 
1493
        /* Not found in path */
 
1494
        return InvalidOid;
 
1495
}
 
1496
 
 
1497
/*
 
1498
 * recomputeNamespacePath - recompute path derived variables if needed.
 
1499
 */
 
1500
static void
 
1501
recomputeNamespacePath(void)
 
1502
{
 
1503
        AclId           userId = GetUserId();
 
1504
        char       *rawname;
 
1505
        List       *namelist;
 
1506
        List       *oidlist;
 
1507
        List       *newpath;
 
1508
        ListCell   *l;
 
1509
        Oid                     firstNS;
 
1510
        MemoryContext oldcxt;
 
1511
 
 
1512
        /*
 
1513
         * Do nothing if path is already valid.
 
1514
         */
 
1515
        if (namespaceSearchPathValid && namespaceUser == userId)
 
1516
                return;
 
1517
 
 
1518
        /* Need a modifiable copy of namespace_search_path string */
 
1519
        rawname = pstrdup(namespace_search_path);
 
1520
 
 
1521
        /* Parse string into list of identifiers */
 
1522
        if (!SplitIdentifierString(rawname, ',', &namelist))
 
1523
        {
 
1524
                /* syntax error in name list */
 
1525
                /* this should not happen if GUC checked check_search_path */
 
1526
                elog(ERROR, "invalid list syntax");
 
1527
        }
 
1528
 
 
1529
        /*
 
1530
         * Convert the list of names to a list of OIDs.  If any names are not
 
1531
         * recognizable or we don't have read access, just leave them out of
 
1532
         * the list.  (We can't raise an error, since the search_path setting
 
1533
         * has already been accepted.)  Don't make duplicate entries, either.
 
1534
         */
 
1535
        oidlist = NIL;
 
1536
        foreach(l, namelist)
 
1537
        {
 
1538
                char       *curname = (char *) lfirst(l);
 
1539
                Oid                     namespaceId;
 
1540
 
 
1541
                if (strcmp(curname, "$user") == 0)
 
1542
                {
 
1543
                        /* $user --- substitute namespace matching user name, if any */
 
1544
                        HeapTuple       tuple;
 
1545
 
 
1546
                        tuple = SearchSysCache(SHADOWSYSID,
 
1547
                                                                   ObjectIdGetDatum(userId),
 
1548
                                                                   0, 0, 0);
 
1549
                        if (HeapTupleIsValid(tuple))
 
1550
                        {
 
1551
                                char       *uname;
 
1552
 
 
1553
                                uname = NameStr(((Form_pg_shadow) GETSTRUCT(tuple))->usename);
 
1554
                                namespaceId = GetSysCacheOid(NAMESPACENAME,
 
1555
                                                                                         CStringGetDatum(uname),
 
1556
                                                                                         0, 0, 0);
 
1557
                                ReleaseSysCache(tuple);
 
1558
                                if (OidIsValid(namespaceId) &&
 
1559
                                        !list_member_oid(oidlist, namespaceId) &&
 
1560
                                        pg_namespace_aclcheck(namespaceId, userId,
 
1561
                                                                                  ACL_USAGE) == ACLCHECK_OK)
 
1562
                                        oidlist = lappend_oid(oidlist, namespaceId);
 
1563
                        }
 
1564
                }
 
1565
                else
 
1566
                {
 
1567
                        /* normal namespace reference */
 
1568
                        namespaceId = GetSysCacheOid(NAMESPACENAME,
 
1569
                                                                                 CStringGetDatum(curname),
 
1570
                                                                                 0, 0, 0);
 
1571
                        if (OidIsValid(namespaceId) &&
 
1572
                                !list_member_oid(oidlist, namespaceId) &&
 
1573
                                pg_namespace_aclcheck(namespaceId, userId,
 
1574
                                                                          ACL_USAGE) == ACLCHECK_OK)
 
1575
                                oidlist = lappend_oid(oidlist, namespaceId);
 
1576
                }
 
1577
        }
 
1578
 
 
1579
        /*
 
1580
         * Remember the first member of the explicit list.
 
1581
         */
 
1582
        if (oidlist == NIL)
 
1583
                firstNS = InvalidOid;
 
1584
        else
 
1585
                firstNS = linitial_oid(oidlist);
 
1586
 
 
1587
        /*
 
1588
         * Add any implicitly-searched namespaces to the list.  Note these go
 
1589
         * on the front, not the back; also notice that we do not check USAGE
 
1590
         * permissions for these.
 
1591
         */
 
1592
        if (!list_member_oid(oidlist, PG_CATALOG_NAMESPACE))
 
1593
                oidlist = lcons_oid(PG_CATALOG_NAMESPACE, oidlist);
 
1594
 
 
1595
        if (OidIsValid(myTempNamespace) &&
 
1596
                !list_member_oid(oidlist, myTempNamespace))
 
1597
                oidlist = lcons_oid(myTempNamespace, oidlist);
 
1598
 
 
1599
        if (OidIsValid(mySpecialNamespace) &&
 
1600
                !list_member_oid(oidlist, mySpecialNamespace))
 
1601
                oidlist = lcons_oid(mySpecialNamespace, oidlist);
 
1602
 
 
1603
        /*
 
1604
         * Now that we've successfully built the new list of namespace OIDs,
 
1605
         * save it in permanent storage.
 
1606
         */
 
1607
        oldcxt = MemoryContextSwitchTo(TopMemoryContext);
 
1608
        newpath = list_copy(oidlist);
 
1609
        MemoryContextSwitchTo(oldcxt);
 
1610
 
 
1611
        /* Now safe to assign to state variable. */
 
1612
        list_free(namespaceSearchPath);
 
1613
        namespaceSearchPath = newpath;
 
1614
 
 
1615
        /*
 
1616
         * Update info derived from search path.
 
1617
         */
 
1618
        firstExplicitNamespace = firstNS;
 
1619
        if (OidIsValid(mySpecialNamespace))
 
1620
                defaultCreationNamespace = mySpecialNamespace;
 
1621
        else
 
1622
                defaultCreationNamespace = firstNS;
 
1623
 
 
1624
        /* Mark the path valid. */
 
1625
        namespaceSearchPathValid = true;
 
1626
        namespaceUser = userId;
 
1627
 
 
1628
        /* Clean up. */
 
1629
        pfree(rawname);
 
1630
        list_free(namelist);
 
1631
        list_free(oidlist);
 
1632
}
 
1633
 
 
1634
/*
 
1635
 * InitTempTableNamespace
 
1636
 *              Initialize temp table namespace on first use in a particular backend
 
1637
 */
 
1638
static void
 
1639
InitTempTableNamespace(void)
 
1640
{
 
1641
        char            namespaceName[NAMEDATALEN];
 
1642
        Oid                     namespaceId;
 
1643
 
 
1644
        /*
 
1645
         * First, do permission check to see if we are authorized to make temp
 
1646
         * tables.      We use a nonstandard error message here since
 
1647
         * "databasename: permission denied" might be a tad cryptic.
 
1648
         *
 
1649
         * Note that ACL_CREATE_TEMP rights are rechecked in
 
1650
         * pg_namespace_aclmask; that's necessary since current user ID could
 
1651
         * change during the session. But there's no need to make the
 
1652
         * namespace in the first place until a temp table creation request is
 
1653
         * made by someone with appropriate rights.
 
1654
         */
 
1655
        if (pg_database_aclcheck(MyDatabaseId, GetUserId(),
 
1656
                                                         ACL_CREATE_TEMP) != ACLCHECK_OK)
 
1657
                ereport(ERROR,
 
1658
                                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
 
1659
                                 errmsg("permission denied to create temporary tables in database \"%s\"",
 
1660
                                                get_database_name(MyDatabaseId))));
 
1661
 
 
1662
        snprintf(namespaceName, sizeof(namespaceName), "pg_temp_%d", MyBackendId);
 
1663
 
 
1664
        namespaceId = GetSysCacheOid(NAMESPACENAME,
 
1665
                                                                 CStringGetDatum(namespaceName),
 
1666
                                                                 0, 0, 0);
 
1667
        if (!OidIsValid(namespaceId))
 
1668
        {
 
1669
                /*
 
1670
                 * First use of this temp namespace in this database; create it.
 
1671
                 * The temp namespaces are always owned by the superuser.  We
 
1672
                 * leave their permissions at default --- i.e., no access except
 
1673
                 * to superuser --- to ensure that unprivileged users can't peek
 
1674
                 * at other backends' temp tables.  This works because the places
 
1675
                 * that access the temp namespace for my own backend skip
 
1676
                 * permissions checks on it.
 
1677
                 */
 
1678
                namespaceId = NamespaceCreate(namespaceName, BOOTSTRAP_USESYSID);
 
1679
                /* Advance command counter to make namespace visible */
 
1680
                CommandCounterIncrement();
 
1681
        }
 
1682
        else
 
1683
        {
 
1684
                /*
 
1685
                 * If the namespace already exists, clean it out (in case the
 
1686
                 * former owner crashed without doing so).
 
1687
                 */
 
1688
                RemoveTempRelations(namespaceId);
 
1689
        }
 
1690
 
 
1691
        /*
 
1692
         * Okay, we've prepared the temp namespace ... but it's not committed
 
1693
         * yet, so all our work could be undone by transaction rollback.  Set
 
1694
         * flag for AtEOXact_Namespace to know what to do.
 
1695
         */
 
1696
        myTempNamespace = namespaceId;
 
1697
 
 
1698
        /* It should not be done already. */
 
1699
        AssertState(myTempNamespaceSubID == InvalidSubTransactionId);
 
1700
        myTempNamespaceSubID = GetCurrentSubTransactionId();
 
1701
 
 
1702
        namespaceSearchPathValid = false;       /* need to rebuild list */
 
1703
}
 
1704
 
 
1705
/*
 
1706
 * End-of-transaction cleanup for namespaces.
 
1707
 */
 
1708
void
 
1709
AtEOXact_Namespace(bool isCommit)
 
1710
{
 
1711
        /*
 
1712
         * If we abort the transaction in which a temp namespace was selected,
 
1713
         * we'll have to do any creation or cleanout work over again.  So,
 
1714
         * just forget the namespace entirely until next time.  On the other
 
1715
         * hand, if we commit then register an exit callback to clean out the
 
1716
         * temp tables at backend shutdown.  (We only want to register the
 
1717
         * callback once per session, so this is a good place to do it.)
 
1718
         */
 
1719
        if (myTempNamespaceSubID != InvalidSubTransactionId)
 
1720
        {
 
1721
                if (isCommit)
 
1722
                        on_shmem_exit(RemoveTempRelationsCallback, 0);
 
1723
                else
 
1724
                {
 
1725
                        myTempNamespace = InvalidOid;
 
1726
                        namespaceSearchPathValid = false;       /* need to rebuild list */
 
1727
                }
 
1728
                myTempNamespaceSubID = InvalidSubTransactionId;
 
1729
        }
 
1730
 
 
1731
        /*
 
1732
         * Clean up if someone failed to do PopSpecialNamespace
 
1733
         */
 
1734
        if (OidIsValid(mySpecialNamespace))
 
1735
        {
 
1736
                mySpecialNamespace = InvalidOid;
 
1737
                namespaceSearchPathValid = false;               /* need to rebuild list */
 
1738
        }
 
1739
}
 
1740
 
 
1741
/*
 
1742
 * AtEOSubXact_Namespace
 
1743
 *
 
1744
 * At subtransaction commit, propagate the temp-namespace-creation
 
1745
 * flag to the parent subtransaction.
 
1746
 *
 
1747
 * At subtransaction abort, forget the flag if we set it up.
 
1748
 */
 
1749
void
 
1750
AtEOSubXact_Namespace(bool isCommit, SubTransactionId mySubid,
 
1751
                                          SubTransactionId parentSubid)
 
1752
{
 
1753
        if (myTempNamespaceSubID == mySubid)
 
1754
        {
 
1755
                if (isCommit)
 
1756
                        myTempNamespaceSubID = parentSubid;
 
1757
                else
 
1758
                {
 
1759
                        myTempNamespaceSubID = InvalidSubTransactionId;
 
1760
                        /* TEMP namespace creation failed, so reset state */
 
1761
                        myTempNamespace = InvalidOid;
 
1762
                        namespaceSearchPathValid = false;       /* need to rebuild list */
 
1763
                }
 
1764
        }
 
1765
}
 
1766
 
 
1767
/*
 
1768
 * Remove all relations in the specified temp namespace.
 
1769
 *
 
1770
 * This is called at backend shutdown (if we made any temp relations).
 
1771
 * It is also called when we begin using a pre-existing temp namespace,
 
1772
 * in order to clean out any relations that might have been created by
 
1773
 * a crashed backend.
 
1774
 */
 
1775
static void
 
1776
RemoveTempRelations(Oid tempNamespaceId)
 
1777
{
 
1778
        ObjectAddress object;
 
1779
 
 
1780
        /*
 
1781
         * We want to get rid of everything in the target namespace, but not
 
1782
         * the namespace itself (deleting it only to recreate it later would
 
1783
         * be a waste of cycles).  We do this by finding everything that has a
 
1784
         * dependency on the namespace.
 
1785
         */
 
1786
        object.classId = get_system_catalog_relid(NamespaceRelationName);
 
1787
        object.objectId = tempNamespaceId;
 
1788
        object.objectSubId = 0;
 
1789
 
 
1790
        deleteWhatDependsOn(&object, false);
 
1791
}
 
1792
 
 
1793
/*
 
1794
 * Callback to remove temp relations at backend exit.
 
1795
 */
 
1796
static void
 
1797
RemoveTempRelationsCallback(int code, Datum arg)
 
1798
{
 
1799
        if (OidIsValid(myTempNamespace))        /* should always be true */
 
1800
        {
 
1801
                /* Need to ensure we have a usable transaction. */
 
1802
                AbortOutOfAnyTransaction();
 
1803
                StartTransactionCommand();
 
1804
 
 
1805
                RemoveTempRelations(myTempNamespace);
 
1806
 
 
1807
                CommitTransactionCommand();
 
1808
        }
 
1809
}
 
1810
 
 
1811
 
 
1812
/*
 
1813
 * Routines for handling the GUC variable 'search_path'.
 
1814
 */
 
1815
 
 
1816
/* assign_hook: validate new search_path, do extra actions as needed */
 
1817
const char *
 
1818
assign_search_path(const char *newval, bool doit, GucSource source)
 
1819
{
 
1820
        char       *rawname;
 
1821
        List       *namelist;
 
1822
        ListCell   *l;
 
1823
 
 
1824
        /* Need a modifiable copy of string */
 
1825
        rawname = pstrdup(newval);
 
1826
 
 
1827
        /* Parse string into list of identifiers */
 
1828
        if (!SplitIdentifierString(rawname, ',', &namelist))
 
1829
        {
 
1830
                /* syntax error in name list */
 
1831
                pfree(rawname);
 
1832
                list_free(namelist);
 
1833
                return NULL;
 
1834
        }
 
1835
 
 
1836
        /*
 
1837
         * If we aren't inside a transaction, we cannot do database access so
 
1838
         * cannot verify the individual names.  Must accept the list on faith.
 
1839
         */
 
1840
        if (source >= PGC_S_INTERACTIVE && IsTransactionState())
 
1841
        {
 
1842
                /*
 
1843
                 * Verify that all the names are either valid namespace names or
 
1844
                 * "$user".  We do not require $user to correspond to a valid
 
1845
                 * namespace.  We do not check for USAGE rights, either; should
 
1846
                 * we?
 
1847
                 *
 
1848
                 * When source == PGC_S_TEST, we are checking the argument of an
 
1849
                 * ALTER DATABASE SET or ALTER USER SET command.  It could be that
 
1850
                 * the intended use of the search path is for some other database,
 
1851
                 * so we should not error out if it mentions schemas not present
 
1852
                 * in the current database.  We reduce the message to NOTICE
 
1853
                 * instead.
 
1854
                 */
 
1855
                foreach(l, namelist)
 
1856
                {
 
1857
                        char       *curname = (char *) lfirst(l);
 
1858
 
 
1859
                        if (strcmp(curname, "$user") == 0)
 
1860
                                continue;
 
1861
                        if (!SearchSysCacheExists(NAMESPACENAME,
 
1862
                                                                          CStringGetDatum(curname),
 
1863
                                                                          0, 0, 0))
 
1864
                                ereport((source == PGC_S_TEST) ? NOTICE : ERROR,
 
1865
                                                (errcode(ERRCODE_UNDEFINED_SCHEMA),
 
1866
                                           errmsg("schema \"%s\" does not exist", curname)));
 
1867
                }
 
1868
        }
 
1869
 
 
1870
        pfree(rawname);
 
1871
        list_free(namelist);
 
1872
 
 
1873
        /*
 
1874
         * We mark the path as needing recomputation, but don't do anything
 
1875
         * until it's needed.  This avoids trying to do database access during
 
1876
         * GUC initialization.
 
1877
         */
 
1878
        if (doit)
 
1879
                namespaceSearchPathValid = false;
 
1880
 
 
1881
        return newval;
 
1882
}
 
1883
 
 
1884
/*
 
1885
 * InitializeSearchPath: initialize module during InitPostgres.
 
1886
 *
 
1887
 * This is called after we are up enough to be able to do catalog lookups.
 
1888
 */
 
1889
void
 
1890
InitializeSearchPath(void)
 
1891
{
 
1892
        if (IsBootstrapProcessingMode())
 
1893
        {
 
1894
                /*
 
1895
                 * In bootstrap mode, the search path must be 'pg_catalog' so that
 
1896
                 * tables are created in the proper namespace; ignore the GUC
 
1897
                 * setting.
 
1898
                 */
 
1899
                MemoryContext oldcxt;
 
1900
 
 
1901
                oldcxt = MemoryContextSwitchTo(TopMemoryContext);
 
1902
                namespaceSearchPath = list_make1_oid(PG_CATALOG_NAMESPACE);
 
1903
                MemoryContextSwitchTo(oldcxt);
 
1904
                defaultCreationNamespace = PG_CATALOG_NAMESPACE;
 
1905
                firstExplicitNamespace = PG_CATALOG_NAMESPACE;
 
1906
                namespaceSearchPathValid = true;
 
1907
                namespaceUser = GetUserId();
 
1908
        }
 
1909
        else
 
1910
        {
 
1911
                /*
 
1912
                 * In normal mode, arrange for a callback on any syscache
 
1913
                 * invalidation of pg_namespace rows.
 
1914
                 */
 
1915
                CacheRegisterSyscacheCallback(NAMESPACEOID,
 
1916
                                                                          NamespaceCallback,
 
1917
                                                                          (Datum) 0);
 
1918
                /* Force search path to be recomputed on next use */
 
1919
                namespaceSearchPathValid = false;
 
1920
        }
 
1921
}
 
1922
 
 
1923
/*
 
1924
 * NamespaceCallback
 
1925
 *              Syscache inval callback function
 
1926
 */
 
1927
static void
 
1928
NamespaceCallback(Datum arg, Oid relid)
 
1929
{
 
1930
        /* Force search path to be recomputed on next use */
 
1931
        namespaceSearchPathValid = false;
 
1932
}
 
1933
 
 
1934
/*
 
1935
 * Fetch the active search path. The return value is a palloc'ed list
 
1936
 * of OIDs; the caller is responsible for freeing this storage as
 
1937
 * appropriate.
 
1938
 *
 
1939
 * The returned list includes the implicitly-prepended namespaces only if
 
1940
 * includeImplicit is true.
 
1941
 */
 
1942
List *
 
1943
fetch_search_path(bool includeImplicit)
 
1944
{
 
1945
        List       *result;
 
1946
 
 
1947
        recomputeNamespacePath();
 
1948
 
 
1949
        result = list_copy(namespaceSearchPath);
 
1950
        if (!includeImplicit)
 
1951
        {
 
1952
                while (result && linitial_oid(result) != firstExplicitNamespace)
 
1953
                        result = list_delete_first(result);
 
1954
        }
 
1955
 
 
1956
        return result;
 
1957
}
 
1958
 
 
1959
/*
 
1960
 * Export the FooIsVisible functions as SQL-callable functions.
 
1961
 */
 
1962
 
 
1963
Datum
 
1964
pg_table_is_visible(PG_FUNCTION_ARGS)
 
1965
{
 
1966
        Oid                     oid = PG_GETARG_OID(0);
 
1967
 
 
1968
        PG_RETURN_BOOL(RelationIsVisible(oid));
 
1969
}
 
1970
 
 
1971
Datum
 
1972
pg_type_is_visible(PG_FUNCTION_ARGS)
 
1973
{
 
1974
        Oid                     oid = PG_GETARG_OID(0);
 
1975
 
 
1976
        PG_RETURN_BOOL(TypeIsVisible(oid));
 
1977
}
 
1978
 
 
1979
Datum
 
1980
pg_function_is_visible(PG_FUNCTION_ARGS)
 
1981
{
 
1982
        Oid                     oid = PG_GETARG_OID(0);
 
1983
 
 
1984
        PG_RETURN_BOOL(FunctionIsVisible(oid));
 
1985
}
 
1986
 
 
1987
Datum
 
1988
pg_operator_is_visible(PG_FUNCTION_ARGS)
 
1989
{
 
1990
        Oid                     oid = PG_GETARG_OID(0);
 
1991
 
 
1992
        PG_RETURN_BOOL(OperatorIsVisible(oid));
 
1993
}
 
1994
 
 
1995
Datum
 
1996
pg_opclass_is_visible(PG_FUNCTION_ARGS)
 
1997
{
 
1998
        Oid                     oid = PG_GETARG_OID(0);
 
1999
 
 
2000
        PG_RETURN_BOOL(OpclassIsVisible(oid));
 
2001
}
 
2002
 
 
2003
Datum
 
2004
pg_conversion_is_visible(PG_FUNCTION_ARGS)
 
2005
{
 
2006
        Oid                     oid = PG_GETARG_OID(0);
 
2007
 
 
2008
        PG_RETURN_BOOL(ConversionIsVisible(oid));
 
2009
}