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