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