Age Owner TLA Line data Source code
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-2023, PostgreSQL Global Development Group
13 : * Portions Copyright (c) 1994, Regents of the University of California
14 : *
15 : * IDENTIFICATION
16 : * src/backend/catalog/namespace.c
17 : *
18 : *-------------------------------------------------------------------------
19 : */
20 : #include "postgres.h"
21 :
22 : #include "access/htup_details.h"
23 : #include "access/parallel.h"
24 : #include "access/xact.h"
25 : #include "access/xlog.h"
26 : #include "catalog/dependency.h"
27 : #include "catalog/objectaccess.h"
28 : #include "catalog/pg_authid.h"
29 : #include "catalog/pg_collation.h"
30 : #include "catalog/pg_conversion.h"
31 : #include "catalog/pg_database.h"
32 : #include "catalog/pg_namespace.h"
33 : #include "catalog/pg_opclass.h"
34 : #include "catalog/pg_operator.h"
35 : #include "catalog/pg_opfamily.h"
36 : #include "catalog/pg_proc.h"
37 : #include "catalog/pg_statistic_ext.h"
38 : #include "catalog/pg_ts_config.h"
39 : #include "catalog/pg_ts_dict.h"
40 : #include "catalog/pg_ts_parser.h"
41 : #include "catalog/pg_ts_template.h"
42 : #include "catalog/pg_type.h"
43 : #include "commands/dbcommands.h"
44 : #include "funcapi.h"
45 : #include "mb/pg_wchar.h"
46 : #include "miscadmin.h"
47 : #include "nodes/makefuncs.h"
48 : #include "parser/parse_func.h"
49 : #include "storage/ipc.h"
50 : #include "storage/lmgr.h"
51 : #include "storage/sinvaladt.h"
52 : #include "utils/acl.h"
53 : #include "utils/builtins.h"
54 : #include "utils/catcache.h"
55 : #include "utils/guc_hooks.h"
56 : #include "utils/inval.h"
57 : #include "utils/lsyscache.h"
58 : #include "utils/memutils.h"
59 : #include "utils/snapmgr.h"
60 : #include "utils/syscache.h"
61 : #include "utils/varlena.h"
62 :
63 :
64 : /*
65 : * The namespace search path is a possibly-empty list of namespace OIDs.
66 : * In addition to the explicit list, implicitly-searched namespaces
67 : * may be included:
68 : *
69 : * 1. If a TEMP table namespace has been initialized in this session, it
70 : * is implicitly searched first. (The only time this doesn't happen is
71 : * when we are obeying an override search path spec that says not to use the
72 : * temp namespace, or the temp namespace is included in the explicit list.)
73 : *
74 : * 2. The system catalog namespace is always searched. If the system
75 : * namespace is present in the explicit path then it will be searched in
76 : * the specified order; otherwise it will be searched after TEMP tables and
77 : * *before* the explicit list. (It might seem that the system namespace
78 : * should be implicitly last, but this behavior appears to be required by
79 : * SQL99. Also, this provides a way to search the system namespace first
80 : * without thereby making it the default creation target namespace.)
81 : *
82 : * For security reasons, searches using the search path will ignore the temp
83 : * namespace when searching for any object type other than relations and
84 : * types. (We must allow types since temp tables have rowtypes.)
85 : *
86 : * The default creation target namespace is always the first element of the
87 : * explicit list. If the explicit list is empty, there is no default target.
88 : *
89 : * The textual specification of search_path can include "$user" to refer to
90 : * the namespace named the same as the current user, if any. (This is just
91 : * ignored if there is no such namespace.) Also, it can include "pg_temp"
92 : * to refer to the current backend's temp namespace. This is usually also
93 : * ignorable if the temp namespace hasn't been set up, but there's a special
94 : * case: if "pg_temp" appears first then it should be the default creation
95 : * target. We kluge this case a little bit so that the temp namespace isn't
96 : * set up until the first attempt to create something in it. (The reason for
97 : * klugery is that we can't create the temp namespace outside a transaction,
98 : * but initial GUC processing of search_path happens outside a transaction.)
99 : * activeTempCreationPending is true if "pg_temp" appears first in the string
100 : * but is not reflected in activeCreationNamespace because the namespace isn't
101 : * set up yet.
102 : *
103 : * In bootstrap mode, the search path is set equal to "pg_catalog", so that
104 : * the system namespace is the only one searched or inserted into.
105 : * initdb is also careful to set search_path to "pg_catalog" for its
106 : * post-bootstrap standalone backend runs. Otherwise the default search
107 : * path is determined by GUC. The factory default path contains the PUBLIC
108 : * namespace (if it exists), preceded by the user's personal namespace
109 : * (if one exists).
110 : *
111 : * We support a stack of "override" search path settings for use within
112 : * specific sections of backend code. namespace_search_path is ignored
113 : * whenever the override stack is nonempty. activeSearchPath is always
114 : * the actually active path; it points either to the search list of the
115 : * topmost stack entry, or to baseSearchPath which is the list derived
116 : * from namespace_search_path.
117 : *
118 : * If baseSearchPathValid is false, then baseSearchPath (and other
119 : * derived variables) need to be recomputed from namespace_search_path.
120 : * We mark it invalid upon an assignment to namespace_search_path or receipt
121 : * of a syscache invalidation event for pg_namespace. The recomputation
122 : * is done during the next non-overridden lookup attempt. Note that an
123 : * override spec is never subject to recomputation.
124 : *
125 : * Any namespaces mentioned in namespace_search_path that are not readable
126 : * by the current user ID are simply left out of baseSearchPath; so
127 : * we have to be willing to recompute the path when current userid changes.
128 : * namespaceUser is the userid the path has been computed for.
129 : *
130 : * Note: all data pointed to by these List variables is in TopMemoryContext.
131 : *
132 : * activePathGeneration is incremented whenever the effective values of
133 : * activeSearchPath/activeCreationNamespace/activeTempCreationPending change.
134 : * This can be used to quickly detect whether any change has happened since
135 : * a previous examination of the search path state.
136 : */
137 :
138 : /* These variables define the actually active state: */
139 :
140 : static List *activeSearchPath = NIL;
141 :
142 : /* default place to create stuff; if InvalidOid, no default */
143 : static Oid activeCreationNamespace = InvalidOid;
144 :
145 : /* if true, activeCreationNamespace is wrong, it should be temp namespace */
146 : static bool activeTempCreationPending = false;
147 :
148 : /* current generation counter; make sure this is never zero */
149 : static uint64 activePathGeneration = 1;
150 :
151 : /* These variables are the values last derived from namespace_search_path: */
152 :
153 : static List *baseSearchPath = NIL;
154 :
155 : static Oid baseCreationNamespace = InvalidOid;
156 :
157 : static bool baseTempCreationPending = false;
158 :
159 : static Oid namespaceUser = InvalidOid;
160 :
161 : /* The above four values are valid only if baseSearchPathValid */
162 : static bool baseSearchPathValid = true;
163 :
164 : /* Override requests are remembered in a stack of OverrideStackEntry structs */
165 :
166 : typedef struct
167 : {
168 : List *searchPath; /* the desired search path */
169 : Oid creationNamespace; /* the desired creation namespace */
170 : int nestLevel; /* subtransaction nesting level */
171 : } OverrideStackEntry;
172 :
173 : static List *overrideStack = NIL;
174 :
175 : /*
176 : * myTempNamespace is InvalidOid until and unless a TEMP namespace is set up
177 : * in a particular backend session (this happens when a CREATE TEMP TABLE
178 : * command is first executed). Thereafter it's the OID of the temp namespace.
179 : *
180 : * myTempToastNamespace is the OID of the namespace for my temp tables' toast
181 : * tables. It is set when myTempNamespace is, and is InvalidOid before that.
182 : *
183 : * myTempNamespaceSubID shows whether we've created the TEMP namespace in the
184 : * current subtransaction. The flag propagates up the subtransaction tree,
185 : * so the main transaction will correctly recognize the flag if all
186 : * intermediate subtransactions commit. When it is InvalidSubTransactionId,
187 : * we either haven't made the TEMP namespace yet, or have successfully
188 : * committed its creation, depending on whether myTempNamespace is valid.
189 : */
190 : static Oid myTempNamespace = InvalidOid;
191 :
192 : static Oid myTempToastNamespace = InvalidOid;
193 :
194 : static SubTransactionId myTempNamespaceSubID = InvalidSubTransactionId;
195 :
196 : /*
197 : * This is the user's textual search path specification --- it's the value
198 : * of the GUC variable 'search_path'.
199 : */
200 : char *namespace_search_path = NULL;
201 :
202 :
203 : /* Local functions */
204 : static void recomputeNamespacePath(void);
205 : static void AccessTempTableNamespace(bool force);
206 : static void InitTempTableNamespace(void);
207 : static void RemoveTempRelations(Oid tempNamespaceId);
208 : static void RemoveTempRelationsCallback(int code, Datum arg);
209 : static void NamespaceCallback(Datum arg, int cacheid, uint32 hashvalue);
210 : static bool MatchNamedCall(HeapTuple proctup, int nargs, List *argnames,
211 : bool include_out_arguments, int pronargs,
212 : int **argnumbers);
213 :
214 :
215 : /*
216 : * RangeVarGetRelidExtended
217 : * Given a RangeVar describing an existing relation,
218 : * select the proper namespace and look up the relation OID.
219 : *
220 : * If the schema or relation is not found, return InvalidOid if flags contains
221 : * RVR_MISSING_OK, otherwise raise an error.
222 : *
223 : * If flags contains RVR_NOWAIT, throw an error if we'd have to wait for a
224 : * lock.
225 : *
226 : * If flags contains RVR_SKIP_LOCKED, return InvalidOid if we'd have to wait
227 : * for a lock.
228 : *
229 : * flags cannot contain both RVR_NOWAIT and RVR_SKIP_LOCKED.
230 : *
231 : * Note that if RVR_MISSING_OK and RVR_SKIP_LOCKED are both specified, a
232 : * return value of InvalidOid could either mean the relation is missing or it
233 : * could not be locked.
234 : *
235 : * Callback allows caller to check permissions or acquire additional locks
236 : * prior to grabbing the relation lock.
237 : */
238 : Oid
4148 rhaas 239 GIC 528885 : RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode,
1836 andres 240 ECB : uint32 flags,
241 : RangeVarGetRelidCallback callback, void *callback_arg)
242 : {
243 : uint64 inval_count;
244 : Oid relId;
4293 rhaas 245 GIC 528885 : Oid oldRelId = InvalidOid;
4293 rhaas 246 CBC 528885 : bool retry = false;
1836 andres 247 528885 : bool missing_ok = (flags & RVR_MISSING_OK) != 0;
7684 tgl 248 ECB :
249 : /* verify that flags do no conflict */
1836 andres 250 GIC 528885 : Assert(!((flags & RVR_NOWAIT) && (flags & RVR_SKIP_LOCKED)));
1836 andres 251 ECB :
252 : /*
253 : * We check the catalog name and then ignore it.
254 : */
7684 tgl 255 GIC 528885 : if (relation->catalogname)
7684 tgl 256 ECB : {
7226 peter_e 257 GIC 39 : if (strcmp(relation->catalogname, get_database_name(MyDatabaseId)) != 0)
7202 tgl 258 CBC 39 : ereport(ERROR,
7202 tgl 259 ECB : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
260 : errmsg("cross-database references are not implemented: \"%s.%s.%s\"",
261 : relation->catalogname, relation->schemaname,
262 : relation->relname)));
263 : }
264 :
265 : /*
266 : * DDL operations can change the results of a name lookup. Since all such
267 : * operations will generate invalidation messages, we keep track of
268 : * whether any such messages show up while we're performing the operation,
269 : * and retry until either (1) no more invalidation messages show up or (2)
270 : * the answer doesn't change.
271 : *
272 : * But if lockmode = NoLock, then we assume that either the caller is OK
273 : * with the answer changing under them, or that they already hold some
274 : * appropriate lock, and therefore return the first answer we get without
275 : * checking for invalidation messages. Also, if the requested lock is
276 : * already held, LockRelationOid will not AcceptInvalidationMessages, so
277 : * we may fail to notice a change. We could protect against that case by
278 : * calling AcceptInvalidationMessages() before beginning this loop, but
279 : * that would add a significant amount overhead, so for now we don't.
280 : */
281 : for (;;)
282 : {
283 : /*
284 : * Remember this value, so that, after looking up the relation name
285 : * and locking its OID, we can check whether any invalidation messages
286 : * have been processed that might require a do-over.
287 : */
4293 rhaas 288 GIC 530398 : inval_count = SharedInvalidMessageCounter;
4293 rhaas 289 ECB :
290 : /*
291 : * Some non-default relpersistence value may have been specified. The
292 : * parser never generates such a RangeVar in simple DML, but it can
293 : * happen in contexts such as "CREATE TEMP TABLE foo (f1 int PRIMARY
294 : * KEY)". Such a command will generate an added CREATE INDEX
295 : * operation, which must be careful to find the temp table, even when
296 : * pg_temp is not first in the search path.
297 : */
4293 rhaas 298 GIC 530398 : if (relation->relpersistence == RELPERSISTENCE_TEMP)
4293 rhaas 299 ECB : {
4218 rhaas 300 GIC 503 : if (!OidIsValid(myTempNamespace))
2118 tgl 301 LBC 0 : relId = InvalidOid; /* this probably can't happen? */
4218 rhaas 302 EUB : else
303 : {
4218 rhaas 304 GIC 503 : if (relation->schemaname)
4218 rhaas 305 ECB : {
306 : Oid namespaceId;
307 :
3725 bruce 308 GIC 12 : namespaceId = LookupExplicitNamespace(relation->schemaname, missing_ok);
3602 bruce 309 ECB :
310 : /*
311 : * For missing_ok, allow a non-existent schema name to
312 : * return InvalidOid.
313 : */
4218 rhaas 314 GIC 12 : if (namespaceId != myTempNamespace)
4218 rhaas 315 LBC 0 : ereport(ERROR,
4218 rhaas 316 EUB : (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
317 : errmsg("temporary tables cannot specify a schema name")));
318 : }
319 :
4293 rhaas 320 GIC 503 : relId = get_relname_relid(relation->relname, myTempNamespace);
4218 rhaas 321 ECB : }
322 : }
4293 rhaas 323 GIC 529895 : else if (relation->schemaname)
4293 rhaas 324 ECB : {
325 : Oid namespaceId;
326 :
327 : /* use exact schema given */
3725 bruce 328 GIC 109416 : namespaceId = LookupExplicitNamespace(relation->schemaname, missing_ok);
3725 bruce 329 CBC 109364 : if (missing_ok && !OidIsValid(namespaceId))
330 42 : relId = InvalidOid;
3725 bruce 331 ECB : else
3725 bruce 332 GIC 109322 : relId = get_relname_relid(relation->relname, namespaceId);
4293 rhaas 333 ECB : }
334 : else
335 : {
336 : /* search the namespace path */
4293 rhaas 337 GIC 420479 : relId = RelnameGetRelid(relation->relname);
4293 rhaas 338 ECB : }
339 :
340 : /*
341 : * Invoke caller-supplied callback, if any.
342 : *
343 : * This callback is a good place to check permissions: we haven't
344 : * taken the table lock yet (and it's really best to check permissions
345 : * before locking anything!), but we've gotten far enough to know what
346 : * OID we think we should lock. Of course, concurrent DDL might
347 : * change things while we're waiting for the lock, but in that case
348 : * the callback will be invoked again for the new OID.
349 : */
4148 rhaas 350 GIC 530346 : if (callback)
4148 rhaas 351 CBC 68411 : callback(relation, relId, oldRelId, callback_arg);
4148 rhaas 352 ECB :
353 : /*
354 : * If no lock requested, we assume the caller knows what they're
355 : * doing. They should have already acquired a heavyweight lock on
356 : * this relation earlier in the processing of this same statement, so
357 : * it wouldn't be appropriate to AcceptInvalidationMessages() here, as
358 : * that might pull the rug out from under them.
359 : */
4293 rhaas 360 GIC 530183 : if (lockmode == NoLock)
4293 rhaas 361 CBC 101858 : break;
4293 rhaas 362 ECB :
363 : /*
364 : * If, upon retry, we get back the same OID we did last time, then the
365 : * invalidation messages we processed did not change the final answer.
366 : * So we're done.
367 : *
368 : * If we got a different OID, we've locked the relation that used to
369 : * have this name rather than the one that does now. So release the
370 : * lock.
371 : */
4166 rhaas 372 GIC 428325 : if (retry)
4166 rhaas 373 ECB : {
4166 rhaas 374 GIC 1552 : if (relId == oldRelId)
4166 rhaas 375 CBC 1546 : break;
376 6 : if (OidIsValid(oldRelId))
377 6 : UnlockRelationOid(oldRelId, lockmode);
4166 rhaas 378 ECB : }
379 :
380 : /*
381 : * Lock relation. This will also accept any pending invalidation
382 : * messages. If we got back InvalidOid, indicating not found, then
383 : * there's nothing to lock, but we accept invalidation messages
384 : * anyway, to flush any negative catcache entries that may be
385 : * lingering.
386 : */
4293 rhaas 387 GIC 426779 : if (!OidIsValid(relId))
4293 rhaas 388 CBC 948 : AcceptInvalidationMessages();
1836 andres 389 425831 : else if (!(flags & (RVR_NOWAIT | RVR_SKIP_LOCKED)))
4293 rhaas 390 425514 : LockRelationOid(relId, lockmode);
391 317 : else if (!ConditionalLockRelationOid(relId, lockmode))
4293 rhaas 392 ECB : {
1836 andres 393 GIC 8 : int elevel = (flags & RVR_SKIP_LOCKED) ? DEBUG1 : ERROR;
1836 andres 394 ECB :
4293 rhaas 395 GIC 8 : if (relation->schemaname)
1836 andres 396 LBC 0 : ereport(elevel,
4293 rhaas 397 EUB : (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
398 : errmsg("could not obtain lock on relation \"%s.%s\"",
399 : relation->schemaname, relation->relname)));
400 : else
1836 andres 401 GIC 8 : ereport(elevel,
4293 rhaas 402 ECB : (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
403 : errmsg("could not obtain lock on relation \"%s\"",
404 : relation->relname)));
405 :
1836 andres 406 GIC 4 : return InvalidOid;
4293 rhaas 407 ECB : }
408 :
409 : /*
410 : * If no invalidation message were processed, we're done!
411 : */
4293 rhaas 412 GIC 426764 : if (inval_count == SharedInvalidMessageCounter)
4293 rhaas 413 CBC 425212 : break;
4293 rhaas 414 ECB :
415 : /*
416 : * Something may have changed. Let's repeat the name lookup, to make
417 : * sure this name still references the same relation it did
418 : * previously.
419 : */
4293 rhaas 420 GIC 1552 : retry = true;
4293 rhaas 421 CBC 1552 : oldRelId = relId;
7684 tgl 422 ECB : }
423 :
1836 andres 424 GIC 528616 : if (!OidIsValid(relId))
7684 tgl 425 ECB : {
1836 andres 426 GIC 986 : int elevel = missing_ok ? DEBUG1 : ERROR;
1836 andres 427 ECB :
7684 tgl 428 GIC 986 : if (relation->schemaname)
1836 andres 429 CBC 130 : ereport(elevel,
7202 tgl 430 ECB : (errcode(ERRCODE_UNDEFINED_TABLE),
431 : errmsg("relation \"%s.%s\" does not exist",
432 : relation->schemaname, relation->relname)));
433 : else
1836 andres 434 GIC 856 : ereport(elevel,
7202 tgl 435 ECB : (errcode(ERRCODE_UNDEFINED_TABLE),
436 : errmsg("relation \"%s\" does not exist",
437 : relation->relname)));
438 : }
7684 tgl 439 GIC 528394 : return relId;
7684 tgl 440 ECB : }
441 :
442 : /*
443 : * RangeVarGetCreationNamespace
444 : * Given a RangeVar describing a to-be-created relation,
445 : * choose which namespace to create it in.
446 : *
447 : * Note: calling this may result in a CommandCounterIncrement operation.
448 : * That will happen on the first request for a temp table in any particular
449 : * backend run; we will need to either create or clean out the temp schema.
450 : */
451 : Oid
7684 tgl 452 GIC 126763 : RangeVarGetCreationNamespace(const RangeVar *newRelation)
7684 tgl 453 ECB : {
454 : Oid namespaceId;
455 :
456 : /*
457 : * We check the catalog name and then ignore it.
458 : */
7684 tgl 459 GIC 126763 : if (newRelation->catalogname)
7684 tgl 460 ECB : {
7226 peter_e 461 UIC 0 : if (strcmp(newRelation->catalogname, get_database_name(MyDatabaseId)) != 0)
7202 tgl 462 UBC 0 : ereport(ERROR,
7202 tgl 463 EUB : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
464 : errmsg("cross-database references are not implemented: \"%s.%s.%s\"",
465 : newRelation->catalogname, newRelation->schemaname,
466 : newRelation->relname)));
467 : }
468 :
7684 tgl 469 GIC 126763 : if (newRelation->schemaname)
7684 tgl 470 ECB : {
471 : /* check for pg_temp alias */
5833 tgl 472 GIC 19070 : if (strcmp(newRelation->schemaname, "pg_temp") == 0)
5833 tgl 473 ECB : {
474 : /* Initialize temp namespace */
1542 michael 475 GIC 37 : AccessTempTableNamespace(false);
5833 tgl 476 CBC 37 : return myTempNamespace;
5833 tgl 477 ECB : }
478 : /* use exact schema given */
4630 rhaas 479 GIC 19033 : namespaceId = get_namespace_oid(newRelation->schemaname, false);
7559 tgl 480 ECB : /* we do not check for USAGE rights here! */
481 : }
4298 rhaas 482 GIC 107693 : else if (newRelation->relpersistence == RELPERSISTENCE_TEMP)
4298 rhaas 483 ECB : {
484 : /* Initialize temp namespace */
1542 michael 485 GIC 2921 : AccessTempTableNamespace(false);
4298 rhaas 486 CBC 2921 : return myTempNamespace;
4298 rhaas 487 ECB : }
488 : else
489 : {
490 : /* use the default creation namespace */
7650 tgl 491 GIC 104772 : recomputeNamespacePath();
5833 tgl 492 CBC 104772 : if (activeTempCreationPending)
5833 tgl 493 ECB : {
494 : /* Need to initialize temp namespace */
1542 michael 495 UIC 0 : AccessTempTableNamespace(true);
5833 tgl 496 UBC 0 : return myTempNamespace;
5833 tgl 497 EUB : }
5861 tgl 498 GIC 104772 : namespaceId = activeCreationNamespace;
7664 tgl 499 CBC 104772 : if (!OidIsValid(namespaceId))
7202 tgl 500 LBC 0 : ereport(ERROR,
7202 tgl 501 EUB : (errcode(ERRCODE_UNDEFINED_SCHEMA),
502 : errmsg("no schema has been selected to create in")));
503 : }
504 :
505 : /* Note: callers will check for CREATE rights when appropriate */
506 :
7684 tgl 507 GIC 123805 : return namespaceId;
7684 tgl 508 ECB : }
509 :
510 : /*
511 : * RangeVarGetAndCheckCreationNamespace
512 : *
513 : * This function returns the OID of the namespace in which a new relation
514 : * with a given name should be created. If the user does not have CREATE
515 : * permission on the target namespace, this function will instead signal
516 : * an ERROR.
517 : *
518 : * If non-NULL, *existing_relation_id is set to the OID of any existing relation
519 : * with the same name which already exists in that namespace, or to InvalidOid
520 : * if no such relation exists.
521 : *
522 : * If lockmode != NoLock, the specified lock mode is acquired on the existing
523 : * relation, if any, provided that the current user owns the target relation.
524 : * However, if lockmode != NoLock and the user does not own the target
525 : * relation, we throw an ERROR, as we must not try to lock relations the
526 : * user does not have permissions on.
527 : *
528 : * As a side effect, this function acquires AccessShareLock on the target
529 : * namespace. Without this, the namespace could be dropped before our
530 : * transaction commits, leaving behind relations with relnamespace pointing
531 : * to a no-longer-existent namespace.
532 : *
533 : * As a further side-effect, if the selected namespace is a temporary namespace,
534 : * we mark the RangeVar as RELPERSISTENCE_TEMP.
535 : */
536 : Oid
4101 rhaas 537 GIC 124629 : RangeVarGetAndCheckCreationNamespace(RangeVar *relation,
4101 rhaas 538 ECB : LOCKMODE lockmode,
539 : Oid *existing_relation_id)
540 : {
541 : uint64 inval_count;
542 : Oid relid;
4101 rhaas 543 GIC 124629 : Oid oldrelid = InvalidOid;
4101 rhaas 544 ECB : Oid nspid;
4101 rhaas 545 GIC 124629 : Oid oldnspid = InvalidOid;
4101 rhaas 546 CBC 124629 : bool retry = false;
4367 rhaas 547 ECB :
548 : /*
549 : * We check the catalog name and then ignore it.
550 : */
4101 rhaas 551 GIC 124629 : if (relation->catalogname)
4101 rhaas 552 ECB : {
4101 rhaas 553 UIC 0 : if (strcmp(relation->catalogname, get_database_name(MyDatabaseId)) != 0)
4101 rhaas 554 UBC 0 : ereport(ERROR,
4101 rhaas 555 EUB : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
556 : errmsg("cross-database references are not implemented: \"%s.%s.%s\"",
557 : relation->catalogname, relation->schemaname,
558 : relation->relname)));
559 : }
560 :
561 : /*
562 : * As in RangeVarGetRelidExtended(), we guard against concurrent DDL
563 : * operations by tracking whether any invalidation messages are processed
564 : * while we're doing the name lookups and acquiring locks. See comments
565 : * in that function for a more detailed explanation of this logic.
566 : */
567 : for (;;)
4367 rhaas 568 GIC 792 : {
4367 rhaas 569 ECB : AclResult aclresult;
570 :
4101 rhaas 571 GIC 125421 : inval_count = SharedInvalidMessageCounter;
4101 rhaas 572 ECB :
573 : /* Look up creation namespace and check for existing relation. */
4101 rhaas 574 GIC 125421 : nspid = RangeVarGetCreationNamespace(relation);
4101 rhaas 575 CBC 125421 : Assert(OidIsValid(nspid));
576 125421 : if (existing_relation_id != NULL)
577 61934 : relid = get_relname_relid(relation->relname, nspid);
4101 rhaas 578 ECB : else
4101 rhaas 579 GIC 63487 : relid = InvalidOid;
4101 rhaas 580 ECB :
581 : /*
582 : * In bootstrap processing mode, we don't bother with permissions or
583 : * locking. Permissions might not be working yet, and locking is
584 : * unnecessary.
585 : */
4101 rhaas 586 GIC 125421 : if (IsBootstrapProcessingMode())
4101 rhaas 587 LBC 0 : break;
4101 rhaas 588 EUB :
589 : /* Check namespace permissions. */
147 peter 590 GNC 125421 : aclresult = object_aclcheck(NamespaceRelationId, nspid, GetUserId(), ACL_CREATE);
4367 rhaas 591 CBC 125421 : if (aclresult != ACLCHECK_OK)
1954 peter_e 592 LBC 0 : aclcheck_error(aclresult, OBJECT_SCHEMA,
4101 rhaas 593 UBC 0 : get_namespace_name(nspid));
4101 rhaas 594 EUB :
4101 rhaas 595 GIC 125421 : if (retry)
4101 rhaas 596 ECB : {
597 : /* If nothing changed, we're done. */
4101 rhaas 598 GIC 792 : if (relid == oldrelid && nspid == oldnspid)
4101 rhaas 599 CBC 792 : break;
4101 rhaas 600 ECB : /* If creation namespace has changed, give up old lock. */
4101 rhaas 601 UIC 0 : if (nspid != oldnspid)
4101 rhaas 602 UBC 0 : UnlockDatabaseObject(NamespaceRelationId, oldnspid, 0,
4101 rhaas 603 EUB : AccessShareLock);
604 : /* If name points to something different, give up old lock. */
4101 rhaas 605 UIC 0 : if (relid != oldrelid && OidIsValid(oldrelid) && lockmode != NoLock)
4101 rhaas 606 UBC 0 : UnlockRelationOid(oldrelid, lockmode);
4101 rhaas 607 EUB : }
608 :
609 : /* Lock namespace. */
4101 rhaas 610 GIC 124629 : if (nspid != oldnspid)
4101 rhaas 611 CBC 124629 : LockDatabaseObject(NamespaceRelationId, nspid, 0, AccessShareLock);
4101 rhaas 612 ECB :
613 : /* Lock relation, if required if and we have permission. */
4101 rhaas 614 GIC 124629 : if (lockmode != NoLock && OidIsValid(relid))
4101 rhaas 615 ECB : {
147 peter 616 GNC 112 : if (!object_ownercheck(RelationRelationId, relid, GetUserId()))
1954 peter_e 617 LBC 0 : aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(get_rel_relkind(relid)),
4101 rhaas 618 UBC 0 : relation->relname);
4101 rhaas 619 GBC 112 : if (relid != oldrelid)
4101 rhaas 620 CBC 112 : LockRelationOid(relid, lockmode);
4101 rhaas 621 ECB : }
622 :
623 : /* If no invalidation message were processed, we're done! */
4101 rhaas 624 GIC 124629 : if (inval_count == SharedInvalidMessageCounter)
4101 rhaas 625 CBC 123837 : break;
4101 rhaas 626 ECB :
627 : /* Something may have changed, so recheck our work. */
4101 rhaas 628 GIC 792 : retry = true;
4101 rhaas 629 CBC 792 : oldrelid = relid;
630 792 : oldnspid = nspid;
4367 rhaas 631 ECB : }
632 :
4101 rhaas 633 GIC 124629 : RangeVarAdjustRelationPersistence(relation, nspid);
4101 rhaas 634 CBC 124617 : if (existing_relation_id != NULL)
635 61314 : *existing_relation_id = relid;
636 124617 : return nspid;
4367 rhaas 637 ECB : }
638 :
639 : /*
640 : * Adjust the relpersistence for an about-to-be-created relation based on the
641 : * creation namespace, and throw an error for invalid combinations.
642 : */
643 : void
4298 rhaas 644 GIC 125364 : RangeVarAdjustRelationPersistence(RangeVar *newRelation, Oid nspid)
4298 rhaas 645 ECB : {
4298 rhaas 646 GIC 125364 : switch (newRelation->relpersistence)
4298 rhaas 647 ECB : {
4298 rhaas 648 GIC 2705 : case RELPERSISTENCE_TEMP:
3149 bruce 649 CBC 2705 : if (!isTempOrTempToastNamespace(nspid))
4298 rhaas 650 ECB : {
4298 rhaas 651 GIC 9 : if (isAnyTempNamespace(nspid))
4298 rhaas 652 LBC 0 : ereport(ERROR,
4298 rhaas 653 EUB : (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
654 : errmsg("cannot create relations in temporary schemas of other sessions")));
655 : else
4298 rhaas 656 GIC 9 : ereport(ERROR,
4298 rhaas 657 ECB : (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
658 : errmsg("cannot create temporary relation in non-temporary schema")));
659 : }
4298 rhaas 660 GIC 2696 : break;
4298 rhaas 661 CBC 122501 : case RELPERSISTENCE_PERMANENT:
3149 bruce 662 122501 : if (isTempOrTempToastNamespace(nspid))
4298 rhaas 663 13 : newRelation->relpersistence = RELPERSISTENCE_TEMP;
664 122488 : else if (isAnyTempNamespace(nspid))
4298 rhaas 665 LBC 0 : ereport(ERROR,
4298 rhaas 666 EUB : (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
667 : errmsg("cannot create relations in temporary schemas of other sessions")));
4298 rhaas 668 GIC 122501 : break;
4298 rhaas 669 CBC 158 : default:
4279 670 158 : if (isAnyTempNamespace(nspid))
671 3 : ereport(ERROR,
4279 rhaas 672 ECB : (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
673 : errmsg("only temporary relations may be created in temporary schemas")));
674 : }
4298 rhaas 675 GIC 125352 : }
4298 rhaas 676 ECB :
677 : /*
678 : * RelnameGetRelid
679 : * Try to resolve an unqualified relation name.
680 : * Returns OID if relation found in search path, else InvalidOid.
681 : */
682 : Oid
7684 tgl 683 GIC 420521 : RelnameGetRelid(const char *relname)
7684 tgl 684 ECB : {
685 : Oid relid;
686 : ListCell *l;
687 :
7650 tgl 688 GIC 420521 : recomputeNamespacePath();
7650 tgl 689 ECB :
5861 tgl 690 GIC 592021 : foreach(l, activeSearchPath)
7679 tgl 691 ECB : {
6892 neilc 692 GIC 591145 : Oid namespaceId = lfirst_oid(l);
7679 tgl 693 ECB :
7679 tgl 694 GIC 591145 : relid = get_relname_relid(relname, namespaceId);
7679 tgl 695 CBC 591145 : if (OidIsValid(relid))
696 419645 : return relid;
7679 tgl 697 ECB : }
698 :
699 : /* Not found in path */
7679 tgl 700 GIC 876 : return InvalidOid;
7684 tgl 701 ECB : }
702 :
703 :
704 : /*
705 : * RelationIsVisible
706 : * Determine whether a relation (identified by OID) is visible in the
707 : * current search path. Visible means "would be found by searching
708 : * for the unqualified relation name".
709 : */
710 : bool
7648 tgl 711 GIC 120449 : RelationIsVisible(Oid relid)
7648 tgl 712 ECB : {
713 : HeapTuple reltup;
714 : Form_pg_class relform;
715 : Oid relnamespace;
716 : bool visible;
717 :
4802 rhaas 718 GIC 120449 : reltup = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
7648 tgl 719 CBC 120449 : if (!HeapTupleIsValid(reltup))
7202 tgl 720 LBC 0 : elog(ERROR, "cache lookup failed for relation %u", relid);
7648 tgl 721 GBC 120449 : relform = (Form_pg_class) GETSTRUCT(reltup);
7648 tgl 722 ECB :
7632 tgl 723 GIC 120449 : recomputeNamespacePath();
7632 tgl 724 ECB :
725 : /*
726 : * Quick check: if it ain't in the path at all, it ain't visible. Items in
727 : * the system namespace are surely in the path and so we needn't even do
728 : * list_member_oid() for them.
729 : */
7648 tgl 730 GIC 120449 : relnamespace = relform->relnamespace;
7632 tgl 731 CBC 120449 : if (relnamespace != PG_CATALOG_NAMESPACE &&
5861 732 100430 : !list_member_oid(activeSearchPath, relnamespace))
7648 733 40098 : visible = false;
7648 tgl 734 ECB : else
735 : {
736 : /*
737 : * If it is in the path, it might still not be visible; it could be
738 : * hidden by another relation of the same name earlier in the path. So
739 : * we must do a slow check for conflicting relations.
740 : */
7648 tgl 741 GIC 80351 : char *relname = NameStr(relform->relname);
6394 tgl 742 ECB : ListCell *l;
743 :
6394 tgl 744 GIC 80351 : visible = false;
5861 tgl 745 CBC 195724 : foreach(l, activeSearchPath)
6394 tgl 746 ECB : {
6394 tgl 747 GIC 195724 : Oid namespaceId = lfirst_oid(l);
6394 tgl 748 ECB :
6394 tgl 749 GIC 195724 : if (namespaceId == relnamespace)
6394 tgl 750 ECB : {
751 : /* Found it first in path */
6394 tgl 752 GIC 80327 : visible = true;
6394 tgl 753 CBC 80327 : break;
6394 tgl 754 ECB : }
6394 tgl 755 GIC 115397 : if (OidIsValid(get_relname_relid(relname, namespaceId)))
6394 tgl 756 ECB : {
757 : /* Found something else first in path */
6394 tgl 758 GIC 24 : break;
6394 tgl 759 ECB : }
760 : }
761 : }
762 :
7648 tgl 763 GIC 120449 : ReleaseSysCache(reltup);
7648 tgl 764 ECB :
7648 tgl 765 GIC 120449 : return visible;
7648 tgl 766 ECB : }
767 :
768 :
769 : /*
770 : * TypenameGetTypid
771 : * Wrapper for binary compatibility.
772 : */
773 : Oid
1343 noah 774 UIC 0 : TypenameGetTypid(const char *typname)
1343 noah 775 EUB : {
1343 noah 776 UIC 0 : return TypenameGetTypidExtended(typname, true);
1343 noah 777 EUB : }
778 :
779 : /*
780 : * TypenameGetTypidExtended
781 : * Try to resolve an unqualified datatype name.
782 : * Returns OID if type found in search path, else InvalidOid.
783 : *
784 : * This is essentially the same as RelnameGetRelid.
785 : */
786 : Oid
1343 noah 787 GIC 450727 : TypenameGetTypidExtended(const char *typname, bool temp_ok)
7680 tgl 788 ECB : {
789 : Oid typid;
790 : ListCell *l;
791 :
7650 tgl 792 GIC 450727 : recomputeNamespacePath();
7650 tgl 793 ECB :
5861 tgl 794 GIC 746667 : foreach(l, activeSearchPath)
7679 tgl 795 ECB : {
6892 neilc 796 GIC 712147 : Oid namespaceId = lfirst_oid(l);
7679 tgl 797 ECB :
1343 noah 798 GIC 712147 : if (!temp_ok && namespaceId == myTempNamespace)
1343 noah 799 CBC 2926 : continue; /* do not look in temp namespace */
1343 noah 800 ECB :
1601 andres 801 GIC 709221 : typid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid,
4802 rhaas 802 ECB : PointerGetDatum(typname),
803 : ObjectIdGetDatum(namespaceId));
7679 tgl 804 GIC 709221 : if (OidIsValid(typid))
7679 tgl 805 CBC 416207 : return typid;
7679 tgl 806 ECB : }
807 :
808 : /* Not found in path */
7679 tgl 809 GIC 34520 : return InvalidOid;
7680 tgl 810 ECB : }
811 :
812 : /*
813 : * TypeIsVisible
814 : * Determine whether a type (identified by OID) is visible in the
815 : * current search path. Visible means "would be found by searching
816 : * for the unqualified type name".
817 : */
818 : bool
7648 tgl 819 GIC 201192 : TypeIsVisible(Oid typid)
7662 tgl 820 ECB : {
821 : HeapTuple typtup;
822 : Form_pg_type typform;
823 : Oid typnamespace;
824 : bool visible;
825 :
4802 rhaas 826 GIC 201192 : typtup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
7648 tgl 827 CBC 201192 : if (!HeapTupleIsValid(typtup))
7202 tgl 828 LBC 0 : elog(ERROR, "cache lookup failed for type %u", typid);
7648 tgl 829 GBC 201192 : typform = (Form_pg_type) GETSTRUCT(typtup);
7662 tgl 830 ECB :
7632 tgl 831 GIC 201192 : recomputeNamespacePath();
7632 tgl 832 ECB :
833 : /*
834 : * Quick check: if it ain't in the path at all, it ain't visible. Items in
835 : * the system namespace are surely in the path and so we needn't even do
836 : * list_member_oid() for them.
837 : */
7648 tgl 838 GIC 201192 : typnamespace = typform->typnamespace;
7648 tgl 839 CBC 201192 : if (typnamespace != PG_CATALOG_NAMESPACE &&
5861 840 37472 : !list_member_oid(activeSearchPath, typnamespace))
7648 841 4051 : visible = false;
7648 tgl 842 ECB : else
843 : {
844 : /*
845 : * If it is in the path, it might still not be visible; it could be
846 : * hidden by another type of the same name earlier in the path. So we
847 : * must do a slow check for conflicting types.
848 : */
7648 tgl 849 GIC 197141 : char *typname = NameStr(typform->typname);
6394 tgl 850 ECB : ListCell *l;
851 :
6394 tgl 852 GIC 197141 : visible = false;
5861 tgl 853 CBC 248842 : foreach(l, activeSearchPath)
6394 tgl 854 ECB : {
6394 tgl 855 GIC 248842 : Oid namespaceId = lfirst_oid(l);
6394 tgl 856 ECB :
6394 tgl 857 GIC 248842 : if (namespaceId == typnamespace)
6394 tgl 858 ECB : {
859 : /* Found it first in path */
6394 tgl 860 GIC 197135 : visible = true;
6394 tgl 861 CBC 197135 : break;
6394 tgl 862 ECB : }
4802 rhaas 863 GIC 51707 : if (SearchSysCacheExists2(TYPENAMENSP,
4802 rhaas 864 ECB : PointerGetDatum(typname),
865 : ObjectIdGetDatum(namespaceId)))
866 : {
867 : /* Found something else first in path */
6394 tgl 868 GIC 6 : break;
6394 tgl 869 ECB : }
870 : }
871 : }
872 :
7648 tgl 873 GIC 201192 : ReleaseSysCache(typtup);
7648 tgl 874 ECB :
7648 tgl 875 GIC 201192 : return visible;
7662 tgl 876 ECB : }
877 :
878 :
879 : /*
880 : * FuncnameGetCandidates
881 : * Given a possibly-qualified function name and argument count,
882 : * retrieve a list of the possible matches.
883 : *
884 : * If nargs is -1, we return all functions matching the given name,
885 : * regardless of argument count. (argnames must be NIL, and expand_variadic
886 : * and expand_defaults must be false, in this case.)
887 : *
888 : * If argnames isn't NIL, we are considering a named- or mixed-notation call,
889 : * and only functions having all the listed argument names will be returned.
890 : * (We assume that length(argnames) <= nargs and all the passed-in names are
891 : * distinct.) The returned structs will include an argnumbers array showing
892 : * the actual argument index for each logical argument position.
893 : *
894 : * If expand_variadic is true, then variadic functions having the same number
895 : * or fewer arguments will be retrieved, with the variadic argument and any
896 : * additional argument positions filled with the variadic element type.
897 : * nvargs in the returned struct is set to the number of such arguments.
898 : * If expand_variadic is false, variadic arguments are not treated specially,
899 : * and the returned nvargs will always be zero.
900 : *
901 : * If expand_defaults is true, functions that could match after insertion of
902 : * default argument values will also be retrieved. In this case the returned
903 : * structs could have nargs > passed-in nargs, and ndargs is set to the number
904 : * of additional args (which can be retrieved from the function's
905 : * proargdefaults entry).
906 : *
907 : * If include_out_arguments is true, then OUT-mode arguments are considered to
908 : * be included in the argument list. Their types are included in the returned
909 : * arrays, and argnumbers are indexes in proallargtypes not proargtypes.
910 : * We also set nominalnargs to be the length of proallargtypes not proargtypes.
911 : * Otherwise OUT-mode arguments are ignored.
912 : *
913 : * It is not possible for nvargs and ndargs to both be nonzero in the same
914 : * list entry, since default insertion allows matches to functions with more
915 : * than nargs arguments while the variadic transformation requires the same
916 : * number or less.
917 : *
918 : * When argnames isn't NIL, the returned args[] type arrays are not ordered
919 : * according to the functions' declarations, but rather according to the call:
920 : * first any positional arguments, then the named arguments, then defaulted
921 : * arguments (if needed and allowed by expand_defaults). The argnumbers[]
922 : * array can be used to map this back to the catalog information.
923 : * argnumbers[k] is set to the proargtypes or proallargtypes index of the
924 : * k'th call argument.
925 : *
926 : * We search a single namespace if the function name is qualified, else
927 : * all namespaces in the search path. In the multiple-namespace case,
928 : * we arrange for entries in earlier namespaces to mask identical entries in
929 : * later namespaces.
930 : *
931 : * When expanding variadics, we arrange for non-variadic functions to mask
932 : * variadic ones if the expanded argument list is the same. It is still
933 : * possible for there to be conflicts between different variadic functions,
934 : * however.
935 : *
936 : * It is guaranteed that the return list will never contain multiple entries
937 : * with identical argument lists. When expand_defaults is true, the entries
938 : * could have more than nargs positions, but we still guarantee that they are
939 : * distinct in the first nargs positions. However, if argnames isn't NIL or
940 : * either expand_variadic or expand_defaults is true, there might be multiple
941 : * candidate functions that expand to identical argument lists. Rather than
942 : * throw error here, we report such situations by returning a single entry
943 : * with oid = 0 that represents a set of such conflicting candidates.
944 : * The caller might end up discarding such an entry anyway, but if it selects
945 : * such an entry it should react as though the call were ambiguous.
946 : *
947 : * If missing_ok is true, an empty list (NULL) is returned if the name was
948 : * schema-qualified with a schema that does not exist. Likewise if no
949 : * candidate is found for other reasons.
950 : */
951 : FuncCandidateList
4931 tgl 952 GIC 376192 : FuncnameGetCandidates(List *names, int nargs, List *argnames,
3363 alvherre 953 ECB : bool expand_variadic, bool expand_defaults,
954 : bool include_out_arguments, bool missing_ok)
955 : {
7673 tgl 956 GIC 376192 : FuncCandidateList resultList = NULL;
5225 tgl 957 CBC 376192 : bool any_special = false;
7559 tgl 958 ECB : char *schemaname;
959 : char *funcname;
960 : Oid namespaceId;
961 : CatCList *catlist;
962 : int i;
963 :
964 : /* check for caller error */
5225 tgl 965 GIC 376192 : Assert(nargs >= 0 || !(expand_variadic | expand_defaults));
5380 tgl 966 ECB :
967 : /* deconstruct the name list */
7559 tgl 968 GIC 376192 : DeconstructQualifiedName(names, &schemaname, &funcname);
7673 tgl 969 ECB :
7673 tgl 970 GIC 376174 : if (schemaname)
7673 tgl 971 ECB : {
972 : /* use exact schema given */
3363 alvherre 973 GIC 61165 : namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
3363 alvherre 974 CBC 61165 : if (!OidIsValid(namespaceId))
975 24 : return NULL;
7673 tgl 976 ECB : }
977 : else
978 : {
979 : /* flag to indicate we need namespace search */
7673 tgl 980 GIC 315009 : namespaceId = InvalidOid;
7650 tgl 981 CBC 315009 : recomputeNamespacePath();
7673 tgl 982 ECB : }
983 :
984 : /* Search syscache by name only */
4802 rhaas 985 GIC 376150 : catlist = SearchSysCacheList1(PROCNAMEARGSNSP, CStringGetDatum(funcname));
7673 tgl 986 ECB :
7673 tgl 987 GIC 1238280 : for (i = 0; i < catlist->n_members; i++)
7673 tgl 988 ECB : {
7673 tgl 989 GIC 862130 : HeapTuple proctup = &catlist->members[i]->tuple;
7673 tgl 990 CBC 862130 : Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup);
668 991 862130 : Oid *proargtypes = procform->proargtypes.values;
6585 992 862130 : int pronargs = procform->pronargs;
5380 tgl 993 ECB : int effective_nargs;
7673 tgl 994 GIC 862130 : int pathpos = 0;
5380 tgl 995 ECB : bool variadic;
996 : bool use_defaults;
997 : Oid va_elem_type;
4931 tgl 998 GIC 862130 : int *argnumbers = NULL;
7673 tgl 999 ECB : FuncCandidateList newResult;
1000 :
7673 tgl 1001 GIC 862130 : if (OidIsValid(namespaceId))
7673 tgl 1002 ECB : {
1003 : /* Consider only procs in specified namespace */
7673 tgl 1004 GIC 155206 : if (procform->pronamespace != namespaceId)
7673 tgl 1005 CBC 252507 : continue;
7673 tgl 1006 ECB : }
1007 : else
1008 : {
1009 : /*
1010 : * Consider only procs that are in the search path and are not in
1011 : * the temp namespace.
1012 : */
1013 : ListCell *nsp;
1014 :
5861 tgl 1015 GIC 838268 : foreach(nsp, activeSearchPath)
7632 tgl 1016 ECB : {
5833 tgl 1017 GIC 836638 : if (procform->pronamespace == lfirst_oid(nsp) &&
5833 tgl 1018 CBC 705312 : procform->pronamespace != myTempNamespace)
7632 1019 705294 : break;
1020 131344 : pathpos++;
7673 tgl 1021 ECB : }
6892 neilc 1022 GIC 706924 : if (nsp == NULL)
7632 tgl 1023 CBC 1630 : continue; /* proc is not in search path */
5380 tgl 1024 ECB : }
1025 :
1026 : /*
1027 : * If we are asked to match to OUT arguments, then use the
1028 : * proallargtypes array (which includes those); otherwise use
1029 : * proargtypes (which doesn't). Of course, if proallargtypes is null,
1030 : * we always use proargtypes.
1031 : */
668 tgl 1032 GIC 856839 : if (include_out_arguments)
668 tgl 1033 ECB : {
1034 : Datum proallargtypes;
1035 : bool isNull;
1036 :
668 tgl 1037 GIC 290 : proallargtypes = SysCacheGetAttr(PROCNAMEARGSNSP, proctup,
668 tgl 1038 ECB : Anum_pg_proc_proallargtypes,
1039 : &isNull);
668 tgl 1040 GIC 290 : if (!isNull)
668 tgl 1041 ECB : {
668 tgl 1042 GIC 85 : ArrayType *arr = DatumGetArrayTypeP(proallargtypes);
668 tgl 1043 ECB :
668 tgl 1044 GIC 85 : pronargs = ARR_DIMS(arr)[0];
668 tgl 1045 CBC 85 : if (ARR_NDIM(arr) != 1 ||
1046 85 : pronargs < 0 ||
1047 85 : ARR_HASNULL(arr) ||
1048 85 : ARR_ELEMTYPE(arr) != OIDOID)
668 tgl 1049 LBC 0 : elog(ERROR, "proallargtypes is not a 1-D Oid array or it contains nulls");
668 tgl 1050 GBC 85 : Assert(pronargs >= procform->pronargs);
668 tgl 1051 CBC 85 : proargtypes = (Oid *) ARR_DATA_PTR(arr);
668 tgl 1052 ECB : }
1053 : }
1054 :
4931 tgl 1055 GIC 856839 : if (argnames != NIL)
4931 tgl 1056 ECB : {
1057 : /*
1058 : * Call uses named or mixed notation
1059 : *
1060 : * Named or mixed notation can match a variadic function only if
1061 : * expand_variadic is off; otherwise there is no way to match the
1062 : * presumed-nameless parameters expanded from the variadic array.
1063 : */
4931 tgl 1064 GIC 8782 : if (OidIsValid(procform->provariadic) && expand_variadic)
4931 tgl 1065 LBC 0 : continue;
4931 tgl 1066 GBC 8782 : va_elem_type = InvalidOid;
4931 tgl 1067 CBC 8782 : variadic = false;
4931 tgl 1068 ECB :
1069 : /*
1070 : * Check argument count.
1071 : */
4790 bruce 1072 GIC 8782 : Assert(nargs >= 0); /* -1 not supported with argnames */
4931 tgl 1073 ECB :
4931 tgl 1074 GIC 8782 : if (pronargs > nargs && expand_defaults)
4931 tgl 1075 ECB : {
1076 : /* Ignore if not enough default expressions */
4931 tgl 1077 GIC 2786 : if (nargs + procform->pronargdefaults < pronargs)
4931 tgl 1078 LBC 0 : continue;
4931 tgl 1079 GBC 2786 : use_defaults = true;
4931 tgl 1080 ECB : }
1081 : else
4931 tgl 1082 GIC 5996 : use_defaults = false;
4931 tgl 1083 ECB :
1084 : /* Ignore if it doesn't match requested argument count */
4931 tgl 1085 GIC 8782 : if (pronargs != nargs && !use_defaults)
4931 tgl 1086 CBC 2842 : continue;
4931 tgl 1087 ECB :
1088 : /* Check for argument name match, generate positional mapping */
4931 tgl 1089 GIC 5940 : if (!MatchNamedCall(proctup, nargs, argnames,
668 tgl 1090 ECB : include_out_arguments, pronargs,
1091 : &argnumbers))
4931 tgl 1092 GIC 9 : continue;
4931 tgl 1093 ECB :
1094 : /* Named argument matching is always "special" */
4931 tgl 1095 GIC 5931 : any_special = true;
4931 tgl 1096 ECB : }
1097 : else
1098 : {
1099 : /*
1100 : * Call uses positional notation
1101 : *
1102 : * Check if function is variadic, and get variadic element type if
1103 : * so. If expand_variadic is false, we should just ignore
1104 : * variadic-ness.
1105 : */
4931 tgl 1106 GIC 848057 : if (pronargs <= nargs && expand_variadic)
4931 tgl 1107 ECB : {
4931 tgl 1108 GIC 573635 : va_elem_type = procform->provariadic;
4931 tgl 1109 CBC 573635 : variadic = OidIsValid(va_elem_type);
1110 573635 : any_special |= variadic;
4931 tgl 1111 ECB : }
1112 : else
1113 : {
4931 tgl 1114 GIC 274422 : va_elem_type = InvalidOid;
4931 tgl 1115 CBC 274422 : variadic = false;
4931 tgl 1116 ECB : }
1117 :
1118 : /*
1119 : * Check if function can match by using parameter defaults.
1120 : */
4931 tgl 1121 GIC 848057 : if (pronargs > nargs && expand_defaults)
4931 tgl 1122 ECB : {
1123 : /* Ignore if not enough default expressions */
4931 tgl 1124 GIC 197430 : if (nargs + procform->pronargdefaults < pronargs)
4931 tgl 1125 CBC 195510 : continue;
1126 1920 : use_defaults = true;
1127 1920 : any_special = true;
4931 tgl 1128 ECB : }
1129 : else
4931 tgl 1130 GIC 650627 : use_defaults = false;
4931 tgl 1131 ECB :
1132 : /* Ignore if it doesn't match requested argument count */
4931 tgl 1133 GIC 652547 : if (nargs >= 0 && pronargs != nargs && !variadic && !use_defaults)
4931 tgl 1134 CBC 48218 : continue;
4931 tgl 1135 ECB : }
1136 :
1137 : /*
1138 : * We must compute the effective argument list so that we can easily
1139 : * compare it to earlier results. We waste a palloc cycle if it gets
1140 : * masked by an earlier result, but really that's a pretty infrequent
1141 : * case so it's not worth worrying about.
1142 : */
5380 tgl 1143 GIC 610260 : effective_nargs = Max(pronargs, nargs);
5380 tgl 1144 ECB : newResult = (FuncCandidateList)
2970 tgl 1145 GIC 610260 : palloc(offsetof(struct _FuncCandidateList, args) +
2970 tgl 1146 ECB : effective_nargs * sizeof(Oid));
5380 tgl 1147 GIC 610260 : newResult->pathpos = pathpos;
1601 andres 1148 CBC 610260 : newResult->oid = procform->oid;
668 tgl 1149 610260 : newResult->nominalnargs = pronargs;
5380 1150 610260 : newResult->nargs = effective_nargs;
4931 1151 610260 : newResult->argnumbers = argnumbers;
1152 610260 : if (argnumbers)
4931 tgl 1153 ECB : {
1154 : /* Re-order the argument types into call's logical order */
186 drowley 1155 GNC 29415 : for (int j = 0; j < pronargs; j++)
1156 23484 : newResult->args[j] = proargtypes[argnumbers[j]];
1157 : }
1158 : else
1159 : {
4931 tgl 1160 ECB : /* Simple positional case, just copy proargtypes as-is */
668 tgl 1161 GIC 604329 : memcpy(newResult->args, proargtypes, pronargs * sizeof(Oid));
4931 tgl 1162 ECB : }
5380 tgl 1163 GIC 610260 : if (variadic)
5380 tgl 1164 ECB : {
5380 tgl 1165 CBC 3255 : newResult->nvargs = effective_nargs - pronargs + 1;
1166 : /* Expand variadic argument into N copies of element type */
186 drowley 1167 GNC 9018 : for (int j = pronargs - 1; j < effective_nargs; j++)
1168 5763 : newResult->args[j] = va_elem_type;
5380 tgl 1169 ECB : }
1170 : else
5380 tgl 1171 GIC 607005 : newResult->nvargs = 0;
5225 1172 610260 : newResult->ndargs = use_defaults ? pronargs - nargs : 0;
1173 :
1174 : /*
1175 : * Does it have the same arguments as something we already accepted?
1176 : * If so, decide what to do to avoid returning duplicate argument
1177 : * lists. We can skip this check for the single-namespace case if no
1178 : * special (named, variadic or defaults) match has been made, since
4931 tgl 1179 ECB : * then the unique index on pg_proc guarantees all the matches have
1180 : * different argument lists.
1181 : */
5225 tgl 1182 GIC 610260 : if (resultList != NULL &&
1183 236192 : (any_special || !OidIsValid(namespaceId)))
1184 : {
1185 : /*
1186 : * If we have an ordered list from SearchSysCacheList (the normal
1187 : * case), then any conflicting proc must immediately adjoin this
1188 : * one in the list, so we only need to look at the newest result
1189 : * item. If we have an unordered list, we have to scan the whole
1190 : * result list. Also, if either the current candidate or any
1191 : * previous candidate is a special match, we can't assume that
1192 : * conflicts are adjacent.
1193 : *
1194 : * We ignore defaulted arguments in deciding what is a match.
7673 tgl 1195 ECB : */
1196 : FuncCandidateList prevResult;
1197 :
5225 tgl 1198 CBC 181007 : if (catlist->ordered && !any_special)
7673 tgl 1199 ECB : {
5225 1200 : /* ndargs must be 0 if !any_special */
5225 tgl 1201 GIC 180317 : if (effective_nargs == resultList->nargs &&
5225 tgl 1202 CBC 180314 : memcmp(newResult->args,
5225 tgl 1203 GIC 180314 : resultList->args,
5225 tgl 1204 ECB : effective_nargs * sizeof(Oid)) == 0)
5225 tgl 1205 GIC 4 : prevResult = resultList;
1206 : else
1207 180313 : prevResult = NULL;
5225 tgl 1208 ECB : }
1209 : else
1210 : {
5050 bruce 1211 CBC 690 : int cmp_nargs = newResult->nargs - newResult->ndargs;
7673 tgl 1212 ECB :
5225 tgl 1213 GIC 690 : for (prevResult = resultList;
5225 tgl 1214 CBC 708 : prevResult;
1215 18 : prevResult = prevResult->next)
7673 tgl 1216 ECB : {
5225 tgl 1217 GIC 690 : if (cmp_nargs == prevResult->nargs - prevResult->ndargs &&
5380 tgl 1218 CBC 690 : memcmp(newResult->args,
5225 tgl 1219 GIC 690 : prevResult->args,
1220 : cmp_nargs * sizeof(Oid)) == 0)
1221 672 : break;
7673 tgl 1222 ECB : }
1223 : }
1224 :
5225 tgl 1225 GIC 181007 : if (prevResult)
1226 : {
1227 : /*
1228 : * We have a match with a previous result. Decide which one
1229 : * to keep, or mark it ambiguous if we can't decide. The
1230 : * logic here is preference > 0 means prefer the old result,
1231 : * preference < 0 means prefer the new, preference = 0 means
1232 : * ambiguous.
5225 tgl 1233 ECB : */
1234 : int preference;
1235 :
5225 tgl 1236 GIC 676 : if (pathpos != prevResult->pathpos)
1237 : {
5225 tgl 1238 ECB : /*
1239 : * Prefer the one that's earlier in the search path.
1240 : */
5225 tgl 1241 GIC 1 : preference = pathpos - prevResult->pathpos;
1242 : }
1243 675 : else if (variadic && prevResult->nvargs == 0)
1244 : {
1245 : /*
1246 : * With variadic functions we could have, for example,
1247 : * both foo(numeric) and foo(variadic numeric[]) in the
5050 bruce 1248 ECB : * same namespace; if so we prefer the non-variadic match
1249 : * on efficiency grounds.
5380 tgl 1250 : */
5225 tgl 1251 GIC 615 : preference = 1;
5225 tgl 1252 ECB : }
5225 tgl 1253 GIC 60 : else if (!variadic && prevResult->nvargs > 0)
1254 : {
1255 39 : preference = -1;
1256 : }
1257 : else
1258 : {
1259 : /*----------
1260 : * We can't decide. This can happen with, for example,
1261 : * both foo(numeric, variadic numeric[]) and
1262 : * foo(variadic numeric[]) in the same namespace, or
1263 : * both foo(int) and foo (int, int default something)
1264 : * in the same namespace, or both foo(a int, b text)
4931 tgl 1265 ECB : * and foo(b text, a int) in the same namespace.
1266 : *----------
1267 : */
5225 tgl 1268 CBC 21 : preference = 0;
1269 : }
1270 :
1271 676 : if (preference > 0)
5225 tgl 1272 ECB : {
1273 : /* keep previous result */
5225 tgl 1274 CBC 616 : pfree(newResult);
5225 tgl 1275 GIC 616 : continue;
1276 : }
5225 tgl 1277 CBC 60 : else if (preference < 0)
5225 tgl 1278 ECB : {
1279 : /* remove previous result from the list */
5225 tgl 1280 GIC 39 : if (prevResult == resultList)
1281 39 : resultList = prevResult->next;
1282 : else
5380 tgl 1283 EUB : {
5225 1284 : FuncCandidateList prevPrevResult;
5239 peter_e 1285 :
5225 tgl 1286 UIC 0 : for (prevPrevResult = resultList;
5225 tgl 1287 UBC 0 : prevPrevResult;
5225 tgl 1288 UIC 0 : prevPrevResult = prevPrevResult->next)
5239 peter_e 1289 EUB : {
5225 tgl 1290 UBC 0 : if (prevResult == prevPrevResult->next)
1291 : {
5225 tgl 1292 UIC 0 : prevPrevResult->next = prevResult->next;
5225 tgl 1293 UBC 0 : break;
1294 : }
5239 peter_e 1295 ECB : }
5050 bruce 1296 UIC 0 : Assert(prevPrevResult); /* assert we found it */
1297 : }
5225 tgl 1298 GIC 39 : pfree(prevResult);
1299 : /* fall through to add newResult to list */
1300 : }
5225 tgl 1301 ECB : else
1302 : {
1303 : /* mark old result as ambiguous, discard new */
5225 tgl 1304 GIC 21 : prevResult->oid = InvalidOid;
5380 1305 21 : pfree(newResult);
5225 1306 21 : continue;
1307 : }
1308 : }
1309 : }
1310 :
7673 tgl 1311 ECB : /*
1312 : * Okay to add it to result list
1313 : */
7673 tgl 1314 GIC 609623 : newResult->next = resultList;
7673 tgl 1315 CBC 609623 : resultList = newResult;
1316 : }
7673 tgl 1317 ECB :
7673 tgl 1318 GIC 376150 : ReleaseSysCacheList(catlist);
1319 :
7663 1320 376150 : return resultList;
1321 : }
1322 :
1323 : /*
1324 : * MatchNamedCall
1325 : * Given a pg_proc heap tuple and a call's list of argument names,
1326 : * check whether the function could match the call.
1327 : *
1328 : * The call could match if all supplied argument names are accepted by
1329 : * the function, in positions after the last positional argument, and there
1330 : * are defaults for all unsupplied arguments.
1331 : *
1332 : * If include_out_arguments is true, we are treating OUT arguments as
1333 : * included in the argument list. pronargs is the number of arguments
1334 : * we're considering (the length of either proargtypes or proallargtypes).
1335 : *
1336 : * The number of positional arguments is nargs - list_length(argnames).
1337 : * Note caller has already done basic checks on argument count.
1338 : *
1339 : * On match, return true and fill *argnumbers with a palloc'd array showing
1340 : * the mapping from call argument positions to actual function argument
1341 : * numbers. Defaulted arguments are included in this map, at positions
4931 tgl 1342 ECB : * after the last supplied argument.
1343 : */
1344 : static bool
4931 tgl 1345 GIC 5940 : MatchNamedCall(HeapTuple proctup, int nargs, List *argnames,
668 tgl 1346 ECB : bool include_out_arguments, int pronargs,
4931 1347 : int **argnumbers)
1348 : {
4931 tgl 1349 GIC 5940 : Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup);
1350 5940 : int numposargs = nargs - list_length(argnames);
1351 : int pronallargs;
1352 : Oid *p_argtypes;
1353 : char **p_argnames;
1354 : char *p_argmodes;
1355 : bool arggiven[FUNC_MAX_ARGS];
1356 : bool isnull;
1357 : int ap; /* call args position */
4931 tgl 1358 ECB : int pp; /* proargs position */
1359 : ListCell *lc;
1360 :
4931 tgl 1361 GIC 5940 : Assert(argnames != NIL);
1362 5940 : Assert(numposargs >= 0);
4931 tgl 1363 CBC 5940 : Assert(nargs <= pronargs);
1364 :
4931 tgl 1365 ECB : /* Ignore this function if its proargnames is null */
4931 tgl 1366 GBC 5940 : (void) SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_proargnames,
1367 : &isnull);
4931 tgl 1368 GIC 5940 : if (isnull)
4931 tgl 1369 LBC 0 : return false;
1370 :
4931 tgl 1371 ECB : /* OK, let's extract the argument names and types */
4931 tgl 1372 GIC 5940 : pronallargs = get_func_arg_info(proctup,
4931 tgl 1373 ECB : &p_argtypes, &p_argnames, &p_argmodes);
4931 tgl 1374 GIC 5940 : Assert(p_argnames != NULL);
1375 :
668 tgl 1376 CBC 5940 : Assert(include_out_arguments ? (pronargs == pronallargs) : (pronargs <= pronallargs));
668 tgl 1377 ECB :
1378 : /* initialize state for matching */
4931 tgl 1379 GIC 5940 : *argnumbers = (int *) palloc(pronargs * sizeof(int));
4931 tgl 1380 CBC 5940 : memset(arggiven, false, pronargs * sizeof(bool));
1381 :
4931 tgl 1382 ECB : /* there are numposargs positional args before the named args */
4931 tgl 1383 CBC 6688 : for (ap = 0; ap < numposargs; ap++)
1384 : {
4931 tgl 1385 GIC 748 : (*argnumbers)[ap] = ap;
1386 748 : arggiven[ap] = true;
4931 tgl 1387 ECB : }
1388 :
1389 : /* now examine the named args */
4931 tgl 1390 GIC 23233 : foreach(lc, argnames)
1391 : {
4790 bruce 1392 17299 : char *argname = (char *) lfirst(lc);
4790 bruce 1393 ECB : bool found;
1394 : int i;
4931 tgl 1395 :
4931 tgl 1396 GIC 17299 : pp = 0;
1397 17299 : found = false;
4931 tgl 1398 CBC 39795 : for (i = 0; i < pronallargs; i++)
4931 tgl 1399 ECB : {
668 1400 : /* consider only input params, except with include_out_arguments */
668 tgl 1401 CBC 39792 : if (!include_out_arguments &&
1402 29667 : p_argmodes &&
4931 1403 29667 : (p_argmodes[i] != FUNC_PARAM_IN &&
1404 24 : p_argmodes[i] != FUNC_PARAM_INOUT &&
4931 tgl 1405 GIC 24 : p_argmodes[i] != FUNC_PARAM_VARIADIC))
1406 24 : continue;
4931 tgl 1407 CBC 39768 : if (p_argnames[i] && strcmp(p_argnames[i], argname) == 0)
4931 tgl 1408 ECB : {
1409 : /* fail if argname matches a positional argument */
4931 tgl 1410 CBC 17296 : if (arggiven[pp])
1411 6 : return false;
1412 17293 : arggiven[pp] = true;
4931 tgl 1413 GIC 17293 : (*argnumbers)[ap] = pp;
1414 17293 : found = true;
4931 tgl 1415 CBC 17293 : break;
1416 : }
1417 : /* increase pp only for considered parameters */
1418 22472 : pp++;
4931 tgl 1419 ECB : }
1420 : /* if name isn't in proargnames, fail */
4931 tgl 1421 GIC 17296 : if (!found)
1422 3 : return false;
4931 tgl 1423 CBC 17293 : ap++;
1424 : }
1425 :
1426 5934 : Assert(ap == nargs); /* processed all actual parameters */
1427 :
4931 tgl 1428 ECB : /* Check for default arguments */
4931 tgl 1429 GIC 5934 : if (nargs < pronargs)
4931 tgl 1430 ECB : {
4790 bruce 1431 GIC 2780 : int first_arg_with_default = pronargs - procform->pronargdefaults;
4931 tgl 1432 ECB :
4931 tgl 1433 CBC 18470 : for (pp = numposargs; pp < pronargs; pp++)
1434 : {
1435 15693 : if (arggiven[pp])
1436 10232 : continue;
4931 tgl 1437 ECB : /* fail if arg not given and no default available */
4931 tgl 1438 GIC 5461 : if (pp < first_arg_with_default)
1439 3 : return false;
1440 5458 : (*argnumbers)[ap++] = pp;
4931 tgl 1441 ECB : }
1442 : }
1443 :
4931 tgl 1444 GIC 5931 : Assert(ap == pronargs); /* processed all function parameters */
1445 :
1446 5931 : return true;
1447 : }
1448 :
1449 : /*
1450 : * FunctionIsVisible
1451 : * Determine whether a function (identified by OID) is visible in the
1452 : * current search path. Visible means "would be found by searching
7648 tgl 1453 ECB : * for the unqualified function name with exact argument matches".
1454 : */
1455 : bool
7648 tgl 1456 GIC 10279 : FunctionIsVisible(Oid funcid)
1457 : {
1458 : HeapTuple proctup;
1459 : Form_pg_proc procform;
7648 tgl 1460 ECB : Oid pronamespace;
1461 : bool visible;
7648 tgl 1462 EUB :
4802 rhaas 1463 CBC 10279 : proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
7648 tgl 1464 GIC 10279 : if (!HeapTupleIsValid(proctup))
7202 tgl 1465 LBC 0 : elog(ERROR, "cache lookup failed for function %u", funcid);
7648 tgl 1466 GIC 10279 : procform = (Form_pg_proc) GETSTRUCT(proctup);
1467 :
7632 1468 10279 : recomputeNamespacePath();
1469 :
1470 : /*
1471 : * Quick check: if it ain't in the path at all, it ain't visible. Items in
6385 bruce 1472 ECB : * the system namespace are surely in the path and so we needn't even do
1473 : * list_member_oid() for them.
7648 tgl 1474 : */
7648 tgl 1475 CBC 10279 : pronamespace = procform->pronamespace;
7648 tgl 1476 GIC 10279 : if (pronamespace != PG_CATALOG_NAMESPACE &&
5861 1477 5233 : !list_member_oid(activeSearchPath, pronamespace))
7648 1478 297 : visible = false;
1479 : else
1480 : {
1481 : /*
1482 : * If it is in the path, it might still not be visible; it could be
1483 : * hidden by another proc of the same name and arguments earlier in
6385 bruce 1484 ECB : * the path. So we must do a slow check to see if this is the same
1485 : * proc that would be found by FuncnameGetCandidates.
1486 : */
7648 tgl 1487 GIC 9982 : char *proname = NameStr(procform->proname);
7648 tgl 1488 CBC 9982 : int nargs = procform->pronargs;
1489 : FuncCandidateList clist;
7648 tgl 1490 ECB :
7648 tgl 1491 GIC 9982 : visible = false;
1492 :
5380 tgl 1493 CBC 9982 : clist = FuncnameGetCandidates(list_make1(makeString(proname)),
1494 : nargs, NIL, false, false, false, false);
7648 tgl 1495 ECB :
7648 tgl 1496 GIC 14384 : for (; clist; clist = clist->next)
1497 : {
6585 1498 14378 : if (memcmp(clist->args, procform->proargtypes.values,
7648 tgl 1499 ECB : nargs * sizeof(Oid)) == 0)
1500 : {
1501 : /* Found the expected entry; is it the right proc? */
7648 tgl 1502 GIC 9976 : visible = (clist->oid == funcid);
1503 9976 : break;
1504 : }
7648 tgl 1505 ECB : }
1506 : }
1507 :
7648 tgl 1508 GIC 10279 : ReleaseSysCache(proctup);
1509 :
1510 10279 : return visible;
1511 : }
1512 :
1513 :
1514 : /*
1515 : * OpernameGetOprid
1516 : * Given a possibly-qualified operator name and exact input datatypes,
1517 : * look up the operator. Returns InvalidOid if not found.
1518 : *
1519 : * Pass oprleft = InvalidOid for a prefix op.
1520 : *
1521 : * If the operator name is not schema-qualified, it is sought in the current
1522 : * namespace search path. If the name is schema-qualified and the given
3363 alvherre 1523 ECB : * schema does not exist, InvalidOid is returned.
1524 : */
1525 : Oid
6187 tgl 1526 GIC 59253 : OpernameGetOprid(List *names, Oid oprleft, Oid oprright)
1527 : {
1528 : char *schemaname;
1529 : char *opername;
1530 : CatCList *catlist;
6187 tgl 1531 ECB : ListCell *l;
1532 :
1533 : /* deconstruct the name list */
6187 tgl 1534 GIC 59253 : DeconstructQualifiedName(names, &schemaname, &opername);
1535 :
1536 59253 : if (schemaname)
1537 : {
6187 tgl 1538 ECB : /* search only in exact schema given */
1539 : Oid namespaceId;
1540 :
3363 alvherre 1541 GIC 992 : namespaceId = LookupExplicitNamespace(schemaname, true);
1542 992 : if (OidIsValid(namespaceId))
6187 tgl 1543 ECB : {
1544 : HeapTuple opertup;
1545 :
3363 alvherre 1546 GIC 980 : opertup = SearchSysCache4(OPERNAMENSP,
1547 : CStringGetDatum(opername),
3363 alvherre 1548 ECB : ObjectIdGetDatum(oprleft),
1549 : ObjectIdGetDatum(oprright),
1550 : ObjectIdGetDatum(namespaceId));
3363 alvherre 1551 CBC 980 : if (HeapTupleIsValid(opertup))
1552 : {
1601 andres 1553 570 : Form_pg_operator operclass = (Form_pg_operator) GETSTRUCT(opertup);
1554 570 : Oid result = operclass->oid;
1555 :
3363 alvherre 1556 GIC 570 : ReleaseSysCache(opertup);
1557 570 : return result;
3363 alvherre 1558 ECB : }
1559 : }
1560 :
6187 tgl 1561 GIC 422 : return InvalidOid;
6187 tgl 1562 ECB : }
1563 :
1564 : /* Search syscache by name and argument types */
4802 rhaas 1565 GIC 58261 : catlist = SearchSysCacheList3(OPERNAMENSP,
1566 : CStringGetDatum(opername),
4802 rhaas 1567 ECB : ObjectIdGetDatum(oprleft),
1568 : ObjectIdGetDatum(oprright));
1569 :
6187 tgl 1570 CBC 58261 : if (catlist->n_members == 0)
6187 tgl 1571 ECB : {
1572 : /* no hope, fall out early */
6187 tgl 1573 GIC 14408 : ReleaseSysCacheList(catlist);
1574 14408 : return InvalidOid;
1575 : }
1576 :
1577 : /*
1578 : * We have to find the list member that is first in the search path, if
6031 bruce 1579 ECB : * there's more than one. This doubly-nested loop looks ugly, but in
1580 : * practice there should usually be few catlist members.
6187 tgl 1581 : */
6187 tgl 1582 GIC 43853 : recomputeNamespacePath();
6187 tgl 1583 ECB :
5861 tgl 1584 GIC 49171 : foreach(l, activeSearchPath)
1585 : {
6187 tgl 1586 CBC 49166 : Oid namespaceId = lfirst_oid(l);
6187 tgl 1587 ECB : int i;
1588 :
5833 tgl 1589 CBC 49166 : if (namespaceId == myTempNamespace)
5833 tgl 1590 GIC 3306 : continue; /* do not look in temp namespace */
5833 tgl 1591 ECB :
6187 tgl 1592 CBC 47890 : for (i = 0; i < catlist->n_members; i++)
1593 : {
1594 45878 : HeapTuple opertup = &catlist->members[i]->tuple;
6187 tgl 1595 GIC 45878 : Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup);
6187 tgl 1596 ECB :
6187 tgl 1597 GIC 45878 : if (operform->oprnamespace == namespaceId)
6187 tgl 1598 ECB : {
1601 andres 1599 CBC 43848 : Oid result = operform->oid;
1600 :
6187 tgl 1601 GIC 43848 : ReleaseSysCacheList(catlist);
1602 43848 : return result;
1603 : }
6187 tgl 1604 ECB : }
1605 : }
1606 :
6187 tgl 1607 GIC 5 : ReleaseSysCacheList(catlist);
1608 5 : return InvalidOid;
1609 : }
1610 :
1611 : /*
1612 : * OpernameGetCandidates
1613 : * Given a possibly-qualified operator name and operator kind,
1614 : * retrieve a list of the possible matches.
1615 : *
1616 : * If oprkind is '\0', we return all operators matching the given name,
1617 : * regardless of arguments.
1618 : *
1619 : * We search a single namespace if the operator name is qualified, else
1620 : * all namespaces in the search path. The return list will never contain
1621 : * multiple entries with identical argument lists --- in the multiple-
1622 : * namespace case, we arrange for entries in earlier namespaces to mask
1623 : * identical entries in later namespaces.
1624 : *
1625 : * The returned items always have two args[] entries --- the first will be
934 tgl 1626 ECB : * InvalidOid for a prefix oprkind. nargs is always 2, too.
1627 : */
7663 1628 : FuncCandidateList
3288 rhaas 1629 CBC 13811 : OpernameGetCandidates(List *names, char oprkind, bool missing_schema_ok)
7663 tgl 1630 ECB : {
7663 tgl 1631 GIC 13811 : FuncCandidateList resultList = NULL;
7041 1632 13811 : char *resultSpace = NULL;
1633 13811 : int nextResult = 0;
1634 : char *schemaname;
1635 : char *opername;
1636 : Oid namespaceId;
1637 : CatCList *catlist;
7663 tgl 1638 ECB : int i;
1639 :
1640 : /* deconstruct the name list */
7559 tgl 1641 GIC 13811 : DeconstructQualifiedName(names, &schemaname, &opername);
1642 :
7663 tgl 1643 CBC 13811 : if (schemaname)
7663 tgl 1644 ECB : {
1645 : /* use exact schema given */
3288 rhaas 1646 GIC 420 : namespaceId = LookupExplicitNamespace(schemaname, missing_schema_ok);
1647 420 : if (missing_schema_ok && !OidIsValid(namespaceId))
1648 9 : return NULL;
1649 : }
7663 tgl 1650 ECB : else
1651 : {
1652 : /* flag to indicate we need namespace search */
7663 tgl 1653 GIC 13391 : namespaceId = InvalidOid;
7650 1654 13391 : recomputeNamespacePath();
7663 tgl 1655 ECB : }
1656 :
1657 : /* Search syscache by name only */
4802 rhaas 1658 GIC 13802 : catlist = SearchSysCacheList1(OPERNAMENSP, CStringGetDatum(opername));
1659 :
1660 : /*
1661 : * In typical scenarios, most if not all of the operators found by the
1662 : * catcache search will end up getting returned; and there can be quite a
1663 : * few, for common operator names such as '=' or '+'. To reduce the time
1664 : * spent in palloc, we allocate the result space as an array large enough
1665 : * to hold all the operators. The original coding of this routine did a
1666 : * separate palloc for each operator, but profiling revealed that the
1667 : * pallocs used an unreasonably large fraction of parsing time.
1668 : */
2970 tgl 1669 ECB : #define SPACE_PER_OP MAXALIGN(offsetof(struct _FuncCandidateList, args) + \
1670 : 2 * sizeof(Oid))
1671 :
7041 tgl 1672 CBC 13802 : if (catlist->n_members > 0)
7041 tgl 1673 GIC 13796 : resultSpace = palloc(catlist->n_members * SPACE_PER_OP);
7041 tgl 1674 ECB :
7663 tgl 1675 CBC 647194 : for (i = 0; i < catlist->n_members; i++)
7663 tgl 1676 ECB : {
7663 tgl 1677 GIC 633392 : HeapTuple opertup = &catlist->members[i]->tuple;
1678 633392 : Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup);
1679 633392 : int pathpos = 0;
7663 tgl 1680 ECB : FuncCandidateList newResult;
1681 :
1682 : /* Ignore operators of wrong kind, if specific kind requested */
7654 tgl 1683 CBC 633392 : if (oprkind && operform->oprkind != oprkind)
7663 tgl 1684 GIC 5870 : continue;
1685 :
7663 tgl 1686 CBC 627522 : if (OidIsValid(namespaceId))
7663 tgl 1687 EUB : {
1688 : /* Consider only opers in specified namespace */
7663 tgl 1689 GIC 5771 : if (operform->oprnamespace != namespaceId)
7663 tgl 1690 UIC 0 : continue;
1691 : /* No need to check args, they must all be different */
1692 : }
1693 : else
1694 : {
1695 : /*
1696 : * Consider only opers that are in the search path and are not in
1697 : * the temp namespace.
5833 tgl 1698 ECB : */
1699 : ListCell *nsp;
7663 1700 :
5861 tgl 1701 CBC 660549 : foreach(nsp, activeSearchPath)
7632 tgl 1702 ECB : {
5833 tgl 1703 CBC 660287 : if (operform->oprnamespace == lfirst_oid(nsp) &&
5833 tgl 1704 GIC 621489 : operform->oprnamespace != myTempNamespace)
7632 tgl 1705 CBC 621489 : break;
1706 38798 : pathpos++;
1707 : }
6892 neilc 1708 GIC 621751 : if (nsp == NULL)
7632 tgl 1709 262 : continue; /* oper is not in search path */
1710 :
1711 : /*
1712 : * Okay, it's in the search path, but does it have the same
1713 : * arguments as something we already accepted? If so, keep only
1714 : * the one that appears earlier in the search path.
1715 : *
1716 : * If we have an ordered list from SearchSysCacheList (the normal
1717 : * case), then any conflicting oper must immediately adjoin this
1718 : * one in the list, so we only need to look at the newest result
6385 bruce 1719 ECB : * item. If we have an unordered list, we have to scan the whole
1720 : * result list.
1721 : */
7663 tgl 1722 GIC 621489 : if (resultList)
7663 tgl 1723 ECB : {
1724 : FuncCandidateList prevResult;
1725 :
7663 tgl 1726 CBC 608104 : if (catlist->ordered)
7663 tgl 1727 EUB : {
7663 tgl 1728 GIC 608104 : if (operform->oprleft == resultList->args[0] &&
7663 tgl 1729 CBC 170353 : operform->oprright == resultList->args[1])
7663 tgl 1730 UIC 0 : prevResult = resultList;
1731 : else
7663 tgl 1732 GIC 608104 : prevResult = NULL;
7663 tgl 1733 EUB : }
1734 : else
1735 : {
7663 tgl 1736 UIC 0 : for (prevResult = resultList;
7663 tgl 1737 UBC 0 : prevResult;
1738 0 : prevResult = prevResult->next)
7663 tgl 1739 EUB : {
7663 tgl 1740 UIC 0 : if (operform->oprleft == prevResult->args[0] &&
1741 0 : operform->oprright == prevResult->args[1])
7663 tgl 1742 LBC 0 : break;
1743 : }
1744 : }
7663 tgl 1745 GBC 608104 : if (prevResult)
7663 tgl 1746 EUB : {
1747 : /* We have a match with a previous result */
7663 tgl 1748 UIC 0 : Assert(pathpos != prevResult->pathpos);
7663 tgl 1749 UBC 0 : if (pathpos > prevResult->pathpos)
2118 1750 0 : continue; /* keep previous result */
7663 tgl 1751 EUB : /* replace previous result */
7663 tgl 1752 UIC 0 : prevResult->pathpos = pathpos;
1601 andres 1753 0 : prevResult->oid = operform->oid;
7663 tgl 1754 0 : continue; /* args are same, of course */
1755 : }
1756 : }
1757 : }
1758 :
7663 tgl 1759 ECB : /*
1760 : * Okay to add it to result list
1761 : */
7041 tgl 1762 CBC 627260 : newResult = (FuncCandidateList) (resultSpace + nextResult);
1763 627260 : nextResult += SPACE_PER_OP;
7041 tgl 1764 ECB :
7663 tgl 1765 CBC 627260 : newResult->pathpos = pathpos;
1601 andres 1766 627260 : newResult->oid = operform->oid;
668 tgl 1767 627260 : newResult->nominalnargs = 2;
7654 1768 627260 : newResult->nargs = 2;
5380 1769 627260 : newResult->nvargs = 0;
5225 1770 627260 : newResult->ndargs = 0;
4931 1771 627260 : newResult->argnumbers = NULL;
7663 1772 627260 : newResult->args[0] = operform->oprleft;
7663 tgl 1773 GIC 627260 : newResult->args[1] = operform->oprright;
1774 627260 : newResult->next = resultList;
7663 tgl 1775 CBC 627260 : resultList = newResult;
1776 : }
7663 tgl 1777 ECB :
7663 tgl 1778 GIC 13802 : ReleaseSysCacheList(catlist);
1779 :
7673 1780 13802 : return resultList;
1781 : }
1782 :
1783 : /*
1784 : * OperatorIsVisible
1785 : * Determine whether an operator (identified by OID) is visible in the
1786 : * current search path. Visible means "would be found by searching
7648 tgl 1787 ECB : * for the unqualified operator name with exact argument matches".
1788 : */
1789 : bool
7648 tgl 1790 GIC 2128 : OperatorIsVisible(Oid oprid)
1791 : {
1792 : HeapTuple oprtup;
1793 : Form_pg_operator oprform;
7648 tgl 1794 ECB : Oid oprnamespace;
1795 : bool visible;
7648 tgl 1796 EUB :
4802 rhaas 1797 CBC 2128 : oprtup = SearchSysCache1(OPEROID, ObjectIdGetDatum(oprid));
7648 tgl 1798 GIC 2128 : if (!HeapTupleIsValid(oprtup))
7202 tgl 1799 LBC 0 : elog(ERROR, "cache lookup failed for operator %u", oprid);
7648 tgl 1800 GIC 2128 : oprform = (Form_pg_operator) GETSTRUCT(oprtup);
1801 :
7632 1802 2128 : recomputeNamespacePath();
1803 :
1804 : /*
1805 : * Quick check: if it ain't in the path at all, it ain't visible. Items in
6385 bruce 1806 ECB : * the system namespace are surely in the path and so we needn't even do
1807 : * list_member_oid() for them.
7648 tgl 1808 : */
7648 tgl 1809 CBC 2128 : oprnamespace = oprform->oprnamespace;
7648 tgl 1810 GIC 2128 : if (oprnamespace != PG_CATALOG_NAMESPACE &&
5861 1811 683 : !list_member_oid(activeSearchPath, oprnamespace))
7648 1812 126 : visible = false;
1813 : else
1814 : {
1815 : /*
1816 : * If it is in the path, it might still not be visible; it could be
1817 : * hidden by another operator of the same name and arguments earlier
6385 bruce 1818 ECB : * in the path. So we must do a slow check to see if this is the same
1819 : * operator that would be found by OpernameGetOprid.
7648 tgl 1820 : */
7648 tgl 1821 GIC 2002 : char *oprname = NameStr(oprform->oprname);
1822 :
6187 1823 2002 : visible = (OpernameGetOprid(list_make1(makeString(oprname)),
1824 : oprform->oprleft, oprform->oprright)
6187 tgl 1825 ECB : == oprid);
1826 : }
7648 1827 :
7648 tgl 1828 GIC 2128 : ReleaseSysCache(oprtup);
1829 :
1830 2128 : return visible;
1831 : }
1832 :
1833 :
1834 : /*
1835 : * OpclassnameGetOpcid
1836 : * Try to resolve an unqualified index opclass name.
1837 : * Returns OID if opclass found in search path, else InvalidOid.
1838 : *
1839 : * This is essentially the same as TypenameGetTypid, but we have to have
7648 tgl 1840 ECB : * an extra argument for the index AM OID.
1841 : */
1842 : Oid
7648 tgl 1843 GIC 63537 : OpclassnameGetOpcid(Oid amid, const char *opcname)
1844 : {
7648 tgl 1845 ECB : Oid opcid;
1846 : ListCell *l;
1847 :
7648 tgl 1848 GIC 63537 : recomputeNamespacePath();
7648 tgl 1849 ECB :
5861 tgl 1850 GIC 63916 : foreach(l, activeSearchPath)
7648 tgl 1851 ECB : {
6892 neilc 1852 CBC 63904 : Oid namespaceId = lfirst_oid(l);
1853 :
5833 tgl 1854 63904 : if (namespaceId == myTempNamespace)
5833 tgl 1855 GIC 151 : continue; /* do not look in temp namespace */
1856 :
1601 andres 1857 63753 : opcid = GetSysCacheOid3(CLAAMNAMENSP, Anum_pg_opclass_oid,
4802 rhaas 1858 ECB : ObjectIdGetDatum(amid),
1859 : PointerGetDatum(opcname),
1860 : ObjectIdGetDatum(namespaceId));
7648 tgl 1861 GIC 63753 : if (OidIsValid(opcid))
1862 63525 : return opcid;
7648 tgl 1863 ECB : }
1864 :
1865 : /* Not found in path */
7648 tgl 1866 GIC 12 : return InvalidOid;
1867 : }
1868 :
1869 : /*
1870 : * OpclassIsVisible
1871 : * Determine whether an opclass (identified by OID) is visible in the
1872 : * current search path. Visible means "would be found by searching
7648 tgl 1873 ECB : * for the unqualified opclass name".
1874 : */
1875 : bool
7648 tgl 1876 GIC 350 : OpclassIsVisible(Oid opcid)
1877 : {
1878 : HeapTuple opctup;
1879 : Form_pg_opclass opcform;
7648 tgl 1880 ECB : Oid opcnamespace;
1881 : bool visible;
7648 tgl 1882 EUB :
4802 rhaas 1883 CBC 350 : opctup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opcid));
7648 tgl 1884 GIC 350 : if (!HeapTupleIsValid(opctup))
7202 tgl 1885 LBC 0 : elog(ERROR, "cache lookup failed for opclass %u", opcid);
7648 tgl 1886 GIC 350 : opcform = (Form_pg_opclass) GETSTRUCT(opctup);
1887 :
7632 1888 350 : recomputeNamespacePath();
1889 :
1890 : /*
1891 : * Quick check: if it ain't in the path at all, it ain't visible. Items in
6385 bruce 1892 ECB : * the system namespace are surely in the path and so we needn't even do
1893 : * list_member_oid() for them.
7648 tgl 1894 : */
7648 tgl 1895 CBC 350 : opcnamespace = opcform->opcnamespace;
7648 tgl 1896 GIC 350 : if (opcnamespace != PG_CATALOG_NAMESPACE &&
5861 1897 64 : !list_member_oid(activeSearchPath, opcnamespace))
7648 1898 12 : visible = false;
1899 : else
1900 : {
1901 : /*
1902 : * If it is in the path, it might still not be visible; it could be
1903 : * hidden by another opclass of the same name earlier in the path. So
6385 bruce 1904 ECB : * we must do a slow check to see if this opclass would be found by
1905 : * OpclassnameGetOpcid.
7648 tgl 1906 : */
7648 tgl 1907 GIC 338 : char *opcname = NameStr(opcform->opcname);
1908 :
5951 tgl 1909 CBC 338 : visible = (OpclassnameGetOpcid(opcform->opcmethod, opcname) == opcid);
1910 : }
7648 tgl 1911 ECB :
7648 tgl 1912 GIC 350 : ReleaseSysCache(opctup);
1913 :
1914 350 : return visible;
1915 : }
1916 :
1917 : /*
1918 : * OpfamilynameGetOpfid
1919 : * Try to resolve an unqualified index opfamily name.
1920 : * Returns OID if opfamily found in search path, else InvalidOid.
1921 : *
1922 : * This is essentially the same as TypenameGetTypid, but we have to have
5951 tgl 1923 ECB : * an extra argument for the index AM OID.
1924 : */
1925 : Oid
5951 tgl 1926 GIC 1115 : OpfamilynameGetOpfid(Oid amid, const char *opfname)
1927 : {
5951 tgl 1928 ECB : Oid opfid;
1929 : ListCell *l;
1930 :
5951 tgl 1931 GIC 1115 : recomputeNamespacePath();
5951 tgl 1932 ECB :
5861 tgl 1933 GIC 2202 : foreach(l, activeSearchPath)
5951 tgl 1934 ECB : {
5951 tgl 1935 CBC 2196 : Oid namespaceId = lfirst_oid(l);
1936 :
5833 1937 2196 : if (namespaceId == myTempNamespace)
5833 tgl 1938 GIC 171 : continue; /* do not look in temp namespace */
1939 :
1601 andres 1940 2025 : opfid = GetSysCacheOid3(OPFAMILYAMNAMENSP, Anum_pg_opfamily_oid,
4802 rhaas 1941 ECB : ObjectIdGetDatum(amid),
1942 : PointerGetDatum(opfname),
1943 : ObjectIdGetDatum(namespaceId));
5951 tgl 1944 GIC 2025 : if (OidIsValid(opfid))
1945 1109 : return opfid;
5951 tgl 1946 ECB : }
1947 :
1948 : /* Not found in path */
5951 tgl 1949 GIC 6 : return InvalidOid;
1950 : }
1951 :
1952 : /*
1953 : * OpfamilyIsVisible
1954 : * Determine whether an opfamily (identified by OID) is visible in the
1955 : * current search path. Visible means "would be found by searching
5951 tgl 1956 ECB : * for the unqualified opfamily name".
1957 : */
1958 : bool
5951 tgl 1959 GIC 829 : OpfamilyIsVisible(Oid opfid)
1960 : {
1961 : HeapTuple opftup;
1962 : Form_pg_opfamily opfform;
5951 tgl 1963 ECB : Oid opfnamespace;
1964 : bool visible;
5951 tgl 1965 EUB :
4802 rhaas 1966 CBC 829 : opftup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfid));
5951 tgl 1967 GIC 829 : if (!HeapTupleIsValid(opftup))
5951 tgl 1968 LBC 0 : elog(ERROR, "cache lookup failed for opfamily %u", opfid);
5951 tgl 1969 GIC 829 : opfform = (Form_pg_opfamily) GETSTRUCT(opftup);
1970 :
1971 829 : recomputeNamespacePath();
1972 :
1973 : /*
1974 : * Quick check: if it ain't in the path at all, it ain't visible. Items in
5951 tgl 1975 ECB : * the system namespace are surely in the path and so we needn't even do
1976 : * list_member_oid() for them.
1977 : */
5951 tgl 1978 CBC 829 : opfnamespace = opfform->opfnamespace;
5951 tgl 1979 GIC 829 : if (opfnamespace != PG_CATALOG_NAMESPACE &&
5861 1980 685 : !list_member_oid(activeSearchPath, opfnamespace))
5951 1981 75 : visible = false;
1982 : else
1983 : {
1984 : /*
1985 : * If it is in the path, it might still not be visible; it could be
1986 : * hidden by another opfamily of the same name earlier in the path. So
5951 tgl 1987 ECB : * we must do a slow check to see if this opfamily would be found by
1988 : * OpfamilynameGetOpfid.
1989 : */
5951 tgl 1990 GIC 754 : char *opfname = NameStr(opfform->opfname);
1991 :
5951 tgl 1992 CBC 754 : visible = (OpfamilynameGetOpfid(opfform->opfmethod, opfname) == opfid);
1993 : }
5951 tgl 1994 ECB :
5951 tgl 1995 GIC 829 : ReleaseSysCache(opftup);
1996 :
1997 829 : return visible;
1998 : }
1999 :
2000 : /*
2001 : * lookup_collation
2002 : * If there's a collation of the given name/namespace, and it works
2115 tgl 2003 ECB : * with the given encoding, return its OID. Else return InvalidOid.
2004 : */
2005 : static Oid
2115 tgl 2006 GIC 5751 : lookup_collation(const char *collname, Oid collnamespace, int32 encoding)
2007 : {
2008 : Oid collid;
2009 : HeapTuple colltup;
2115 tgl 2010 ECB : Form_pg_collation collform;
2011 :
2012 : /* Check for encoding-specific entry (exact match) */
1601 andres 2013 GIC 5751 : collid = GetSysCacheOid3(COLLNAMEENCNSP, Anum_pg_collation_oid,
2115 tgl 2014 ECB : PointerGetDatum(collname),
2015 : Int32GetDatum(encoding),
2016 : ObjectIdGetDatum(collnamespace));
2115 tgl 2017 GIC 5751 : if (OidIsValid(collid))
2018 164 : return collid;
2019 :
2020 : /*
2021 : * Check for any-encoding entry. This takes a bit more work: while libc
2022 : * collations with collencoding = -1 do work with all encodings, ICU
2115 tgl 2023 ECB : * collations only work with certain encodings, so we have to check that
2024 : * aspect before deciding it's a match.
2025 : */
2115 tgl 2026 GIC 5587 : colltup = SearchSysCache3(COLLNAMEENCNSP,
2115 tgl 2027 ECB : PointerGetDatum(collname),
2028 : Int32GetDatum(-1),
2029 : ObjectIdGetDatum(collnamespace));
2115 tgl 2030 CBC 5587 : if (!HeapTupleIsValid(colltup))
2115 tgl 2031 GIC 530 : return InvalidOid;
2115 tgl 2032 CBC 5057 : collform = (Form_pg_collation) GETSTRUCT(colltup);
2033 5057 : if (collform->collprovider == COLLPROVIDER_ICU)
2034 : {
2115 tgl 2035 GBC 439 : if (is_encoding_supported_by_icu(encoding))
1601 andres 2036 GIC 439 : collid = collform->oid;
2037 : else
2115 tgl 2038 UIC 0 : collid = InvalidOid;
2115 tgl 2039 ECB : }
2040 : else
2041 : {
1601 andres 2042 CBC 4618 : collid = collform->oid;
2043 : }
2115 tgl 2044 GIC 5057 : ReleaseSysCache(colltup);
2045 5057 : return collid;
2046 : }
2047 :
2048 : /*
2049 : * CollationGetCollid
2050 : * Try to resolve an unqualified collation name.
2051 : * Returns OID if collation found in search path, else InvalidOid.
2052 : *
2053 : * Note that this will only find collations that work with the current
2115 tgl 2054 ECB : * database's encoding.
2055 : */
4443 peter_e 2056 : Oid
4443 peter_e 2057 GIC 215 : CollationGetCollid(const char *collname)
2058 : {
4412 tgl 2059 CBC 215 : int32 dbencoding = GetDatabaseEncoding();
2060 : ListCell *l;
4443 peter_e 2061 ECB :
4443 peter_e 2062 GIC 215 : recomputeNamespacePath();
4443 peter_e 2063 ECB :
4443 peter_e 2064 GIC 334 : foreach(l, activeSearchPath)
2065 : {
4443 peter_e 2066 CBC 334 : Oid namespaceId = lfirst_oid(l);
4412 tgl 2067 ECB : Oid collid;
2068 :
4443 peter_e 2069 CBC 334 : if (namespaceId == myTempNamespace)
2070 71 : continue; /* do not look in temp namespace */
4443 peter_e 2071 ECB :
2115 tgl 2072 GIC 263 : collid = lookup_collation(collname, namespaceId, dbencoding);
4443 peter_e 2073 263 : if (OidIsValid(collid))
2074 215 : return collid;
4443 peter_e 2075 EUB : }
2076 :
2077 : /* Not found in path */
4443 peter_e 2078 UIC 0 : return InvalidOid;
2079 : }
2080 :
2081 : /*
2082 : * CollationIsVisible
2083 : * Determine whether a collation (identified by OID) is visible in the
2084 : * current search path. Visible means "would be found by searching
2085 : * for the unqualified collation name".
2086 : *
2087 : * Note that only collations that work with the current database's encoding
2115 tgl 2088 ECB : * will be considered visible.
2089 : */
2090 : bool
4443 peter_e 2091 GIC 215 : CollationIsVisible(Oid collid)
2092 : {
2093 : HeapTuple colltup;
2094 : Form_pg_collation collform;
4443 peter_e 2095 ECB : Oid collnamespace;
2096 : bool visible;
4443 peter_e 2097 EUB :
4443 peter_e 2098 CBC 215 : colltup = SearchSysCache1(COLLOID, ObjectIdGetDatum(collid));
4443 peter_e 2099 GIC 215 : if (!HeapTupleIsValid(colltup))
4443 peter_e 2100 LBC 0 : elog(ERROR, "cache lookup failed for collation %u", collid);
4443 peter_e 2101 GIC 215 : collform = (Form_pg_collation) GETSTRUCT(colltup);
2102 :
2103 215 : recomputeNamespacePath();
2104 :
2105 : /*
2106 : * Quick check: if it ain't in the path at all, it ain't visible. Items in
4443 peter_e 2107 ECB : * the system namespace are surely in the path and so we needn't even do
2108 : * list_member_oid() for them.
2109 : */
4443 peter_e 2110 GBC 215 : collnamespace = collform->collnamespace;
4443 peter_e 2111 GIC 215 : if (collnamespace != PG_CATALOG_NAMESPACE &&
2112 48 : !list_member_oid(activeSearchPath, collnamespace))
4443 peter_e 2113 UIC 0 : visible = false;
2114 : else
2115 : {
2116 : /*
2117 : * If it is in the path, it might still not be visible; it could be
2118 : * hidden by another collation of the same name earlier in the path,
2119 : * or it might not work with the current DB encoding. So we must do a
2115 tgl 2120 ECB : * slow check to see if this collation would be found by
2121 : * CollationGetCollid.
4443 peter_e 2122 : */
4443 peter_e 2123 GIC 215 : char *collname = NameStr(collform->collname);
2124 :
4443 peter_e 2125 CBC 215 : visible = (CollationGetCollid(collname) == collid);
2126 : }
4443 peter_e 2127 ECB :
4443 peter_e 2128 GIC 215 : ReleaseSysCache(colltup);
2129 :
2130 215 : return visible;
2131 : }
2132 :
2133 :
2134 : /*
2135 : * ConversionGetConid
2136 : * Try to resolve an unqualified conversion name.
2137 : * Returns OID if conversion found in search path, else InvalidOid.
2138 : *
7423 bruce 2139 ECB : * This is essentially the same as RelnameGetRelid.
2140 : */
2141 : Oid
7423 bruce 2142 GIC 9 : ConversionGetConid(const char *conname)
2143 : {
7188 bruce 2144 ECB : Oid conid;
2145 : ListCell *l;
7423 2146 :
7423 bruce 2147 GIC 9 : recomputeNamespacePath();
7423 bruce 2148 ECB :
5861 tgl 2149 GIC 18 : foreach(l, activeSearchPath)
7423 bruce 2150 ECB : {
6892 neilc 2151 GBC 18 : Oid namespaceId = lfirst_oid(l);
2152 :
5833 tgl 2153 CBC 18 : if (namespaceId == myTempNamespace)
5833 tgl 2154 UIC 0 : continue; /* do not look in temp namespace */
2155 :
1601 andres 2156 CBC 18 : conid = GetSysCacheOid2(CONNAMENSP, Anum_pg_conversion_oid,
4802 rhaas 2157 ECB : PointerGetDatum(conname),
2158 : ObjectIdGetDatum(namespaceId));
7423 bruce 2159 GIC 18 : if (OidIsValid(conid))
2160 9 : return conid;
7423 bruce 2161 EUB : }
2162 :
2163 : /* Not found in path */
7423 bruce 2164 UIC 0 : return InvalidOid;
2165 : }
2166 :
2167 : /*
2168 : * ConversionIsVisible
2169 : * Determine whether a conversion (identified by OID) is visible in the
2170 : * current search path. Visible means "would be found by searching
7423 bruce 2171 ECB : * for the unqualified conversion name".
2172 : */
2173 : bool
7423 bruce 2174 GIC 15 : ConversionIsVisible(Oid conid)
2175 : {
2176 : HeapTuple contup;
2177 : Form_pg_conversion conform;
7423 bruce 2178 ECB : Oid connamespace;
2179 : bool visible;
7423 bruce 2180 EUB :
4802 rhaas 2181 CBC 15 : contup = SearchSysCache1(CONVOID, ObjectIdGetDatum(conid));
7423 bruce 2182 GIC 15 : if (!HeapTupleIsValid(contup))
7202 tgl 2183 LBC 0 : elog(ERROR, "cache lookup failed for conversion %u", conid);
7423 bruce 2184 GIC 15 : conform = (Form_pg_conversion) GETSTRUCT(contup);
2185 :
2186 15 : recomputeNamespacePath();
2187 :
2188 : /*
2189 : * Quick check: if it ain't in the path at all, it ain't visible. Items in
6385 bruce 2190 ECB : * the system namespace are surely in the path and so we needn't even do
2191 : * list_member_oid() for them.
7423 2192 : */
7423 bruce 2193 CBC 15 : connamespace = conform->connamespace;
7423 bruce 2194 GIC 15 : if (connamespace != PG_CATALOG_NAMESPACE &&
5861 tgl 2195 15 : !list_member_oid(activeSearchPath, connamespace))
7423 bruce 2196 6 : visible = false;
2197 : else
2198 : {
2199 : /*
2200 : * If it is in the path, it might still not be visible; it could be
2201 : * hidden by another conversion of the same name earlier in the path.
6385 bruce 2202 ECB : * So we must do a slow check to see if this conversion would be found
2203 : * by ConversionGetConid.
7423 2204 : */
7423 bruce 2205 GIC 9 : char *conname = NameStr(conform->conname);
2206 :
7423 bruce 2207 CBC 9 : visible = (ConversionGetConid(conname) == conid);
2208 : }
7423 bruce 2209 ECB :
7423 bruce 2210 GIC 15 : ReleaseSysCache(contup);
2211 :
2212 15 : return visible;
2213 : }
2214 :
2215 : /*
2216 : * get_statistics_object_oid - find a statistics object by possibly qualified name
2217 : *
2207 alvherre 2218 ECB : * If not found, returns InvalidOid if missing_ok, else throws error
2219 : */
2220 : Oid
2156 tgl 2221 GIC 158 : get_statistics_object_oid(List *names, bool missing_ok)
2222 : {
2207 alvherre 2223 ECB : char *schemaname;
2224 : char *stats_name;
2225 : Oid namespaceId;
2207 alvherre 2226 GIC 158 : Oid stats_oid = InvalidOid;
2207 alvherre 2227 ECB : ListCell *l;
2228 :
2229 : /* deconstruct the name list */
2207 alvherre 2230 GIC 158 : DeconstructQualifiedName(names, &schemaname, &stats_name);
2231 :
2207 alvherre 2232 CBC 158 : if (schemaname)
2207 alvherre 2233 ECB : {
2207 alvherre 2234 EUB : /* use exact schema given */
2207 alvherre 2235 GIC 14 : namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
2207 alvherre 2236 CBC 14 : if (missing_ok && !OidIsValid(namespaceId))
2207 alvherre 2237 UIC 0 : stats_oid = InvalidOid;
2238 : else
1601 andres 2239 GIC 14 : stats_oid = GetSysCacheOid2(STATEXTNAMENSP, Anum_pg_statistic_ext_oid,
2240 : PointerGetDatum(stats_name),
2241 : ObjectIdGetDatum(namespaceId));
2242 : }
2207 alvherre 2243 ECB : else
2244 : {
2245 : /* search for it in search path */
2207 alvherre 2246 GIC 144 : recomputeNamespacePath();
2207 alvherre 2247 ECB :
2207 alvherre 2248 GIC 294 : foreach(l, activeSearchPath)
2207 alvherre 2249 ECB : {
2207 alvherre 2250 GBC 288 : namespaceId = lfirst_oid(l);
2207 alvherre 2251 ECB :
2207 alvherre 2252 GIC 288 : if (namespaceId == myTempNamespace)
2207 alvherre 2253 UIC 0 : continue; /* do not look in temp namespace */
1601 andres 2254 CBC 288 : stats_oid = GetSysCacheOid2(STATEXTNAMENSP, Anum_pg_statistic_ext_oid,
2207 alvherre 2255 ECB : PointerGetDatum(stats_name),
2256 : ObjectIdGetDatum(namespaceId));
2207 alvherre 2257 GIC 288 : if (OidIsValid(stats_oid))
2258 138 : break;
2207 alvherre 2259 ECB : }
2260 : }
2261 :
2207 alvherre 2262 GIC 158 : if (!OidIsValid(stats_oid) && !missing_ok)
2263 3 : ereport(ERROR,
2264 : (errcode(ERRCODE_UNDEFINED_OBJECT),
2156 tgl 2265 ECB : errmsg("statistics object \"%s\" does not exist",
2266 : NameListToString(names))));
2267 :
2207 alvherre 2268 GIC 155 : return stats_oid;
2269 : }
2270 :
2271 : /*
2272 : * StatisticsObjIsVisible
2273 : * Determine whether a statistics object (identified by OID) is visible in
2274 : * the current search path. Visible means "would be found by searching
2157 alvherre 2275 ECB : * for the unqualified statistics object name".
2276 : */
2277 : bool
2157 alvherre 2278 GIC 323 : StatisticsObjIsVisible(Oid relid)
2279 : {
2280 : HeapTuple stxtup;
2281 : Form_pg_statistic_ext stxform;
2157 alvherre 2282 ECB : Oid stxnamespace;
2283 : bool visible;
2157 alvherre 2284 EUB :
2157 alvherre 2285 CBC 323 : stxtup = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(relid));
2157 alvherre 2286 GIC 323 : if (!HeapTupleIsValid(stxtup))
2157 alvherre 2287 LBC 0 : elog(ERROR, "cache lookup failed for statistics object %u", relid);
2157 alvherre 2288 GIC 323 : stxform = (Form_pg_statistic_ext) GETSTRUCT(stxtup);
2289 :
2290 323 : recomputeNamespacePath();
2291 :
2292 : /*
2293 : * Quick check: if it ain't in the path at all, it ain't visible. Items in
2157 alvherre 2294 ECB : * the system namespace are surely in the path and so we needn't even do
2295 : * list_member_oid() for them.
2296 : */
2157 alvherre 2297 CBC 323 : stxnamespace = stxform->stxnamespace;
2157 alvherre 2298 GIC 323 : if (stxnamespace != PG_CATALOG_NAMESPACE &&
2299 323 : !list_member_oid(activeSearchPath, stxnamespace))
2300 39 : visible = false;
2301 : else
2302 : {
2303 : /*
2304 : * If it is in the path, it might still not be visible; it could be
2157 alvherre 2305 ECB : * hidden by another statistics object of the same name earlier in the
2306 : * path. So we must do a slow check for conflicting objects.
2307 : */
2157 alvherre 2308 CBC 284 : char *stxname = NameStr(stxform->stxname);
2157 alvherre 2309 ECB : ListCell *l;
2310 :
2157 alvherre 2311 CBC 284 : visible = false;
2157 alvherre 2312 GIC 611 : foreach(l, activeSearchPath)
2157 alvherre 2313 ECB : {
2157 alvherre 2314 GIC 611 : Oid namespaceId = lfirst_oid(l);
2315 :
2157 alvherre 2316 CBC 611 : if (namespaceId == stxnamespace)
2157 alvherre 2317 ECB : {
2318 : /* Found it first in path */
2157 alvherre 2319 CBC 284 : visible = true;
2157 alvherre 2320 GIC 284 : break;
2321 : }
2322 327 : if (SearchSysCacheExists2(STATEXTNAMENSP,
2323 : PointerGetDatum(stxname),
2157 alvherre 2324 EUB : ObjectIdGetDatum(namespaceId)))
2325 : {
2326 : /* Found something else first in path */
2157 alvherre 2327 UIC 0 : break;
2328 : }
2157 alvherre 2329 ECB : }
2330 : }
2331 :
2157 alvherre 2332 GIC 323 : ReleaseSysCache(stxtup);
2333 :
2334 323 : return visible;
2335 : }
2336 :
2337 : /*
2338 : * get_ts_parser_oid - find a TS parser by possibly qualified name
2339 : *
4630 rhaas 2340 ECB : * If not found, returns InvalidOid if missing_ok, else throws error
2341 : */
2342 : Oid
4630 rhaas 2343 GIC 8549 : get_ts_parser_oid(List *names, bool missing_ok)
2344 : {
5710 tgl 2345 ECB : char *schemaname;
2346 : char *parser_name;
2347 : Oid namespaceId;
5710 tgl 2348 GIC 8549 : Oid prsoid = InvalidOid;
5710 tgl 2349 ECB : ListCell *l;
2350 :
2351 : /* deconstruct the name list */
5710 tgl 2352 GIC 8549 : DeconstructQualifiedName(names, &schemaname, &parser_name);
2353 :
5710 tgl 2354 CBC 8543 : if (schemaname)
5710 tgl 2355 ECB : {
2356 : /* use exact schema given */
3725 bruce 2357 GIC 23 : namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
3725 bruce 2358 CBC 23 : if (missing_ok && !OidIsValid(namespaceId))
3725 bruce 2359 GIC 3 : prsoid = InvalidOid;
2360 : else
1601 andres 2361 20 : prsoid = GetSysCacheOid2(TSPARSERNAMENSP, Anum_pg_ts_parser_oid,
2362 : PointerGetDatum(parser_name),
2363 : ObjectIdGetDatum(namespaceId));
2364 : }
5710 tgl 2365 ECB : else
2366 : {
2367 : /* search for it in search path */
5710 tgl 2368 GIC 8520 : recomputeNamespacePath();
5710 tgl 2369 ECB :
5710 tgl 2370 GIC 8562 : foreach(l, activeSearchPath)
5710 tgl 2371 ECB : {
5710 tgl 2372 GBC 8550 : namespaceId = lfirst_oid(l);
2373 :
5710 tgl 2374 CBC 8550 : if (namespaceId == myTempNamespace)
5624 bruce 2375 UIC 0 : continue; /* do not look in temp namespace */
2376 :
1601 andres 2377 CBC 8550 : prsoid = GetSysCacheOid2(TSPARSERNAMENSP, Anum_pg_ts_parser_oid,
4802 rhaas 2378 ECB : PointerGetDatum(parser_name),
2379 : ObjectIdGetDatum(namespaceId));
5710 tgl 2380 GIC 8550 : if (OidIsValid(prsoid))
2381 8508 : break;
5710 tgl 2382 ECB : }
2383 : }
2384 :
4630 rhaas 2385 GIC 8543 : if (!OidIsValid(prsoid) && !missing_ok)
5710 tgl 2386 15 : ereport(ERROR,
2387 : (errcode(ERRCODE_UNDEFINED_OBJECT),
5710 tgl 2388 ECB : errmsg("text search parser \"%s\" does not exist",
2389 : NameListToString(names))));
2390 :
5710 tgl 2391 GIC 8528 : return prsoid;
2392 : }
2393 :
2394 : /*
2395 : * TSParserIsVisible
2396 : * Determine whether a parser (identified by OID) is visible in the
2397 : * current search path. Visible means "would be found by searching
5710 tgl 2398 ECB : * for the unqualified parser name".
2399 : */
2400 : bool
5710 tgl 2401 GIC 15 : TSParserIsVisible(Oid prsId)
2402 : {
2403 : HeapTuple tup;
2404 : Form_pg_ts_parser form;
5710 tgl 2405 ECB : Oid namespace;
2406 : bool visible;
5710 tgl 2407 EUB :
4802 rhaas 2408 CBC 15 : tup = SearchSysCache1(TSPARSEROID, ObjectIdGetDatum(prsId));
5710 tgl 2409 GIC 15 : if (!HeapTupleIsValid(tup))
5710 tgl 2410 LBC 0 : elog(ERROR, "cache lookup failed for text search parser %u", prsId);
5710 tgl 2411 GIC 15 : form = (Form_pg_ts_parser) GETSTRUCT(tup);
2412 :
2413 15 : recomputeNamespacePath();
2414 :
2415 : /*
2416 : * Quick check: if it ain't in the path at all, it ain't visible. Items in
5710 tgl 2417 ECB : * the system namespace are surely in the path and so we needn't even do
2418 : * list_member_oid() for them.
2419 : */
5710 tgl 2420 CBC 15 : namespace = form->prsnamespace;
5710 tgl 2421 GIC 15 : if (namespace != PG_CATALOG_NAMESPACE &&
2422 15 : !list_member_oid(activeSearchPath, namespace))
2423 6 : visible = false;
2424 : else
2425 : {
2426 : /*
2427 : * If it is in the path, it might still not be visible; it could be
5624 bruce 2428 ECB : * hidden by another parser of the same name earlier in the path. So
2429 : * we must do a slow check for conflicting parsers.
2430 : */
5710 tgl 2431 CBC 9 : char *name = NameStr(form->prsname);
5710 tgl 2432 ECB : ListCell *l;
2433 :
5710 tgl 2434 CBC 9 : visible = false;
5710 tgl 2435 GIC 18 : foreach(l, activeSearchPath)
5710 tgl 2436 ECB : {
5710 tgl 2437 GBC 18 : Oid namespaceId = lfirst_oid(l);
2438 :
5710 tgl 2439 CBC 18 : if (namespaceId == myTempNamespace)
5624 bruce 2440 UIC 0 : continue; /* do not look in temp namespace */
2441 :
5710 tgl 2442 CBC 18 : if (namespaceId == namespace)
5710 tgl 2443 ECB : {
2444 : /* Found it first in path */
5710 tgl 2445 CBC 9 : visible = true;
5710 tgl 2446 GIC 9 : break;
2447 : }
4802 rhaas 2448 9 : if (SearchSysCacheExists2(TSPARSERNAMENSP,
2449 : PointerGetDatum(name),
4802 rhaas 2450 EUB : ObjectIdGetDatum(namespaceId)))
2451 : {
2452 : /* Found something else first in path */
5710 tgl 2453 UIC 0 : break;
2454 : }
5710 tgl 2455 ECB : }
2456 : }
2457 :
5710 tgl 2458 GIC 15 : ReleaseSysCache(tup);
2459 :
2460 15 : return visible;
2461 : }
2462 :
2463 : /*
2464 : * get_ts_dict_oid - find a TS dictionary by possibly qualified name
2465 : *
1363 michael 2466 ECB : * If not found, returns InvalidOid if missing_ok, else throws error
2467 : */
2468 : Oid
4630 rhaas 2469 GIC 34507 : get_ts_dict_oid(List *names, bool missing_ok)
2470 : {
5710 tgl 2471 ECB : char *schemaname;
2472 : char *dict_name;
2473 : Oid namespaceId;
5710 tgl 2474 GIC 34507 : Oid dictoid = InvalidOid;
5710 tgl 2475 ECB : ListCell *l;
2476 :
2477 : /* deconstruct the name list */
5710 tgl 2478 GIC 34507 : DeconstructQualifiedName(names, &schemaname, &dict_name);
2479 :
5710 tgl 2480 CBC 34501 : if (schemaname)
5710 tgl 2481 ECB : {
2482 : /* use exact schema given */
3725 bruce 2483 GIC 52 : namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
3725 bruce 2484 CBC 52 : if (missing_ok && !OidIsValid(namespaceId))
3725 bruce 2485 GIC 3 : dictoid = InvalidOid;
2486 : else
1601 andres 2487 49 : dictoid = GetSysCacheOid2(TSDICTNAMENSP, Anum_pg_ts_dict_oid,
2488 : PointerGetDatum(dict_name),
2489 : ObjectIdGetDatum(namespaceId));
2490 : }
5710 tgl 2491 ECB : else
2492 : {
2493 : /* search for it in search path */
5710 tgl 2494 GIC 34449 : recomputeNamespacePath();
5710 tgl 2495 ECB :
5710 tgl 2496 GIC 34877 : foreach(l, activeSearchPath)
5710 tgl 2497 ECB : {
5710 tgl 2498 GBC 34862 : namespaceId = lfirst_oid(l);
2499 :
5710 tgl 2500 CBC 34862 : if (namespaceId == myTempNamespace)
5624 bruce 2501 UIC 0 : continue; /* do not look in temp namespace */
2502 :
1601 andres 2503 CBC 34862 : dictoid = GetSysCacheOid2(TSDICTNAMENSP, Anum_pg_ts_dict_oid,
4802 rhaas 2504 ECB : PointerGetDatum(dict_name),
2505 : ObjectIdGetDatum(namespaceId));
5710 tgl 2506 GIC 34862 : if (OidIsValid(dictoid))
2507 34434 : break;
5710 tgl 2508 ECB : }
2509 : }
2510 :
4630 rhaas 2511 GIC 34501 : if (!OidIsValid(dictoid) && !missing_ok)
5710 tgl 2512 15 : ereport(ERROR,
2513 : (errcode(ERRCODE_UNDEFINED_OBJECT),
5710 tgl 2514 ECB : errmsg("text search dictionary \"%s\" does not exist",
2515 : NameListToString(names))));
2516 :
5710 tgl 2517 GIC 34486 : return dictoid;
2518 : }
2519 :
2520 : /*
2521 : * TSDictionaryIsVisible
2522 : * Determine whether a dictionary (identified by OID) is visible in the
2523 : * current search path. Visible means "would be found by searching
5710 tgl 2524 ECB : * for the unqualified dictionary name".
2525 : */
2526 : bool
5710 tgl 2527 GIC 1319 : TSDictionaryIsVisible(Oid dictId)
2528 : {
2529 : HeapTuple tup;
2530 : Form_pg_ts_dict form;
5710 tgl 2531 ECB : Oid namespace;
2532 : bool visible;
5710 tgl 2533 EUB :
4802 rhaas 2534 GIC 1319 : tup = SearchSysCache1(TSDICTOID, ObjectIdGetDatum(dictId));
5710 tgl 2535 CBC 1319 : if (!HeapTupleIsValid(tup))
5710 tgl 2536 UIC 0 : elog(ERROR, "cache lookup failed for text search dictionary %u",
5710 tgl 2537 ECB : dictId);
5710 tgl 2538 GIC 1319 : form = (Form_pg_ts_dict) GETSTRUCT(tup);
2539 :
2540 1319 : recomputeNamespacePath();
2541 :
2542 : /*
2543 : * Quick check: if it ain't in the path at all, it ain't visible. Items in
5710 tgl 2544 ECB : * the system namespace are surely in the path and so we needn't even do
2545 : * list_member_oid() for them.
2546 : */
5710 tgl 2547 CBC 1319 : namespace = form->dictnamespace;
5710 tgl 2548 GIC 1319 : if (namespace != PG_CATALOG_NAMESPACE &&
2549 153 : !list_member_oid(activeSearchPath, namespace))
2550 141 : visible = false;
2551 : else
2552 : {
2553 : /*
2554 : * If it is in the path, it might still not be visible; it could be
5624 bruce 2555 ECB : * hidden by another dictionary of the same name earlier in the path.
2556 : * So we must do a slow check for conflicting dictionaries.
2557 : */
5710 tgl 2558 CBC 1178 : char *name = NameStr(form->dictname);
5710 tgl 2559 ECB : ListCell *l;
2560 :
5710 tgl 2561 CBC 1178 : visible = false;
5710 tgl 2562 GIC 1190 : foreach(l, activeSearchPath)
5710 tgl 2563 ECB : {
5710 tgl 2564 GBC 1190 : Oid namespaceId = lfirst_oid(l);
2565 :
5710 tgl 2566 CBC 1190 : if (namespaceId == myTempNamespace)
5624 bruce 2567 UIC 0 : continue; /* do not look in temp namespace */
2568 :
5710 tgl 2569 CBC 1190 : if (namespaceId == namespace)
5710 tgl 2570 ECB : {
2571 : /* Found it first in path */
5710 tgl 2572 CBC 1178 : visible = true;
5710 tgl 2573 GIC 1178 : break;
2574 : }
4802 rhaas 2575 12 : if (SearchSysCacheExists2(TSDICTNAMENSP,
2576 : PointerGetDatum(name),
4802 rhaas 2577 EUB : ObjectIdGetDatum(namespaceId)))
2578 : {
2579 : /* Found something else first in path */
5710 tgl 2580 UIC 0 : break;
2581 : }
5710 tgl 2582 ECB : }
2583 : }
2584 :
5710 tgl 2585 GIC 1319 : ReleaseSysCache(tup);
2586 :
2587 1319 : return visible;
2588 : }
2589 :
2590 : /*
2591 : * get_ts_template_oid - find a TS template by possibly qualified name
2592 : *
4630 rhaas 2593 ECB : * If not found, returns InvalidOid if missing_ok, else throws error
2594 : */
2595 : Oid
4630 rhaas 2596 GIC 8910 : get_ts_template_oid(List *names, bool missing_ok)
2597 : {
5710 tgl 2598 ECB : char *schemaname;
2599 : char *template_name;
2600 : Oid namespaceId;
5710 tgl 2601 GIC 8910 : Oid tmploid = InvalidOid;
5710 tgl 2602 ECB : ListCell *l;
2603 :
2604 : /* deconstruct the name list */
5710 tgl 2605 GIC 8910 : DeconstructQualifiedName(names, &schemaname, &template_name);
2606 :
5710 tgl 2607 CBC 8904 : if (schemaname)
5710 tgl 2608 ECB : {
2609 : /* use exact schema given */
3725 bruce 2610 GIC 28 : namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
3725 bruce 2611 CBC 28 : if (missing_ok && !OidIsValid(namespaceId))
3725 bruce 2612 GIC 3 : tmploid = InvalidOid;
2613 : else
1601 andres 2614 25 : tmploid = GetSysCacheOid2(TSTEMPLATENAMENSP, Anum_pg_ts_template_oid,
2615 : PointerGetDatum(template_name),
2616 : ObjectIdGetDatum(namespaceId));
2617 : }
5710 tgl 2618 ECB : else
2619 : {
2620 : /* search for it in search path */
5710 tgl 2621 GIC 8876 : recomputeNamespacePath();
5710 tgl 2622 ECB :
5710 tgl 2623 GIC 8919 : foreach(l, activeSearchPath)
5710 tgl 2624 ECB : {
5710 tgl 2625 GBC 8907 : namespaceId = lfirst_oid(l);
2626 :
5710 tgl 2627 CBC 8907 : if (namespaceId == myTempNamespace)
5624 bruce 2628 UIC 0 : continue; /* do not look in temp namespace */
2629 :
1601 andres 2630 CBC 8907 : tmploid = GetSysCacheOid2(TSTEMPLATENAMENSP, Anum_pg_ts_template_oid,
4802 rhaas 2631 ECB : PointerGetDatum(template_name),
2632 : ObjectIdGetDatum(namespaceId));
5710 tgl 2633 GIC 8907 : if (OidIsValid(tmploid))
2634 8864 : break;
5710 tgl 2635 ECB : }
2636 : }
2637 :
4630 rhaas 2638 GIC 8904 : if (!OidIsValid(tmploid) && !missing_ok)
5710 tgl 2639 15 : ereport(ERROR,
2640 : (errcode(ERRCODE_UNDEFINED_OBJECT),
5710 tgl 2641 ECB : errmsg("text search template \"%s\" does not exist",
2642 : NameListToString(names))));
2643 :
5710 tgl 2644 GIC 8889 : return tmploid;
2645 : }
2646 :
2647 : /*
2648 : * TSTemplateIsVisible
2649 : * Determine whether a template (identified by OID) is visible in the
2650 : * current search path. Visible means "would be found by searching
5710 tgl 2651 ECB : * for the unqualified template name".
2652 : */
2653 : bool
5710 tgl 2654 GIC 15 : TSTemplateIsVisible(Oid tmplId)
2655 : {
2656 : HeapTuple tup;
2657 : Form_pg_ts_template form;
5710 tgl 2658 ECB : Oid namespace;
2659 : bool visible;
5710 tgl 2660 EUB :
4802 rhaas 2661 CBC 15 : tup = SearchSysCache1(TSTEMPLATEOID, ObjectIdGetDatum(tmplId));
5710 tgl 2662 GIC 15 : if (!HeapTupleIsValid(tup))
5710 tgl 2663 LBC 0 : elog(ERROR, "cache lookup failed for text search template %u", tmplId);
5710 tgl 2664 GIC 15 : form = (Form_pg_ts_template) GETSTRUCT(tup);
2665 :
2666 15 : recomputeNamespacePath();
2667 :
2668 : /*
2669 : * Quick check: if it ain't in the path at all, it ain't visible. Items in
5710 tgl 2670 ECB : * the system namespace are surely in the path and so we needn't even do
2671 : * list_member_oid() for them.
2672 : */
5710 tgl 2673 CBC 15 : namespace = form->tmplnamespace;
5710 tgl 2674 GIC 15 : if (namespace != PG_CATALOG_NAMESPACE &&
2675 15 : !list_member_oid(activeSearchPath, namespace))
2676 6 : visible = false;
2677 : else
2678 : {
2679 : /*
2680 : * If it is in the path, it might still not be visible; it could be
5624 bruce 2681 ECB : * hidden by another template of the same name earlier in the path. So
2682 : * we must do a slow check for conflicting templates.
2683 : */
5710 tgl 2684 CBC 9 : char *name = NameStr(form->tmplname);
5710 tgl 2685 ECB : ListCell *l;
2686 :
5710 tgl 2687 CBC 9 : visible = false;
5710 tgl 2688 GIC 18 : foreach(l, activeSearchPath)
5710 tgl 2689 ECB : {
5710 tgl 2690 GBC 18 : Oid namespaceId = lfirst_oid(l);
2691 :
5710 tgl 2692 CBC 18 : if (namespaceId == myTempNamespace)
5624 bruce 2693 UIC 0 : continue; /* do not look in temp namespace */
2694 :
5710 tgl 2695 CBC 18 : if (namespaceId == namespace)
5710 tgl 2696 ECB : {
2697 : /* Found it first in path */
5710 tgl 2698 CBC 9 : visible = true;
5710 tgl 2699 GIC 9 : break;
2700 : }
4802 rhaas 2701 9 : if (SearchSysCacheExists2(TSTEMPLATENAMENSP,
2702 : PointerGetDatum(name),
4802 rhaas 2703 EUB : ObjectIdGetDatum(namespaceId)))
2704 : {
2705 : /* Found something else first in path */
5710 tgl 2706 UIC 0 : break;
2707 : }
5710 tgl 2708 ECB : }
2709 : }
2710 :
5710 tgl 2711 GIC 15 : ReleaseSysCache(tup);
2712 :
2713 15 : return visible;
2714 : }
2715 :
2716 : /*
2717 : * get_ts_config_oid - find a TS config by possibly qualified name
2718 : *
4630 rhaas 2719 ECB : * If not found, returns InvalidOid if missing_ok, else throws error
2720 : */
2721 : Oid
4630 rhaas 2722 GIC 37749 : get_ts_config_oid(List *names, bool missing_ok)
2723 : {
5710 tgl 2724 ECB : char *schemaname;
2725 : char *config_name;
2726 : Oid namespaceId;
5710 tgl 2727 GIC 37749 : Oid cfgoid = InvalidOid;
5710 tgl 2728 ECB : ListCell *l;
2729 :
2730 : /* deconstruct the name list */
5710 tgl 2731 GIC 37749 : DeconstructQualifiedName(names, &schemaname, &config_name);
2732 :
5710 tgl 2733 CBC 37743 : if (schemaname)
5710 tgl 2734 ECB : {
2735 : /* use exact schema given */
3725 bruce 2736 GIC 2722 : namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
3725 bruce 2737 CBC 2722 : if (missing_ok && !OidIsValid(namespaceId))
3725 bruce 2738 GIC 3 : cfgoid = InvalidOid;
2739 : else
1601 andres 2740 2719 : cfgoid = GetSysCacheOid2(TSCONFIGNAMENSP, Anum_pg_ts_config_oid,
2741 : PointerGetDatum(config_name),
2742 : ObjectIdGetDatum(namespaceId));
2743 : }
5710 tgl 2744 ECB : else
2745 : {
2746 : /* search for it in search path */
5710 tgl 2747 GIC 35021 : recomputeNamespacePath();
5710 tgl 2748 ECB :
5710 tgl 2749 GIC 35564 : foreach(l, activeSearchPath)
5710 tgl 2750 ECB : {
5710 tgl 2751 CBC 35536 : namespaceId = lfirst_oid(l);
2752 :
2753 35536 : if (namespaceId == myTempNamespace)
5624 bruce 2754 GIC 348 : continue; /* do not look in temp namespace */
2755 :
1601 andres 2756 CBC 35188 : cfgoid = GetSysCacheOid2(TSCONFIGNAMENSP, Anum_pg_ts_config_oid,
4802 rhaas 2757 ECB : PointerGetDatum(config_name),
2758 : ObjectIdGetDatum(namespaceId));
5710 tgl 2759 GIC 35188 : if (OidIsValid(cfgoid))
2760 34993 : break;
5710 tgl 2761 ECB : }
2762 : }
2763 :
4630 rhaas 2764 GIC 37743 : if (!OidIsValid(cfgoid) && !missing_ok)
5710 tgl 2765 15 : ereport(ERROR,
2766 : (errcode(ERRCODE_UNDEFINED_OBJECT),
5710 tgl 2767 ECB : errmsg("text search configuration \"%s\" does not exist",
2768 : NameListToString(names))));
2769 :
5710 tgl 2770 GIC 37728 : return cfgoid;
2771 : }
2772 :
2773 : /*
2774 : * TSConfigIsVisible
2775 : * Determine whether a text search configuration (identified by OID)
2776 : * is visible in the current search path. Visible means "would be found
5710 tgl 2777 ECB : * by searching for the unqualified text search configuration name".
2778 : */
2779 : bool
5710 tgl 2780 GIC 23 : TSConfigIsVisible(Oid cfgid)
2781 : {
2782 : HeapTuple tup;
2783 : Form_pg_ts_config form;
5710 tgl 2784 ECB : Oid namespace;
2785 : bool visible;
5710 tgl 2786 EUB :
4802 rhaas 2787 GIC 23 : tup = SearchSysCache1(TSCONFIGOID, ObjectIdGetDatum(cfgid));
5710 tgl 2788 CBC 23 : if (!HeapTupleIsValid(tup))
5710 tgl 2789 UIC 0 : elog(ERROR, "cache lookup failed for text search configuration %u",
5710 tgl 2790 ECB : cfgid);
5710 tgl 2791 GIC 23 : form = (Form_pg_ts_config) GETSTRUCT(tup);
2792 :
2793 23 : recomputeNamespacePath();
2794 :
2795 : /*
2796 : * Quick check: if it ain't in the path at all, it ain't visible. Items in
5710 tgl 2797 ECB : * the system namespace are surely in the path and so we needn't even do
2798 : * list_member_oid() for them.
2799 : */
5710 tgl 2800 CBC 23 : namespace = form->cfgnamespace;
5710 tgl 2801 GIC 23 : if (namespace != PG_CATALOG_NAMESPACE &&
2802 23 : !list_member_oid(activeSearchPath, namespace))
2803 8 : visible = false;
2804 : else
2805 : {
2806 : /*
2807 : * If it is in the path, it might still not be visible; it could be
5710 tgl 2808 ECB : * hidden by another configuration of the same name earlier in the
2809 : * path. So we must do a slow check for conflicting configurations.
2810 : */
5710 tgl 2811 CBC 15 : char *name = NameStr(form->cfgname);
5710 tgl 2812 ECB : ListCell *l;
2813 :
5710 tgl 2814 CBC 15 : visible = false;
5710 tgl 2815 GIC 30 : foreach(l, activeSearchPath)
5710 tgl 2816 ECB : {
5710 tgl 2817 GBC 30 : Oid namespaceId = lfirst_oid(l);
2818 :
5710 tgl 2819 CBC 30 : if (namespaceId == myTempNamespace)
5624 bruce 2820 UIC 0 : continue; /* do not look in temp namespace */
2821 :
5710 tgl 2822 CBC 30 : if (namespaceId == namespace)
5710 tgl 2823 ECB : {
2824 : /* Found it first in path */
5710 tgl 2825 CBC 15 : visible = true;
5710 tgl 2826 GIC 15 : break;
2827 : }
4802 rhaas 2828 15 : if (SearchSysCacheExists2(TSCONFIGNAMENSP,
2829 : PointerGetDatum(name),
4802 rhaas 2830 EUB : ObjectIdGetDatum(namespaceId)))
2831 : {
2832 : /* Found something else first in path */
5710 tgl 2833 UIC 0 : break;
2834 : }
5710 tgl 2835 ECB : }
2836 : }
2837 :
5710 tgl 2838 GIC 23 : ReleaseSysCache(tup);
2839 :
2840 23 : return visible;
2841 : }
2842 :
2843 :
2844 : /*
2845 : * DeconstructQualifiedName
2846 : * Given a possibly-qualified name expressed as a list of String nodes,
2847 : * extract the schema name and object name.
2848 : *
7559 tgl 2849 ECB : * *nspname_p is set to NULL if there is no explicit schema name.
2850 : */
2851 : void
7559 tgl 2852 GIC 1761688 : DeconstructQualifiedName(List *names,
2853 : char **nspname_p,
7559 tgl 2854 ECB : char **objname_p)
7681 2855 : {
2856 : char *catalogname;
7681 tgl 2857 CBC 1761688 : char *schemaname = NULL;
7681 tgl 2858 GIC 1761688 : char *objname = NULL;
7681 tgl 2859 ECB :
6892 neilc 2860 CBC 1761688 : switch (list_length(names))
7681 tgl 2861 ECB : {
7681 tgl 2862 CBC 1549357 : case 1:
6892 neilc 2863 1549357 : objname = strVal(linitial(names));
7681 tgl 2864 1549357 : break;
2865 212277 : case 2:
6892 neilc 2866 212277 : schemaname = strVal(linitial(names));
7681 tgl 2867 212277 : objname = strVal(lsecond(names));
2868 212277 : break;
2869 51 : case 3:
6892 neilc 2870 GIC 51 : catalogname = strVal(linitial(names));
7681 tgl 2871 51 : schemaname = strVal(lsecond(names));
7364 2872 51 : objname = strVal(lthird(names));
2873 :
7681 tgl 2874 ECB : /*
2875 : * We check the catalog name and then ignore it.
2876 : */
7226 peter_e 2877 GIC 51 : if (strcmp(catalogname, get_database_name(MyDatabaseId)) != 0)
7202 tgl 2878 51 : ereport(ERROR,
7202 tgl 2879 EUB : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2118 tgl 2880 ECB : errmsg("cross-database references are not implemented: %s",
2881 : NameListToString(names))));
7681 tgl 2882 UIC 0 : break;
7681 tgl 2883 GIC 3 : default:
7202 2884 3 : ereport(ERROR,
2885 : (errcode(ERRCODE_SYNTAX_ERROR),
2886 : errmsg("improper qualified name (too many dotted names): %s",
2887 : NameListToString(names))));
7681 tgl 2888 ECB : break;
2889 : }
2890 :
7559 tgl 2891 GIC 1761634 : *nspname_p = schemaname;
2892 1761634 : *objname_p = objname;
2893 1761634 : }
2894 :
2895 : /*
2896 : * LookupNamespaceNoError
2897 : * Look up a schema name.
2898 : *
2899 : * Returns the namespace OID, or InvalidOid if not found.
2900 : *
2901 : * Note this does NOT perform any permissions check --- callers are
2902 : * responsible for being sure that an appropriate check is made.
4908 tgl 2903 ECB : * In the majority of cases LookupExplicitNamespace is preferable.
2904 : */
2905 : Oid
4908 tgl 2906 CBC 165 : LookupNamespaceNoError(const char *nspname)
2907 : {
4908 tgl 2908 EUB : /* check for pg_temp alias */
4908 tgl 2909 GIC 165 : if (strcmp(nspname, "pg_temp") == 0)
4908 tgl 2910 EUB : {
4908 tgl 2911 UBC 0 : if (OidIsValid(myTempNamespace))
2912 : {
3656 rhaas 2913 UIC 0 : InvokeNamespaceSearchHook(myTempNamespace, true);
4908 tgl 2914 0 : return myTempNamespace;
2915 : }
2916 :
2917 : /*
2918 : * Since this is used only for looking up existing objects, there is
4908 tgl 2919 EUB : * no point in trying to initialize the temp namespace here; and doing
2920 : * so might create problems for some callers. Just report "not found".
2921 : */
4908 tgl 2922 LBC 0 : return InvalidOid;
2923 : }
2924 :
4630 rhaas 2925 GIC 165 : return get_namespace_oid(nspname, true);
2926 : }
2927 :
2928 : /*
2929 : * LookupExplicitNamespace
2930 : * Process an explicitly-specified schema name: look up the schema
2931 : * and verify we have USAGE (lookup) rights in it.
2932 : *
3725 bruce 2933 ECB : * Returns the namespace OID
2934 : */
2935 : Oid
3725 bruce 2936 GIC 320975 : LookupExplicitNamespace(const char *nspname, bool missing_ok)
2937 : {
2938 : Oid namespaceId;
7559 tgl 2939 ECB : AclResult aclresult;
2940 :
5833 2941 : /* check for pg_temp alias */
5833 tgl 2942 CBC 320975 : if (strcmp(nspname, "pg_temp") == 0)
2943 : {
5833 tgl 2944 GIC 168 : if (OidIsValid(myTempNamespace))
2945 168 : return myTempNamespace;
2946 :
2947 : /*
2948 : * Since this is used only for looking up existing objects, there is
2949 : * no point in trying to initialize the temp namespace here; and doing
2950 : * so might create problems for some callers --- just fall through.
5833 tgl 2951 ECB : */
2952 : }
2953 :
3725 bruce 2954 GIC 320807 : namespaceId = get_namespace_oid(nspname, missing_ok);
3725 bruce 2955 CBC 320753 : if (missing_ok && !OidIsValid(namespaceId))
2956 168 : return InvalidOid;
3602 bruce 2957 ECB :
147 peter 2958 GNC 320585 : aclresult = object_aclcheck(NamespaceRelationId, namespaceId, GetUserId(), ACL_USAGE);
7559 tgl 2959 GIC 320585 : if (aclresult != ACLCHECK_OK)
1954 peter_e 2960 CBC 4 : aclcheck_error(aclresult, OBJECT_SCHEMA,
2961 : nspname);
3656 rhaas 2962 ECB : /* Schema search hook for this lookup */
3656 rhaas 2963 GIC 320581 : InvokeNamespaceSearchHook(namespaceId, true);
2964 :
7559 tgl 2965 320581 : return namespaceId;
2966 : }
2967 :
2968 : /*
2969 : * LookupCreationNamespace
2970 : * Look up the schema and verify we have CREATE rights on it.
2971 : *
2972 : * This is just like LookupExplicitNamespace except for the different
2973 : * permission check, and that we are willing to create pg_temp if needed.
2974 : *
2975 : * Note: calling this may result in a CommandCounterIncrement operation,
5833 tgl 2976 ECB : * if we have to create or clean out the temp namespace.
2977 : */
2978 : Oid
6460 tgl 2979 GIC 233 : LookupCreationNamespace(const char *nspname)
2980 : {
2981 : Oid namespaceId;
6460 tgl 2982 ECB : AclResult aclresult;
2983 :
2984 : /* check for pg_temp alias */
5833 tgl 2985 CBC 233 : if (strcmp(nspname, "pg_temp") == 0)
5833 tgl 2986 ECB : {
2987 : /* Initialize temp namespace */
1542 michael 2988 GIC 70 : AccessTempTableNamespace(false);
5833 tgl 2989 CBC 70 : return myTempNamespace;
2990 : }
5833 tgl 2991 ECB :
4630 rhaas 2992 CBC 163 : namespaceId = get_namespace_oid(nspname, false);
6460 tgl 2993 EUB :
147 peter 2994 GNC 162 : aclresult = object_aclcheck(NamespaceRelationId, namespaceId, GetUserId(), ACL_CREATE);
6460 tgl 2995 GIC 162 : if (aclresult != ACLCHECK_OK)
1954 peter_e 2996 LBC 0 : aclcheck_error(aclresult, OBJECT_SCHEMA,
2997 : nspname);
2998 :
6460 tgl 2999 GIC 162 : return namespaceId;
3000 : }
3001 :
3002 : /*
3003 : * Common checks on switching namespaces.
3004 : *
3005 : * We complain if either the old or new namespaces is a temporary schema
3006 : * (or temporary toast schema), or if either the old or new namespaces is the
2698 rhaas 3007 ECB : * TOAST schema.
3008 : */
3009 : void
2698 rhaas 3010 CBC 254 : CheckSetNamespace(Oid oldNspOid, Oid nspOid)
4521 rhaas 3011 EUB : {
3012 : /* disallow renaming into or out of temp schemas */
4521 rhaas 3013 GIC 254 : if (isAnyTempNamespace(nspOid) || isAnyTempNamespace(oldNspOid))
4521 rhaas 3014 UIC 0 : ereport(ERROR,
3015 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2118 tgl 3016 ECB : errmsg("cannot move objects into or out of temporary schemas")));
4521 rhaas 3017 EUB :
3018 : /* same for TOAST schema */
4521 rhaas 3019 GIC 254 : if (nspOid == PG_TOAST_NAMESPACE || oldNspOid == PG_TOAST_NAMESPACE)
4521 rhaas 3020 LBC 0 : ereport(ERROR,
3021 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3022 : errmsg("cannot move objects into or out of TOAST schema")));
4521 rhaas 3023 GIC 254 : }
3024 :
3025 : /*
3026 : * QualifiedNameGetCreationNamespace
3027 : * Given a possibly-qualified name for an object (in List-of-Strings
3028 : * format), determine what namespace the object should be created in.
3029 : * Also extract and return the object name (last component of list).
3030 : *
3031 : * Note: this does not apply any permissions check. Callers must check
3032 : * for CREATE rights on the selected namespace when appropriate.
3033 : *
3034 : * Note: calling this may result in a CommandCounterIncrement operation,
5833 tgl 3035 ECB : * if we have to create or clean out the temp namespace.
3036 : */
3037 : Oid
7559 tgl 3038 GIC 57491 : QualifiedNameGetCreationNamespace(List *names, char **objname_p)
3039 : {
3040 : char *schemaname;
7559 tgl 3041 ECB : Oid namespaceId;
3042 :
3043 : /* deconstruct the name list */
5833 tgl 3044 GIC 57491 : DeconstructQualifiedName(names, &schemaname, objname_p);
3045 :
7681 tgl 3046 CBC 57491 : if (schemaname)
3047 : {
3048 : /* check for pg_temp alias */
5833 3049 769 : if (strcmp(schemaname, "pg_temp") == 0)
5833 tgl 3050 ECB : {
3051 : /* Initialize temp namespace */
1542 michael 3052 GIC 150 : AccessTempTableNamespace(false);
5833 tgl 3053 CBC 150 : return myTempNamespace;
3054 : }
3055 : /* use exact schema given */
4630 rhaas 3056 GIC 619 : namespaceId = get_namespace_oid(schemaname, false);
3057 : /* we do not check for USAGE rights here! */
3058 : }
7681 tgl 3059 ECB : else
3060 : {
3061 : /* use the default creation namespace */
7650 tgl 3062 GIC 56722 : recomputeNamespacePath();
5833 tgl 3063 GBC 56722 : if (activeTempCreationPending)
5833 tgl 3064 EUB : {
3065 : /* Need to initialize temp namespace */
1542 michael 3066 LBC 0 : AccessTempTableNamespace(true);
5833 tgl 3067 0 : return myTempNamespace;
5833 tgl 3068 EUB : }
5861 tgl 3069 GIC 56722 : namespaceId = activeCreationNamespace;
7664 3070 56722 : if (!OidIsValid(namespaceId))
7202 tgl 3071 UIC 0 : ereport(ERROR,
3072 : (errcode(ERRCODE_UNDEFINED_SCHEMA),
7202 tgl 3073 ECB : errmsg("no schema has been selected to create in")));
3074 : }
3075 :
7681 tgl 3076 GIC 57341 : return namespaceId;
3077 : }
3078 :
3079 : /*
3080 : * get_namespace_oid - given a namespace name, look up the OID
3081 : *
3082 : * If missing_ok is false, throw an error if namespace name not found. If
4630 rhaas 3083 ECB : * true, just return InvalidOid.
3084 : */
3085 : Oid
4630 rhaas 3086 GIC 368870 : get_namespace_oid(const char *nspname, bool missing_ok)
4630 rhaas 3087 ECB : {
3088 : Oid oid;
3089 :
1601 andres 3090 CBC 368870 : oid = GetSysCacheOid1(NAMESPACENAME, Anum_pg_namespace_oid,
3091 : CStringGetDatum(nspname));
4630 rhaas 3092 GIC 368870 : if (!OidIsValid(oid) && !missing_ok)
4382 bruce 3093 87 : ereport(ERROR,
4382 bruce 3094 ECB : (errcode(ERRCODE_UNDEFINED_SCHEMA),
3095 : errmsg("schema \"%s\" does not exist", nspname)));
3096 :
4630 rhaas 3097 GIC 368783 : return oid;
3098 : }
3099 :
3100 : /*
3101 : * makeRangeVarFromNameList
7681 tgl 3102 ECB : * Utility routine to convert a qualified-name list into RangeVar form.
3103 : */
3104 : RangeVar *
7681 tgl 3105 GIC 31393 : makeRangeVarFromNameList(List *names)
7681 tgl 3106 ECB : {
5333 tgl 3107 GIC 31393 : RangeVar *rel = makeRangeVar(NULL, NULL, -1);
7681 tgl 3108 ECB :
6892 neilc 3109 CBC 31393 : switch (list_length(names))
7681 tgl 3110 ECB : {
7681 tgl 3111 CBC 18841 : case 1:
6892 neilc 3112 18841 : rel->relname = strVal(linitial(names));
7681 tgl 3113 18841 : break;
3114 12513 : case 2:
6892 neilc 3115 12513 : rel->schemaname = strVal(linitial(names));
7681 tgl 3116 12513 : rel->relname = strVal(lsecond(names));
3117 12513 : break;
3118 39 : case 3:
6892 neilc 3119 39 : rel->catalogname = strVal(linitial(names));
7681 tgl 3120 GBC 39 : rel->schemaname = strVal(lsecond(names));
7364 3121 39 : rel->relname = strVal(lthird(names));
7681 tgl 3122 GIC 39 : break;
7681 tgl 3123 UIC 0 : default:
7202 3124 0 : ereport(ERROR,
3125 : (errcode(ERRCODE_SYNTAX_ERROR),
3126 : errmsg("improper relation name (too many dotted names): %s",
3127 : NameListToString(names))));
7681 tgl 3128 ECB : break;
3129 : }
3130 :
7681 tgl 3131 GIC 31393 : return rel;
3132 : }
3133 :
3134 : /*
3135 : * NameListToString
3136 : * Utility routine to convert a qualified-name list into a string.
3137 : *
3138 : * This is used primarily to form error messages, and so we do not quote
3139 : * the list elements, for the sake of legibility.
3140 : *
3141 : * In most scenarios the list elements should always be String values,
5335 tgl 3142 ECB : * but we also allow A_Star for the convenience of ColumnRef processing.
3143 : */
3144 : char *
7670 tgl 3145 GIC 858 : NameListToString(List *names)
3146 : {
7670 tgl 3147 ECB : StringInfoData string;
3148 : ListCell *l;
3149 :
7670 tgl 3150 GIC 858 : initStringInfo(&string);
7670 tgl 3151 ECB :
7670 tgl 3152 GIC 1911 : foreach(l, names)
7670 tgl 3153 ECB : {
5335 tgl 3154 CBC 1053 : Node *name = (Node *) lfirst(l);
3155 :
6892 neilc 3156 1053 : if (l != list_head(names))
7670 tgl 3157 195 : appendStringInfoChar(&string, '.');
5335 tgl 3158 EUB :
5335 tgl 3159 GBC 1053 : if (IsA(name, String))
5335 tgl 3160 GIC 1053 : appendStringInfoString(&string, strVal(name));
5335 tgl 3161 UBC 0 : else if (IsA(name, A_Star))
2890 peter_e 3162 UIC 0 : appendStringInfoChar(&string, '*');
3163 : else
5335 tgl 3164 0 : elog(ERROR, "unexpected node type in name list: %d",
5335 tgl 3165 ECB : (int) nodeTag(name));
3166 : }
3167 :
7670 tgl 3168 GIC 858 : return string.data;
3169 : }
3170 :
3171 : /*
3172 : * NameListToQuotedString
3173 : * Utility routine to convert a qualified-name list into a string.
3174 : *
3175 : * Same as above except that names will be double-quoted where necessary,
7463 tgl 3176 EUB : * so the string could be re-parsed (eg, by textToQualifiedNameList).
3177 : */
3178 : char *
7463 tgl 3179 UIC 0 : NameListToQuotedString(List *names)
3180 : {
7463 tgl 3181 EUB : StringInfoData string;
3182 : ListCell *l;
3183 :
7463 tgl 3184 UIC 0 : initStringInfo(&string);
7463 tgl 3185 EUB :
7463 tgl 3186 UBC 0 : foreach(l, names)
7463 tgl 3187 EUB : {
6892 neilc 3188 UIC 0 : if (l != list_head(names))
7463 tgl 3189 0 : appendStringInfoChar(&string, '.');
7290 tgl 3190 UBC 0 : appendStringInfoString(&string, quote_identifier(strVal(lfirst(l))));
3191 : }
3192 :
7463 tgl 3193 UIC 0 : return string.data;
3194 : }
3195 :
3196 : /*
7679 tgl 3197 ECB : * isTempNamespace - is the given namespace my temporary-table namespace?
3198 : */
3199 : bool
7679 tgl 3200 CBC 24406 : isTempNamespace(Oid namespaceId)
7679 tgl 3201 ECB : {
7679 tgl 3202 GIC 24406 : if (OidIsValid(myTempNamespace) && myTempNamespace == namespaceId)
3203 317 : return true;
3204 24089 : return false;
3205 : }
3206 :
3207 : /*
3208 : * isTempToastNamespace - is the given namespace my temporary-toast-table
5737 tgl 3209 ECB : * namespace?
3210 : */
3211 : bool
5737 tgl 3212 CBC 5183703 : isTempToastNamespace(Oid namespaceId)
5737 tgl 3213 ECB : {
5737 tgl 3214 GIC 5183703 : if (OidIsValid(myTempToastNamespace) && myTempToastNamespace == namespaceId)
3215 1243 : return true;
3216 5182460 : return false;
3217 : }
3218 :
3219 : /*
3220 : * isTempOrTempToastNamespace - is the given namespace my temporary-table
5737 tgl 3221 ECB : * namespace or my temporary-toast-table namespace?
3222 : */
3223 : bool
3149 bruce 3224 CBC 160469 : isTempOrTempToastNamespace(Oid namespaceId)
5737 tgl 3225 ECB : {
5737 tgl 3226 CBC 160469 : if (OidIsValid(myTempNamespace) &&
2118 tgl 3227 GIC 30260 : (myTempNamespace == namespaceId || myTempToastNamespace == namespaceId))
5737 3228 17771 : return true;
3229 142698 : return false;
3230 : }
3231 :
3232 : /*
3233 : * isAnyTempNamespace - is the given namespace a temporary-table namespace
3234 : * (either my own, or another backend's)? Temporary-toast-table namespaces
5737 tgl 3235 ECB : * are included, too.
3236 : */
3237 : bool
6460 tgl 3238 GIC 126856 : isAnyTempNamespace(Oid namespaceId)
3239 : {
3240 : bool result;
7503 tgl 3241 ECB : char *nspname;
3242 :
5737 3243 : /* True if the namespace name starts with "pg_temp_" or "pg_toast_temp_" */
7503 tgl 3244 CBC 126856 : nspname = get_namespace_name(namespaceId);
3245 126856 : if (!nspname)
3246 1 : return false; /* no such namespace? */
5737 3247 253415 : result = (strncmp(nspname, "pg_temp_", 8) == 0) ||
5737 tgl 3248 GIC 126560 : (strncmp(nspname, "pg_toast_temp_", 14) == 0);
7503 3249 126855 : pfree(nspname);
3250 126855 : return result;
3251 : }
3252 :
3253 : /*
3254 : * isOtherTempNamespace - is the given namespace some other backend's
3255 : * temporary-table namespace (including temporary-toast-table namespaces)?
3256 : *
3257 : * Note: for most purposes in the C code, this function is obsolete. Use
5122 tgl 3258 ECB : * RELATION_IS_OTHER_TEMP() instead to detect non-local temp relations.
3259 : */
3260 : bool
6460 tgl 3261 CBC 2588 : isOtherTempNamespace(Oid namespaceId)
6460 tgl 3262 EUB : {
3263 : /* If it's my own temp namespace, say "false" */
3149 bruce 3264 CBC 2588 : if (isTempOrTempToastNamespace(namespaceId))
6460 tgl 3265 UIC 0 : return false;
3266 : /* Else, if it's any temp namespace, say "true" */
6460 tgl 3267 GIC 2588 : return isAnyTempNamespace(namespaceId);
3268 : }
3269 :
3270 : /*
3271 : * checkTempNamespaceStatus - is the given namespace owned and actively used
3272 : * by a backend?
3273 : *
3274 : * Note: this can be used while scanning relations in pg_class to detect
3275 : * orphaned temporary tables or namespaces with a backend connected to a
3276 : * given database. The result may be out of date quickly, so the caller
1700 michael 3277 EUB : * must be careful how to handle this information.
3278 : */
3279 : TempNamespaceStatus
1136 tgl 3280 UIC 0 : checkTempNamespaceStatus(Oid namespaceId)
3281 : {
1700 michael 3282 EUB : PGPROC *proc;
3283 : int backendId;
3284 :
1700 michael 3285 UIC 0 : Assert(OidIsValid(MyDatabaseId));
3286 :
1700 michael 3287 UBC 0 : backendId = GetTempNamespaceBackendId(namespaceId);
1700 michael 3288 EUB :
3289 : /* No such namespace, or its name shows it's not temp? */
1180 michael 3290 UIC 0 : if (backendId == InvalidBackendId)
1136 tgl 3291 UBC 0 : return TEMP_NAMESPACE_NOT_TEMP;
1700 michael 3292 EUB :
3293 : /* Is the backend alive? */
1700 michael 3294 UIC 0 : proc = BackendIdGetProc(backendId);
3295 0 : if (proc == NULL)
1136 tgl 3296 UBC 0 : return TEMP_NAMESPACE_IDLE;
1700 michael 3297 EUB :
3298 : /* Is the backend connected to the same database we are looking at? */
1700 michael 3299 UIC 0 : if (proc->databaseId != MyDatabaseId)
1136 tgl 3300 UBC 0 : return TEMP_NAMESPACE_IDLE;
1700 michael 3301 EUB :
3302 : /* Does the backend own the temporary namespace? */
1700 michael 3303 UIC 0 : if (proc->tempNamespaceId != namespaceId)
1136 tgl 3304 UBC 0 : return TEMP_NAMESPACE_IDLE;
3305 :
3306 : /* Yup, so namespace is busy */
1136 tgl 3307 UIC 0 : return TEMP_NAMESPACE_IN_USE;
3308 : }
3309 :
3310 : /*
3311 : * GetTempNamespaceBackendId - if the given namespace is a temporary-table
3312 : * namespace (either my own, or another backend's), return the BackendId
3313 : * that owns it. Temporary-toast-table namespaces are included, too.
4622 rhaas 3314 ECB : * If it isn't a temp namespace, return InvalidBackendId.
3315 : */
3316 : int
5395 tgl 3317 GIC 17 : GetTempNamespaceBackendId(Oid namespaceId)
3318 : {
3319 : int result;
5395 tgl 3320 ECB : char *nspname;
3321 :
5395 tgl 3322 EUB : /* See if the namespace name starts with "pg_temp_" or "pg_toast_temp_" */
5395 tgl 3323 CBC 17 : nspname = get_namespace_name(namespaceId);
3324 17 : if (!nspname)
4382 bruce 3325 UBC 0 : return InvalidBackendId; /* no such namespace? */
5395 tgl 3326 GBC 17 : if (strncmp(nspname, "pg_temp_", 8) == 0)
5395 tgl 3327 GIC 17 : result = atoi(nspname + 8);
5395 tgl 3328 UBC 0 : else if (strncmp(nspname, "pg_toast_temp_", 14) == 0)
5395 tgl 3329 LBC 0 : result = atoi(nspname + 14);
5395 tgl 3330 ECB : else
4622 rhaas 3331 UIC 0 : result = InvalidBackendId;
5395 tgl 3332 GIC 17 : pfree(nspname);
3333 17 : return result;
3334 : }
3335 :
3336 : /*
3337 : * GetTempToastNamespace - get the OID of my temporary-toast-table namespace,
3338 : * which must already be assigned. (This is only used when creating a toast
5737 tgl 3339 ECB : * table for a temp table, so we must have already done InitTempTableNamespace)
3340 : */
3341 : Oid
5737 tgl 3342 CBC 430 : GetTempToastNamespace(void)
3343 : {
5737 tgl 3344 GIC 430 : Assert(OidIsValid(myTempToastNamespace));
3345 430 : return myTempToastNamespace;
3346 : }
3347 :
3348 :
3349 : /*
3350 : * GetTempNamespaceState - fetch status of session's temporary namespace
3351 : *
3352 : * This is used for conveying state to a parallel worker, and is not meant
2495 tgl 3353 ECB : * for general-purpose access.
3354 : */
3355 : void
2495 tgl 3356 CBC 403 : GetTempNamespaceState(Oid *tempNamespaceId, Oid *tempToastNamespaceId)
2495 tgl 3357 ECB : {
3358 : /* Return namespace OIDs, or 0 if session has not created temp namespace */
2495 tgl 3359 GIC 403 : *tempNamespaceId = myTempNamespace;
3360 403 : *tempToastNamespaceId = myTempToastNamespace;
3361 403 : }
3362 :
3363 : /*
3364 : * SetTempNamespaceState - set status of session's temporary namespace
3365 : *
3366 : * This is used for conveying state to a parallel worker, and is not meant for
3367 : * general-purpose access. By transferring these namespace OIDs to workers,
3368 : * we ensure they will have the same notion of the search path as their leader
2495 tgl 3369 ECB : * does.
3370 : */
3371 : void
2495 tgl 3372 CBC 1298 : SetTempNamespaceState(Oid tempNamespaceId, Oid tempToastNamespaceId)
2495 tgl 3373 ECB : {
3374 : /* Worker should not have created its own namespaces ... */
2495 tgl 3375 GIC 1298 : Assert(myTempNamespace == InvalidOid);
3376 1298 : Assert(myTempToastNamespace == InvalidOid);
2495 tgl 3377 CBC 1298 : Assert(myTempNamespaceSubID == InvalidSubTransactionId);
2495 tgl 3378 ECB :
3379 : /* Assign same namespace OIDs that leader has */
2495 tgl 3380 GIC 1298 : myTempNamespace = tempNamespaceId;
3381 1298 : myTempToastNamespace = tempToastNamespaceId;
3382 :
3383 : /*
3384 : * It's fine to leave myTempNamespaceSubID == InvalidSubTransactionId.
3385 : * Even if the namespace is new so far as the leader is concerned, it's
3386 : * not new to the worker, and we certainly wouldn't want the worker trying
2495 tgl 3387 ECB : * to destroy it.
3388 : */
3389 :
2495 tgl 3390 GIC 1298 : baseSearchPathValid = false; /* may need to rebuild list */
3391 1298 : }
3392 :
3393 :
3394 : /*
3395 : * GetOverrideSearchPath - fetch current search path definition in form
3396 : * used by PushOverrideSearchPath.
3397 : *
3398 : * The result structure is allocated in the specified memory context
3399 : * (which might or might not be equal to CurrentMemoryContext); but any
5861 tgl 3400 ECB : * junk created by revalidation calculations will be in CurrentMemoryContext.
3401 : */
3402 : OverrideSearchPath *
5861 tgl 3403 GIC 25790 : GetOverrideSearchPath(MemoryContext context)
3404 : {
3405 : OverrideSearchPath *result;
5861 tgl 3406 ECB : List *schemas;
3407 : MemoryContext oldcxt;
3408 :
5861 tgl 3409 GIC 25790 : recomputeNamespacePath();
5861 tgl 3410 ECB :
5861 tgl 3411 CBC 25790 : oldcxt = MemoryContextSwitchTo(context);
5861 tgl 3412 ECB :
5861 tgl 3413 GIC 25790 : result = (OverrideSearchPath *) palloc0(sizeof(OverrideSearchPath));
5861 tgl 3414 CBC 25790 : schemas = list_copy(activeSearchPath);
3415 55165 : while (schemas && linitial_oid(schemas) != activeCreationNamespace)
3416 : {
5861 tgl 3417 GIC 29375 : if (linitial_oid(schemas) == myTempNamespace)
5861 tgl 3418 CBC 4948 : result->addTemp = true;
5861 tgl 3419 ECB : else
3420 : {
5861 tgl 3421 CBC 24427 : Assert(linitial_oid(schemas) == PG_CATALOG_NAMESPACE);
5861 tgl 3422 GIC 24427 : result->addCatalog = true;
5861 tgl 3423 ECB : }
5861 tgl 3424 CBC 29375 : schemas = list_delete_first(schemas);
3425 : }
3426 25790 : result->schemas = schemas;
1109 tgl 3427 GIC 25790 : result->generation = activePathGeneration;
5861 tgl 3428 ECB :
5861 tgl 3429 GIC 25790 : MemoryContextSwitchTo(oldcxt);
3430 :
3431 25790 : return result;
3432 : }
3433 :
3434 : /*
3435 : * CopyOverrideSearchPath - copy the specified OverrideSearchPath.
3436 : *
4223 tgl 3437 EUB : * The result structure is allocated in CurrentMemoryContext.
3438 : */
3439 : OverrideSearchPath *
4223 tgl 3440 UIC 0 : CopyOverrideSearchPath(OverrideSearchPath *path)
4223 tgl 3441 EUB : {
3442 : OverrideSearchPath *result;
3443 :
4223 tgl 3444 UBC 0 : result = (OverrideSearchPath *) palloc(sizeof(OverrideSearchPath));
3445 0 : result->schemas = list_copy(path->schemas);
4223 tgl 3446 UIC 0 : result->addCatalog = path->addCatalog;
4223 tgl 3447 UBC 0 : result->addTemp = path->addTemp;
1109 tgl 3448 UIC 0 : result->generation = path->generation;
3449 :
4223 3450 0 : return result;
3451 : }
3452 :
3453 : /*
3454 : * OverrideSearchPathMatchesCurrent - does path match current setting?
3455 : *
3456 : * This is tested over and over in some common code paths, and in the typical
3457 : * scenario where the active search path seldom changes, it'll always succeed.
3458 : * We make that case fast by keeping a generation counter that is advanced
1109 tgl 3459 ECB : * whenever the active search path changes.
3460 : */
3461 : bool
3726 tgl 3462 GIC 208943 : OverrideSearchPathMatchesCurrent(OverrideSearchPath *path)
3463 : {
3054 tgl 3464 ECB : ListCell *lc,
3465 : *lcp;
3466 :
3054 tgl 3467 CBC 208943 : recomputeNamespacePath();
3054 tgl 3468 ECB :
3469 : /* Quick out if already known equal to active path. */
1109 tgl 3470 GIC 208943 : if (path->generation == activePathGeneration)
1109 tgl 3471 CBC 208843 : return true;
3472 :
3473 : /* We scan down the activeSearchPath to see if it matches the input. */
3054 3474 100 : lc = list_head(activeSearchPath);
3475 :
3054 tgl 3476 ECB : /* If path->addTemp, first item should be my temp namespace. */
3054 tgl 3477 CBC 100 : if (path->addTemp)
3478 : {
3054 tgl 3479 GBC 3 : if (lc && lfirst_oid(lc) == myTempNamespace)
1364 tgl 3480 GIC 3 : lc = lnext(activeSearchPath, lc);
3481 : else
3054 tgl 3482 LBC 0 : return false;
3483 : }
3054 tgl 3484 ECB : /* If path->addCatalog, next item should be pg_catalog. */
3054 tgl 3485 CBC 100 : if (path->addCatalog)
3486 : {
3487 100 : if (lc && lfirst_oid(lc) == PG_CATALOG_NAMESPACE)
1364 tgl 3488 GIC 30 : lc = lnext(activeSearchPath, lc);
3489 : else
3054 tgl 3490 CBC 70 : return false;
3054 tgl 3491 EUB : }
3492 : /* We should now be looking at the activeCreationNamespace. */
3054 tgl 3493 CBC 30 : if (activeCreationNamespace != (lc ? lfirst_oid(lc) : InvalidOid))
3054 tgl 3494 UIC 0 : return false;
3054 tgl 3495 ECB : /* The remainder of activeSearchPath should match path->schemas. */
3054 tgl 3496 CBC 40 : foreach(lcp, path->schemas)
3497 : {
3498 30 : if (lc && lfirst_oid(lc) == lfirst_oid(lcp))
1364 tgl 3499 GIC 10 : lc = lnext(activeSearchPath, lc);
3054 tgl 3500 ECB : else
3054 tgl 3501 GBC 20 : return false;
3502 : }
3054 tgl 3503 GIC 10 : if (lc)
3054 tgl 3504 UIC 0 : return false;
3505 :
3506 : /*
1109 tgl 3507 ECB : * Update path->generation so that future tests will return quickly, so
3508 : * long as the active search path doesn't change.
3509 : */
1109 tgl 3510 GIC 10 : path->generation = activePathGeneration;
3511 :
3054 3512 10 : return true;
3513 : }
3514 :
3515 : /*
3516 : * PushOverrideSearchPath - temporarily override the search path
3517 : *
3518 : * We allow nested overrides, hence the push/pop terminology. The GUC
3519 : * search_path variable is ignored while an override is active.
3520 : *
3521 : * It's possible that newpath->useTemp is set but there is no longer any
3522 : * active temp namespace, if the path was saved during a transaction that
3523 : * created a temp namespace and was later rolled back. In that case we just
3524 : * ignore useTemp. A plausible alternative would be to create a new temp
3525 : * namespace, but for existing callers that's not necessary because an empty
3526 : * temp namespace wouldn't affect their results anyway.
3527 : *
3528 : * It's also worth noting that other schemas listed in newpath might not
3529 : * exist anymore either. We don't worry about this because OIDs that match
4622 tgl 3530 ECB : * no existing namespace will simply not produce any hits during searches.
3531 : */
3532 : void
5624 bruce 3533 GIC 649 : PushOverrideSearchPath(OverrideSearchPath *newpath)
3534 : {
3535 : OverrideStackEntry *entry;
3536 : List *oidlist;
3537 : Oid firstNS;
3538 : MemoryContext oldcxt;
3539 :
3540 : /*
5861 tgl 3541 ECB : * Copy the list for safekeeping, and insert implicitly-searched
3542 : * namespaces as needed. This code should track recomputeNamespacePath.
3543 : */
5861 tgl 3544 GIC 649 : oldcxt = MemoryContextSwitchTo(TopMemoryContext);
3545 :
3546 649 : oidlist = list_copy(newpath->schemas);
3547 :
5861 tgl 3548 ECB : /*
5861 tgl 3549 EUB : * Remember the first member of the explicit list.
3550 : */
5861 tgl 3551 CBC 649 : if (oidlist == NIL)
5861 tgl 3552 UIC 0 : firstNS = InvalidOid;
3553 : else
5861 tgl 3554 GIC 649 : firstNS = linitial_oid(oidlist);
3555 :
3556 : /*
3557 : * Add any implicitly-searched namespaces to the list. Note these go on
5861 tgl 3558 ECB : * the front, not the back; also notice that we do not check USAGE
3559 : * permissions for these.
3560 : */
5861 tgl 3561 CBC 649 : if (newpath->addCatalog)
3562 346 : oidlist = lcons_oid(PG_CATALOG_NAMESPACE, oidlist);
3563 :
4622 tgl 3564 GIC 649 : if (newpath->addTemp && OidIsValid(myTempNamespace))
5861 3565 120 : oidlist = lcons_oid(myTempNamespace, oidlist);
3566 :
5861 tgl 3567 ECB : /*
3568 : * Build the new stack entry, then insert it at the head of the list.
3569 : */
5861 tgl 3570 CBC 649 : entry = (OverrideStackEntry *) palloc(sizeof(OverrideStackEntry));
5861 tgl 3571 GIC 649 : entry->searchPath = oidlist;
5861 tgl 3572 CBC 649 : entry->creationNamespace = firstNS;
5861 tgl 3573 GIC 649 : entry->nestLevel = GetCurrentTransactionNestLevel();
3574 :
5861 tgl 3575 CBC 649 : overrideStack = lcons(entry, overrideStack);
5861 tgl 3576 ECB :
3577 : /* And make it active. */
5861 tgl 3578 GIC 649 : activeSearchPath = entry->searchPath;
3579 649 : activeCreationNamespace = entry->creationNamespace;
5624 bruce 3580 649 : activeTempCreationPending = false; /* XXX is this OK? */
3581 :
3582 : /*
3583 : * We always increment activePathGeneration when pushing/popping an
3584 : * override path. In current usage, these actions always change the
1109 tgl 3585 ECB : * effective path state, so there's no value in checking to see if it
3586 : * didn't change.
3587 : */
1109 tgl 3588 CBC 649 : activePathGeneration++;
3589 :
5861 tgl 3590 GIC 649 : MemoryContextSwitchTo(oldcxt);
7632 3591 649 : }
3592 :
3593 : /*
3594 : * PopOverrideSearchPath - undo a previous PushOverrideSearchPath
3595 : *
3596 : * Any push during a (sub)transaction will be popped automatically at abort.
5861 tgl 3597 ECB : * But it's caller error if a push isn't popped in normal control flow.
3598 : */
3599 : void
5861 tgl 3600 GIC 646 : PopOverrideSearchPath(void)
3601 : {
5861 tgl 3602 ECB : OverrideStackEntry *entry;
5861 tgl 3603 EUB :
5861 tgl 3604 ECB : /* Sanity checks. */
5861 tgl 3605 CBC 646 : if (overrideStack == NIL)
5861 tgl 3606 UBC 0 : elog(ERROR, "bogus PopOverrideSearchPath call");
5861 tgl 3607 GIC 646 : entry = (OverrideStackEntry *) linitial(overrideStack);
3608 646 : if (entry->nestLevel != GetCurrentTransactionNestLevel())
5861 tgl 3609 LBC 0 : elog(ERROR, "bogus PopOverrideSearchPath call");
5861 tgl 3610 ECB :
3611 : /* Pop the stack and free storage. */
5861 tgl 3612 GIC 646 : overrideStack = list_delete_first(overrideStack);
3613 646 : list_free(entry->searchPath);
5861 tgl 3614 CBC 646 : pfree(entry);
3615 :
5861 tgl 3616 EUB : /* Activate the next level down. */
5861 tgl 3617 GBC 646 : if (overrideStack)
5861 tgl 3618 EUB : {
5861 tgl 3619 UBC 0 : entry = (OverrideStackEntry *) linitial(overrideStack);
5861 tgl 3620 UIC 0 : activeSearchPath = entry->searchPath;
3621 0 : activeCreationNamespace = entry->creationNamespace;
2118 3622 0 : activeTempCreationPending = false; /* XXX is this OK? */
3623 : }
5861 tgl 3624 ECB : else
3625 : {
3626 : /* If not baseSearchPathValid, this is useless but harmless */
5861 tgl 3627 GIC 646 : activeSearchPath = baseSearchPath;
3628 646 : activeCreationNamespace = baseCreationNamespace;
5833 3629 646 : activeTempCreationPending = baseTempCreationPending;
5861 tgl 3630 ECB : }
1109 3631 :
3632 : /* As above, the generation always increments. */
1109 tgl 3633 GIC 646 : activePathGeneration++;
7632 3634 646 : }
3635 :
3636 :
3637 : /*
3638 : * get_collation_oid - find a collation by possibly qualified name
3639 : *
3640 : * Note that this will only find collations that work with the current
2115 tgl 3641 ECB : * database's encoding.
3642 : */
3643 : Oid
202 pg 3644 GNC 5061 : get_collation_oid(List *collname, bool missing_ok)
4443 peter_e 3645 ECB : {
3646 : char *schemaname;
3647 : char *collation_name;
4412 tgl 3648 GIC 5061 : int32 dbencoding = GetDatabaseEncoding();
3649 : Oid namespaceId;
3650 : Oid colloid;
4443 peter_e 3651 ECB : ListCell *l;
3652 :
3653 : /* deconstruct the name list */
202 pg 3654 GNC 5061 : DeconstructQualifiedName(collname, &schemaname, &collation_name);
3655 :
4443 peter_e 3656 CBC 5061 : if (schemaname)
4443 peter_e 3657 ECB : {
3658 : /* use exact schema given */
3725 bruce 3659 GIC 2948 : namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
3725 bruce 3660 CBC 2948 : if (missing_ok && !OidIsValid(namespaceId))
3661 12 : return InvalidOid;
4412 tgl 3662 ECB :
2115 tgl 3663 GIC 2936 : colloid = lookup_collation(collation_name, namespaceId, dbencoding);
4412 3664 2936 : if (OidIsValid(colloid))
3665 2936 : return colloid;
3666 : }
4443 peter_e 3667 ECB : else
3668 : {
3669 : /* search for it in search path */
4443 peter_e 3670 GIC 2113 : recomputeNamespacePath();
4443 peter_e 3671 ECB :
4443 peter_e 3672 GIC 2909 : foreach(l, activeSearchPath)
4443 peter_e 3673 ECB : {
4443 peter_e 3674 CBC 2866 : namespaceId = lfirst_oid(l);
3675 :
3676 2866 : if (namespaceId == myTempNamespace)
3677 314 : continue; /* do not look in temp namespace */
4443 peter_e 3678 ECB :
2115 tgl 3679 GIC 2552 : colloid = lookup_collation(collation_name, namespaceId, dbencoding);
4443 peter_e 3680 2552 : if (OidIsValid(colloid))
3681 2070 : return colloid;
3682 : }
4443 peter_e 3683 ECB : }
3684 :
3685 : /* Not found in path */
4412 tgl 3686 GIC 43 : if (!missing_ok)
4443 peter_e 3687 31 : ereport(ERROR,
4443 peter_e 3688 ECB : (errcode(ERRCODE_UNDEFINED_OBJECT),
3689 : errmsg("collation \"%s\" for encoding \"%s\" does not exist",
3690 : NameListToString(collname), GetDatabaseEncodingName())));
4412 tgl 3691 GIC 12 : return InvalidOid;
3692 : }
3693 :
3694 : /*
4630 rhaas 3695 ECB : * get_conversion_oid - find a conversion by possibly qualified name
3696 : */
3697 : Oid
202 pg 3698 GNC 93 : get_conversion_oid(List *conname, bool missing_ok)
3699 : {
7463 tgl 3700 ECB : char *schemaname;
3701 : char *conversion_name;
3702 : Oid namespaceId;
4630 rhaas 3703 GIC 93 : Oid conoid = InvalidOid;
6892 neilc 3704 ECB : ListCell *l;
3705 :
7463 tgl 3706 : /* deconstruct the name list */
202 pg 3707 GNC 93 : DeconstructQualifiedName(conname, &schemaname, &conversion_name);
3708 :
7463 tgl 3709 CBC 87 : if (schemaname)
7551 ishii 3710 ECB : {
7463 tgl 3711 : /* use exact schema given */
3725 bruce 3712 GIC 19 : namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
3725 bruce 3713 CBC 19 : if (missing_ok && !OidIsValid(namespaceId))
3725 bruce 3714 GIC 3 : conoid = InvalidOid;
3715 : else
1601 andres 3716 16 : conoid = GetSysCacheOid2(CONNAMENSP, Anum_pg_conversion_oid,
3717 : PointerGetDatum(conversion_name),
3718 : ObjectIdGetDatum(namespaceId));
3719 : }
7463 tgl 3720 ECB : else
3721 : {
3722 : /* search for it in search path */
7463 tgl 3723 GIC 68 : recomputeNamespacePath();
7551 ishii 3724 ECB :
5861 tgl 3725 GIC 151 : foreach(l, activeSearchPath)
7463 tgl 3726 ECB : {
6892 neilc 3727 GBC 136 : namespaceId = lfirst_oid(l);
3728 :
5833 tgl 3729 CBC 136 : if (namespaceId == myTempNamespace)
5624 bruce 3730 UIC 0 : continue; /* do not look in temp namespace */
3731 :
1601 andres 3732 CBC 136 : conoid = GetSysCacheOid2(CONNAMENSP, Anum_pg_conversion_oid,
4802 rhaas 3733 ECB : PointerGetDatum(conversion_name),
3734 : ObjectIdGetDatum(namespaceId));
7463 tgl 3735 GIC 136 : if (OidIsValid(conoid))
3736 53 : return conoid;
3737 : }
7551 ishii 3738 ECB : }
3739 :
3740 : /* Not found in path */
4630 rhaas 3741 GIC 34 : if (!OidIsValid(conoid) && !missing_ok)
3742 18 : ereport(ERROR,
4630 rhaas 3743 ECB : (errcode(ERRCODE_UNDEFINED_OBJECT),
3744 : errmsg("conversion \"%s\" does not exist",
3745 : NameListToString(conname))));
4630 rhaas 3746 GIC 16 : return conoid;
3747 : }
3748 :
3749 : /*
7463 tgl 3750 ECB : * FindDefaultConversionProc - find default encoding conversion proc
3751 : */
3752 : Oid
3940 peter_e 3753 GIC 3458 : FindDefaultConversionProc(int32 for_encoding, int32 to_encoding)
3754 : {
7572 ishii 3755 ECB : Oid proc;
3756 : ListCell *l;
3757 :
7572 ishii 3758 GIC 3458 : recomputeNamespacePath();
7572 ishii 3759 ECB :
5861 tgl 3760 GIC 3458 : foreach(l, activeSearchPath)
7572 ishii 3761 ECB : {
6892 neilc 3762 GBC 3458 : Oid namespaceId = lfirst_oid(l);
3763 :
5833 tgl 3764 CBC 3458 : if (namespaceId == myTempNamespace)
5833 tgl 3765 LBC 0 : continue; /* do not look in temp namespace */
5833 tgl 3766 ECB :
7572 ishii 3767 GIC 3458 : proc = FindDefaultConversion(namespaceId, for_encoding, to_encoding);
3768 3458 : if (OidIsValid(proc))
3769 3458 : return proc;
7572 ishii 3770 EUB : }
3771 :
3772 : /* Not found in path */
7572 ishii 3773 UIC 0 : return InvalidOid;
3774 : }
3775 :
3776 : /*
7650 tgl 3777 ECB : * recomputeNamespacePath - recompute path derived variables if needed.
3778 : */
3779 : static void
7650 tgl 3780 GIC 2637267 : recomputeNamespacePath(void)
3781 : {
6385 bruce 3782 2637267 : Oid roleid = GetUserId();
3783 : char *rawname;
3784 : List *namelist;
3785 : List *oidlist;
3786 : List *newpath;
3787 : ListCell *l;
3788 : bool temp_missing;
3789 : Oid firstNS;
3790 : bool pathChanged;
7650 tgl 3791 ECB : MemoryContext oldcxt;
3792 :
3793 : /* Do nothing if an override search spec is active. */
5861 tgl 3794 GIC 2637267 : if (overrideStack)
5861 tgl 3795 CBC 2622694 : return;
5861 tgl 3796 ECB :
3797 : /* Do nothing if path is already valid. */
5861 tgl 3798 GIC 2637149 : if (baseSearchPathValid && namespaceUser == roleid)
7650 tgl 3799 CBC 2622576 : return;
3800 :
3801 : /* Need a modifiable copy of namespace_search_path string */
3802 14573 : rawname = pstrdup(namespace_search_path);
3803 :
3804 : /* Parse string into list of identifiers */
7650 tgl 3805 GIC 14573 : if (!SplitIdentifierString(rawname, ',', &namelist))
7650 tgl 3806 EUB : {
3807 : /* syntax error in name list */
3808 : /* this should not happen if GUC checked check_search_path */
7202 tgl 3809 UIC 0 : elog(ERROR, "invalid list syntax");
3810 : }
3811 :
3812 : /*
3813 : * Convert the list of names to a list of OIDs. If any names are not
3814 : * recognizable or we don't have read access, just leave them out of the
6385 bruce 3815 ECB : * list. (We can't raise an error, since the search_path setting has
3816 : * already been accepted.) Don't make duplicate entries, either.
7650 tgl 3817 : */
7650 tgl 3818 GIC 14573 : oidlist = NIL;
5833 tgl 3819 CBC 14573 : temp_missing = false;
7650 tgl 3820 GIC 39789 : foreach(l, namelist)
3821 : {
7522 bruce 3822 CBC 25216 : char *curname = (char *) lfirst(l);
3823 : Oid namespaceId;
3824 :
7650 tgl 3825 GIC 25216 : if (strcmp(curname, "$user") == 0)
3826 : {
7650 tgl 3827 ECB : /* $user --- substitute namespace matching user name, if any */
3828 : HeapTuple tuple;
3829 :
4802 rhaas 3830 GIC 10426 : tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
7650 tgl 3831 10426 : if (HeapTupleIsValid(tuple))
7650 tgl 3832 ECB : {
6494 3833 : char *rname;
7650 3834 :
6494 tgl 3835 CBC 10426 : rname = NameStr(((Form_pg_authid) GETSTRUCT(tuple))->rolname);
4630 rhaas 3836 GBC 10426 : namespaceId = get_namespace_oid(rname, true);
7650 tgl 3837 10426 : ReleaseSysCache(tuple);
3838 10426 : if (OidIsValid(namespaceId) &&
6892 neilc 3839 UBC 0 : !list_member_oid(oidlist, namespaceId) &&
147 peter 3840 UNC 0 : object_aclcheck(NamespaceRelationId, namespaceId, roleid,
3656 rhaas 3841 UIC 0 : ACL_USAGE) == ACLCHECK_OK &&
3842 0 : InvokeNamespaceSearchHook(namespaceId, false))
6892 neilc 3843 LBC 0 : oidlist = lappend_oid(oidlist, namespaceId);
3844 : }
3845 : }
5833 tgl 3846 CBC 14790 : else if (strcmp(curname, "pg_temp") == 0)
3847 : {
5833 tgl 3848 ECB : /* pg_temp --- substitute temp namespace, if any */
5833 tgl 3849 CBC 649 : if (OidIsValid(myTempNamespace))
5833 tgl 3850 ECB : {
3656 rhaas 3851 GIC 37 : if (!list_member_oid(oidlist, myTempNamespace) &&
3852 37 : InvokeNamespaceSearchHook(myTempNamespace, false))
5833 tgl 3853 37 : oidlist = lappend_oid(oidlist, myTempNamespace);
3854 : }
5833 tgl 3855 ECB : else
3856 : {
3857 : /* If it ought to be the creation namespace, set flag */
5833 tgl 3858 GIC 612 : if (oidlist == NIL)
3859 3 : temp_missing = true;
3860 : }
3861 : }
7650 tgl 3862 ECB : else
3863 : {
3864 : /* normal namespace reference */
4630 rhaas 3865 CBC 14141 : namespaceId = get_namespace_oid(curname, true);
7650 tgl 3866 14141 : if (OidIsValid(namespaceId) &&
6892 neilc 3867 28209 : !list_member_oid(oidlist, namespaceId) &&
147 peter 3868 GNC 14101 : object_aclcheck(NamespaceRelationId, namespaceId, roleid,
3656 rhaas 3869 GIC 3 : ACL_USAGE) == ACLCHECK_OK &&
3870 14098 : InvokeNamespaceSearchHook(namespaceId, false))
6892 neilc 3871 14098 : oidlist = lappend_oid(oidlist, namespaceId);
3872 : }
3873 : }
3874 :
3875 : /*
3876 : * Remember the first member of the explicit list. (Note: this is
5833 tgl 3877 ECB : * nominally wrong if temp_missing, but we need it anyway to distinguish
3878 : * explicit from implicit mention of pg_catalog.)
3879 : */
7632 tgl 3880 CBC 14573 : if (oidlist == NIL)
7632 tgl 3881 GIC 630 : firstNS = InvalidOid;
3882 : else
6892 neilc 3883 13943 : firstNS = linitial_oid(oidlist);
3884 :
3885 : /*
3886 : * Add any implicitly-searched namespaces to the list. Note these go on
6385 bruce 3887 ECB : * the front, not the back; also notice that we do not check USAGE
7522 3888 : * permissions for these.
3889 : */
6892 neilc 3890 CBC 14573 : if (!list_member_oid(oidlist, PG_CATALOG_NAMESPACE))
3891 12938 : oidlist = lcons_oid(PG_CATALOG_NAMESPACE, oidlist);
7632 tgl 3892 ECB :
7632 tgl 3893 GIC 14573 : if (OidIsValid(myTempNamespace) &&
6892 neilc 3894 1373 : !list_member_oid(oidlist, myTempNamespace))
3895 1336 : oidlist = lcons_oid(myTempNamespace, oidlist);
3896 :
3897 : /*
3898 : * We want to detect the case where the effective value of the base search
1109 tgl 3899 ECB : * path variables didn't change. As long as we're doing so, we can avoid
888 michael 3900 : * copying the OID list unnecessarily.
7650 tgl 3901 : */
1109 tgl 3902 GIC 14573 : if (baseCreationNamespace == firstNS &&
1109 tgl 3903 CBC 14045 : baseTempCreationPending == temp_missing &&
1109 tgl 3904 GIC 7021 : equal(oidlist, baseSearchPath))
3905 : {
3906 6141 : pathChanged = false;
1109 tgl 3907 ECB : }
3908 : else
3909 : {
1109 tgl 3910 CBC 8432 : pathChanged = true;
1109 tgl 3911 ECB :
3912 : /* Must save OID list in permanent storage. */
1109 tgl 3913 GIC 8432 : oldcxt = MemoryContextSwitchTo(TopMemoryContext);
3914 8432 : newpath = list_copy(oidlist);
1109 tgl 3915 CBC 8432 : MemoryContextSwitchTo(oldcxt);
7650 tgl 3916 ECB :
1109 3917 : /* Now safe to assign to state variables. */
1109 tgl 3918 CBC 8432 : list_free(baseSearchPath);
1109 tgl 3919 GIC 8432 : baseSearchPath = newpath;
3920 8432 : baseCreationNamespace = firstNS;
3921 8432 : baseTempCreationPending = temp_missing;
1109 tgl 3922 ECB : }
7650 3923 :
3924 : /* Mark the path valid. */
5861 tgl 3925 GIC 14573 : baseSearchPathValid = true;
6494 tgl 3926 CBC 14573 : namespaceUser = roleid;
7650 tgl 3927 ECB :
5861 3928 : /* And make it active. */
5861 tgl 3929 GIC 14573 : activeSearchPath = baseSearchPath;
3930 14573 : activeCreationNamespace = baseCreationNamespace;
5833 3931 14573 : activeTempCreationPending = baseTempCreationPending;
3932 :
3933 : /*
3934 : * Bump the generation only if something actually changed. (Notice that
3935 : * what we compared to was the old state of the base path variables; so
3936 : * this does not deal with the situation where we have just popped an
1109 tgl 3937 ECB : * override path and restored the prior state of the base path. Instead
3938 : * we rely on the override-popping logic to have bumped the generation.)
3939 : */
1109 tgl 3940 GIC 14573 : if (pathChanged)
1109 tgl 3941 CBC 8432 : activePathGeneration++;
1109 tgl 3942 ECB :
7650 3943 : /* Clean up. */
7650 tgl 3944 GIC 14573 : pfree(rawname);
6892 neilc 3945 14573 : list_free(namelist);
3946 14573 : list_free(oidlist);
3947 : }
3948 :
3949 : /*
3950 : * AccessTempTableNamespace
3951 : * Provide access to a temporary namespace, potentially creating it
3952 : * if not present yet. This routine registers if the namespace gets
3953 : * in use in this transaction. 'force' can be set to true to allow
3954 : * the caller to enforce the creation of the temporary namespace for
1542 michael 3955 ECB : * use in this backend, which happens if its creation is pending.
3956 : */
3957 : static void
1542 michael 3958 GIC 3181 : AccessTempTableNamespace(bool force)
3959 : {
3960 : /*
1542 michael 3961 ECB : * Make note that this temporary namespace has been accessed in this
3962 : * transaction.
3963 : */
1542 michael 3964 GIC 3181 : MyXactFlags |= XACT_FLAGS_ACCESSEDTEMPNAMESPACE;
3965 :
3966 : /*
3967 : * If the caller attempting to access a temporary schema expects the
1542 michael 3968 ECB : * creation of the namespace to be pending and should be enforced, then go
3969 : * through the creation.
3970 : */
1542 michael 3971 GIC 3181 : if (!force && OidIsValid(myTempNamespace))
3972 2897 : return;
3973 :
3974 : /*
1542 michael 3975 ECB : * The temporary tablespace does not exist yet and is wanted, so
3976 : * initialize it.
3977 : */
1542 michael 3978 GIC 284 : InitTempTableNamespace();
3979 : }
3980 :
3981 : /*
3982 : * InitTempTableNamespace
7679 tgl 3983 ECB : * Initialize temp table namespace on first use in a particular backend
3984 : */
3985 : static void
7632 tgl 3986 GIC 284 : InitTempTableNamespace(void)
3987 : {
3988 : char namespaceName[NAMEDATALEN];
7679 tgl 3989 ECB : Oid namespaceId;
3990 : Oid toastspaceId;
3991 :
5833 tgl 3992 GIC 284 : Assert(!OidIsValid(myTempNamespace));
3993 :
3994 : /*
3995 : * First, do permission check to see if we are authorized to make temp
3996 : * tables. We use a nonstandard error message here since "databasename:
3997 : * permission denied" might be a tad cryptic.
3998 : *
3999 : * Note that ACL_CREATE_TEMP rights are rechecked in pg_namespace_aclmask;
4000 : * that's necessary since current user ID could change during the session.
6385 bruce 4001 ECB : * But there's no need to make the namespace in the first place until a
4002 : * temp table creation request is made by someone with appropriate rights.
7652 tgl 4003 EUB : */
147 peter 4004 GNC 284 : if (object_aclcheck(DatabaseRelationId, MyDatabaseId, GetUserId(),
4005 : ACL_CREATE_TEMP) != ACLCHECK_OK)
7202 tgl 4006 UIC 0 : ereport(ERROR,
4007 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
4008 : errmsg("permission denied to create temporary tables in database \"%s\"",
4009 : get_database_name(MyDatabaseId))));
4010 :
4011 : /*
4012 : * Do not allow a Hot Standby session to make temp tables. Aside from
4013 : * problems with modifying the system catalogs, there is a naming
4014 : * conflict: pg_temp_N belongs to the session with BackendId N on the
4015 : * primary, not to a hot standby session with the same BackendId. We
4016 : * should not be able to get here anyway due to XactReadOnly checks, but
4017 : * let's just make real sure. Note that this also backstops various
2064 tgl 4018 ECB : * operations that allow XactReadOnly transactions to modify temp tables;
2064 tgl 4019 EUB : * they'd need RecoveryInProgress checks if not for this.
4020 : */
4796 tgl 4021 GIC 284 : if (RecoveryInProgress())
4796 tgl 4022 UIC 0 : ereport(ERROR,
4023 : (errcode(ERRCODE_READ_ONLY_SQL_TRANSACTION),
4796 tgl 4024 ECB : errmsg("cannot create temporary tables during recovery")));
4796 tgl 4025 EUB :
4026 : /* Parallel workers can't create temporary tables, either. */
2901 rhaas 4027 GIC 284 : if (IsParallelWorker())
2901 rhaas 4028 UIC 0 : ereport(ERROR,
2901 rhaas 4029 ECB : (errcode(ERRCODE_READ_ONLY_SQL_TRANSACTION),
4030 : errmsg("cannot create temporary tables during a parallel operation")));
4031 :
7325 bruce 4032 CBC 284 : snprintf(namespaceName, sizeof(namespaceName), "pg_temp_%d", MyBackendId);
4033 :
4630 rhaas 4034 GIC 284 : namespaceId = get_namespace_oid(namespaceName, true);
7679 tgl 4035 284 : if (!OidIsValid(namespaceId))
4036 : {
4037 : /*
4038 : * First use of this temp namespace in this database; create it. The
4039 : * temp namespaces are always owned by the superuser. We leave their
4040 : * permissions at default --- i.e., no access except to superuser ---
4041 : * to ensure that unprivileged users can't peek at other backends'
6385 bruce 4042 ECB : * temp tables. This works because the places that access the temp
4043 : * namespace for my own backend skip permissions checks on it.
4044 : */
4049 tgl 4045 CBC 85 : namespaceId = NamespaceCreate(namespaceName, BOOTSTRAP_SUPERUSERID,
4046 : true);
4047 : /* Advance command counter to make namespace visible */
7679 tgl 4048 GIC 85 : CommandCounterIncrement();
4049 : }
4050 : else
4051 : {
4052 : /*
6385 bruce 4053 ECB : * If the namespace already exists, clean it out (in case the former
4054 : * owner crashed without doing so).
4055 : */
7679 tgl 4056 GIC 199 : RemoveTempRelations(namespaceId);
4057 : }
4058 :
4059 : /*
4060 : * If the corresponding toast-table namespace doesn't exist yet, create
5050 bruce 4061 ECB : * it. (We assume there is no need to clean it out if it does exist, since
4062 : * dropping a parent table should make its toast table go away.)
4063 : */
5737 tgl 4064 CBC 284 : snprintf(namespaceName, sizeof(namespaceName), "pg_toast_temp_%d",
5737 tgl 4065 ECB : MyBackendId);
4066 :
4630 rhaas 4067 CBC 284 : toastspaceId = get_namespace_oid(namespaceName, true);
5737 tgl 4068 GIC 284 : if (!OidIsValid(toastspaceId))
4069 : {
4049 tgl 4070 CBC 85 : toastspaceId = NamespaceCreate(namespaceName, BOOTSTRAP_SUPERUSERID,
4071 : true);
4072 : /* Advance command counter to make namespace visible */
5737 tgl 4073 GIC 85 : CommandCounterIncrement();
4074 : }
4075 :
4076 : /*
4077 : * Okay, we've prepared the temp namespace ... but it's not committed yet,
6385 bruce 4078 ECB : * so all our work could be undone by transaction rollback. Set flag for
4079 : * AtEOXact_Namespace to know what to do.
4080 : */
7632 tgl 4081 GIC 284 : myTempNamespace = namespaceId;
5737 4082 284 : myTempToastNamespace = toastspaceId;
4083 :
4084 : /*
4085 : * Mark MyProc as owning this namespace which other processes can use to
4086 : * decide if a temporary namespace is in use or not. We assume that
4087 : * assignment of namespaceId is an atomic operation. Even if it is not,
4088 : * the temporary relation which resulted in the creation of this temporary
4089 : * namespace is still locked until the current transaction commits, and
4090 : * its pg_namespace row is not visible yet. However it does not matter:
1692 michael 4091 ECB : * this flag makes the namespace as being in use, so no objects created on
4092 : * it would be removed concurrently.
4093 : */
1700 michael 4094 CBC 284 : MyProc->tempNamespaceId = namespaceId;
1700 michael 4095 ECB :
4096 : /* It should not be done already. */
163 peter 4097 GNC 284 : Assert(myTempNamespaceSubID == InvalidSubTransactionId);
6779 tgl 4098 CBC 284 : myTempNamespaceSubID = GetCurrentSubTransactionId();
4099 :
5861 tgl 4100 GIC 284 : baseSearchPathValid = false; /* need to rebuild list */
7632 4101 284 : }
4102 :
4103 : /*
7632 tgl 4104 ECB : * End-of-transaction cleanup for namespaces.
4105 : */
4106 : void
2901 rhaas 4107 GIC 485429 : AtEOXact_Namespace(bool isCommit, bool parallel)
4108 : {
4109 : /*
4110 : * If we abort the transaction in which a temp namespace was selected,
4111 : * we'll have to do any creation or cleanout work over again. So, just
4112 : * forget the namespace entirely until next time. On the other hand, if
4113 : * we commit then register an exit callback to clean out the temp tables
6385 bruce 4114 ECB : * at backend shutdown. (We only want to register the callback once per
4115 : * session, so this is a good place to do it.)
7632 tgl 4116 : */
2901 rhaas 4117 CBC 485429 : if (myTempNamespaceSubID != InvalidSubTransactionId && !parallel)
4118 : {
7632 tgl 4119 GIC 283 : if (isCommit)
3399 rhaas 4120 CBC 273 : before_shmem_exit(RemoveTempRelationsCallback, 0);
7632 tgl 4121 ECB : else
4122 : {
7632 tgl 4123 GIC 10 : myTempNamespace = InvalidOid;
5737 4124 10 : myTempToastNamespace = InvalidOid;
2118 4125 10 : baseSearchPathValid = false; /* need to rebuild list */
4126 :
4127 : /*
4128 : * Reset the temporary namespace flag in MyProc. We assume that
4129 : * this operation is atomic.
4130 : *
4131 : * Because this transaction is aborting, the pg_namespace row is
4132 : * not visible to anyone else anyway, but that doesn't matter:
1692 michael 4133 ECB : * it's not a problem if objects contained in this namespace are
4134 : * removed concurrently.
1700 4135 : */
1700 michael 4136 GIC 10 : MyProc->tempNamespaceId = InvalidOid;
4137 : }
6779 tgl 4138 283 : myTempNamespaceSubID = InvalidSubTransactionId;
4139 : }
4140 :
7632 tgl 4141 ECB : /*
4142 : * Clean up if someone failed to do PopOverrideSearchPath
4143 : */
5861 tgl 4144 GBC 485429 : if (overrideStack)
7632 tgl 4145 ECB : {
5861 tgl 4146 GIC 3 : if (isCommit)
5861 tgl 4147 UIC 0 : elog(WARNING, "leaked override search path");
5861 tgl 4148 GIC 6 : while (overrideStack)
5861 tgl 4149 ECB : {
4150 : OverrideStackEntry *entry;
4151 :
5861 tgl 4152 CBC 3 : entry = (OverrideStackEntry *) linitial(overrideStack);
5861 tgl 4153 GIC 3 : overrideStack = list_delete_first(overrideStack);
4154 3 : list_free(entry->searchPath);
5861 tgl 4155 CBC 3 : pfree(entry);
5861 tgl 4156 ECB : }
4157 : /* If not baseSearchPathValid, this is useless but harmless */
5861 tgl 4158 GIC 3 : activeSearchPath = baseSearchPath;
5861 tgl 4159 CBC 3 : activeCreationNamespace = baseCreationNamespace;
5833 tgl 4160 GIC 3 : activeTempCreationPending = baseTempCreationPending;
1109 tgl 4161 ECB : /* Always bump generation --- see note in recomputeNamespacePath */
1109 tgl 4162 GIC 3 : activePathGeneration++;
4163 : }
7679 4164 485429 : }
4165 :
4166 : /*
4167 : * AtEOSubXact_Namespace
4168 : *
4169 : * At subtransaction commit, propagate the temp-namespace-creation
4170 : * flag to the parent subtransaction.
4171 : *
6829 tgl 4172 ECB : * At subtransaction abort, forget the flag if we set it up.
4173 : */
4174 : void
6779 tgl 4175 GIC 8785 : AtEOSubXact_Namespace(bool isCommit, SubTransactionId mySubid,
4176 : SubTransactionId parentSubid)
6829 tgl 4177 ECB : {
4178 : OverrideStackEntry *entry;
5861 4179 :
6779 tgl 4180 CBC 8785 : if (myTempNamespaceSubID == mySubid)
4181 : {
6829 tgl 4182 GIC 4 : if (isCommit)
6779 tgl 4183 CBC 3 : myTempNamespaceSubID = parentSubid;
4184 : else
6829 tgl 4185 ECB : {
6779 tgl 4186 CBC 1 : myTempNamespaceSubID = InvalidSubTransactionId;
6829 tgl 4187 ECB : /* TEMP namespace creation failed, so reset state */
6829 tgl 4188 GIC 1 : myTempNamespace = InvalidOid;
5737 4189 1 : myTempToastNamespace = InvalidOid;
2118 4190 1 : baseSearchPathValid = false; /* need to rebuild list */
4191 :
4192 : /*
4193 : * Reset the temporary namespace flag in MyProc. We assume that
4194 : * this operation is atomic.
4195 : *
4196 : * Because this subtransaction is aborting, the pg_namespace row
4197 : * is not visible to anyone else anyway, but that doesn't matter:
1692 michael 4198 ECB : * it's not a problem if objects contained in this namespace are
4199 : * removed concurrently.
4200 : */
1700 michael 4201 GIC 1 : MyProc->tempNamespaceId = InvalidOid;
4202 : }
4203 : }
4204 :
5861 tgl 4205 ECB : /*
4206 : * Clean up if someone failed to do PopOverrideSearchPath
5861 tgl 4207 EUB : */
5861 tgl 4208 GBC 8785 : while (overrideStack)
5861 tgl 4209 EUB : {
5861 tgl 4210 UBC 0 : entry = (OverrideStackEntry *) linitial(overrideStack);
4211 0 : if (entry->nestLevel < GetCurrentTransactionNestLevel())
4212 0 : break;
4213 0 : if (isCommit)
4214 0 : elog(WARNING, "leaked override search path");
5861 tgl 4215 UIC 0 : overrideStack = list_delete_first(overrideStack);
5861 tgl 4216 UBC 0 : list_free(entry->searchPath);
5861 tgl 4217 UIC 0 : pfree(entry);
4218 : /* Always bump generation --- see note in recomputeNamespacePath */
1109 4219 0 : activePathGeneration++;
5861 tgl 4220 ECB : }
4221 :
5861 tgl 4222 EUB : /* Activate the next level down. */
5861 tgl 4223 GBC 8785 : if (overrideStack)
5861 tgl 4224 EUB : {
5861 tgl 4225 UBC 0 : entry = (OverrideStackEntry *) linitial(overrideStack);
5861 tgl 4226 UIC 0 : activeSearchPath = entry->searchPath;
4227 0 : activeCreationNamespace = entry->creationNamespace;
2118 4228 0 : activeTempCreationPending = false; /* XXX is this OK? */
4229 :
4230 : /*
1109 tgl 4231 EUB : * It's probably unnecessary to bump generation here, but this should
4232 : * not be a performance-critical case, so better to be over-cautious.
4233 : */
1109 tgl 4234 UIC 0 : activePathGeneration++;
4235 : }
5861 tgl 4236 ECB : else
4237 : {
4238 : /* If not baseSearchPathValid, this is useless but harmless */
5861 tgl 4239 GIC 8785 : activeSearchPath = baseSearchPath;
4240 8785 : activeCreationNamespace = baseCreationNamespace;
5833 4241 8785 : activeTempCreationPending = baseTempCreationPending;
4242 :
4243 : /*
4244 : * If we popped an override stack entry, then we already bumped the
4245 : * generation above. If we did not, then the above assignments did
1109 tgl 4246 ECB : * nothing and we need not bump the generation.
4247 : */
4248 : }
6829 tgl 4249 GIC 8785 : }
4250 :
4251 : /*
4252 : * Remove all relations in the specified temp namespace.
4253 : *
4254 : * This is called at backend shutdown (if we made any temp relations).
4255 : * It is also called when we begin using a pre-existing temp namespace,
4256 : * in order to clean out any relations that might have been created by
7679 tgl 4257 ECB : * a crashed backend.
4258 : */
4259 : static void
7679 tgl 4260 GIC 479 : RemoveTempRelations(Oid tempNamespaceId)
4261 : {
4262 : ObjectAddress object;
4263 :
4264 : /*
4265 : * We want to get rid of everything in the target namespace, but not the
4266 : * namespace itself (deleting it only to recreate it later would be a
4267 : * waste of cycles). Hence, specify SKIP_ORIGINAL. It's also an INTERNAL
2319 tgl 4268 ECB : * deletion, and we want to not drop any extensions that might happen to
4269 : * own temp objects.
7679 4270 : */
6569 tgl 4271 GIC 479 : object.classId = NamespaceRelationId;
7366 tgl 4272 CBC 479 : object.objectId = tempNamespaceId;
7366 tgl 4273 GIC 479 : object.objectSubId = 0;
4274 :
2319 4275 479 : performDeletion(&object, DROP_CASCADE,
4276 : PERFORM_DELETION_INTERNAL |
2319 tgl 4277 ECB : PERFORM_DELETION_QUIETLY |
4278 : PERFORM_DELETION_SKIP_ORIGINAL |
4279 : PERFORM_DELETION_SKIP_EXTENSIONS);
7679 tgl 4280 GIC 479 : }
4281 :
4282 : /*
7679 tgl 4283 ECB : * Callback to remove temp relations at backend exit.
4284 : */
4285 : static void
7058 peter_e 4286 GIC 273 : RemoveTempRelationsCallback(int code, Datum arg)
4287 : {
7522 bruce 4288 CBC 273 : if (OidIsValid(myTempNamespace)) /* should always be true */
7679 tgl 4289 ECB : {
4290 : /* Need to ensure we have a usable transaction. */
7679 tgl 4291 GIC 273 : AbortOutOfAnyTransaction();
7270 tgl 4292 CBC 273 : StartTransactionCommand();
412 andres 4293 GIC 273 : PushActiveSnapshot(GetTransactionSnapshot());
7679 tgl 4294 ECB :
7679 tgl 4295 CBC 273 : RemoveTempRelations(myTempNamespace);
4296 :
412 andres 4297 273 : PopActiveSnapshot();
7270 tgl 4298 GIC 273 : CommitTransactionCommand();
4299 : }
7679 4300 273 : }
4301 :
4302 : /*
5833 tgl 4303 ECB : * Remove all temp tables from the temporary namespace.
4304 : */
4305 : void
5833 tgl 4306 CBC 7 : ResetTempTableNamespace(void)
5833 tgl 4307 ECB : {
5833 tgl 4308 GIC 7 : if (OidIsValid(myTempNamespace))
4309 7 : RemoveTempRelations(myTempNamespace);
4310 7 : }
4311 :
4312 :
4313 : /*
4314 : * Routines for handling the GUC variable 'search_path'.
4315 : */
7678 tgl 4316 ECB :
4317 : /* check_hook: validate new search_path value */
4318 : bool
4385 tgl 4319 GIC 8821 : check_search_path(char **newval, void **extra, GucSource source)
4320 : {
4321 : char *rawname;
7678 tgl 4322 ECB : List *namelist;
4323 :
4324 : /* Need a modifiable copy of string */
4385 tgl 4325 CBC 8821 : rawname = pstrdup(*newval);
4326 :
4327 : /* Parse string into list of identifiers */
7678 tgl 4328 GBC 8821 : if (!SplitIdentifierString(rawname, ',', &namelist))
7678 tgl 4329 EUB : {
4330 : /* syntax error in name list */
4385 tgl 4331 UBC 0 : GUC_check_errdetail("List syntax is invalid.");
7678 tgl 4332 UIC 0 : pfree(rawname);
6892 neilc 4333 0 : list_free(namelist);
4385 tgl 4334 0 : return false;
4335 : }
4336 :
4337 : /*
4338 : * We used to try to check that the named schemas exist, but there are
4339 : * many valid use-cases for having search_path settings that include
4340 : * schemas that don't exist; and often, we are not inside a transaction
4341 : * here and so can't consult the system catalogs anyway. So now, the only
4015 tgl 4342 ECB : * requirement is syntactic validity of the identifier list.
7678 4343 : */
4344 :
7678 tgl 4345 CBC 8821 : pfree(rawname);
6892 neilc 4346 GIC 8821 : list_free(namelist);
4347 :
4015 tgl 4348 8821 : return true;
4349 : }
4385 tgl 4350 ECB :
4351 : /* assign_hook: do extra actions as needed */
4352 : void
4385 tgl 4353 GIC 12897 : assign_search_path(const char *newval, void *extra)
4354 : {
4355 : /*
4356 : * We mark the path as needing recomputation, but don't do anything until
6385 bruce 4357 ECB : * it's needed. This avoids trying to do database access during GUC
4385 tgl 4358 : * initialization, or outside a transaction.
4359 : */
4385 tgl 4360 GIC 12897 : baseSearchPathValid = false;
7678 4361 12897 : }
4362 :
4363 : /*
4364 : * InitializeSearchPath: initialize module during InitPostgres.
4365 : *
7678 tgl 4366 ECB : * This is called after we are up enough to be able to do catalog lookups.
4367 : */
4368 : void
7678 tgl 4369 GIC 10393 : InitializeSearchPath(void)
4370 : {
7664 4371 10393 : if (IsBootstrapProcessingMode())
4372 : {
4373 : /*
4374 : * In bootstrap mode, the search path must be 'pg_catalog' so that
4375 : * tables are created in the proper namespace; ignore the GUC setting.
7664 tgl 4376 ECB : */
4377 : MemoryContext oldcxt;
4378 :
7664 tgl 4379 CBC 305 : oldcxt = MemoryContextSwitchTo(TopMemoryContext);
5861 4380 305 : baseSearchPath = list_make1_oid(PG_CATALOG_NAMESPACE);
7664 4381 305 : MemoryContextSwitchTo(oldcxt);
5861 4382 305 : baseCreationNamespace = PG_CATALOG_NAMESPACE;
5833 4383 305 : baseTempCreationPending = false;
5861 4384 305 : baseSearchPathValid = true;
7650 4385 305 : namespaceUser = GetUserId();
5861 4386 305 : activeSearchPath = baseSearchPath;
5861 tgl 4387 GIC 305 : activeCreationNamespace = baseCreationNamespace;
5833 4388 305 : activeTempCreationPending = baseTempCreationPending;
1109 4389 305 : activePathGeneration++; /* pro forma */
4390 : }
4391 : else
4392 : {
4393 : /*
6385 bruce 4394 ECB : * In normal mode, arrange for a callback on any syscache invalidation
4395 : * of pg_namespace rows.
4396 : */
7650 tgl 4397 GIC 10088 : CacheRegisterSyscacheCallback(NAMESPACEOID,
7650 tgl 4398 ECB : NamespaceCallback,
4399 : (Datum) 0);
7632 4400 : /* Force search path to be recomputed on next use */
5861 tgl 4401 GIC 10088 : baseSearchPathValid = false;
4402 : }
7678 4403 10393 : }
4404 :
4405 : /*
4406 : * NamespaceCallback
7650 tgl 4407 ECB : * Syscache inval callback function
4408 : */
4409 : static void
4254 tgl 4410 CBC 8693 : NamespaceCallback(Datum arg, int cacheid, uint32 hashvalue)
7650 tgl 4411 ECB : {
4412 : /* Force search path to be recomputed on next use */
5861 tgl 4413 GIC 8693 : baseSearchPathValid = false;
7650 4414 8693 : }
4415 :
4416 : /*
4417 : * Fetch the active search path. The return value is a palloc'ed list
4418 : * of OIDs; the caller is responsible for freeing this storage as
4419 : * appropriate.
4420 : *
4421 : * The returned list includes the implicitly-prepended namespaces only if
4422 : * includeImplicit is true.
4423 : *
4424 : * Note: calling this may result in a CommandCounterIncrement operation,
5833 tgl 4425 ECB : * if we have to create or clean out the temp namespace.
4426 : */
4427 : List *
7632 tgl 4428 GIC 366 : fetch_search_path(bool includeImplicit)
7653 tgl 4429 ECB : {
4430 : List *result;
4431 :
7650 tgl 4432 GIC 366 : recomputeNamespacePath();
4433 :
4434 : /*
4435 : * If the temp namespace should be first, force it to exist. This is so
4436 : * that callers can trust the result to reflect the actual default
4437 : * creation namespace. It's a bit bogus to do this here, since
5833 tgl 4438 ECB : * current_schema() is supposedly a stable function without side-effects,
4439 : * but the alternatives seem worse.
4440 : */
5833 tgl 4441 CBC 366 : if (activeTempCreationPending)
4442 : {
1542 michael 4443 GIC 3 : AccessTempTableNamespace(true);
5833 tgl 4444 CBC 3 : recomputeNamespacePath();
5833 tgl 4445 ECB : }
4446 :
5861 tgl 4447 CBC 366 : result = list_copy(activeSearchPath);
7632 4448 366 : if (!includeImplicit)
4449 : {
5861 tgl 4450 GIC 580 : while (result && linitial_oid(result) != activeCreationNamespace)
6892 neilc 4451 CBC 307 : result = list_delete_first(result);
4452 : }
4453 :
7632 tgl 4454 GIC 366 : return result;
4455 : }
4456 :
4457 : /*
4458 : * Fetch the active search path into a caller-allocated array of OIDs.
4459 : * Returns the number of path entries. (If this is more than sarray_len,
4460 : * then the data didn't fit and is not all stored.)
4461 : *
4462 : * The returned list always includes the implicitly-prepended namespaces,
4463 : * but never includes the temp namespace. (This is suitable for existing
4464 : * users, which would want to ignore the temp namespace anyway.) This
5611 tgl 4465 ECB : * definition allows us to not worry about initializing the temp namespace.
4466 : */
4467 : int
5611 tgl 4468 GIC 502493 : fetch_search_path_array(Oid *sarray, int sarray_len)
4469 : {
5611 tgl 4470 CBC 502493 : int count = 0;
4471 : ListCell *l;
5611 tgl 4472 ECB :
5611 tgl 4473 GIC 502493 : recomputeNamespacePath();
5611 tgl 4474 ECB :
5611 tgl 4475 GIC 1395921 : foreach(l, activeSearchPath)
5611 tgl 4476 ECB : {
5611 tgl 4477 CBC 893428 : Oid namespaceId = lfirst_oid(l);
4478 :
4479 893428 : if (namespaceId == myTempNamespace)
4480 61760 : continue; /* do not include temp namespace */
5611 tgl 4481 ECB :
5611 tgl 4482 GIC 831668 : if (count < sarray_len)
4483 831668 : sarray[count] = namespaceId;
5611 tgl 4484 CBC 831668 : count++;
4485 : }
4486 :
5611 tgl 4487 GIC 502493 : return count;
4488 : }
4489 :
4490 :
4491 : /*
4492 : * Export the FooIsVisible functions as SQL-callable functions.
4493 : *
4494 : * Note: as of Postgres 8.4, these will silently return NULL if called on
4495 : * a nonexistent object OID, rather than failing. This is to avoid race
4496 : * condition errors when a query that's scanning a catalog using an MVCC
4497 : * snapshot uses one of these functions. The underlying IsVisible functions
4498 : * always use an up-to-date snapshot and so might see the object as already
4499 : * gone when it's still visible to the transaction snapshot. (There is no race
4500 : * condition in the current coding because we don't accept sinval messages
4501 : * between the SearchSysCacheExists test and the subsequent lookup.)
7548 tgl 4502 ECB : */
4503 :
4504 : Datum
7548 tgl 4505 GIC 7976 : pg_table_is_visible(PG_FUNCTION_ARGS)
7548 tgl 4506 ECB : {
7548 tgl 4507 GBC 7976 : Oid oid = PG_GETARG_OID(0);
4508 :
4802 rhaas 4509 CBC 7976 : if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(oid)))
5228 tgl 4510 UIC 0 : PG_RETURN_NULL();
4511 :
7548 tgl 4512 GIC 7976 : PG_RETURN_BOOL(RelationIsVisible(oid));
7548 tgl 4513 ECB : }
4514 :
4515 : Datum
7548 tgl 4516 GIC 1935 : pg_type_is_visible(PG_FUNCTION_ARGS)
7548 tgl 4517 ECB : {
7548 tgl 4518 GBC 1935 : Oid oid = PG_GETARG_OID(0);
4519 :
4802 rhaas 4520 CBC 1935 : if (!SearchSysCacheExists1(TYPEOID, ObjectIdGetDatum(oid)))
5228 tgl 4521 UIC 0 : PG_RETURN_NULL();
4522 :
7548 tgl 4523 GIC 1935 : PG_RETURN_BOOL(TypeIsVisible(oid));
7548 tgl 4524 ECB : }
4525 :
4526 : Datum
7548 tgl 4527 GIC 3667 : pg_function_is_visible(PG_FUNCTION_ARGS)
7548 tgl 4528 ECB : {
7548 tgl 4529 GBC 3667 : Oid oid = PG_GETARG_OID(0);
4530 :
4802 rhaas 4531 CBC 3667 : if (!SearchSysCacheExists1(PROCOID, ObjectIdGetDatum(oid)))
5228 tgl 4532 UIC 0 : PG_RETURN_NULL();
4533 :
7548 tgl 4534 GIC 3667 : PG_RETURN_BOOL(FunctionIsVisible(oid));
7548 tgl 4535 ECB : }
4536 :
4537 : Datum
7548 tgl 4538 GIC 850 : pg_operator_is_visible(PG_FUNCTION_ARGS)
7548 tgl 4539 ECB : {
7548 tgl 4540 GBC 850 : Oid oid = PG_GETARG_OID(0);
4541 :
4802 rhaas 4542 CBC 850 : if (!SearchSysCacheExists1(OPEROID, ObjectIdGetDatum(oid)))
5228 tgl 4543 UIC 0 : PG_RETURN_NULL();
4544 :
7548 tgl 4545 GIC 850 : PG_RETURN_BOOL(OperatorIsVisible(oid));
7548 tgl 4546 ECB : }
4547 :
4548 : Datum
7548 tgl 4549 GIC 9 : pg_opclass_is_visible(PG_FUNCTION_ARGS)
7548 tgl 4550 ECB : {
7548 tgl 4551 GBC 9 : Oid oid = PG_GETARG_OID(0);
4552 :
4802 rhaas 4553 CBC 9 : if (!SearchSysCacheExists1(CLAOID, ObjectIdGetDatum(oid)))
5228 tgl 4554 UIC 0 : PG_RETURN_NULL();
4555 :
7548 tgl 4556 GIC 9 : PG_RETURN_BOOL(OpclassIsVisible(oid));
7548 tgl 4557 ECB : }
4558 :
4284 rhaas 4559 : Datum
4284 rhaas 4560 GIC 132 : pg_opfamily_is_visible(PG_FUNCTION_ARGS)
4284 rhaas 4561 ECB : {
4284 rhaas 4562 GBC 132 : Oid oid = PG_GETARG_OID(0);
4563 :
4284 rhaas 4564 CBC 132 : if (!SearchSysCacheExists1(OPFAMILYOID, ObjectIdGetDatum(oid)))
4284 rhaas 4565 UIC 0 : PG_RETURN_NULL();
4566 :
4284 rhaas 4567 GIC 132 : PG_RETURN_BOOL(OpfamilyIsVisible(oid));
4284 rhaas 4568 EUB : }
4569 :
4443 peter_e 4570 : Datum
4443 peter_e 4571 UIC 0 : pg_collation_is_visible(PG_FUNCTION_ARGS)
4443 peter_e 4572 EUB : {
4443 peter_e 4573 UBC 0 : Oid oid = PG_GETARG_OID(0);
4574 :
4575 0 : if (!SearchSysCacheExists1(COLLOID, ObjectIdGetDatum(oid)))
4443 peter_e 4576 UIC 0 : PG_RETURN_NULL();
4577 :
4578 0 : PG_RETURN_BOOL(CollationIsVisible(oid));
4443 peter_e 4579 EUB : }
4580 :
7423 bruce 4581 : Datum
7423 bruce 4582 UIC 0 : pg_conversion_is_visible(PG_FUNCTION_ARGS)
7423 bruce 4583 EUB : {
7423 bruce 4584 UBC 0 : Oid oid = PG_GETARG_OID(0);
4585 :
4802 rhaas 4586 0 : if (!SearchSysCacheExists1(CONVOID, ObjectIdGetDatum(oid)))
5228 tgl 4587 UIC 0 : PG_RETURN_NULL();
4588 :
7423 bruce 4589 0 : PG_RETURN_BOOL(ConversionIsVisible(oid));
7423 bruce 4590 ECB : }
4591 :
2157 alvherre 4592 : Datum
2156 tgl 4593 GIC 183 : pg_statistics_obj_is_visible(PG_FUNCTION_ARGS)
2157 alvherre 4594 ECB : {
2157 alvherre 4595 GBC 183 : Oid oid = PG_GETARG_OID(0);
4596 :
2157 alvherre 4597 CBC 183 : if (!SearchSysCacheExists1(STATEXTOID, ObjectIdGetDatum(oid)))
2157 alvherre 4598 UIC 0 : PG_RETURN_NULL();
4599 :
2157 alvherre 4600 GIC 183 : PG_RETURN_BOOL(StatisticsObjIsVisible(oid));
2157 alvherre 4601 EUB : }
4602 :
5710 tgl 4603 : Datum
5710 tgl 4604 UIC 0 : pg_ts_parser_is_visible(PG_FUNCTION_ARGS)
5710 tgl 4605 EUB : {
5710 tgl 4606 UBC 0 : Oid oid = PG_GETARG_OID(0);
4607 :
4802 rhaas 4608 0 : if (!SearchSysCacheExists1(TSPARSEROID, ObjectIdGetDatum(oid)))
5228 tgl 4609 UIC 0 : PG_RETURN_NULL();
4610 :
5710 4611 0 : PG_RETURN_BOOL(TSParserIsVisible(oid));
5710 tgl 4612 EUB : }
4613 :
4614 : Datum
5710 tgl 4615 UIC 0 : pg_ts_dict_is_visible(PG_FUNCTION_ARGS)
5710 tgl 4616 EUB : {
5710 tgl 4617 UBC 0 : Oid oid = PG_GETARG_OID(0);
4618 :
4802 rhaas 4619 0 : if (!SearchSysCacheExists1(TSDICTOID, ObjectIdGetDatum(oid)))
5228 tgl 4620 UIC 0 : PG_RETURN_NULL();
4621 :
5710 4622 0 : PG_RETURN_BOOL(TSDictionaryIsVisible(oid));
5710 tgl 4623 EUB : }
4624 :
4625 : Datum
5710 tgl 4626 UIC 0 : pg_ts_template_is_visible(PG_FUNCTION_ARGS)
5710 tgl 4627 EUB : {
5710 tgl 4628 UBC 0 : Oid oid = PG_GETARG_OID(0);
4629 :
4802 rhaas 4630 0 : if (!SearchSysCacheExists1(TSTEMPLATEOID, ObjectIdGetDatum(oid)))
5228 tgl 4631 UIC 0 : PG_RETURN_NULL();
4632 :
5710 4633 0 : PG_RETURN_BOOL(TSTemplateIsVisible(oid));
5710 tgl 4634 EUB : }
4635 :
4636 : Datum
5710 tgl 4637 UIC 0 : pg_ts_config_is_visible(PG_FUNCTION_ARGS)
5710 tgl 4638 EUB : {
5710 tgl 4639 UBC 0 : Oid oid = PG_GETARG_OID(0);
4640 :
4802 rhaas 4641 0 : if (!SearchSysCacheExists1(TSCONFIGOID, ObjectIdGetDatum(oid)))
5228 tgl 4642 UIC 0 : PG_RETURN_NULL();
4643 :
5710 4644 0 : PG_RETURN_BOOL(TSConfigIsVisible(oid));
5710 tgl 4645 ECB : }
4646 :
6051 4647 : Datum
6051 tgl 4648 GIC 503 : pg_my_temp_schema(PG_FUNCTION_ARGS)
4649 : {
4650 503 : PG_RETURN_OID(myTempNamespace);
6051 tgl 4651 ECB : }
4652 :
4653 : Datum
6051 tgl 4654 GIC 2588 : pg_is_other_temp_schema(PG_FUNCTION_ARGS)
6051 tgl 4655 ECB : {
6051 tgl 4656 GIC 2588 : Oid oid = PG_GETARG_OID(0);
4657 :
4658 2588 : PG_RETURN_BOOL(isOtherTempNamespace(oid));
4659 : }
|