|
22 | 22 | #include "catalog/dependency.h" |
23 | 23 | #include "catalog/heap.h" |
24 | 24 | #include "catalog/index.h" |
| 25 | +#include "catalog/namespace.h" |
25 | 26 | #include "catalog/objectaccess.h" |
26 | 27 | #include "catalog/pg_am.h" |
27 | 28 | #include "catalog/pg_amop.h" |
@@ -1554,25 +1555,57 @@ recordDependencyOnExpr(const ObjectAddress *depender, |
1554 | 1555 | Node *expr, List *rtable, |
1555 | 1556 | DependencyType behavior) |
1556 | 1557 | { |
1557 | | - find_expr_references_context context; |
| 1558 | + ObjectAddresses *addrs; |
1558 | 1559 |
|
1559 | | - context.addrs = new_object_addresses(); |
| 1560 | + addrs = new_object_addresses(); |
1560 | 1561 |
|
1561 | | - /* Set up interpretation for Vars at varlevelsup = 0 */ |
1562 | | - context.rtables = list_make1(rtable); |
| 1562 | + /* Collect all dependencies from the expression */ |
| 1563 | + collectDependenciesOfExpr(addrs, expr, rtable); |
1563 | 1564 |
|
1564 | | - /* Scan the expression tree for referenceable objects */ |
1565 | | - find_expr_references_walker(expr, &context); |
1566 | | - |
1567 | | - /* Remove any duplicates */ |
1568 | | - eliminate_duplicate_dependencies(context.addrs); |
| 1565 | + /* Remove duplicates */ |
| 1566 | + eliminate_duplicate_dependencies(addrs); |
1569 | 1567 |
|
1570 | 1568 | /* And record 'em */ |
1571 | 1569 | recordMultipleDependencies(depender, |
1572 | | - context.addrs->refs, context.addrs->numrefs, |
| 1570 | + addrs->refs, addrs->numrefs, |
1573 | 1571 | behavior); |
1574 | 1572 |
|
1575 | | - free_object_addresses(context.addrs); |
| 1573 | + free_object_addresses(addrs); |
| 1574 | +} |
| 1575 | + |
| 1576 | +/* |
| 1577 | + * collectDependenciesOfExpr - collect expression dependencies |
| 1578 | + * |
| 1579 | + * This function analyzes an expression or query in node-tree form to |
| 1580 | + * find all the objects it refers to (tables, columns, operators, |
| 1581 | + * functions, etc.) and adds them to the provided ObjectAddresses |
| 1582 | + * structure. Unlike recordDependencyOnExpr, this function does not |
| 1583 | + * immediately record the dependencies, allowing the caller to add to, |
| 1584 | + * filter, or modify the collected dependencies before recording them. |
| 1585 | + * |
| 1586 | + * rtable is the rangetable to be used to interpret Vars with varlevelsup=0. |
| 1587 | + * It can be NIL if no such variables are expected. |
| 1588 | + * |
| 1589 | + * Note: the returned list may well contain duplicates. The caller should |
| 1590 | + * de-duplicate before recording the dependencies. Within this file, callers |
| 1591 | + * must call eliminate_duplicate_dependencies(). External callers typically |
| 1592 | + * go through record_object_address_dependencies() which will see to that. |
| 1593 | + * This choice allows collecting dependencies from multiple sources without |
| 1594 | + * redundant de-duplication work. |
| 1595 | + */ |
| 1596 | +void |
| 1597 | +collectDependenciesOfExpr(ObjectAddresses *addrs, |
| 1598 | + Node *expr, List *rtable) |
| 1599 | +{ |
| 1600 | + find_expr_references_context context; |
| 1601 | + |
| 1602 | + context.addrs = addrs; |
| 1603 | + |
| 1604 | + /* Set up interpretation for Vars at varlevelsup = 0 */ |
| 1605 | + context.rtables = list_make1(rtable); |
| 1606 | + |
| 1607 | + /* Scan the expression tree for referenceable objects */ |
| 1608 | + find_expr_references_walker(expr, &context); |
1576 | 1609 | } |
1577 | 1610 |
|
1578 | 1611 | /* |
@@ -2402,6 +2435,50 @@ process_function_rte_ref(RangeTblEntry *rte, AttrNumber attnum, |
2402 | 2435 | attnum, rte->eref->aliasname))); |
2403 | 2436 | } |
2404 | 2437 |
|
| 2438 | +/* |
| 2439 | + * find_temp_object - search an array of dependency references for temp objects |
| 2440 | + * |
| 2441 | + * Scan an ObjectAddresses array for references to temporary objects (objects |
| 2442 | + * in temporary namespaces), ignoring those in our own temp namespace if |
| 2443 | + * local_temp_okay is true. If one is found, return true after storing its |
| 2444 | + * address in *foundobj. |
| 2445 | + * |
| 2446 | + * Current callers only use this to deliver helpful notices, so reporting |
| 2447 | + * one such object seems sufficient. We return the first one, which should |
| 2448 | + * be a stable result for a given query since it depends only on the order |
| 2449 | + * in which this module searches query trees. (However, it's important to |
| 2450 | + * call this before de-duplicating the objects, else OID order would affect |
| 2451 | + * the result.) |
| 2452 | + */ |
| 2453 | +bool |
| 2454 | +find_temp_object(const ObjectAddresses *addrs, bool local_temp_okay, |
| 2455 | + ObjectAddress *foundobj) |
| 2456 | +{ |
| 2457 | + for (int i = 0; i < addrs->numrefs; i++) |
| 2458 | + { |
| 2459 | + const ObjectAddress *thisobj = addrs->refs + i; |
| 2460 | + Oid objnamespace; |
| 2461 | + |
| 2462 | + /* |
| 2463 | + * Use get_object_namespace() to see if this object belongs to a |
| 2464 | + * schema. If not, we can skip it. |
| 2465 | + */ |
| 2466 | + objnamespace = get_object_namespace(thisobj); |
| 2467 | + |
| 2468 | + /* |
| 2469 | + * If the object is in a temporary namespace, complain, except if |
| 2470 | + * local_temp_okay and it's our own temp namespace. |
| 2471 | + */ |
| 2472 | + if (OidIsValid(objnamespace) && isAnyTempNamespace(objnamespace) && |
| 2473 | + !(local_temp_okay && isTempNamespace(objnamespace))) |
| 2474 | + { |
| 2475 | + *foundobj = *thisobj; |
| 2476 | + return true; |
| 2477 | + } |
| 2478 | + } |
| 2479 | + return false; |
| 2480 | +} |
| 2481 | + |
2405 | 2482 | /* |
2406 | 2483 | * Given an array of dependency references, eliminate any duplicates. |
2407 | 2484 | */ |
|
0 commit comments