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