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