* ExplainOneUtility - * print out the execution plan for one utility statement * (In general, utility statements don't have plans, but there are some * we treat as special cases) * * "into" is NULL unless we are explaining the contents of a CreateTableAsStmt. * * This is exported because it's called back from prepare.c in the * EXPLAIN EXECUTE case. In that case, we'll be dealing wi
| 580 | * that's in the plan cache, so we have to ensure we don't modify it. |
| 581 | */ |
| 582 | void |
| 583 | ExplainOneUtility(Node *utilityStmt, IntoClause *into, ExplainState *es, |
| 584 | const char *queryString, ParamListInfo params, |
| 585 | QueryEnvironment *queryEnv) |
| 586 | { |
| 587 | if (utilityStmt == NULL) |
| 588 | return; |
| 589 | |
| 590 | if (IsA(utilityStmt, CreateTableAsStmt)) |
| 591 | { |
| 592 | /* |
| 593 | * We have to rewrite the contained SELECT and then pass it back to |
| 594 | * ExplainOneQuery. Copy to be safe in the EXPLAIN EXECUTE case. |
| 595 | */ |
| 596 | CreateTableAsStmt *ctas = (CreateTableAsStmt *) utilityStmt; |
| 597 | List *rewritten; |
| 598 | |
| 599 | /* |
| 600 | * Check if the relation exists or not. This is done at this stage to |
| 601 | * avoid query planning or execution. |
| 602 | */ |
| 603 | if (CreateTableAsRelExists(ctas)) |
| 604 | { |
| 605 | if (ctas->objtype == OBJECT_TABLE) |
| 606 | ExplainDummyGroup("CREATE TABLE AS", NULL, es); |
| 607 | else if (ctas->objtype == OBJECT_MATVIEW) |
| 608 | { |
| 609 | if(ctas->into && ctas->into->dynamicTbl) |
| 610 | ExplainDummyGroup("CREATE DYNAMIC TABLE", NULL, es); |
| 611 | else |
| 612 | ExplainDummyGroup("CREATE MATERIALIZED VIEW", NULL, es); |
| 613 | } |
| 614 | else |
| 615 | elog(ERROR, "unexpected object type: %d", |
| 616 | (int) ctas->objtype); |
| 617 | return; |
| 618 | } |
| 619 | |
| 620 | rewritten = QueryRewrite(castNode(Query, copyObject(ctas->query))); |
| 621 | Assert(list_length(rewritten) == 1); |
| 622 | ExplainOneQuery(linitial_node(Query, rewritten), |
| 623 | CURSOR_OPT_PARALLEL_OK, ctas->into, es, |
| 624 | queryString, params, queryEnv); |
| 625 | } |
| 626 | else if (IsA(utilityStmt, DeclareCursorStmt)) |
| 627 | { |
| 628 | /* |
| 629 | * Likewise for DECLARE CURSOR. |
| 630 | * |
| 631 | * Notice that if you say EXPLAIN ANALYZE DECLARE CURSOR then we'll |
| 632 | * actually run the query. This is different from pre-8.3 behavior |
| 633 | * but seems more useful than not running the query. No cursor will |
| 634 | * be created, however. |
| 635 | */ |
| 636 | DeclareCursorStmt *dcs = (DeclareCursorStmt *) utilityStmt; |
| 637 | List *rewritten; |
| 638 | |
| 639 | rewritten = QueryRewrite(castNode(Query, copyObject(dcs->query))); |
no test coverage detected