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