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
CommandIsReadOnly(PlannedStmt * pstmt)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
ClassifyUtilityCommandAsReadOnly(Node * parsetree)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
PreventCommandIfReadOnly(const char * cmdname)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
PreventCommandIfParallelMode(const char * cmdname)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
PreventCommandDuringRecovery(const char * cmdname)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
CheckRestrictedOperation(const char * cmdname)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
ProcessUtility(PlannedStmt * pstmt,const char * queryString,ProcessUtilityContext context,ParamListInfo params,QueryEnvironment * queryEnv,DestReceiver * dest,QueryCompletion * qc)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
standard_ProcessUtility(PlannedStmt * pstmt,const char * queryString,ProcessUtilityContext context,ParamListInfo params,QueryEnvironment * queryEnv,DestReceiver * dest,QueryCompletion * qc)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
ProcessUtilitySlow(ParseState * pstate,PlannedStmt * pstmt,const char * queryString,ProcessUtilityContext context,ParamListInfo params,QueryEnvironment * queryEnv,DestReceiver * dest,QueryCompletion * qc)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
ProcessUtilityForAlterTable(Node * stmt,AlterTableUtilityContext * context)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
ExecDropStmt(DropStmt * stmt,bool isTopLevel)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
UtilityReturnsTuples(Node * parsetree)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
UtilityTupleDescriptor(Node * parsetree)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
QueryReturnsTuples(Query * parsetree)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 *
UtilityContainsQuery(Node * parsetree)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
AlterObjectTypeCommandTag(ObjectType objtype)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
CreateCommandTag(Node * parsetree)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
GetCommandLogLevel(Node * parsetree)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