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