1 /*------------------------------------------------------------------------- 2 * 3 * utility.c 4 * Contains functions which control the execution of the POSTGRES utility 5 * commands. At one time acted as an interface between the Lisp and C 6 * systems. 7 * 8 * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group 9 * Portions Copyright (c) 1994, Regents of the University of California 10 * 11 * 12 * IDENTIFICATION 13 * src/backend/tcop/utility.c 14 * 15 *------------------------------------------------------------------------- 16 */ 17 #include "postgres.h" 18 19 #include "access/htup_details.h" 20 #include "access/reloptions.h" 21 #include "access/twophase.h" 22 #include "access/xact.h" 23 #include "access/xlog.h" 24 #include "catalog/catalog.h" 25 #include "catalog/namespace.h" 26 #include "catalog/pg_inherits.h" 27 #include "catalog/toasting.h" 28 #include "commands/alter.h" 29 #include "commands/async.h" 30 #include "commands/cluster.h" 31 #include "commands/collationcmds.h" 32 #include "commands/comment.h" 33 #include "commands/conversioncmds.h" 34 #include "commands/copy.h" 35 #include "commands/createas.h" 36 #include "commands/dbcommands.h" 37 #include "commands/defrem.h" 38 #include "commands/discard.h" 39 #include "commands/event_trigger.h" 40 #include "commands/explain.h" 41 #include "commands/extension.h" 42 #include "commands/lockcmds.h" 43 #include "commands/matview.h" 44 #include "commands/policy.h" 45 #include "commands/portalcmds.h" 46 #include "commands/prepare.h" 47 #include "commands/proclang.h" 48 #include "commands/publicationcmds.h" 49 #include "commands/schemacmds.h" 50 #include "commands/seclabel.h" 51 #include "commands/sequence.h" 52 #include "commands/subscriptioncmds.h" 53 #include "commands/tablecmds.h" 54 #include "commands/tablespace.h" 55 #include "commands/trigger.h" 56 #include "commands/typecmds.h" 57 #include "commands/user.h" 58 #include "commands/vacuum.h" 59 #include "commands/view.h" 60 #include "miscadmin.h" 61 #include "parser/parse_utilcmd.h" 62 #include "postmaster/bgwriter.h" 63 #include "rewrite/rewriteDefine.h" 64 #include "rewrite/rewriteRemove.h" 65 #include "storage/fd.h" 66 #include "tcop/pquery.h" 67 #include "tcop/utility.h" 68 #include "utils/acl.h" 69 #include "utils/guc.h" 70 #include "utils/lsyscache.h" 71 #include "utils/rel.h" 72 #include "utils/syscache.h" 73 74 /* Hook for plugins to get control in ProcessUtility() */ 75 ProcessUtility_hook_type ProcessUtility_hook = NULL; 76 77 /* local function declarations */ 78 static int ClassifyUtilityCommandAsReadOnly(Node *parsetree); 79 static void ProcessUtilitySlow(ParseState *pstate, 80 PlannedStmt *pstmt, 81 const char *queryString, 82 ProcessUtilityContext context, 83 ParamListInfo params, 84 QueryEnvironment *queryEnv, 85 DestReceiver *dest, 86 QueryCompletion *qc); 87 static void ExecDropStmt(DropStmt *stmt, bool isTopLevel); 88 89 /* 90 * CommandIsReadOnly: is an executable query read-only? 91 * 92 * This is a much stricter test than we apply for XactReadOnly mode; 93 * the query must be *in truth* read-only, because the caller wishes 94 * not to do CommandCounterIncrement for it. 95 * 96 * Note: currently no need to support raw or analyzed queries here 97 */ 98 bool 99 CommandIsReadOnly(PlannedStmt *pstmt) 100 { 101 Assert(IsA(pstmt, PlannedStmt)); 102 switch (pstmt->commandType) 103 { 104 case CMD_SELECT: 105 if (pstmt->rowMarks != NIL) 106 return false; /* SELECT FOR [KEY] UPDATE/SHARE */ 107 else if (pstmt->hasModifyingCTE) 108 return false; /* data-modifying CTE */ 109 else 110 return true; 111 case CMD_UPDATE: 112 case CMD_INSERT: 113 case CMD_DELETE: 114 return false; 115 case CMD_UTILITY: 116 /* For now, treat all utility commands as read/write */ 117 return false; 118 default: 119 elog(WARNING, "unrecognized commandType: %d", 120 (int) pstmt->commandType); 121 break; 122 } 123 return false; 124 } 125 126 /* 127 * Determine the degree to which a utility command is read only. 128 * 129 * Note the definitions of the relevant flags in src/include/utility/tcop.h. 130 */ 131 static int 132 ClassifyUtilityCommandAsReadOnly(Node *parsetree) 133 { 134 switch (nodeTag(parsetree)) 135 { 136 case T_AlterCollationStmt: 137 case T_AlterDatabaseSetStmt: 138 case T_AlterDatabaseStmt: 139 case T_AlterDefaultPrivilegesStmt: 140 case T_AlterDomainStmt: 141 case T_AlterEnumStmt: 142 case T_AlterEventTrigStmt: 143 case T_AlterExtensionContentsStmt: 144 case T_AlterExtensionStmt: 145 case T_AlterFdwStmt: 146 case T_AlterForeignServerStmt: 147 case T_AlterFunctionStmt: 148 case T_AlterObjectDependsStmt: 149 case T_AlterObjectSchemaStmt: 150 case T_AlterOpFamilyStmt: 151 case T_AlterOperatorStmt: 152 case T_AlterOwnerStmt: 153 case T_AlterPolicyStmt: 154 case T_AlterPublicationStmt: 155 case T_AlterRoleSetStmt: 156 case T_AlterRoleStmt: 157 case T_AlterSeqStmt: 158 case T_AlterStatsStmt: 159 case T_AlterSubscriptionStmt: 160 case T_AlterTSConfigurationStmt: 161 case T_AlterTSDictionaryStmt: 162 case T_AlterTableMoveAllStmt: 163 case T_AlterTableSpaceOptionsStmt: 164 case T_AlterTableStmt: 165 case T_AlterTypeStmt: 166 case T_AlterUserMappingStmt: 167 case T_CommentStmt: 168 case T_CompositeTypeStmt: 169 case T_CreateAmStmt: 170 case T_CreateCastStmt: 171 case T_CreateConversionStmt: 172 case T_CreateDomainStmt: 173 case T_CreateEnumStmt: 174 case T_CreateEventTrigStmt: 175 case T_CreateExtensionStmt: 176 case T_CreateFdwStmt: 177 case T_CreateForeignServerStmt: 178 case T_CreateForeignTableStmt: 179 case T_CreateFunctionStmt: 180 case T_CreateOpClassStmt: 181 case T_CreateOpFamilyStmt: 182 case T_CreatePLangStmt: 183 case T_CreatePolicyStmt: 184 case T_CreatePublicationStmt: 185 case T_CreateRangeStmt: 186 case T_CreateRoleStmt: 187 case T_CreateSchemaStmt: 188 case T_CreateSeqStmt: 189 case T_CreateStatsStmt: 190 case T_CreateStmt: 191 case T_CreateSubscriptionStmt: 192 case T_CreateTableAsStmt: 193 case T_CreateTableSpaceStmt: 194 case T_CreateTransformStmt: 195 case T_CreateTrigStmt: 196 case T_CreateUserMappingStmt: 197 case T_CreatedbStmt: 198 case T_DefineStmt: 199 case T_DropOwnedStmt: 200 case T_DropRoleStmt: 201 case T_DropStmt: 202 case T_DropSubscriptionStmt: 203 case T_DropTableSpaceStmt: 204 case T_DropUserMappingStmt: 205 case T_DropdbStmt: 206 case T_GrantRoleStmt: 207 case T_GrantStmt: 208 case T_ImportForeignSchemaStmt: 209 case T_IndexStmt: 210 case T_ReassignOwnedStmt: 211 case T_RefreshMatViewStmt: 212 case T_RenameStmt: 213 case T_RuleStmt: 214 case T_SecLabelStmt: 215 case T_TruncateStmt: 216 case T_ViewStmt: 217 { 218 /* DDL is not read-only, and neither is TRUNCATE. */ 219 return COMMAND_IS_NOT_READ_ONLY; 220 } 221 222 case T_AlterSystemStmt: 223 { 224 /* 225 * Surprisingly, ALTER SYSTEM meets all our definitions of 226 * read-only: it changes nothing that affects the output of 227 * pg_dump, it doesn't write WAL or imperil the application of 228 * future WAL, and it doesn't depend on any state that needs 229 * to be synchronized with parallel workers. 230 * 231 * So, despite the fact that it writes to a file, it's read 232 * only! 233 */ 234 return COMMAND_IS_STRICTLY_READ_ONLY; 235 } 236 237 case T_CallStmt: 238 case T_DoStmt: 239 { 240 /* 241 * Commands inside the DO block or the called procedure might 242 * not be read only, but they'll be checked separately when we 243 * try to execute them. Here we only need to worry about the 244 * DO or CALL command itself. 245 */ 246 return COMMAND_IS_STRICTLY_READ_ONLY; 247 } 248 249 case T_CheckPointStmt: 250 { 251 /* 252 * You might think that this should not be permitted in 253 * recovery, but we interpret a CHECKPOINT command during 254 * recovery as a request for a restartpoint instead. We allow 255 * this since it can be a useful way of reducing switchover 256 * time when using various forms of replication. 257 */ 258 return COMMAND_IS_STRICTLY_READ_ONLY; 259 } 260 261 case T_ClosePortalStmt: 262 case T_ConstraintsSetStmt: 263 case T_DeallocateStmt: 264 case T_DeclareCursorStmt: 265 case T_DiscardStmt: 266 case T_ExecuteStmt: 267 case T_FetchStmt: 268 case T_LoadStmt: 269 case T_PrepareStmt: 270 case T_UnlistenStmt: 271 case T_VariableSetStmt: 272 { 273 /* 274 * These modify only backend-local state, so they're OK to run 275 * in a read-only transaction or on a standby. However, they 276 * are disallowed in parallel mode, because they either rely 277 * upon or modify backend-local state that might not be 278 * synchronized among cooperating backends. 279 */ 280 return COMMAND_OK_IN_RECOVERY | COMMAND_OK_IN_READ_ONLY_TXN; 281 } 282 283 case T_ClusterStmt: 284 case T_ReindexStmt: 285 case T_VacuumStmt: 286 { 287 /* 288 * These commands write WAL, so they're not strictly 289 * read-only, and running them in parallel workers isn't 290 * supported. 291 * 292 * However, they don't change the database state in a way that 293 * would affect pg_dump output, so it's fine to run them in a 294 * read-only transaction. (CLUSTER might change the order of 295 * rows on disk, which could affect the ordering of pg_dump 296 * output, but that's not semantically significant.) 297 */ 298 return COMMAND_OK_IN_READ_ONLY_TXN; 299 } 300 301 case T_CopyStmt: 302 { 303 CopyStmt *stmt = (CopyStmt *) parsetree; 304 305 /* 306 * You might think that COPY FROM is not at all read only, but 307 * it's OK to copy into a temporary table, because that 308 * wouldn't change the output of pg_dump. If the target table 309 * turns out to be non-temporary, DoCopy itself will call 310 * PreventCommandIfReadOnly. 311 */ 312 if (stmt->is_from) 313 return COMMAND_OK_IN_READ_ONLY_TXN; 314 else 315 return COMMAND_IS_STRICTLY_READ_ONLY; 316 } 317 318 case T_ExplainStmt: 319 case T_VariableShowStmt: 320 { 321 /* 322 * These commands don't modify any data and are safe to run in 323 * a parallel worker. 324 */ 325 return COMMAND_IS_STRICTLY_READ_ONLY; 326 } 327 328 case T_ListenStmt: 329 case T_NotifyStmt: 330 { 331 /* 332 * NOTIFY requires an XID assignment, so it can't be permitted 333 * on a standby. Perhaps LISTEN could, since without NOTIFY it 334 * would be OK to just do nothing, at least until promotion, 335 * but we currently prohibit it lest the user get the wrong 336 * idea. 337 * 338 * (We do allow T_UnlistenStmt on a standby, though, because 339 * it's a no-op.) 340 */ 341 return COMMAND_OK_IN_READ_ONLY_TXN; 342 } 343 344 case T_LockStmt: 345 { 346 LockStmt *stmt = (LockStmt *) parsetree; 347 348 /* 349 * Only weaker locker modes are allowed during recovery. The 350 * restrictions here must match those in 351 * LockAcquireExtended(). 352 */ 353 if (stmt->mode > RowExclusiveLock) 354 return COMMAND_OK_IN_READ_ONLY_TXN; 355 else 356 return COMMAND_IS_STRICTLY_READ_ONLY; 357 } 358 359 case T_TransactionStmt: 360 { 361 TransactionStmt *stmt = (TransactionStmt *) parsetree; 362 363 /* 364 * PREPARE, COMMIT PREPARED, and ROLLBACK PREPARED all write 365 * WAL, so they're not read-only in the strict sense; but the 366 * first and third do not change pg_dump output, so they're OK 367 * in a read-only transactions. 368 * 369 * We also consider COMMIT PREPARED to be OK in a read-only 370 * transaction environment, by way of exception. 371 */ 372 switch (stmt->kind) 373 { 374 case TRANS_STMT_BEGIN: 375 case TRANS_STMT_START: 376 case TRANS_STMT_COMMIT: 377 case TRANS_STMT_ROLLBACK: 378 case TRANS_STMT_SAVEPOINT: 379 case TRANS_STMT_RELEASE: 380 case TRANS_STMT_ROLLBACK_TO: 381 return COMMAND_IS_STRICTLY_READ_ONLY; 382 383 case TRANS_STMT_PREPARE: 384 case TRANS_STMT_COMMIT_PREPARED: 385 case TRANS_STMT_ROLLBACK_PREPARED: 386 return COMMAND_OK_IN_READ_ONLY_TXN; 387 } 388 elog(ERROR, "unrecognized TransactionStmtKind: %d", 389 (int) stmt->kind); 390 return 0; /* silence stupider compilers */ 391 } 392 393 default: 394 elog(ERROR, "unrecognized node type: %d", 395 (int) nodeTag(parsetree)); 396 return 0; /* silence stupider compilers */ 397 } 398 } 399 400 /* 401 * PreventCommandIfReadOnly: throw error if XactReadOnly 402 * 403 * This is useful partly to ensure consistency of the error message wording; 404 * some callers have checked XactReadOnly for themselves. 405 */ 406 void 407 PreventCommandIfReadOnly(const char *cmdname) 408 { 409 if (XactReadOnly) 410 ereport(ERROR, 411 (errcode(ERRCODE_READ_ONLY_SQL_TRANSACTION), 412 /* translator: %s is name of a SQL command, eg CREATE */ 413 errmsg("cannot execute %s in a read-only transaction", 414 cmdname))); 415 } 416 417 /* 418 * PreventCommandIfParallelMode: throw error if current (sub)transaction is 419 * in parallel mode. 420 * 421 * This is useful partly to ensure consistency of the error message wording; 422 * some callers have checked IsInParallelMode() for themselves. 423 */ 424 void 425 PreventCommandIfParallelMode(const char *cmdname) 426 { 427 if (IsInParallelMode()) 428 ereport(ERROR, 429 (errcode(ERRCODE_INVALID_TRANSACTION_STATE), 430 /* translator: %s is name of a SQL command, eg CREATE */ 431 errmsg("cannot execute %s during a parallel operation", 432 cmdname))); 433 } 434 435 /* 436 * PreventCommandDuringRecovery: throw error if RecoveryInProgress 437 * 438 * The majority of operations that are unsafe in a Hot Standby 439 * will be rejected by XactReadOnly tests. However there are a few 440 * commands that are allowed in "read-only" xacts but cannot be allowed 441 * in Hot Standby mode. Those commands should call this function. 442 */ 443 void 444 PreventCommandDuringRecovery(const char *cmdname) 445 { 446 if (RecoveryInProgress()) 447 ereport(ERROR, 448 (errcode(ERRCODE_READ_ONLY_SQL_TRANSACTION), 449 /* translator: %s is name of a SQL command, eg CREATE */ 450 errmsg("cannot execute %s during recovery", 451 cmdname))); 452 } 453 454 /* 455 * CheckRestrictedOperation: throw error for hazardous command if we're 456 * inside a security restriction context. 457 * 458 * This is needed to protect session-local state for which there is not any 459 * better-defined protection mechanism, such as ownership. 460 */ 461 static void 462 CheckRestrictedOperation(const char *cmdname) 463 { 464 if (InSecurityRestrictedOperation()) 465 ereport(ERROR, 466 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), 467 /* translator: %s is name of a SQL command, eg PREPARE */ 468 errmsg("cannot execute %s within security-restricted operation", 469 cmdname))); 470 } 471 472 /* 473 * ProcessUtility 474 * general utility function invoker 475 * 476 * pstmt: PlannedStmt wrapper for the utility statement 477 * queryString: original source text of command 478 * context: identifies source of statement (toplevel client command, 479 * non-toplevel client command, subcommand of a larger utility command) 480 * params: parameters to use during execution 481 * queryEnv: environment for parse through execution (e.g., ephemeral named 482 * tables like trigger transition tables). May be NULL. 483 * dest: where to send results 484 * qc: where to store command completion status data. May be NULL, 485 * but if not, then caller must have initialized it. 486 * 487 * Caller MUST supply a queryString; it is not allowed (anymore) to pass NULL. 488 * If you really don't have source text, you can pass a constant string, 489 * perhaps "(query not available)". 490 * 491 * Note for users of ProcessUtility_hook: the same queryString may be passed 492 * to multiple invocations of ProcessUtility when processing a query string 493 * containing multiple semicolon-separated statements. One should use 494 * pstmt->stmt_location and pstmt->stmt_len to identify the substring 495 * containing the current statement. Keep in mind also that some utility 496 * statements (e.g., CREATE SCHEMA) will recurse to ProcessUtility to process 497 * sub-statements, often passing down the same queryString, stmt_location, 498 * and stmt_len that were given for the whole statement. 499 */ 500 void 501 ProcessUtility(PlannedStmt *pstmt, 502 const char *queryString, 503 ProcessUtilityContext context, 504 ParamListInfo params, 505 QueryEnvironment *queryEnv, 506 DestReceiver *dest, 507 QueryCompletion *qc) 508 { 509 Assert(IsA(pstmt, PlannedStmt)); 510 Assert(pstmt->commandType == CMD_UTILITY); 511 Assert(queryString != NULL); /* required as of 8.4 */ 512 Assert(qc == NULL || qc->commandTag == CMDTAG_UNKNOWN); 513 514 /* 515 * We provide a function hook variable that lets loadable plugins get 516 * control when ProcessUtility is called. Such a plugin would normally 517 * call standard_ProcessUtility(). 518 */ 519 if (ProcessUtility_hook) 520 (*ProcessUtility_hook) (pstmt, queryString, 521 context, params, queryEnv, 522 dest, qc); 523 else 524 standard_ProcessUtility(pstmt, queryString, 525 context, params, queryEnv, 526 dest, qc); 527 } 528 529 /* 530 * standard_ProcessUtility itself deals only with utility commands for 531 * which we do not provide event trigger support. Commands that do have 532 * such support are passed down to ProcessUtilitySlow, which contains the 533 * necessary infrastructure for such triggers. 534 * 535 * This division is not just for performance: it's critical that the 536 * event trigger code not be invoked when doing START TRANSACTION for 537 * example, because we might need to refresh the event trigger cache, 538 * which requires being in a valid transaction. 539 */ 540 void 541 standard_ProcessUtility(PlannedStmt *pstmt, 542 const char *queryString, 543 ProcessUtilityContext context, 544 ParamListInfo params, 545 QueryEnvironment *queryEnv, 546 DestReceiver *dest, 547 QueryCompletion *qc) 548 { 549 Node *parsetree = pstmt->utilityStmt; 550 bool isTopLevel = (context == PROCESS_UTILITY_TOPLEVEL); 551 bool isAtomicContext = (!(context == PROCESS_UTILITY_TOPLEVEL || context == PROCESS_UTILITY_QUERY_NONATOMIC) || IsTransactionBlock()); 552 ParseState *pstate; 553 int readonly_flags; 554 555 /* This can recurse, so check for excessive recursion */ 556 check_stack_depth(); 557 558 /* Prohibit read/write commands in read-only states. */ 559 readonly_flags = ClassifyUtilityCommandAsReadOnly(parsetree); 560 if (readonly_flags != COMMAND_IS_STRICTLY_READ_ONLY && 561 (XactReadOnly || IsInParallelMode())) 562 { 563 CommandTag commandtag = CreateCommandTag(parsetree); 564 565 if ((readonly_flags & COMMAND_OK_IN_READ_ONLY_TXN) == 0) 566 PreventCommandIfReadOnly(GetCommandTagName(commandtag)); 567 if ((readonly_flags & COMMAND_OK_IN_PARALLEL_MODE) == 0) 568 PreventCommandIfParallelMode(GetCommandTagName(commandtag)); 569 if ((readonly_flags & COMMAND_OK_IN_RECOVERY) == 0) 570 PreventCommandDuringRecovery(GetCommandTagName(commandtag)); 571 } 572 573 pstate = make_parsestate(NULL); 574 pstate->p_sourcetext = queryString; 575 pstate->p_queryEnv = queryEnv; 576 577 switch (nodeTag(parsetree)) 578 { 579 /* 580 * ******************** transactions ******************** 581 */ 582 case T_TransactionStmt: 583 { 584 TransactionStmt *stmt = (TransactionStmt *) parsetree; 585 586 switch (stmt->kind) 587 { 588 /* 589 * START TRANSACTION, as defined by SQL99: Identical 590 * to BEGIN. Same code for both. 591 */ 592 case TRANS_STMT_BEGIN: 593 case TRANS_STMT_START: 594 { 595 ListCell *lc; 596 597 BeginTransactionBlock(); 598 foreach(lc, stmt->options) 599 { 600 DefElem *item = (DefElem *) lfirst(lc); 601 602 if (strcmp(item->defname, "transaction_isolation") == 0) 603 SetPGVariable("transaction_isolation", 604 list_make1(item->arg), 605 true); 606 else if (strcmp(item->defname, "transaction_read_only") == 0) 607 SetPGVariable("transaction_read_only", 608 list_make1(item->arg), 609 true); 610 else if (strcmp(item->defname, "transaction_deferrable") == 0) 611 SetPGVariable("transaction_deferrable", 612 list_make1(item->arg), 613 true); 614 } 615 } 616 break; 617 618 case TRANS_STMT_COMMIT: 619 if (!EndTransactionBlock(stmt->chain)) 620 { 621 /* report unsuccessful commit in qc */ 622 if (qc) 623 SetQueryCompletion(qc, CMDTAG_ROLLBACK, 0); 624 } 625 break; 626 627 case TRANS_STMT_PREPARE: 628 if (!PrepareTransactionBlock(stmt->gid)) 629 { 630 /* report unsuccessful commit in qc */ 631 if (qc) 632 SetQueryCompletion(qc, CMDTAG_ROLLBACK, 0); 633 } 634 break; 635 636 case TRANS_STMT_COMMIT_PREPARED: 637 PreventInTransactionBlock(isTopLevel, "COMMIT PREPARED"); 638 FinishPreparedTransaction(stmt->gid, true); 639 break; 640 641 case TRANS_STMT_ROLLBACK_PREPARED: 642 PreventInTransactionBlock(isTopLevel, "ROLLBACK PREPARED"); 643 FinishPreparedTransaction(stmt->gid, false); 644 break; 645 646 case TRANS_STMT_ROLLBACK: 647 UserAbortTransactionBlock(stmt->chain); 648 break; 649 650 case TRANS_STMT_SAVEPOINT: 651 RequireTransactionBlock(isTopLevel, "SAVEPOINT"); 652 DefineSavepoint(stmt->savepoint_name); 653 break; 654 655 case TRANS_STMT_RELEASE: 656 RequireTransactionBlock(isTopLevel, "RELEASE SAVEPOINT"); 657 ReleaseSavepoint(stmt->savepoint_name); 658 break; 659 660 case TRANS_STMT_ROLLBACK_TO: 661 RequireTransactionBlock(isTopLevel, "ROLLBACK TO SAVEPOINT"); 662 RollbackToSavepoint(stmt->savepoint_name); 663 664 /* 665 * CommitTransactionCommand is in charge of 666 * re-defining the savepoint again 667 */ 668 break; 669 } 670 } 671 break; 672 673 /* 674 * Portal (cursor) manipulation 675 */ 676 case T_DeclareCursorStmt: 677 PerformCursorOpen(pstate, (DeclareCursorStmt *) parsetree, params, 678 isTopLevel); 679 break; 680 681 case T_ClosePortalStmt: 682 { 683 ClosePortalStmt *stmt = (ClosePortalStmt *) parsetree; 684 685 CheckRestrictedOperation("CLOSE"); 686 PerformPortalClose(stmt->portalname); 687 } 688 break; 689 690 case T_FetchStmt: 691 PerformPortalFetch((FetchStmt *) parsetree, dest, qc); 692 break; 693 694 case T_DoStmt: 695 ExecuteDoStmt((DoStmt *) parsetree, isAtomicContext); 696 break; 697 698 case T_CreateTableSpaceStmt: 699 /* no event triggers for global objects */ 700 PreventInTransactionBlock(isTopLevel, "CREATE TABLESPACE"); 701 CreateTableSpace((CreateTableSpaceStmt *) parsetree); 702 break; 703 704 case T_DropTableSpaceStmt: 705 /* no event triggers for global objects */ 706 PreventInTransactionBlock(isTopLevel, "DROP TABLESPACE"); 707 DropTableSpace((DropTableSpaceStmt *) parsetree); 708 break; 709 710 case T_AlterTableSpaceOptionsStmt: 711 /* no event triggers for global objects */ 712 AlterTableSpaceOptions((AlterTableSpaceOptionsStmt *) parsetree); 713 break; 714 715 case T_TruncateStmt: 716 ExecuteTruncate((TruncateStmt *) parsetree); 717 break; 718 719 case T_CopyStmt: 720 { 721 uint64 processed; 722 723 DoCopy(pstate, (CopyStmt *) parsetree, 724 pstmt->stmt_location, pstmt->stmt_len, 725 &processed); 726 if (qc) 727 SetQueryCompletion(qc, CMDTAG_COPY, processed); 728 } 729 break; 730 731 case T_PrepareStmt: 732 CheckRestrictedOperation("PREPARE"); 733 PrepareQuery(pstate, (PrepareStmt *) parsetree, 734 pstmt->stmt_location, pstmt->stmt_len); 735 break; 736 737 case T_ExecuteStmt: 738 ExecuteQuery(pstate, 739 (ExecuteStmt *) parsetree, NULL, 740 params, 741 dest, qc); 742 break; 743 744 case T_DeallocateStmt: 745 CheckRestrictedOperation("DEALLOCATE"); 746 DeallocateQuery((DeallocateStmt *) parsetree); 747 break; 748 749 case T_GrantRoleStmt: 750 /* no event triggers for global objects */ 751 GrantRole((GrantRoleStmt *) parsetree); 752 break; 753 754 case T_CreatedbStmt: 755 /* no event triggers for global objects */ 756 PreventInTransactionBlock(isTopLevel, "CREATE DATABASE"); 757 createdb(pstate, (CreatedbStmt *) parsetree); 758 break; 759 760 case T_AlterDatabaseStmt: 761 /* no event triggers for global objects */ 762 AlterDatabase(pstate, (AlterDatabaseStmt *) parsetree, isTopLevel); 763 break; 764 765 case T_AlterDatabaseSetStmt: 766 /* no event triggers for global objects */ 767 AlterDatabaseSet((AlterDatabaseSetStmt *) parsetree); 768 break; 769 770 case T_DropdbStmt: 771 /* no event triggers for global objects */ 772 PreventInTransactionBlock(isTopLevel, "DROP DATABASE"); 773 DropDatabase(pstate, (DropdbStmt *) parsetree); 774 break; 775 776 /* Query-level asynchronous notification */ 777 case T_NotifyStmt: 778 { 779 NotifyStmt *stmt = (NotifyStmt *) parsetree; 780 781 Async_Notify(stmt->conditionname, stmt->payload); 782 } 783 break; 784 785 case T_ListenStmt: 786 { 787 ListenStmt *stmt = (ListenStmt *) parsetree; 788 789 CheckRestrictedOperation("LISTEN"); 790 791 /* 792 * We don't allow LISTEN in background processes, as there is 793 * no mechanism for them to collect NOTIFY messages, so they'd 794 * just block cleanout of the async SLRU indefinitely. 795 * (Authors of custom background workers could bypass this 796 * restriction by calling Async_Listen directly, but then it's 797 * on them to provide some mechanism to process the message 798 * queue.) Note there seems no reason to forbid UNLISTEN. 799 */ 800 if (MyBackendType != B_BACKEND) 801 ereport(ERROR, 802 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), 803 /* translator: %s is name of a SQL command, eg LISTEN */ 804 errmsg("cannot execute %s within a background process", 805 "LISTEN"))); 806 807 Async_Listen(stmt->conditionname); 808 } 809 break; 810 811 case T_UnlistenStmt: 812 { 813 UnlistenStmt *stmt = (UnlistenStmt *) parsetree; 814 815 CheckRestrictedOperation("UNLISTEN"); 816 if (stmt->conditionname) 817 Async_Unlisten(stmt->conditionname); 818 else 819 Async_UnlistenAll(); 820 } 821 break; 822 823 case T_LoadStmt: 824 { 825 LoadStmt *stmt = (LoadStmt *) parsetree; 826 827 closeAllVfds(); /* probably not necessary... */ 828 /* Allowed names are restricted if you're not superuser */ 829 load_file(stmt->filename, !superuser()); 830 } 831 break; 832 833 case T_CallStmt: 834 ExecuteCallStmt(castNode(CallStmt, parsetree), params, isAtomicContext, dest); 835 break; 836 837 case T_ClusterStmt: 838 cluster((ClusterStmt *) parsetree, isTopLevel); 839 break; 840 841 case T_VacuumStmt: 842 ExecVacuum(pstate, (VacuumStmt *) parsetree, isTopLevel); 843 break; 844 845 case T_ExplainStmt: 846 ExplainQuery(pstate, (ExplainStmt *) parsetree, params, dest); 847 break; 848 849 case T_AlterSystemStmt: 850 PreventInTransactionBlock(isTopLevel, "ALTER SYSTEM"); 851 AlterSystemSetConfigFile((AlterSystemStmt *) parsetree); 852 break; 853 854 case T_VariableSetStmt: 855 ExecSetVariableStmt((VariableSetStmt *) parsetree, isTopLevel); 856 break; 857 858 case T_VariableShowStmt: 859 { 860 VariableShowStmt *n = (VariableShowStmt *) parsetree; 861 862 GetPGVariable(n->name, dest); 863 } 864 break; 865 866 case T_DiscardStmt: 867 /* should we allow DISCARD PLANS? */ 868 CheckRestrictedOperation("DISCARD"); 869 DiscardCommand((DiscardStmt *) parsetree, isTopLevel); 870 break; 871 872 case T_CreateEventTrigStmt: 873 /* no event triggers on event triggers */ 874 CreateEventTrigger((CreateEventTrigStmt *) parsetree); 875 break; 876 877 case T_AlterEventTrigStmt: 878 /* no event triggers on event triggers */ 879 AlterEventTrigger((AlterEventTrigStmt *) parsetree); 880 break; 881 882 /* 883 * ******************************** ROLE statements **** 884 */ 885 case T_CreateRoleStmt: 886 /* no event triggers for global objects */ 887 CreateRole(pstate, (CreateRoleStmt *) parsetree); 888 break; 889 890 case T_AlterRoleStmt: 891 /* no event triggers for global objects */ 892 AlterRole((AlterRoleStmt *) parsetree); 893 break; 894 895 case T_AlterRoleSetStmt: 896 /* no event triggers for global objects */ 897 AlterRoleSet((AlterRoleSetStmt *) parsetree); 898 break; 899 900 case T_DropRoleStmt: 901 /* no event triggers for global objects */ 902 DropRole((DropRoleStmt *) parsetree); 903 break; 904 905 case T_ReassignOwnedStmt: 906 /* no event triggers for global objects */ 907 ReassignOwnedObjects((ReassignOwnedStmt *) parsetree); 908 break; 909 910 case T_LockStmt: 911 912 /* 913 * Since the lock would just get dropped immediately, LOCK TABLE 914 * outside a transaction block is presumed to be user error. 915 */ 916 RequireTransactionBlock(isTopLevel, "LOCK TABLE"); 917 LockTableCommand((LockStmt *) parsetree); 918 break; 919 920 case T_ConstraintsSetStmt: 921 WarnNoTransactionBlock(isTopLevel, "SET CONSTRAINTS"); 922 AfterTriggerSetState((ConstraintsSetStmt *) parsetree); 923 break; 924 925 case T_CheckPointStmt: 926 if (!superuser()) 927 ereport(ERROR, 928 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), 929 errmsg("must be superuser to do CHECKPOINT"))); 930 931 RequestCheckpoint(CHECKPOINT_IMMEDIATE | CHECKPOINT_WAIT | 932 (RecoveryInProgress() ? 0 : CHECKPOINT_FORCE)); 933 break; 934 935 case T_ReindexStmt: 936 { 937 ReindexStmt *stmt = (ReindexStmt *) parsetree; 938 939 if (stmt->concurrent) 940 PreventInTransactionBlock(isTopLevel, 941 "REINDEX CONCURRENTLY"); 942 943 switch (stmt->kind) 944 { 945 case REINDEX_OBJECT_INDEX: 946 ReindexIndex(stmt->relation, stmt->options, stmt->concurrent); 947 break; 948 case REINDEX_OBJECT_TABLE: 949 ReindexTable(stmt->relation, stmt->options, stmt->concurrent); 950 break; 951 case REINDEX_OBJECT_SCHEMA: 952 case REINDEX_OBJECT_SYSTEM: 953 case REINDEX_OBJECT_DATABASE: 954 955 /* 956 * This cannot run inside a user transaction block; if 957 * we were inside a transaction, then its commit- and 958 * start-transaction-command calls would not have the 959 * intended effect! 960 */ 961 PreventInTransactionBlock(isTopLevel, 962 (stmt->kind == REINDEX_OBJECT_SCHEMA) ? "REINDEX SCHEMA" : 963 (stmt->kind == REINDEX_OBJECT_SYSTEM) ? "REINDEX SYSTEM" : 964 "REINDEX DATABASE"); 965 ReindexMultipleTables(stmt->name, stmt->kind, stmt->options, stmt->concurrent); 966 break; 967 default: 968 elog(ERROR, "unrecognized object type: %d", 969 (int) stmt->kind); 970 break; 971 } 972 } 973 break; 974 975 /* 976 * The following statements are supported by Event Triggers only 977 * in some cases, so we "fast path" them in the other cases. 978 */ 979 980 case T_GrantStmt: 981 { 982 GrantStmt *stmt = (GrantStmt *) parsetree; 983 984 if (EventTriggerSupportsObjectType(stmt->objtype)) 985 ProcessUtilitySlow(pstate, pstmt, queryString, 986 context, params, queryEnv, 987 dest, qc); 988 else 989 ExecuteGrantStmt(stmt); 990 } 991 break; 992 993 case T_DropStmt: 994 { 995 DropStmt *stmt = (DropStmt *) parsetree; 996 997 if (EventTriggerSupportsObjectType(stmt->removeType)) 998 ProcessUtilitySlow(pstate, pstmt, queryString, 999 context, params, queryEnv, 1000 dest, qc); 1001 else 1002 ExecDropStmt(stmt, isTopLevel); 1003 } 1004 break; 1005 1006 case T_RenameStmt: 1007 { 1008 RenameStmt *stmt = (RenameStmt *) parsetree; 1009 1010 if (EventTriggerSupportsObjectType(stmt->renameType)) 1011 ProcessUtilitySlow(pstate, pstmt, queryString, 1012 context, params, queryEnv, 1013 dest, qc); 1014 else 1015 ExecRenameStmt(stmt); 1016 } 1017 break; 1018 1019 case T_AlterObjectDependsStmt: 1020 { 1021 AlterObjectDependsStmt *stmt = (AlterObjectDependsStmt *) parsetree; 1022 1023 if (EventTriggerSupportsObjectType(stmt->objectType)) 1024 ProcessUtilitySlow(pstate, pstmt, queryString, 1025 context, params, queryEnv, 1026 dest, qc); 1027 else 1028 ExecAlterObjectDependsStmt(stmt, NULL); 1029 } 1030 break; 1031 1032 case T_AlterObjectSchemaStmt: 1033 { 1034 AlterObjectSchemaStmt *stmt = (AlterObjectSchemaStmt *) parsetree; 1035 1036 if (EventTriggerSupportsObjectType(stmt->objectType)) 1037 ProcessUtilitySlow(pstate, pstmt, queryString, 1038 context, params, queryEnv, 1039 dest, qc); 1040 else 1041 ExecAlterObjectSchemaStmt(stmt, NULL); 1042 } 1043 break; 1044 1045 case T_AlterOwnerStmt: 1046 { 1047 AlterOwnerStmt *stmt = (AlterOwnerStmt *) parsetree; 1048 1049 if (EventTriggerSupportsObjectType(stmt->objectType)) 1050 ProcessUtilitySlow(pstate, pstmt, queryString, 1051 context, params, queryEnv, 1052 dest, qc); 1053 else 1054 ExecAlterOwnerStmt(stmt); 1055 } 1056 break; 1057 1058 case T_CommentStmt: 1059 { 1060 CommentStmt *stmt = (CommentStmt *) parsetree; 1061 1062 if (EventTriggerSupportsObjectType(stmt->objtype)) 1063 ProcessUtilitySlow(pstate, pstmt, queryString, 1064 context, params, queryEnv, 1065 dest, qc); 1066 else 1067 CommentObject(stmt); 1068 break; 1069 } 1070 1071 case T_SecLabelStmt: 1072 { 1073 SecLabelStmt *stmt = (SecLabelStmt *) parsetree; 1074 1075 if (EventTriggerSupportsObjectType(stmt->objtype)) 1076 ProcessUtilitySlow(pstate, pstmt, queryString, 1077 context, params, queryEnv, 1078 dest, qc); 1079 else 1080 ExecSecLabelStmt(stmt); 1081 break; 1082 } 1083 1084 default: 1085 /* All other statement types have event trigger support */ 1086 ProcessUtilitySlow(pstate, pstmt, queryString, 1087 context, params, queryEnv, 1088 dest, qc); 1089 break; 1090 } 1091 1092 free_parsestate(pstate); 1093 1094 /* 1095 * Make effects of commands visible, for instance so that 1096 * PreCommit_on_commit_actions() can see them (see for example bug 1097 * #15631). 1098 */ 1099 CommandCounterIncrement(); 1100 } 1101 1102 /* 1103 * The "Slow" variant of ProcessUtility should only receive statements 1104 * supported by the event triggers facility. Therefore, we always 1105 * perform the trigger support calls if the context allows it. 1106 */ 1107 static void 1108 ProcessUtilitySlow(ParseState *pstate, 1109 PlannedStmt *pstmt, 1110 const char *queryString, 1111 ProcessUtilityContext context, 1112 ParamListInfo params, 1113 QueryEnvironment *queryEnv, 1114 DestReceiver *dest, 1115 QueryCompletion *qc) 1116 { 1117 Node *parsetree = pstmt->utilityStmt; 1118 bool isTopLevel = (context == PROCESS_UTILITY_TOPLEVEL); 1119 bool isCompleteQuery = (context != PROCESS_UTILITY_SUBCOMMAND); 1120 bool needCleanup; 1121 bool commandCollected = false; 1122 ObjectAddress address; 1123 ObjectAddress secondaryObject = InvalidObjectAddress; 1124 1125 /* All event trigger calls are done only when isCompleteQuery is true */ 1126 needCleanup = isCompleteQuery && EventTriggerBeginCompleteQuery(); 1127 1128 /* PG_TRY block is to ensure we call EventTriggerEndCompleteQuery */ 1129 PG_TRY(); 1130 { 1131 if (isCompleteQuery) 1132 EventTriggerDDLCommandStart(parsetree); 1133 1134 switch (nodeTag(parsetree)) 1135 { 1136 /* 1137 * relation and attribute manipulation 1138 */ 1139 case T_CreateSchemaStmt: 1140 CreateSchemaCommand((CreateSchemaStmt *) parsetree, 1141 queryString, 1142 pstmt->stmt_location, 1143 pstmt->stmt_len); 1144 1145 /* 1146 * EventTriggerCollectSimpleCommand called by 1147 * CreateSchemaCommand 1148 */ 1149 commandCollected = true; 1150 break; 1151 1152 case T_CreateStmt: 1153 case T_CreateForeignTableStmt: 1154 { 1155 List *stmts; 1156 RangeVar *table_rv = NULL; 1157 1158 /* Run parse analysis ... */ 1159 stmts = transformCreateStmt((CreateStmt *) parsetree, 1160 queryString); 1161 1162 /* 1163 * ... and do it. We can't use foreach() because we may 1164 * modify the list midway through, so pick off the 1165 * elements one at a time, the hard way. 1166 */ 1167 while (stmts != NIL) 1168 { 1169 Node *stmt = (Node *) linitial(stmts); 1170 1171 stmts = list_delete_first(stmts); 1172 1173 if (IsA(stmt, CreateStmt)) 1174 { 1175 CreateStmt *cstmt = (CreateStmt *) stmt; 1176 Datum toast_options; 1177 static char *validnsps[] = HEAP_RELOPT_NAMESPACES; 1178 1179 /* Remember transformed RangeVar for LIKE */ 1180 table_rv = cstmt->relation; 1181 1182 /* Create the table itself */ 1183 address = DefineRelation(cstmt, 1184 RELKIND_RELATION, 1185 InvalidOid, NULL, 1186 queryString); 1187 EventTriggerCollectSimpleCommand(address, 1188 secondaryObject, 1189 stmt); 1190 1191 /* 1192 * Let NewRelationCreateToastTable decide if this 1193 * one needs a secondary relation too. 1194 */ 1195 CommandCounterIncrement(); 1196 1197 /* 1198 * parse and validate reloptions for the toast 1199 * table 1200 */ 1201 toast_options = transformRelOptions((Datum) 0, 1202 cstmt->options, 1203 "toast", 1204 validnsps, 1205 true, 1206 false); 1207 (void) heap_reloptions(RELKIND_TOASTVALUE, 1208 toast_options, 1209 true); 1210 1211 NewRelationCreateToastTable(address.objectId, 1212 toast_options); 1213 } 1214 else if (IsA(stmt, CreateForeignTableStmt)) 1215 { 1216 CreateForeignTableStmt *cstmt = (CreateForeignTableStmt *) stmt; 1217 1218 /* Remember transformed RangeVar for LIKE */ 1219 table_rv = cstmt->base.relation; 1220 1221 /* Create the table itself */ 1222 address = DefineRelation(&cstmt->base, 1223 RELKIND_FOREIGN_TABLE, 1224 InvalidOid, NULL, 1225 queryString); 1226 CreateForeignTable(cstmt, 1227 address.objectId); 1228 EventTriggerCollectSimpleCommand(address, 1229 secondaryObject, 1230 stmt); 1231 } 1232 else if (IsA(stmt, TableLikeClause)) 1233 { 1234 /* 1235 * Do delayed processing of LIKE options. This 1236 * will result in additional sub-statements for us 1237 * to process. Those should get done before any 1238 * remaining actions, so prepend them to "stmts". 1239 */ 1240 TableLikeClause *like = (TableLikeClause *) stmt; 1241 List *morestmts; 1242 1243 Assert(table_rv != NULL); 1244 1245 morestmts = expandTableLikeClause(table_rv, like); 1246 stmts = list_concat(morestmts, stmts); 1247 } 1248 else 1249 { 1250 /* 1251 * Recurse for anything else. Note the recursive 1252 * call will stash the objects so created into our 1253 * event trigger context. 1254 */ 1255 PlannedStmt *wrapper; 1256 1257 wrapper = makeNode(PlannedStmt); 1258 wrapper->commandType = CMD_UTILITY; 1259 wrapper->canSetTag = false; 1260 wrapper->utilityStmt = stmt; 1261 wrapper->stmt_location = pstmt->stmt_location; 1262 wrapper->stmt_len = pstmt->stmt_len; 1263 1264 ProcessUtility(wrapper, 1265 queryString, 1266 PROCESS_UTILITY_SUBCOMMAND, 1267 params, 1268 NULL, 1269 None_Receiver, 1270 NULL); 1271 } 1272 1273 /* Need CCI between commands */ 1274 if (stmts != NIL) 1275 CommandCounterIncrement(); 1276 } 1277 1278 /* 1279 * The multiple commands generated here are stashed 1280 * individually, so disable collection below. 1281 */ 1282 commandCollected = true; 1283 } 1284 break; 1285 1286 case T_AlterTableStmt: 1287 { 1288 AlterTableStmt *atstmt = (AlterTableStmt *) parsetree; 1289 Oid relid; 1290 LOCKMODE lockmode; 1291 1292 /* 1293 * Figure out lock mode, and acquire lock. This also does 1294 * basic permissions checks, so that we won't wait for a 1295 * lock on (for example) a relation on which we have no 1296 * permissions. 1297 */ 1298 lockmode = AlterTableGetLockLevel(atstmt->cmds); 1299 relid = AlterTableLookupRelation(atstmt, lockmode); 1300 1301 if (OidIsValid(relid)) 1302 { 1303 AlterTableUtilityContext atcontext; 1304 1305 /* Set up info needed for recursive callbacks ... */ 1306 atcontext.pstmt = pstmt; 1307 atcontext.queryString = queryString; 1308 atcontext.relid = relid; 1309 atcontext.params = params; 1310 atcontext.queryEnv = queryEnv; 1311 1312 /* ... ensure we have an event trigger context ... */ 1313 EventTriggerAlterTableStart(parsetree); 1314 EventTriggerAlterTableRelid(relid); 1315 1316 /* ... and do it */ 1317 AlterTable(atstmt, lockmode, &atcontext); 1318 1319 /* done */ 1320 EventTriggerAlterTableEnd(); 1321 } 1322 else 1323 ereport(NOTICE, 1324 (errmsg("relation \"%s\" does not exist, skipping", 1325 atstmt->relation->relname))); 1326 } 1327 1328 /* ALTER TABLE stashes commands internally */ 1329 commandCollected = true; 1330 break; 1331 1332 case T_AlterDomainStmt: 1333 { 1334 AlterDomainStmt *stmt = (AlterDomainStmt *) parsetree; 1335 1336 /* 1337 * Some or all of these functions are recursive to cover 1338 * inherited things, so permission checks are done there. 1339 */ 1340 switch (stmt->subtype) 1341 { 1342 case 'T': /* ALTER DOMAIN DEFAULT */ 1343 1344 /* 1345 * Recursively alter column default for table and, 1346 * if requested, for descendants 1347 */ 1348 address = 1349 AlterDomainDefault(stmt->typeName, 1350 stmt->def); 1351 break; 1352 case 'N': /* ALTER DOMAIN DROP NOT NULL */ 1353 address = 1354 AlterDomainNotNull(stmt->typeName, 1355 false); 1356 break; 1357 case 'O': /* ALTER DOMAIN SET NOT NULL */ 1358 address = 1359 AlterDomainNotNull(stmt->typeName, 1360 true); 1361 break; 1362 case 'C': /* ADD CONSTRAINT */ 1363 address = 1364 AlterDomainAddConstraint(stmt->typeName, 1365 stmt->def, 1366 &secondaryObject); 1367 break; 1368 case 'X': /* DROP CONSTRAINT */ 1369 address = 1370 AlterDomainDropConstraint(stmt->typeName, 1371 stmt->name, 1372 stmt->behavior, 1373 stmt->missing_ok); 1374 break; 1375 case 'V': /* VALIDATE CONSTRAINT */ 1376 address = 1377 AlterDomainValidateConstraint(stmt->typeName, 1378 stmt->name); 1379 break; 1380 default: /* oops */ 1381 elog(ERROR, "unrecognized alter domain type: %d", 1382 (int) stmt->subtype); 1383 break; 1384 } 1385 } 1386 break; 1387 1388 /* 1389 * ************* object creation / destruction ************** 1390 */ 1391 case T_DefineStmt: 1392 { 1393 DefineStmt *stmt = (DefineStmt *) parsetree; 1394 1395 switch (stmt->kind) 1396 { 1397 case OBJECT_AGGREGATE: 1398 address = 1399 DefineAggregate(pstate, stmt->defnames, stmt->args, 1400 stmt->oldstyle, 1401 stmt->definition, 1402 stmt->replace); 1403 break; 1404 case OBJECT_OPERATOR: 1405 Assert(stmt->args == NIL); 1406 address = DefineOperator(stmt->defnames, 1407 stmt->definition); 1408 break; 1409 case OBJECT_TYPE: 1410 Assert(stmt->args == NIL); 1411 address = DefineType(pstate, 1412 stmt->defnames, 1413 stmt->definition); 1414 break; 1415 case OBJECT_TSPARSER: 1416 Assert(stmt->args == NIL); 1417 address = DefineTSParser(stmt->defnames, 1418 stmt->definition); 1419 break; 1420 case OBJECT_TSDICTIONARY: 1421 Assert(stmt->args == NIL); 1422 address = DefineTSDictionary(stmt->defnames, 1423 stmt->definition); 1424 break; 1425 case OBJECT_TSTEMPLATE: 1426 Assert(stmt->args == NIL); 1427 address = DefineTSTemplate(stmt->defnames, 1428 stmt->definition); 1429 break; 1430 case OBJECT_TSCONFIGURATION: 1431 Assert(stmt->args == NIL); 1432 address = DefineTSConfiguration(stmt->defnames, 1433 stmt->definition, 1434 &secondaryObject); 1435 break; 1436 case OBJECT_COLLATION: 1437 Assert(stmt->args == NIL); 1438 address = DefineCollation(pstate, 1439 stmt->defnames, 1440 stmt->definition, 1441 stmt->if_not_exists); 1442 break; 1443 default: 1444 elog(ERROR, "unrecognized define stmt type: %d", 1445 (int) stmt->kind); 1446 break; 1447 } 1448 } 1449 break; 1450 1451 case T_IndexStmt: /* CREATE INDEX */ 1452 { 1453 IndexStmt *stmt = (IndexStmt *) parsetree; 1454 Oid relid; 1455 LOCKMODE lockmode; 1456 bool is_alter_table; 1457 1458 if (stmt->concurrent) 1459 PreventInTransactionBlock(isTopLevel, 1460 "CREATE INDEX CONCURRENTLY"); 1461 1462 /* 1463 * Look up the relation OID just once, right here at the 1464 * beginning, so that we don't end up repeating the name 1465 * lookup later and latching onto a different relation 1466 * partway through. To avoid lock upgrade hazards, it's 1467 * important that we take the strongest lock that will 1468 * eventually be needed here, so the lockmode calculation 1469 * needs to match what DefineIndex() does. 1470 */ 1471 lockmode = stmt->concurrent ? ShareUpdateExclusiveLock 1472 : ShareLock; 1473 relid = 1474 RangeVarGetRelidExtended(stmt->relation, lockmode, 1475 0, 1476 RangeVarCallbackOwnsRelation, 1477 NULL); 1478 1479 /* 1480 * CREATE INDEX on partitioned tables (but not regular 1481 * inherited tables) recurses to partitions, so we must 1482 * acquire locks early to avoid deadlocks. 1483 * 1484 * We also take the opportunity to verify that all 1485 * partitions are something we can put an index on, to 1486 * avoid building some indexes only to fail later. 1487 */ 1488 if (stmt->relation->inh && 1489 get_rel_relkind(relid) == RELKIND_PARTITIONED_TABLE) 1490 { 1491 ListCell *lc; 1492 List *inheritors = NIL; 1493 1494 inheritors = find_all_inheritors(relid, lockmode, NULL); 1495 foreach(lc, inheritors) 1496 { 1497 char relkind = get_rel_relkind(lfirst_oid(lc)); 1498 1499 if (relkind != RELKIND_RELATION && 1500 relkind != RELKIND_MATVIEW && 1501 relkind != RELKIND_PARTITIONED_TABLE && 1502 relkind != RELKIND_FOREIGN_TABLE) 1503 elog(ERROR, "unexpected relkind \"%c\" on partition \"%s\"", 1504 relkind, stmt->relation->relname); 1505 1506 if (relkind == RELKIND_FOREIGN_TABLE && 1507 (stmt->unique || stmt->primary)) 1508 ereport(ERROR, 1509 (errcode(ERRCODE_WRONG_OBJECT_TYPE), 1510 errmsg("cannot create unique index on partitioned table \"%s\"", 1511 stmt->relation->relname), 1512 errdetail("Table \"%s\" contains partitions that are foreign tables.", 1513 stmt->relation->relname))); 1514 } 1515 list_free(inheritors); 1516 } 1517 1518 /* 1519 * If the IndexStmt is already transformed, it must have 1520 * come from generateClonedIndexStmt, which in current 1521 * usage means it came from expandTableLikeClause rather 1522 * than from original parse analysis. And that means we 1523 * must treat it like ALTER TABLE ADD INDEX, not CREATE. 1524 * (This is a bit grotty, but currently it doesn't seem 1525 * worth adding a separate bool field for the purpose.) 1526 */ 1527 is_alter_table = stmt->transformed; 1528 1529 /* Run parse analysis ... */ 1530 stmt = transformIndexStmt(relid, stmt, queryString); 1531 1532 /* ... and do it */ 1533 EventTriggerAlterTableStart(parsetree); 1534 address = 1535 DefineIndex(relid, /* OID of heap relation */ 1536 stmt, 1537 InvalidOid, /* no predefined OID */ 1538 InvalidOid, /* no parent index */ 1539 InvalidOid, /* no parent constraint */ 1540 is_alter_table, 1541 true, /* check_rights */ 1542 true, /* check_not_in_use */ 1543 false, /* skip_build */ 1544 false); /* quiet */ 1545 1546 /* 1547 * Add the CREATE INDEX node itself to stash right away; 1548 * if there were any commands stashed in the ALTER TABLE 1549 * code, we need them to appear after this one. 1550 */ 1551 EventTriggerCollectSimpleCommand(address, secondaryObject, 1552 parsetree); 1553 commandCollected = true; 1554 EventTriggerAlterTableEnd(); 1555 } 1556 break; 1557 1558 case T_CreateExtensionStmt: 1559 address = CreateExtension(pstate, (CreateExtensionStmt *) parsetree); 1560 break; 1561 1562 case T_AlterExtensionStmt: 1563 address = ExecAlterExtensionStmt(pstate, (AlterExtensionStmt *) parsetree); 1564 break; 1565 1566 case T_AlterExtensionContentsStmt: 1567 address = ExecAlterExtensionContentsStmt((AlterExtensionContentsStmt *) parsetree, 1568 &secondaryObject); 1569 break; 1570 1571 case T_CreateFdwStmt: 1572 address = CreateForeignDataWrapper((CreateFdwStmt *) parsetree); 1573 break; 1574 1575 case T_AlterFdwStmt: 1576 address = AlterForeignDataWrapper((AlterFdwStmt *) parsetree); 1577 break; 1578 1579 case T_CreateForeignServerStmt: 1580 address = CreateForeignServer((CreateForeignServerStmt *) parsetree); 1581 break; 1582 1583 case T_AlterForeignServerStmt: 1584 address = AlterForeignServer((AlterForeignServerStmt *) parsetree); 1585 break; 1586 1587 case T_CreateUserMappingStmt: 1588 address = CreateUserMapping((CreateUserMappingStmt *) parsetree); 1589 break; 1590 1591 case T_AlterUserMappingStmt: 1592 address = AlterUserMapping((AlterUserMappingStmt *) parsetree); 1593 break; 1594 1595 case T_DropUserMappingStmt: 1596 RemoveUserMapping((DropUserMappingStmt *) parsetree); 1597 /* no commands stashed for DROP */ 1598 commandCollected = true; 1599 break; 1600 1601 case T_ImportForeignSchemaStmt: 1602 ImportForeignSchema((ImportForeignSchemaStmt *) parsetree); 1603 /* commands are stashed inside ImportForeignSchema */ 1604 commandCollected = true; 1605 break; 1606 1607 case T_CompositeTypeStmt: /* CREATE TYPE (composite) */ 1608 { 1609 CompositeTypeStmt *stmt = (CompositeTypeStmt *) parsetree; 1610 1611 address = DefineCompositeType(stmt->typevar, 1612 stmt->coldeflist); 1613 } 1614 break; 1615 1616 case T_CreateEnumStmt: /* CREATE TYPE AS ENUM */ 1617 address = DefineEnum((CreateEnumStmt *) parsetree); 1618 break; 1619 1620 case T_CreateRangeStmt: /* CREATE TYPE AS RANGE */ 1621 address = DefineRange((CreateRangeStmt *) parsetree); 1622 break; 1623 1624 case T_AlterEnumStmt: /* ALTER TYPE (enum) */ 1625 address = AlterEnum((AlterEnumStmt *) parsetree); 1626 break; 1627 1628 case T_ViewStmt: /* CREATE VIEW */ 1629 EventTriggerAlterTableStart(parsetree); 1630 address = DefineView((ViewStmt *) parsetree, queryString, 1631 pstmt->stmt_location, pstmt->stmt_len); 1632 EventTriggerCollectSimpleCommand(address, secondaryObject, 1633 parsetree); 1634 /* stashed internally */ 1635 commandCollected = true; 1636 EventTriggerAlterTableEnd(); 1637 break; 1638 1639 case T_CreateFunctionStmt: /* CREATE FUNCTION */ 1640 address = CreateFunction(pstate, (CreateFunctionStmt *) parsetree); 1641 break; 1642 1643 case T_AlterFunctionStmt: /* ALTER FUNCTION */ 1644 address = AlterFunction(pstate, (AlterFunctionStmt *) parsetree); 1645 break; 1646 1647 case T_RuleStmt: /* CREATE RULE */ 1648 address = DefineRule((RuleStmt *) parsetree, queryString); 1649 break; 1650 1651 case T_CreateSeqStmt: 1652 address = DefineSequence(pstate, (CreateSeqStmt *) parsetree); 1653 break; 1654 1655 case T_AlterSeqStmt: 1656 address = AlterSequence(pstate, (AlterSeqStmt *) parsetree); 1657 break; 1658 1659 case T_CreateTableAsStmt: 1660 address = ExecCreateTableAs(pstate, (CreateTableAsStmt *) parsetree, 1661 params, queryEnv, qc); 1662 break; 1663 1664 case T_RefreshMatViewStmt: 1665 1666 /* 1667 * REFRESH CONCURRENTLY executes some DDL commands internally. 1668 * Inhibit DDL command collection here to avoid those commands 1669 * from showing up in the deparsed command queue. The refresh 1670 * command itself is queued, which is enough. 1671 */ 1672 EventTriggerInhibitCommandCollection(); 1673 PG_TRY(); 1674 { 1675 address = ExecRefreshMatView((RefreshMatViewStmt *) parsetree, 1676 queryString, params, qc); 1677 } 1678 PG_FINALLY(); 1679 { 1680 EventTriggerUndoInhibitCommandCollection(); 1681 } 1682 PG_END_TRY(); 1683 break; 1684 1685 case T_CreateTrigStmt: 1686 address = CreateTrigger((CreateTrigStmt *) parsetree, 1687 queryString, InvalidOid, InvalidOid, 1688 InvalidOid, InvalidOid, InvalidOid, 1689 InvalidOid, NULL, false, false); 1690 break; 1691 1692 case T_CreatePLangStmt: 1693 address = CreateProceduralLanguage((CreatePLangStmt *) parsetree); 1694 break; 1695 1696 case T_CreateDomainStmt: 1697 address = DefineDomain((CreateDomainStmt *) parsetree); 1698 break; 1699 1700 case T_CreateConversionStmt: 1701 address = CreateConversionCommand((CreateConversionStmt *) parsetree); 1702 break; 1703 1704 case T_CreateCastStmt: 1705 address = CreateCast((CreateCastStmt *) parsetree); 1706 break; 1707 1708 case T_CreateOpClassStmt: 1709 DefineOpClass((CreateOpClassStmt *) parsetree); 1710 /* command is stashed in DefineOpClass */ 1711 commandCollected = true; 1712 break; 1713 1714 case T_CreateOpFamilyStmt: 1715 address = DefineOpFamily((CreateOpFamilyStmt *) parsetree); 1716 break; 1717 1718 case T_CreateTransformStmt: 1719 address = CreateTransform((CreateTransformStmt *) parsetree); 1720 break; 1721 1722 case T_AlterOpFamilyStmt: 1723 AlterOpFamily((AlterOpFamilyStmt *) parsetree); 1724 /* commands are stashed in AlterOpFamily */ 1725 commandCollected = true; 1726 break; 1727 1728 case T_AlterTSDictionaryStmt: 1729 address = AlterTSDictionary((AlterTSDictionaryStmt *) parsetree); 1730 break; 1731 1732 case T_AlterTSConfigurationStmt: 1733 AlterTSConfiguration((AlterTSConfigurationStmt *) parsetree); 1734 1735 /* 1736 * Commands are stashed in MakeConfigurationMapping and 1737 * DropConfigurationMapping, which are called from 1738 * AlterTSConfiguration 1739 */ 1740 commandCollected = true; 1741 break; 1742 1743 case T_AlterTableMoveAllStmt: 1744 AlterTableMoveAll((AlterTableMoveAllStmt *) parsetree); 1745 /* commands are stashed in AlterTableMoveAll */ 1746 commandCollected = true; 1747 break; 1748 1749 case T_DropStmt: 1750 ExecDropStmt((DropStmt *) parsetree, isTopLevel); 1751 /* no commands stashed for DROP */ 1752 commandCollected = true; 1753 break; 1754 1755 case T_RenameStmt: 1756 address = ExecRenameStmt((RenameStmt *) parsetree); 1757 break; 1758 1759 case T_AlterObjectDependsStmt: 1760 address = 1761 ExecAlterObjectDependsStmt((AlterObjectDependsStmt *) parsetree, 1762 &secondaryObject); 1763 break; 1764 1765 case T_AlterObjectSchemaStmt: 1766 address = 1767 ExecAlterObjectSchemaStmt((AlterObjectSchemaStmt *) parsetree, 1768 &secondaryObject); 1769 break; 1770 1771 case T_AlterOwnerStmt: 1772 address = ExecAlterOwnerStmt((AlterOwnerStmt *) parsetree); 1773 break; 1774 1775 case T_AlterOperatorStmt: 1776 address = AlterOperator((AlterOperatorStmt *) parsetree); 1777 break; 1778 1779 case T_AlterTypeStmt: 1780 address = AlterType((AlterTypeStmt *) parsetree); 1781 break; 1782 1783 case T_CommentStmt: 1784 address = CommentObject((CommentStmt *) parsetree); 1785 break; 1786 1787 case T_GrantStmt: 1788 ExecuteGrantStmt((GrantStmt *) parsetree); 1789 /* commands are stashed in ExecGrantStmt_oids */ 1790 commandCollected = true; 1791 break; 1792 1793 case T_DropOwnedStmt: 1794 DropOwnedObjects((DropOwnedStmt *) parsetree); 1795 /* no commands stashed for DROP */ 1796 commandCollected = true; 1797 break; 1798 1799 case T_AlterDefaultPrivilegesStmt: 1800 ExecAlterDefaultPrivilegesStmt(pstate, (AlterDefaultPrivilegesStmt *) parsetree); 1801 EventTriggerCollectAlterDefPrivs((AlterDefaultPrivilegesStmt *) parsetree); 1802 commandCollected = true; 1803 break; 1804 1805 case T_CreatePolicyStmt: /* CREATE POLICY */ 1806 address = CreatePolicy((CreatePolicyStmt *) parsetree); 1807 break; 1808 1809 case T_AlterPolicyStmt: /* ALTER POLICY */ 1810 address = AlterPolicy((AlterPolicyStmt *) parsetree); 1811 break; 1812 1813 case T_SecLabelStmt: 1814 address = ExecSecLabelStmt((SecLabelStmt *) parsetree); 1815 break; 1816 1817 case T_CreateAmStmt: 1818 address = CreateAccessMethod((CreateAmStmt *) parsetree); 1819 break; 1820 1821 case T_CreatePublicationStmt: 1822 address = CreatePublication((CreatePublicationStmt *) parsetree); 1823 break; 1824 1825 case T_AlterPublicationStmt: 1826 AlterPublication((AlterPublicationStmt *) parsetree); 1827 1828 /* 1829 * AlterPublication calls EventTriggerCollectSimpleCommand 1830 * directly 1831 */ 1832 commandCollected = true; 1833 break; 1834 1835 case T_CreateSubscriptionStmt: 1836 address = CreateSubscription((CreateSubscriptionStmt *) parsetree, 1837 isTopLevel); 1838 break; 1839 1840 case T_AlterSubscriptionStmt: 1841 address = AlterSubscription((AlterSubscriptionStmt *) parsetree); 1842 break; 1843 1844 case T_DropSubscriptionStmt: 1845 DropSubscription((DropSubscriptionStmt *) parsetree, isTopLevel); 1846 /* no commands stashed for DROP */ 1847 commandCollected = true; 1848 break; 1849 1850 case T_CreateStatsStmt: 1851 address = CreateStatistics((CreateStatsStmt *) parsetree); 1852 break; 1853 1854 case T_AlterStatsStmt: 1855 address = AlterStatistics((AlterStatsStmt *) parsetree); 1856 break; 1857 1858 case T_AlterCollationStmt: 1859 address = AlterCollation((AlterCollationStmt *) parsetree); 1860 break; 1861 1862 default: 1863 elog(ERROR, "unrecognized node type: %d", 1864 (int) nodeTag(parsetree)); 1865 break; 1866 } 1867 1868 /* 1869 * Remember the object so that ddl_command_end event triggers have 1870 * access to it. 1871 */ 1872 if (!commandCollected) 1873 EventTriggerCollectSimpleCommand(address, secondaryObject, 1874 parsetree); 1875 1876 if (isCompleteQuery) 1877 { 1878 EventTriggerSQLDrop(parsetree); 1879 EventTriggerDDLCommandEnd(parsetree); 1880 } 1881 } 1882 PG_FINALLY(); 1883 { 1884 if (needCleanup) 1885 EventTriggerEndCompleteQuery(); 1886 } 1887 PG_END_TRY(); 1888 } 1889 1890 /* 1891 * ProcessUtilityForAlterTable 1892 * Recursive entry from ALTER TABLE 1893 * 1894 * ALTER TABLE sometimes generates subcommands such as CREATE INDEX. 1895 * It calls this, not the main entry point ProcessUtility, to execute 1896 * such subcommands. 1897 * 1898 * stmt: the utility command to execute 1899 * context: opaque passthrough struct with the info we need 1900 * 1901 * It's caller's responsibility to do CommandCounterIncrement after 1902 * calling this, if needed. 1903 */ 1904 void 1905 ProcessUtilityForAlterTable(Node *stmt, AlterTableUtilityContext *context) 1906 { 1907 PlannedStmt *wrapper; 1908 1909 /* 1910 * For event triggers, we must "close" the current complex-command set, 1911 * and start a new one afterwards; this is needed to ensure the ordering 1912 * of command events is consistent with the way they were executed. 1913 */ 1914 EventTriggerAlterTableEnd(); 1915 1916 /* Create a suitable wrapper */ 1917 wrapper = makeNode(PlannedStmt); 1918 wrapper->commandType = CMD_UTILITY; 1919 wrapper->canSetTag = false; 1920 wrapper->utilityStmt = stmt; 1921 wrapper->stmt_location = context->pstmt->stmt_location; 1922 wrapper->stmt_len = context->pstmt->stmt_len; 1923 1924 ProcessUtility(wrapper, 1925 context->queryString, 1926 PROCESS_UTILITY_SUBCOMMAND, 1927 context->params, 1928 context->queryEnv, 1929 None_Receiver, 1930 NULL); 1931 1932 EventTriggerAlterTableStart(context->pstmt->utilityStmt); 1933 EventTriggerAlterTableRelid(context->relid); 1934 } 1935 1936 /* 1937 * Dispatch function for DropStmt 1938 */ 1939 static void 1940 ExecDropStmt(DropStmt *stmt, bool isTopLevel) 1941 { 1942 switch (stmt->removeType) 1943 { 1944 case OBJECT_INDEX: 1945 if (stmt->concurrent) 1946 PreventInTransactionBlock(isTopLevel, 1947 "DROP INDEX CONCURRENTLY"); 1948 /* fall through */ 1949 1950 case OBJECT_TABLE: 1951 case OBJECT_SEQUENCE: 1952 case OBJECT_VIEW: 1953 case OBJECT_MATVIEW: 1954 case OBJECT_FOREIGN_TABLE: 1955 RemoveRelations(stmt); 1956 break; 1957 default: 1958 RemoveObjects(stmt); 1959 break; 1960 } 1961 } 1962 1963 1964 /* 1965 * UtilityReturnsTuples 1966 * Return "true" if this utility statement will send output to the 1967 * destination. 1968 * 1969 * Generally, there should be a case here for each case in ProcessUtility 1970 * where "dest" is passed on. 1971 */ 1972 bool 1973 UtilityReturnsTuples(Node *parsetree) 1974 { 1975 switch (nodeTag(parsetree)) 1976 { 1977 case T_CallStmt: 1978 { 1979 CallStmt *stmt = (CallStmt *) parsetree; 1980 1981 return (stmt->funcexpr->funcresulttype == RECORDOID); 1982 } 1983 case T_FetchStmt: 1984 { 1985 FetchStmt *stmt = (FetchStmt *) parsetree; 1986 Portal portal; 1987 1988 if (stmt->ismove) 1989 return false; 1990 portal = GetPortalByName(stmt->portalname); 1991 if (!PortalIsValid(portal)) 1992 return false; /* not our business to raise error */ 1993 return portal->tupDesc ? true : false; 1994 } 1995 1996 case T_ExecuteStmt: 1997 { 1998 ExecuteStmt *stmt = (ExecuteStmt *) parsetree; 1999 PreparedStatement *entry; 2000 2001 entry = FetchPreparedStatement(stmt->name, false); 2002 if (!entry) 2003 return false; /* not our business to raise error */ 2004 if (entry->plansource->resultDesc) 2005 return true; 2006 return false; 2007 } 2008 2009 case T_ExplainStmt: 2010 return true; 2011 2012 case T_VariableShowStmt: 2013 return true; 2014 2015 default: 2016 return false; 2017 } 2018 } 2019 2020 /* 2021 * UtilityTupleDescriptor 2022 * Fetch the actual output tuple descriptor for a utility statement 2023 * for which UtilityReturnsTuples() previously returned "true". 2024 * 2025 * The returned descriptor is created in (or copied into) the current memory 2026 * context. 2027 */ 2028 TupleDesc 2029 UtilityTupleDescriptor(Node *parsetree) 2030 { 2031 switch (nodeTag(parsetree)) 2032 { 2033 case T_CallStmt: 2034 return CallStmtResultDesc((CallStmt *) parsetree); 2035 2036 case T_FetchStmt: 2037 { 2038 FetchStmt *stmt = (FetchStmt *) parsetree; 2039 Portal portal; 2040 2041 if (stmt->ismove) 2042 return NULL; 2043 portal = GetPortalByName(stmt->portalname); 2044 if (!PortalIsValid(portal)) 2045 return NULL; /* not our business to raise error */ 2046 return CreateTupleDescCopy(portal->tupDesc); 2047 } 2048 2049 case T_ExecuteStmt: 2050 { 2051 ExecuteStmt *stmt = (ExecuteStmt *) parsetree; 2052 PreparedStatement *entry; 2053 2054 entry = FetchPreparedStatement(stmt->name, false); 2055 if (!entry) 2056 return NULL; /* not our business to raise error */ 2057 return FetchPreparedStatementResultDesc(entry); 2058 } 2059 2060 case T_ExplainStmt: 2061 return ExplainResultDesc((ExplainStmt *) parsetree); 2062 2063 case T_VariableShowStmt: 2064 { 2065 VariableShowStmt *n = (VariableShowStmt *) parsetree; 2066 2067 return GetPGVariableResultDesc(n->name); 2068 } 2069 2070 default: 2071 return NULL; 2072 } 2073 } 2074 2075 2076 /* 2077 * QueryReturnsTuples 2078 * Return "true" if this Query will send output to the destination. 2079 */ 2080 #ifdef NOT_USED 2081 bool 2082 QueryReturnsTuples(Query *parsetree) 2083 { 2084 switch (parsetree->commandType) 2085 { 2086 case CMD_SELECT: 2087 /* returns tuples */ 2088 return true; 2089 case CMD_INSERT: 2090 case CMD_UPDATE: 2091 case CMD_DELETE: 2092 /* the forms with RETURNING return tuples */ 2093 if (parsetree->returningList) 2094 return true; 2095 break; 2096 case CMD_UTILITY: 2097 return UtilityReturnsTuples(parsetree->utilityStmt); 2098 case CMD_UNKNOWN: 2099 case CMD_NOTHING: 2100 /* probably shouldn't get here */ 2101 break; 2102 } 2103 return false; /* default */ 2104 } 2105 #endif 2106 2107 2108 /* 2109 * UtilityContainsQuery 2110 * Return the contained Query, or NULL if there is none 2111 * 2112 * Certain utility statements, such as EXPLAIN, contain a plannable Query. 2113 * This function encapsulates knowledge of exactly which ones do. 2114 * We assume it is invoked only on already-parse-analyzed statements 2115 * (else the contained parsetree isn't a Query yet). 2116 * 2117 * In some cases (currently, only EXPLAIN of CREATE TABLE AS/SELECT INTO and 2118 * CREATE MATERIALIZED VIEW), potentially Query-containing utility statements 2119 * can be nested. This function will drill down to a non-utility Query, or 2120 * return NULL if none. 2121 */ 2122 Query * 2123 UtilityContainsQuery(Node *parsetree) 2124 { 2125 Query *qry; 2126 2127 switch (nodeTag(parsetree)) 2128 { 2129 case T_DeclareCursorStmt: 2130 qry = castNode(Query, ((DeclareCursorStmt *) parsetree)->query); 2131 if (qry->commandType == CMD_UTILITY) 2132 return UtilityContainsQuery(qry->utilityStmt); 2133 return qry; 2134 2135 case T_ExplainStmt: 2136 qry = castNode(Query, ((ExplainStmt *) parsetree)->query); 2137 if (qry->commandType == CMD_UTILITY) 2138 return UtilityContainsQuery(qry->utilityStmt); 2139 return qry; 2140 2141 case T_CreateTableAsStmt: 2142 qry = castNode(Query, ((CreateTableAsStmt *) parsetree)->query); 2143 if (qry->commandType == CMD_UTILITY) 2144 return UtilityContainsQuery(qry->utilityStmt); 2145 return qry; 2146 2147 default: 2148 return NULL; 2149 } 2150 } 2151 2152 2153 /* 2154 * AlterObjectTypeCommandTag 2155 * helper function for CreateCommandTag 2156 * 2157 * This covers most cases where ALTER is used with an ObjectType enum. 2158 */ 2159 static CommandTag 2160 AlterObjectTypeCommandTag(ObjectType objtype) 2161 { 2162 CommandTag tag; 2163 2164 switch (objtype) 2165 { 2166 case OBJECT_AGGREGATE: 2167 tag = CMDTAG_ALTER_AGGREGATE; 2168 break; 2169 case OBJECT_ATTRIBUTE: 2170 tag = CMDTAG_ALTER_TYPE; 2171 break; 2172 case OBJECT_CAST: 2173 tag = CMDTAG_ALTER_CAST; 2174 break; 2175 case OBJECT_COLLATION: 2176 tag = CMDTAG_ALTER_COLLATION; 2177 break; 2178 case OBJECT_COLUMN: 2179 tag = CMDTAG_ALTER_TABLE; 2180 break; 2181 case OBJECT_CONVERSION: 2182 tag = CMDTAG_ALTER_CONVERSION; 2183 break; 2184 case OBJECT_DATABASE: 2185 tag = CMDTAG_ALTER_DATABASE; 2186 break; 2187 case OBJECT_DOMAIN: 2188 case OBJECT_DOMCONSTRAINT: 2189 tag = CMDTAG_ALTER_DOMAIN; 2190 break; 2191 case OBJECT_EXTENSION: 2192 tag = CMDTAG_ALTER_EXTENSION; 2193 break; 2194 case OBJECT_FDW: 2195 tag = CMDTAG_ALTER_FOREIGN_DATA_WRAPPER; 2196 break; 2197 case OBJECT_FOREIGN_SERVER: 2198 tag = CMDTAG_ALTER_SERVER; 2199 break; 2200 case OBJECT_FOREIGN_TABLE: 2201 tag = CMDTAG_ALTER_FOREIGN_TABLE; 2202 break; 2203 case OBJECT_FUNCTION: 2204 tag = CMDTAG_ALTER_FUNCTION; 2205 break; 2206 case OBJECT_INDEX: 2207 tag = CMDTAG_ALTER_INDEX; 2208 break; 2209 case OBJECT_LANGUAGE: 2210 tag = CMDTAG_ALTER_LANGUAGE; 2211 break; 2212 case OBJECT_LARGEOBJECT: 2213 tag = CMDTAG_ALTER_LARGE_OBJECT; 2214 break; 2215 case OBJECT_OPCLASS: 2216 tag = CMDTAG_ALTER_OPERATOR_CLASS; 2217 break; 2218 case OBJECT_OPERATOR: 2219 tag = CMDTAG_ALTER_OPERATOR; 2220 break; 2221 case OBJECT_OPFAMILY: 2222 tag = CMDTAG_ALTER_OPERATOR_FAMILY; 2223 break; 2224 case OBJECT_POLICY: 2225 tag = CMDTAG_ALTER_POLICY; 2226 break; 2227 case OBJECT_PROCEDURE: 2228 tag = CMDTAG_ALTER_PROCEDURE; 2229 break; 2230 case OBJECT_ROLE: 2231 tag = CMDTAG_ALTER_ROLE; 2232 break; 2233 case OBJECT_ROUTINE: 2234 tag = CMDTAG_ALTER_ROUTINE; 2235 break; 2236 case OBJECT_RULE: 2237 tag = CMDTAG_ALTER_RULE; 2238 break; 2239 case OBJECT_SCHEMA: 2240 tag = CMDTAG_ALTER_SCHEMA; 2241 break; 2242 case OBJECT_SEQUENCE: 2243 tag = CMDTAG_ALTER_SEQUENCE; 2244 break; 2245 case OBJECT_TABLE: 2246 case OBJECT_TABCONSTRAINT: 2247 tag = CMDTAG_ALTER_TABLE; 2248 break; 2249 case OBJECT_TABLESPACE: 2250 tag = CMDTAG_ALTER_TABLESPACE; 2251 break; 2252 case OBJECT_TRIGGER: 2253 tag = CMDTAG_ALTER_TRIGGER; 2254 break; 2255 case OBJECT_EVENT_TRIGGER: 2256 tag = CMDTAG_ALTER_EVENT_TRIGGER; 2257 break; 2258 case OBJECT_TSCONFIGURATION: 2259 tag = CMDTAG_ALTER_TEXT_SEARCH_CONFIGURATION; 2260 break; 2261 case OBJECT_TSDICTIONARY: 2262 tag = CMDTAG_ALTER_TEXT_SEARCH_DICTIONARY; 2263 break; 2264 case OBJECT_TSPARSER: 2265 tag = CMDTAG_ALTER_TEXT_SEARCH_PARSER; 2266 break; 2267 case OBJECT_TSTEMPLATE: 2268 tag = CMDTAG_ALTER_TEXT_SEARCH_TEMPLATE; 2269 break; 2270 case OBJECT_TYPE: 2271 tag = CMDTAG_ALTER_TYPE; 2272 break; 2273 case OBJECT_VIEW: 2274 tag = CMDTAG_ALTER_VIEW; 2275 break; 2276 case OBJECT_MATVIEW: 2277 tag = CMDTAG_ALTER_MATERIALIZED_VIEW; 2278 break; 2279 case OBJECT_PUBLICATION: 2280 tag = CMDTAG_ALTER_PUBLICATION; 2281 break; 2282 case OBJECT_SUBSCRIPTION: 2283 tag = CMDTAG_ALTER_SUBSCRIPTION; 2284 break; 2285 case OBJECT_STATISTIC_EXT: 2286 tag = CMDTAG_ALTER_STATISTICS; 2287 break; 2288 default: 2289 tag = CMDTAG_UNKNOWN; 2290 break; 2291 } 2292 2293 return tag; 2294 } 2295 2296 /* 2297 * CreateCommandTag 2298 * utility to get a CommandTag for the command operation, 2299 * given either a raw (un-analyzed) parsetree, an analyzed Query, 2300 * or a PlannedStmt. 2301 * 2302 * This must handle all command types, but since the vast majority 2303 * of 'em are utility commands, it seems sensible to keep it here. 2304 */ 2305 CommandTag 2306 CreateCommandTag(Node *parsetree) 2307 { 2308 CommandTag tag; 2309 2310 switch (nodeTag(parsetree)) 2311 { 2312 /* recurse if we're given a RawStmt */ 2313 case T_RawStmt: 2314 tag = CreateCommandTag(((RawStmt *) parsetree)->stmt); 2315 break; 2316 2317 /* raw plannable queries */ 2318 case T_InsertStmt: 2319 tag = CMDTAG_INSERT; 2320 break; 2321 2322 case T_DeleteStmt: 2323 tag = CMDTAG_DELETE; 2324 break; 2325 2326 case T_UpdateStmt: 2327 tag = CMDTAG_UPDATE; 2328 break; 2329 2330 case T_SelectStmt: 2331 tag = CMDTAG_SELECT; 2332 break; 2333 2334 /* utility statements --- same whether raw or cooked */ 2335 case T_TransactionStmt: 2336 { 2337 TransactionStmt *stmt = (TransactionStmt *) parsetree; 2338 2339 switch (stmt->kind) 2340 { 2341 case TRANS_STMT_BEGIN: 2342 tag = CMDTAG_BEGIN; 2343 break; 2344 2345 case TRANS_STMT_START: 2346 tag = CMDTAG_START_TRANSACTION; 2347 break; 2348 2349 case TRANS_STMT_COMMIT: 2350 tag = CMDTAG_COMMIT; 2351 break; 2352 2353 case TRANS_STMT_ROLLBACK: 2354 case TRANS_STMT_ROLLBACK_TO: 2355 tag = CMDTAG_ROLLBACK; 2356 break; 2357 2358 case TRANS_STMT_SAVEPOINT: 2359 tag = CMDTAG_SAVEPOINT; 2360 break; 2361 2362 case TRANS_STMT_RELEASE: 2363 tag = CMDTAG_RELEASE; 2364 break; 2365 2366 case TRANS_STMT_PREPARE: 2367 tag = CMDTAG_PREPARE_TRANSACTION; 2368 break; 2369 2370 case TRANS_STMT_COMMIT_PREPARED: 2371 tag = CMDTAG_COMMIT_PREPARED; 2372 break; 2373 2374 case TRANS_STMT_ROLLBACK_PREPARED: 2375 tag = CMDTAG_ROLLBACK_PREPARED; 2376 break; 2377 2378 default: 2379 tag = CMDTAG_UNKNOWN; 2380 break; 2381 } 2382 } 2383 break; 2384 2385 case T_DeclareCursorStmt: 2386 tag = CMDTAG_DECLARE_CURSOR; 2387 break; 2388 2389 case T_ClosePortalStmt: 2390 { 2391 ClosePortalStmt *stmt = (ClosePortalStmt *) parsetree; 2392 2393 if (stmt->portalname == NULL) 2394 tag = CMDTAG_CLOSE_CURSOR_ALL; 2395 else 2396 tag = CMDTAG_CLOSE_CURSOR; 2397 } 2398 break; 2399 2400 case T_FetchStmt: 2401 { 2402 FetchStmt *stmt = (FetchStmt *) parsetree; 2403 2404 tag = (stmt->ismove) ? CMDTAG_MOVE : CMDTAG_FETCH; 2405 } 2406 break; 2407 2408 case T_CreateDomainStmt: 2409 tag = CMDTAG_CREATE_DOMAIN; 2410 break; 2411 2412 case T_CreateSchemaStmt: 2413 tag = CMDTAG_CREATE_SCHEMA; 2414 break; 2415 2416 case T_CreateStmt: 2417 tag = CMDTAG_CREATE_TABLE; 2418 break; 2419 2420 case T_CreateTableSpaceStmt: 2421 tag = CMDTAG_CREATE_TABLESPACE; 2422 break; 2423 2424 case T_DropTableSpaceStmt: 2425 tag = CMDTAG_DROP_TABLESPACE; 2426 break; 2427 2428 case T_AlterTableSpaceOptionsStmt: 2429 tag = CMDTAG_ALTER_TABLESPACE; 2430 break; 2431 2432 case T_CreateExtensionStmt: 2433 tag = CMDTAG_CREATE_EXTENSION; 2434 break; 2435 2436 case T_AlterExtensionStmt: 2437 tag = CMDTAG_ALTER_EXTENSION; 2438 break; 2439 2440 case T_AlterExtensionContentsStmt: 2441 tag = CMDTAG_ALTER_EXTENSION; 2442 break; 2443 2444 case T_CreateFdwStmt: 2445 tag = CMDTAG_CREATE_FOREIGN_DATA_WRAPPER; 2446 break; 2447 2448 case T_AlterFdwStmt: 2449 tag = CMDTAG_ALTER_FOREIGN_DATA_WRAPPER; 2450 break; 2451 2452 case T_CreateForeignServerStmt: 2453 tag = CMDTAG_CREATE_SERVER; 2454 break; 2455 2456 case T_AlterForeignServerStmt: 2457 tag = CMDTAG_ALTER_SERVER; 2458 break; 2459 2460 case T_CreateUserMappingStmt: 2461 tag = CMDTAG_CREATE_USER_MAPPING; 2462 break; 2463 2464 case T_AlterUserMappingStmt: 2465 tag = CMDTAG_ALTER_USER_MAPPING; 2466 break; 2467 2468 case T_DropUserMappingStmt: 2469 tag = CMDTAG_DROP_USER_MAPPING; 2470 break; 2471 2472 case T_CreateForeignTableStmt: 2473 tag = CMDTAG_CREATE_FOREIGN_TABLE; 2474 break; 2475 2476 case T_ImportForeignSchemaStmt: 2477 tag = CMDTAG_IMPORT_FOREIGN_SCHEMA; 2478 break; 2479 2480 case T_DropStmt: 2481 switch (((DropStmt *) parsetree)->removeType) 2482 { 2483 case OBJECT_TABLE: 2484 tag = CMDTAG_DROP_TABLE; 2485 break; 2486 case OBJECT_SEQUENCE: 2487 tag = CMDTAG_DROP_SEQUENCE; 2488 break; 2489 case OBJECT_VIEW: 2490 tag = CMDTAG_DROP_VIEW; 2491 break; 2492 case OBJECT_MATVIEW: 2493 tag = CMDTAG_DROP_MATERIALIZED_VIEW; 2494 break; 2495 case OBJECT_INDEX: 2496 tag = CMDTAG_DROP_INDEX; 2497 break; 2498 case OBJECT_TYPE: 2499 tag = CMDTAG_DROP_TYPE; 2500 break; 2501 case OBJECT_DOMAIN: 2502 tag = CMDTAG_DROP_DOMAIN; 2503 break; 2504 case OBJECT_COLLATION: 2505 tag = CMDTAG_DROP_COLLATION; 2506 break; 2507 case OBJECT_CONVERSION: 2508 tag = CMDTAG_DROP_CONVERSION; 2509 break; 2510 case OBJECT_SCHEMA: 2511 tag = CMDTAG_DROP_SCHEMA; 2512 break; 2513 case OBJECT_TSPARSER: 2514 tag = CMDTAG_DROP_TEXT_SEARCH_PARSER; 2515 break; 2516 case OBJECT_TSDICTIONARY: 2517 tag = CMDTAG_DROP_TEXT_SEARCH_DICTIONARY; 2518 break; 2519 case OBJECT_TSTEMPLATE: 2520 tag = CMDTAG_DROP_TEXT_SEARCH_TEMPLATE; 2521 break; 2522 case OBJECT_TSCONFIGURATION: 2523 tag = CMDTAG_DROP_TEXT_SEARCH_CONFIGURATION; 2524 break; 2525 case OBJECT_FOREIGN_TABLE: 2526 tag = CMDTAG_DROP_FOREIGN_TABLE; 2527 break; 2528 case OBJECT_EXTENSION: 2529 tag = CMDTAG_DROP_EXTENSION; 2530 break; 2531 case OBJECT_FUNCTION: 2532 tag = CMDTAG_DROP_FUNCTION; 2533 break; 2534 case OBJECT_PROCEDURE: 2535 tag = CMDTAG_DROP_PROCEDURE; 2536 break; 2537 case OBJECT_ROUTINE: 2538 tag = CMDTAG_DROP_ROUTINE; 2539 break; 2540 case OBJECT_AGGREGATE: 2541 tag = CMDTAG_DROP_AGGREGATE; 2542 break; 2543 case OBJECT_OPERATOR: 2544 tag = CMDTAG_DROP_OPERATOR; 2545 break; 2546 case OBJECT_LANGUAGE: 2547 tag = CMDTAG_DROP_LANGUAGE; 2548 break; 2549 case OBJECT_CAST: 2550 tag = CMDTAG_DROP_CAST; 2551 break; 2552 case OBJECT_TRIGGER: 2553 tag = CMDTAG_DROP_TRIGGER; 2554 break; 2555 case OBJECT_EVENT_TRIGGER: 2556 tag = CMDTAG_DROP_EVENT_TRIGGER; 2557 break; 2558 case OBJECT_RULE: 2559 tag = CMDTAG_DROP_RULE; 2560 break; 2561 case OBJECT_FDW: 2562 tag = CMDTAG_DROP_FOREIGN_DATA_WRAPPER; 2563 break; 2564 case OBJECT_FOREIGN_SERVER: 2565 tag = CMDTAG_DROP_SERVER; 2566 break; 2567 case OBJECT_OPCLASS: 2568 tag = CMDTAG_DROP_OPERATOR_CLASS; 2569 break; 2570 case OBJECT_OPFAMILY: 2571 tag = CMDTAG_DROP_OPERATOR_FAMILY; 2572 break; 2573 case OBJECT_POLICY: 2574 tag = CMDTAG_DROP_POLICY; 2575 break; 2576 case OBJECT_TRANSFORM: 2577 tag = CMDTAG_DROP_TRANSFORM; 2578 break; 2579 case OBJECT_ACCESS_METHOD: 2580 tag = CMDTAG_DROP_ACCESS_METHOD; 2581 break; 2582 case OBJECT_PUBLICATION: 2583 tag = CMDTAG_DROP_PUBLICATION; 2584 break; 2585 case OBJECT_STATISTIC_EXT: 2586 tag = CMDTAG_DROP_STATISTICS; 2587 break; 2588 default: 2589 tag = CMDTAG_UNKNOWN; 2590 } 2591 break; 2592 2593 case T_TruncateStmt: 2594 tag = CMDTAG_TRUNCATE_TABLE; 2595 break; 2596 2597 case T_CommentStmt: 2598 tag = CMDTAG_COMMENT; 2599 break; 2600 2601 case T_SecLabelStmt: 2602 tag = CMDTAG_SECURITY_LABEL; 2603 break; 2604 2605 case T_CopyStmt: 2606 tag = CMDTAG_COPY; 2607 break; 2608 2609 case T_RenameStmt: 2610 2611 /* 2612 * When the column is renamed, the command tag is created from its 2613 * relation type 2614 */ 2615 tag = AlterObjectTypeCommandTag(((RenameStmt *) parsetree)->renameType == OBJECT_COLUMN ? 2616 ((RenameStmt *) parsetree)->relationType : 2617 ((RenameStmt *) parsetree)->renameType); 2618 break; 2619 2620 case T_AlterObjectDependsStmt: 2621 tag = AlterObjectTypeCommandTag(((AlterObjectDependsStmt *) parsetree)->objectType); 2622 break; 2623 2624 case T_AlterObjectSchemaStmt: 2625 tag = AlterObjectTypeCommandTag(((AlterObjectSchemaStmt *) parsetree)->objectType); 2626 break; 2627 2628 case T_AlterOwnerStmt: 2629 tag = AlterObjectTypeCommandTag(((AlterOwnerStmt *) parsetree)->objectType); 2630 break; 2631 2632 case T_AlterTableMoveAllStmt: 2633 tag = AlterObjectTypeCommandTag(((AlterTableMoveAllStmt *) parsetree)->objtype); 2634 break; 2635 2636 case T_AlterTableStmt: 2637 tag = AlterObjectTypeCommandTag(((AlterTableStmt *) parsetree)->relkind); 2638 break; 2639 2640 case T_AlterDomainStmt: 2641 tag = CMDTAG_ALTER_DOMAIN; 2642 break; 2643 2644 case T_AlterFunctionStmt: 2645 switch (((AlterFunctionStmt *) parsetree)->objtype) 2646 { 2647 case OBJECT_FUNCTION: 2648 tag = CMDTAG_ALTER_FUNCTION; 2649 break; 2650 case OBJECT_PROCEDURE: 2651 tag = CMDTAG_ALTER_PROCEDURE; 2652 break; 2653 case OBJECT_ROUTINE: 2654 tag = CMDTAG_ALTER_ROUTINE; 2655 break; 2656 default: 2657 tag = CMDTAG_UNKNOWN; 2658 } 2659 break; 2660 2661 case T_GrantStmt: 2662 { 2663 GrantStmt *stmt = (GrantStmt *) parsetree; 2664 2665 tag = (stmt->is_grant) ? CMDTAG_GRANT : CMDTAG_REVOKE; 2666 } 2667 break; 2668 2669 case T_GrantRoleStmt: 2670 { 2671 GrantRoleStmt *stmt = (GrantRoleStmt *) parsetree; 2672 2673 tag = (stmt->is_grant) ? CMDTAG_GRANT_ROLE : CMDTAG_REVOKE_ROLE; 2674 } 2675 break; 2676 2677 case T_AlterDefaultPrivilegesStmt: 2678 tag = CMDTAG_ALTER_DEFAULT_PRIVILEGES; 2679 break; 2680 2681 case T_DefineStmt: 2682 switch (((DefineStmt *) parsetree)->kind) 2683 { 2684 case OBJECT_AGGREGATE: 2685 tag = CMDTAG_CREATE_AGGREGATE; 2686 break; 2687 case OBJECT_OPERATOR: 2688 tag = CMDTAG_CREATE_OPERATOR; 2689 break; 2690 case OBJECT_TYPE: 2691 tag = CMDTAG_CREATE_TYPE; 2692 break; 2693 case OBJECT_TSPARSER: 2694 tag = CMDTAG_CREATE_TEXT_SEARCH_PARSER; 2695 break; 2696 case OBJECT_TSDICTIONARY: 2697 tag = CMDTAG_CREATE_TEXT_SEARCH_DICTIONARY; 2698 break; 2699 case OBJECT_TSTEMPLATE: 2700 tag = CMDTAG_CREATE_TEXT_SEARCH_TEMPLATE; 2701 break; 2702 case OBJECT_TSCONFIGURATION: 2703 tag = CMDTAG_CREATE_TEXT_SEARCH_CONFIGURATION; 2704 break; 2705 case OBJECT_COLLATION: 2706 tag = CMDTAG_CREATE_COLLATION; 2707 break; 2708 case OBJECT_ACCESS_METHOD: 2709 tag = CMDTAG_CREATE_ACCESS_METHOD; 2710 break; 2711 default: 2712 tag = CMDTAG_UNKNOWN; 2713 } 2714 break; 2715 2716 case T_CompositeTypeStmt: 2717 tag = CMDTAG_CREATE_TYPE; 2718 break; 2719 2720 case T_CreateEnumStmt: 2721 tag = CMDTAG_CREATE_TYPE; 2722 break; 2723 2724 case T_CreateRangeStmt: 2725 tag = CMDTAG_CREATE_TYPE; 2726 break; 2727 2728 case T_AlterEnumStmt: 2729 tag = CMDTAG_ALTER_TYPE; 2730 break; 2731 2732 case T_ViewStmt: 2733 tag = CMDTAG_CREATE_VIEW; 2734 break; 2735 2736 case T_CreateFunctionStmt: 2737 if (((CreateFunctionStmt *) parsetree)->is_procedure) 2738 tag = CMDTAG_CREATE_PROCEDURE; 2739 else 2740 tag = CMDTAG_CREATE_FUNCTION; 2741 break; 2742 2743 case T_IndexStmt: 2744 tag = CMDTAG_CREATE_INDEX; 2745 break; 2746 2747 case T_RuleStmt: 2748 tag = CMDTAG_CREATE_RULE; 2749 break; 2750 2751 case T_CreateSeqStmt: 2752 tag = CMDTAG_CREATE_SEQUENCE; 2753 break; 2754 2755 case T_AlterSeqStmt: 2756 tag = CMDTAG_ALTER_SEQUENCE; 2757 break; 2758 2759 case T_DoStmt: 2760 tag = CMDTAG_DO; 2761 break; 2762 2763 case T_CreatedbStmt: 2764 tag = CMDTAG_CREATE_DATABASE; 2765 break; 2766 2767 case T_AlterDatabaseStmt: 2768 tag = CMDTAG_ALTER_DATABASE; 2769 break; 2770 2771 case T_AlterDatabaseSetStmt: 2772 tag = CMDTAG_ALTER_DATABASE; 2773 break; 2774 2775 case T_DropdbStmt: 2776 tag = CMDTAG_DROP_DATABASE; 2777 break; 2778 2779 case T_NotifyStmt: 2780 tag = CMDTAG_NOTIFY; 2781 break; 2782 2783 case T_ListenStmt: 2784 tag = CMDTAG_LISTEN; 2785 break; 2786 2787 case T_UnlistenStmt: 2788 tag = CMDTAG_UNLISTEN; 2789 break; 2790 2791 case T_LoadStmt: 2792 tag = CMDTAG_LOAD; 2793 break; 2794 2795 case T_CallStmt: 2796 tag = CMDTAG_CALL; 2797 break; 2798 2799 case T_ClusterStmt: 2800 tag = CMDTAG_CLUSTER; 2801 break; 2802 2803 case T_VacuumStmt: 2804 if (((VacuumStmt *) parsetree)->is_vacuumcmd) 2805 tag = CMDTAG_VACUUM; 2806 else 2807 tag = CMDTAG_ANALYZE; 2808 break; 2809 2810 case T_ExplainStmt: 2811 tag = CMDTAG_EXPLAIN; 2812 break; 2813 2814 case T_CreateTableAsStmt: 2815 switch (((CreateTableAsStmt *) parsetree)->relkind) 2816 { 2817 case OBJECT_TABLE: 2818 if (((CreateTableAsStmt *) parsetree)->is_select_into) 2819 tag = CMDTAG_SELECT_INTO; 2820 else 2821 tag = CMDTAG_CREATE_TABLE_AS; 2822 break; 2823 case OBJECT_MATVIEW: 2824 tag = CMDTAG_CREATE_MATERIALIZED_VIEW; 2825 break; 2826 default: 2827 tag = CMDTAG_UNKNOWN; 2828 } 2829 break; 2830 2831 case T_RefreshMatViewStmt: 2832 tag = CMDTAG_REFRESH_MATERIALIZED_VIEW; 2833 break; 2834 2835 case T_AlterSystemStmt: 2836 tag = CMDTAG_ALTER_SYSTEM; 2837 break; 2838 2839 case T_VariableSetStmt: 2840 switch (((VariableSetStmt *) parsetree)->kind) 2841 { 2842 case VAR_SET_VALUE: 2843 case VAR_SET_CURRENT: 2844 case VAR_SET_DEFAULT: 2845 case VAR_SET_MULTI: 2846 tag = CMDTAG_SET; 2847 break; 2848 case VAR_RESET: 2849 case VAR_RESET_ALL: 2850 tag = CMDTAG_RESET; 2851 break; 2852 default: 2853 tag = CMDTAG_UNKNOWN; 2854 } 2855 break; 2856 2857 case T_VariableShowStmt: 2858 tag = CMDTAG_SHOW; 2859 break; 2860 2861 case T_DiscardStmt: 2862 switch (((DiscardStmt *) parsetree)->target) 2863 { 2864 case DISCARD_ALL: 2865 tag = CMDTAG_DISCARD_ALL; 2866 break; 2867 case DISCARD_PLANS: 2868 tag = CMDTAG_DISCARD_PLANS; 2869 break; 2870 case DISCARD_TEMP: 2871 tag = CMDTAG_DISCARD_TEMP; 2872 break; 2873 case DISCARD_SEQUENCES: 2874 tag = CMDTAG_DISCARD_SEQUENCES; 2875 break; 2876 default: 2877 tag = CMDTAG_UNKNOWN; 2878 } 2879 break; 2880 2881 case T_CreateTransformStmt: 2882 tag = CMDTAG_CREATE_TRANSFORM; 2883 break; 2884 2885 case T_CreateTrigStmt: 2886 tag = CMDTAG_CREATE_TRIGGER; 2887 break; 2888 2889 case T_CreateEventTrigStmt: 2890 tag = CMDTAG_CREATE_EVENT_TRIGGER; 2891 break; 2892 2893 case T_AlterEventTrigStmt: 2894 tag = CMDTAG_ALTER_EVENT_TRIGGER; 2895 break; 2896 2897 case T_CreatePLangStmt: 2898 tag = CMDTAG_CREATE_LANGUAGE; 2899 break; 2900 2901 case T_CreateRoleStmt: 2902 tag = CMDTAG_CREATE_ROLE; 2903 break; 2904 2905 case T_AlterRoleStmt: 2906 tag = CMDTAG_ALTER_ROLE; 2907 break; 2908 2909 case T_AlterRoleSetStmt: 2910 tag = CMDTAG_ALTER_ROLE; 2911 break; 2912 2913 case T_DropRoleStmt: 2914 tag = CMDTAG_DROP_ROLE; 2915 break; 2916 2917 case T_DropOwnedStmt: 2918 tag = CMDTAG_DROP_OWNED; 2919 break; 2920 2921 case T_ReassignOwnedStmt: 2922 tag = CMDTAG_REASSIGN_OWNED; 2923 break; 2924 2925 case T_LockStmt: 2926 tag = CMDTAG_LOCK_TABLE; 2927 break; 2928 2929 case T_ConstraintsSetStmt: 2930 tag = CMDTAG_SET_CONSTRAINTS; 2931 break; 2932 2933 case T_CheckPointStmt: 2934 tag = CMDTAG_CHECKPOINT; 2935 break; 2936 2937 case T_ReindexStmt: 2938 tag = CMDTAG_REINDEX; 2939 break; 2940 2941 case T_CreateConversionStmt: 2942 tag = CMDTAG_CREATE_CONVERSION; 2943 break; 2944 2945 case T_CreateCastStmt: 2946 tag = CMDTAG_CREATE_CAST; 2947 break; 2948 2949 case T_CreateOpClassStmt: 2950 tag = CMDTAG_CREATE_OPERATOR_CLASS; 2951 break; 2952 2953 case T_CreateOpFamilyStmt: 2954 tag = CMDTAG_CREATE_OPERATOR_FAMILY; 2955 break; 2956 2957 case T_AlterOpFamilyStmt: 2958 tag = CMDTAG_ALTER_OPERATOR_FAMILY; 2959 break; 2960 2961 case T_AlterOperatorStmt: 2962 tag = CMDTAG_ALTER_OPERATOR; 2963 break; 2964 2965 case T_AlterTypeStmt: 2966 tag = CMDTAG_ALTER_TYPE; 2967 break; 2968 2969 case T_AlterTSDictionaryStmt: 2970 tag = CMDTAG_ALTER_TEXT_SEARCH_DICTIONARY; 2971 break; 2972 2973 case T_AlterTSConfigurationStmt: 2974 tag = CMDTAG_ALTER_TEXT_SEARCH_CONFIGURATION; 2975 break; 2976 2977 case T_CreatePolicyStmt: 2978 tag = CMDTAG_CREATE_POLICY; 2979 break; 2980 2981 case T_AlterPolicyStmt: 2982 tag = CMDTAG_ALTER_POLICY; 2983 break; 2984 2985 case T_CreateAmStmt: 2986 tag = CMDTAG_CREATE_ACCESS_METHOD; 2987 break; 2988 2989 case T_CreatePublicationStmt: 2990 tag = CMDTAG_CREATE_PUBLICATION; 2991 break; 2992 2993 case T_AlterPublicationStmt: 2994 tag = CMDTAG_ALTER_PUBLICATION; 2995 break; 2996 2997 case T_CreateSubscriptionStmt: 2998 tag = CMDTAG_CREATE_SUBSCRIPTION; 2999 break; 3000 3001 case T_AlterSubscriptionStmt: 3002 tag = CMDTAG_ALTER_SUBSCRIPTION; 3003 break; 3004 3005 case T_DropSubscriptionStmt: 3006 tag = CMDTAG_DROP_SUBSCRIPTION; 3007 break; 3008 3009 case T_AlterCollationStmt: 3010 tag = CMDTAG_ALTER_COLLATION; 3011 break; 3012 3013 case T_PrepareStmt: 3014 tag = CMDTAG_PREPARE; 3015 break; 3016 3017 case T_ExecuteStmt: 3018 tag = CMDTAG_EXECUTE; 3019 break; 3020 3021 case T_CreateStatsStmt: 3022 tag = CMDTAG_CREATE_STATISTICS; 3023 break; 3024 3025 case T_AlterStatsStmt: 3026 tag = CMDTAG_ALTER_STATISTICS; 3027 break; 3028 3029 case T_DeallocateStmt: 3030 { 3031 DeallocateStmt *stmt = (DeallocateStmt *) parsetree; 3032 3033 if (stmt->name == NULL) 3034 tag = CMDTAG_DEALLOCATE_ALL; 3035 else 3036 tag = CMDTAG_DEALLOCATE; 3037 } 3038 break; 3039 3040 /* already-planned queries */ 3041 case T_PlannedStmt: 3042 { 3043 PlannedStmt *stmt = (PlannedStmt *) parsetree; 3044 3045 switch (stmt->commandType) 3046 { 3047 case CMD_SELECT: 3048 3049 /* 3050 * We take a little extra care here so that the result 3051 * will be useful for complaints about read-only 3052 * statements 3053 */ 3054 if (stmt->rowMarks != NIL) 3055 { 3056 /* not 100% but probably close enough */ 3057 switch (((PlanRowMark *) linitial(stmt->rowMarks))->strength) 3058 { 3059 case LCS_FORKEYSHARE: 3060 tag = CMDTAG_SELECT_FOR_KEY_SHARE; 3061 break; 3062 case LCS_FORSHARE: 3063 tag = CMDTAG_SELECT_FOR_SHARE; 3064 break; 3065 case LCS_FORNOKEYUPDATE: 3066 tag = CMDTAG_SELECT_FOR_NO_KEY_UPDATE; 3067 break; 3068 case LCS_FORUPDATE: 3069 tag = CMDTAG_SELECT_FOR_UPDATE; 3070 break; 3071 default: 3072 tag = CMDTAG_SELECT; 3073 break; 3074 } 3075 } 3076 else 3077 tag = CMDTAG_SELECT; 3078 break; 3079 case CMD_UPDATE: 3080 tag = CMDTAG_UPDATE; 3081 break; 3082 case CMD_INSERT: 3083 tag = CMDTAG_INSERT; 3084 break; 3085 case CMD_DELETE: 3086 tag = CMDTAG_DELETE; 3087 break; 3088 case CMD_UTILITY: 3089 tag = CreateCommandTag(stmt->utilityStmt); 3090 break; 3091 default: 3092 elog(WARNING, "unrecognized commandType: %d", 3093 (int) stmt->commandType); 3094 tag = CMDTAG_UNKNOWN; 3095 break; 3096 } 3097 } 3098 break; 3099 3100 /* parsed-and-rewritten-but-not-planned queries */ 3101 case T_Query: 3102 { 3103 Query *stmt = (Query *) parsetree; 3104 3105 switch (stmt->commandType) 3106 { 3107 case CMD_SELECT: 3108 3109 /* 3110 * We take a little extra care here so that the result 3111 * will be useful for complaints about read-only 3112 * statements 3113 */ 3114 if (stmt->rowMarks != NIL) 3115 { 3116 /* not 100% but probably close enough */ 3117 switch (((RowMarkClause *) linitial(stmt->rowMarks))->strength) 3118 { 3119 case LCS_FORKEYSHARE: 3120 tag = CMDTAG_SELECT_FOR_KEY_SHARE; 3121 break; 3122 case LCS_FORSHARE: 3123 tag = CMDTAG_SELECT_FOR_SHARE; 3124 break; 3125 case LCS_FORNOKEYUPDATE: 3126 tag = CMDTAG_SELECT_FOR_NO_KEY_UPDATE; 3127 break; 3128 case LCS_FORUPDATE: 3129 tag = CMDTAG_SELECT_FOR_UPDATE; 3130 break; 3131 default: 3132 tag = CMDTAG_UNKNOWN; 3133 break; 3134 } 3135 } 3136 else 3137 tag = CMDTAG_SELECT; 3138 break; 3139 case CMD_UPDATE: 3140 tag = CMDTAG_UPDATE; 3141 break; 3142 case CMD_INSERT: 3143 tag = CMDTAG_INSERT; 3144 break; 3145 case CMD_DELETE: 3146 tag = CMDTAG_DELETE; 3147 break; 3148 case CMD_UTILITY: 3149 tag = CreateCommandTag(stmt->utilityStmt); 3150 break; 3151 default: 3152 elog(WARNING, "unrecognized commandType: %d", 3153 (int) stmt->commandType); 3154 tag = CMDTAG_UNKNOWN; 3155 break; 3156 } 3157 } 3158 break; 3159 3160 default: 3161 elog(WARNING, "unrecognized node type: %d", 3162 (int) nodeTag(parsetree)); 3163 tag = CMDTAG_UNKNOWN; 3164 break; 3165 } 3166 3167 return tag; 3168 } 3169 3170 3171 /* 3172 * GetCommandLogLevel 3173 * utility to get the minimum log_statement level for a command, 3174 * given either a raw (un-analyzed) parsetree, an analyzed Query, 3175 * or a PlannedStmt. 3176 * 3177 * This must handle all command types, but since the vast majority 3178 * of 'em are utility commands, it seems sensible to keep it here. 3179 */ 3180 LogStmtLevel 3181 GetCommandLogLevel(Node *parsetree) 3182 { 3183 LogStmtLevel lev; 3184 3185 switch (nodeTag(parsetree)) 3186 { 3187 /* recurse if we're given a RawStmt */ 3188 case T_RawStmt: 3189 lev = GetCommandLogLevel(((RawStmt *) parsetree)->stmt); 3190 break; 3191 3192 /* raw plannable queries */ 3193 case T_InsertStmt: 3194 case T_DeleteStmt: 3195 case T_UpdateStmt: 3196 lev = LOGSTMT_MOD; 3197 break; 3198 3199 case T_SelectStmt: 3200 if (((SelectStmt *) parsetree)->intoClause) 3201 lev = LOGSTMT_DDL; /* SELECT INTO */ 3202 else 3203 lev = LOGSTMT_ALL; 3204 break; 3205 3206 /* utility statements --- same whether raw or cooked */ 3207 case T_TransactionStmt: 3208 lev = LOGSTMT_ALL; 3209 break; 3210 3211 case T_DeclareCursorStmt: 3212 lev = LOGSTMT_ALL; 3213 break; 3214 3215 case T_ClosePortalStmt: 3216 lev = LOGSTMT_ALL; 3217 break; 3218 3219 case T_FetchStmt: 3220 lev = LOGSTMT_ALL; 3221 break; 3222 3223 case T_CreateSchemaStmt: 3224 lev = LOGSTMT_DDL; 3225 break; 3226 3227 case T_CreateStmt: 3228 case T_CreateForeignTableStmt: 3229 lev = LOGSTMT_DDL; 3230 break; 3231 3232 case T_CreateTableSpaceStmt: 3233 case T_DropTableSpaceStmt: 3234 case T_AlterTableSpaceOptionsStmt: 3235 lev = LOGSTMT_DDL; 3236 break; 3237 3238 case T_CreateExtensionStmt: 3239 case T_AlterExtensionStmt: 3240 case T_AlterExtensionContentsStmt: 3241 lev = LOGSTMT_DDL; 3242 break; 3243 3244 case T_CreateFdwStmt: 3245 case T_AlterFdwStmt: 3246 case T_CreateForeignServerStmt: 3247 case T_AlterForeignServerStmt: 3248 case T_CreateUserMappingStmt: 3249 case T_AlterUserMappingStmt: 3250 case T_DropUserMappingStmt: 3251 case T_ImportForeignSchemaStmt: 3252 lev = LOGSTMT_DDL; 3253 break; 3254 3255 case T_DropStmt: 3256 lev = LOGSTMT_DDL; 3257 break; 3258 3259 case T_TruncateStmt: 3260 lev = LOGSTMT_MOD; 3261 break; 3262 3263 case T_CommentStmt: 3264 lev = LOGSTMT_DDL; 3265 break; 3266 3267 case T_SecLabelStmt: 3268 lev = LOGSTMT_DDL; 3269 break; 3270 3271 case T_CopyStmt: 3272 if (((CopyStmt *) parsetree)->is_from) 3273 lev = LOGSTMT_MOD; 3274 else 3275 lev = LOGSTMT_ALL; 3276 break; 3277 3278 case T_PrepareStmt: 3279 { 3280 PrepareStmt *stmt = (PrepareStmt *) parsetree; 3281 3282 /* Look through a PREPARE to the contained stmt */ 3283 lev = GetCommandLogLevel(stmt->query); 3284 } 3285 break; 3286 3287 case T_ExecuteStmt: 3288 { 3289 ExecuteStmt *stmt = (ExecuteStmt *) parsetree; 3290 PreparedStatement *ps; 3291 3292 /* Look through an EXECUTE to the referenced stmt */ 3293 ps = FetchPreparedStatement(stmt->name, false); 3294 if (ps && ps->plansource->raw_parse_tree) 3295 lev = GetCommandLogLevel(ps->plansource->raw_parse_tree->stmt); 3296 else 3297 lev = LOGSTMT_ALL; 3298 } 3299 break; 3300 3301 case T_DeallocateStmt: 3302 lev = LOGSTMT_ALL; 3303 break; 3304 3305 case T_RenameStmt: 3306 lev = LOGSTMT_DDL; 3307 break; 3308 3309 case T_AlterObjectDependsStmt: 3310 lev = LOGSTMT_DDL; 3311 break; 3312 3313 case T_AlterObjectSchemaStmt: 3314 lev = LOGSTMT_DDL; 3315 break; 3316 3317 case T_AlterOwnerStmt: 3318 lev = LOGSTMT_DDL; 3319 break; 3320 3321 case T_AlterOperatorStmt: 3322 lev = LOGSTMT_DDL; 3323 break; 3324 3325 case T_AlterTypeStmt: 3326 lev = LOGSTMT_DDL; 3327 break; 3328 3329 case T_AlterTableMoveAllStmt: 3330 case T_AlterTableStmt: 3331 lev = LOGSTMT_DDL; 3332 break; 3333 3334 case T_AlterDomainStmt: 3335 lev = LOGSTMT_DDL; 3336 break; 3337 3338 case T_GrantStmt: 3339 lev = LOGSTMT_DDL; 3340 break; 3341 3342 case T_GrantRoleStmt: 3343 lev = LOGSTMT_DDL; 3344 break; 3345 3346 case T_AlterDefaultPrivilegesStmt: 3347 lev = LOGSTMT_DDL; 3348 break; 3349 3350 case T_DefineStmt: 3351 lev = LOGSTMT_DDL; 3352 break; 3353 3354 case T_CompositeTypeStmt: 3355 lev = LOGSTMT_DDL; 3356 break; 3357 3358 case T_CreateEnumStmt: 3359 lev = LOGSTMT_DDL; 3360 break; 3361 3362 case T_CreateRangeStmt: 3363 lev = LOGSTMT_DDL; 3364 break; 3365 3366 case T_AlterEnumStmt: 3367 lev = LOGSTMT_DDL; 3368 break; 3369 3370 case T_ViewStmt: 3371 lev = LOGSTMT_DDL; 3372 break; 3373 3374 case T_CreateFunctionStmt: 3375 lev = LOGSTMT_DDL; 3376 break; 3377 3378 case T_AlterFunctionStmt: 3379 lev = LOGSTMT_DDL; 3380 break; 3381 3382 case T_IndexStmt: 3383 lev = LOGSTMT_DDL; 3384 break; 3385 3386 case T_RuleStmt: 3387 lev = LOGSTMT_DDL; 3388 break; 3389 3390 case T_CreateSeqStmt: 3391 lev = LOGSTMT_DDL; 3392 break; 3393 3394 case T_AlterSeqStmt: 3395 lev = LOGSTMT_DDL; 3396 break; 3397 3398 case T_DoStmt: 3399 lev = LOGSTMT_ALL; 3400 break; 3401 3402 case T_CreatedbStmt: 3403 lev = LOGSTMT_DDL; 3404 break; 3405 3406 case T_AlterDatabaseStmt: 3407 lev = LOGSTMT_DDL; 3408 break; 3409 3410 case T_AlterDatabaseSetStmt: 3411 lev = LOGSTMT_DDL; 3412 break; 3413 3414 case T_DropdbStmt: 3415 lev = LOGSTMT_DDL; 3416 break; 3417 3418 case T_NotifyStmt: 3419 lev = LOGSTMT_ALL; 3420 break; 3421 3422 case T_ListenStmt: 3423 lev = LOGSTMT_ALL; 3424 break; 3425 3426 case T_UnlistenStmt: 3427 lev = LOGSTMT_ALL; 3428 break; 3429 3430 case T_LoadStmt: 3431 lev = LOGSTMT_ALL; 3432 break; 3433 3434 case T_CallStmt: 3435 lev = LOGSTMT_ALL; 3436 break; 3437 3438 case T_ClusterStmt: 3439 lev = LOGSTMT_DDL; 3440 break; 3441 3442 case T_VacuumStmt: 3443 lev = LOGSTMT_ALL; 3444 break; 3445 3446 case T_ExplainStmt: 3447 { 3448 ExplainStmt *stmt = (ExplainStmt *) parsetree; 3449 bool analyze = false; 3450 ListCell *lc; 3451 3452 /* Look through an EXPLAIN ANALYZE to the contained stmt */ 3453 foreach(lc, stmt->options) 3454 { 3455 DefElem *opt = (DefElem *) lfirst(lc); 3456 3457 if (strcmp(opt->defname, "analyze") == 0) 3458 analyze = defGetBoolean(opt); 3459 /* don't "break", as explain.c will use the last value */ 3460 } 3461 if (analyze) 3462 return GetCommandLogLevel(stmt->query); 3463 3464 /* Plain EXPLAIN isn't so interesting */ 3465 lev = LOGSTMT_ALL; 3466 } 3467 break; 3468 3469 case T_CreateTableAsStmt: 3470 lev = LOGSTMT_DDL; 3471 break; 3472 3473 case T_RefreshMatViewStmt: 3474 lev = LOGSTMT_DDL; 3475 break; 3476 3477 case T_AlterSystemStmt: 3478 lev = LOGSTMT_DDL; 3479 break; 3480 3481 case T_VariableSetStmt: 3482 lev = LOGSTMT_ALL; 3483 break; 3484 3485 case T_VariableShowStmt: 3486 lev = LOGSTMT_ALL; 3487 break; 3488 3489 case T_DiscardStmt: 3490 lev = LOGSTMT_ALL; 3491 break; 3492 3493 case T_CreateTrigStmt: 3494 lev = LOGSTMT_DDL; 3495 break; 3496 3497 case T_CreateEventTrigStmt: 3498 lev = LOGSTMT_DDL; 3499 break; 3500 3501 case T_AlterEventTrigStmt: 3502 lev = LOGSTMT_DDL; 3503 break; 3504 3505 case T_CreatePLangStmt: 3506 lev = LOGSTMT_DDL; 3507 break; 3508 3509 case T_CreateDomainStmt: 3510 lev = LOGSTMT_DDL; 3511 break; 3512 3513 case T_CreateRoleStmt: 3514 lev = LOGSTMT_DDL; 3515 break; 3516 3517 case T_AlterRoleStmt: 3518 lev = LOGSTMT_DDL; 3519 break; 3520 3521 case T_AlterRoleSetStmt: 3522 lev = LOGSTMT_DDL; 3523 break; 3524 3525 case T_DropRoleStmt: 3526 lev = LOGSTMT_DDL; 3527 break; 3528 3529 case T_DropOwnedStmt: 3530 lev = LOGSTMT_DDL; 3531 break; 3532 3533 case T_ReassignOwnedStmt: 3534 lev = LOGSTMT_DDL; 3535 break; 3536 3537 case T_LockStmt: 3538 lev = LOGSTMT_ALL; 3539 break; 3540 3541 case T_ConstraintsSetStmt: 3542 lev = LOGSTMT_ALL; 3543 break; 3544 3545 case T_CheckPointStmt: 3546 lev = LOGSTMT_ALL; 3547 break; 3548 3549 case T_ReindexStmt: 3550 lev = LOGSTMT_ALL; /* should this be DDL? */ 3551 break; 3552 3553 case T_CreateConversionStmt: 3554 lev = LOGSTMT_DDL; 3555 break; 3556 3557 case T_CreateCastStmt: 3558 lev = LOGSTMT_DDL; 3559 break; 3560 3561 case T_CreateOpClassStmt: 3562 lev = LOGSTMT_DDL; 3563 break; 3564 3565 case T_CreateOpFamilyStmt: 3566 lev = LOGSTMT_DDL; 3567 break; 3568 3569 case T_CreateTransformStmt: 3570 lev = LOGSTMT_DDL; 3571 break; 3572 3573 case T_AlterOpFamilyStmt: 3574 lev = LOGSTMT_DDL; 3575 break; 3576 3577 case T_CreatePolicyStmt: 3578 lev = LOGSTMT_DDL; 3579 break; 3580 3581 case T_AlterPolicyStmt: 3582 lev = LOGSTMT_DDL; 3583 break; 3584 3585 case T_AlterTSDictionaryStmt: 3586 lev = LOGSTMT_DDL; 3587 break; 3588 3589 case T_AlterTSConfigurationStmt: 3590 lev = LOGSTMT_DDL; 3591 break; 3592 3593 case T_CreateAmStmt: 3594 lev = LOGSTMT_DDL; 3595 break; 3596 3597 case T_CreatePublicationStmt: 3598 lev = LOGSTMT_DDL; 3599 break; 3600 3601 case T_AlterPublicationStmt: 3602 lev = LOGSTMT_DDL; 3603 break; 3604 3605 case T_CreateSubscriptionStmt: 3606 lev = LOGSTMT_DDL; 3607 break; 3608 3609 case T_AlterSubscriptionStmt: 3610 lev = LOGSTMT_DDL; 3611 break; 3612 3613 case T_DropSubscriptionStmt: 3614 lev = LOGSTMT_DDL; 3615 break; 3616 3617 case T_CreateStatsStmt: 3618 lev = LOGSTMT_DDL; 3619 break; 3620 3621 case T_AlterStatsStmt: 3622 lev = LOGSTMT_DDL; 3623 break; 3624 3625 case T_AlterCollationStmt: 3626 lev = LOGSTMT_DDL; 3627 break; 3628 3629 /* already-planned queries */ 3630 case T_PlannedStmt: 3631 { 3632 PlannedStmt *stmt = (PlannedStmt *) parsetree; 3633 3634 switch (stmt->commandType) 3635 { 3636 case CMD_SELECT: 3637 lev = LOGSTMT_ALL; 3638 break; 3639 3640 case CMD_UPDATE: 3641 case CMD_INSERT: 3642 case CMD_DELETE: 3643 lev = LOGSTMT_MOD; 3644 break; 3645 3646 case CMD_UTILITY: 3647 lev = GetCommandLogLevel(stmt->utilityStmt); 3648 break; 3649 3650 default: 3651 elog(WARNING, "unrecognized commandType: %d", 3652 (int) stmt->commandType); 3653 lev = LOGSTMT_ALL; 3654 break; 3655 } 3656 } 3657 break; 3658 3659 /* parsed-and-rewritten-but-not-planned queries */ 3660 case T_Query: 3661 { 3662 Query *stmt = (Query *) parsetree; 3663 3664 switch (stmt->commandType) 3665 { 3666 case CMD_SELECT: 3667 lev = LOGSTMT_ALL; 3668 break; 3669 3670 case CMD_UPDATE: 3671 case CMD_INSERT: 3672 case CMD_DELETE: 3673 lev = LOGSTMT_MOD; 3674 break; 3675 3676 case CMD_UTILITY: 3677 lev = GetCommandLogLevel(stmt->utilityStmt); 3678 break; 3679 3680 default: 3681 elog(WARNING, "unrecognized commandType: %d", 3682 (int) stmt->commandType); 3683 lev = LOGSTMT_ALL; 3684 break; 3685 } 3686 3687 } 3688 break; 3689 3690 default: 3691 elog(WARNING, "unrecognized node type: %d", 3692 (int) nodeTag(parsetree)); 3693 lev = LOGSTMT_ALL; 3694 break; 3695 } 3696 3697 return lev; 3698 } 3699