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-2019, 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(stmt->chain))
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(stmt->chain);
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->is_vacuumcmd ?
668 "VACUUM" : "ANALYZE");
669 /* forbidden in parallel mode due to CommandIsReadOnly */
670 ExecVacuum(pstate, 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 if (stmt->concurrent)
778 PreventInTransactionBlock(isTopLevel,
779 "REINDEX CONCURRENTLY");
780
781 /* we choose to allow this during "read only" transactions */
782 PreventCommandDuringRecovery("REINDEX");
783 /* forbidden in parallel mode due to CommandIsReadOnly */
784 switch (stmt->kind)
785 {
786 case REINDEX_OBJECT_INDEX:
787 ReindexIndex(stmt->relation, stmt->options, stmt->concurrent);
788 break;
789 case REINDEX_OBJECT_TABLE:
790 ReindexTable(stmt->relation, stmt->options, stmt->concurrent);
791 break;
792 case REINDEX_OBJECT_SCHEMA:
793 case REINDEX_OBJECT_SYSTEM:
794 case REINDEX_OBJECT_DATABASE:
795
796 /*
797 * This cannot run inside a user transaction block; if
798 * we were inside a transaction, then its commit- and
799 * start-transaction-command calls would not have the
800 * intended effect!
801 */
802 PreventInTransactionBlock(isTopLevel,
803 (stmt->kind == REINDEX_OBJECT_SCHEMA) ? "REINDEX SCHEMA" :
804 (stmt->kind == REINDEX_OBJECT_SYSTEM) ? "REINDEX SYSTEM" :
805 "REINDEX DATABASE");
806 ReindexMultipleTables(stmt->name, stmt->kind, stmt->options, stmt->concurrent);
807 break;
808 default:
809 elog(ERROR, "unrecognized object type: %d",
810 (int) stmt->kind);
811 break;
812 }
813 }
814 break;
815
816 /*
817 * The following statements are supported by Event Triggers only
818 * in some cases, so we "fast path" them in the other cases.
819 */
820
821 case T_GrantStmt:
822 {
823 GrantStmt *stmt = (GrantStmt *) parsetree;
824
825 if (EventTriggerSupportsObjectType(stmt->objtype))
826 ProcessUtilitySlow(pstate, pstmt, queryString,
827 context, params, queryEnv,
828 dest, completionTag);
829 else
830 ExecuteGrantStmt(stmt);
831 }
832 break;
833
834 case T_DropStmt:
835 {
836 DropStmt *stmt = (DropStmt *) parsetree;
837
838 if (EventTriggerSupportsObjectType(stmt->removeType))
839 ProcessUtilitySlow(pstate, pstmt, queryString,
840 context, params, queryEnv,
841 dest, completionTag);
842 else
843 ExecDropStmt(stmt, isTopLevel);
844 }
845 break;
846
847 case T_RenameStmt:
848 {
849 RenameStmt *stmt = (RenameStmt *) parsetree;
850
851 if (EventTriggerSupportsObjectType(stmt->renameType))
852 ProcessUtilitySlow(pstate, pstmt, queryString,
853 context, params, queryEnv,
854 dest, completionTag);
855 else
856 ExecRenameStmt(stmt);
857 }
858 break;
859
860 case T_AlterObjectDependsStmt:
861 {
862 AlterObjectDependsStmt *stmt = (AlterObjectDependsStmt *) parsetree;
863
864 if (EventTriggerSupportsObjectType(stmt->objectType))
865 ProcessUtilitySlow(pstate, pstmt, queryString,
866 context, params, queryEnv,
867 dest, completionTag);
868 else
869 ExecAlterObjectDependsStmt(stmt, NULL);
870 }
871 break;
872
873 case T_AlterObjectSchemaStmt:
874 {
875 AlterObjectSchemaStmt *stmt = (AlterObjectSchemaStmt *) parsetree;
876
877 if (EventTriggerSupportsObjectType(stmt->objectType))
878 ProcessUtilitySlow(pstate, pstmt, queryString,
879 context, params, queryEnv,
880 dest, completionTag);
881 else
882 ExecAlterObjectSchemaStmt(stmt, NULL);
883 }
884 break;
885
886 case T_AlterOwnerStmt:
887 {
888 AlterOwnerStmt *stmt = (AlterOwnerStmt *) parsetree;
889
890 if (EventTriggerSupportsObjectType(stmt->objectType))
891 ProcessUtilitySlow(pstate, pstmt, queryString,
892 context, params, queryEnv,
893 dest, completionTag);
894 else
895 ExecAlterOwnerStmt(stmt);
896 }
897 break;
898
899 case T_CommentStmt:
900 {
901 CommentStmt *stmt = (CommentStmt *) parsetree;
902
903 if (EventTriggerSupportsObjectType(stmt->objtype))
904 ProcessUtilitySlow(pstate, pstmt, queryString,
905 context, params, queryEnv,
906 dest, completionTag);
907 else
908 CommentObject(stmt);
909 break;
910 }
911
912 case T_SecLabelStmt:
913 {
914 SecLabelStmt *stmt = (SecLabelStmt *) parsetree;
915
916 if (EventTriggerSupportsObjectType(stmt->objtype))
917 ProcessUtilitySlow(pstate, pstmt, queryString,
918 context, params, queryEnv,
919 dest, completionTag);
920 else
921 ExecSecLabelStmt(stmt);
922 break;
923 }
924
925 default:
926 /* All other statement types have event trigger support */
927 ProcessUtilitySlow(pstate, pstmt, queryString,
928 context, params, queryEnv,
929 dest, completionTag);
930 break;
931 }
932
933 free_parsestate(pstate);
934
935 /*
936 * Make effects of commands visible, for instance so that
937 * PreCommit_on_commit_actions() can see them (see for example bug
938 * #15631).
939 */
940 CommandCounterIncrement();
941 }
942
943 /*
944 * The "Slow" variant of ProcessUtility should only receive statements
945 * supported by the event triggers facility. Therefore, we always
946 * perform the trigger support calls if the context allows it.
947 */
948 static void
ProcessUtilitySlow(ParseState * pstate,PlannedStmt * pstmt,const char * queryString,ProcessUtilityContext context,ParamListInfo params,QueryEnvironment * queryEnv,DestReceiver * dest,char * completionTag)949 ProcessUtilitySlow(ParseState *pstate,
950 PlannedStmt *pstmt,
951 const char *queryString,
952 ProcessUtilityContext context,
953 ParamListInfo params,
954 QueryEnvironment *queryEnv,
955 DestReceiver *dest,
956 char *completionTag)
957 {
958 Node *parsetree = pstmt->utilityStmt;
959 bool isTopLevel = (context == PROCESS_UTILITY_TOPLEVEL);
960 bool isCompleteQuery = (context != PROCESS_UTILITY_SUBCOMMAND);
961 bool needCleanup;
962 bool commandCollected = false;
963 ObjectAddress address;
964 ObjectAddress secondaryObject = InvalidObjectAddress;
965
966 /* All event trigger calls are done only when isCompleteQuery is true */
967 needCleanup = isCompleteQuery && EventTriggerBeginCompleteQuery();
968
969 /* PG_TRY block is to ensure we call EventTriggerEndCompleteQuery */
970 PG_TRY();
971 {
972 if (isCompleteQuery)
973 EventTriggerDDLCommandStart(parsetree);
974
975 switch (nodeTag(parsetree))
976 {
977 /*
978 * relation and attribute manipulation
979 */
980 case T_CreateSchemaStmt:
981 CreateSchemaCommand((CreateSchemaStmt *) parsetree,
982 queryString,
983 pstmt->stmt_location,
984 pstmt->stmt_len);
985
986 /*
987 * EventTriggerCollectSimpleCommand called by
988 * CreateSchemaCommand
989 */
990 commandCollected = true;
991 break;
992
993 case T_CreateStmt:
994 case T_CreateForeignTableStmt:
995 {
996 List *stmts;
997 RangeVar *table_rv = NULL;
998
999 /* Run parse analysis ... */
1000 stmts = transformCreateStmt((CreateStmt *) parsetree,
1001 queryString);
1002
1003 /*
1004 * ... and do it. We can't use foreach() because we may
1005 * modify the list midway through, so pick off the
1006 * elements one at a time, the hard way.
1007 */
1008 while (stmts != NIL)
1009 {
1010 Node *stmt = (Node *) linitial(stmts);
1011
1012 stmts = list_delete_first(stmts);
1013
1014 if (IsA(stmt, CreateStmt))
1015 {
1016 CreateStmt *cstmt = (CreateStmt *) stmt;
1017 Datum toast_options;
1018 static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
1019
1020 /* Remember transformed RangeVar for LIKE */
1021 table_rv = cstmt->relation;
1022
1023 /* Create the table itself */
1024 address = DefineRelation(cstmt,
1025 RELKIND_RELATION,
1026 InvalidOid, NULL,
1027 queryString);
1028 EventTriggerCollectSimpleCommand(address,
1029 secondaryObject,
1030 stmt);
1031
1032 /*
1033 * Let NewRelationCreateToastTable decide if this
1034 * one needs a secondary relation too.
1035 */
1036 CommandCounterIncrement();
1037
1038 /*
1039 * parse and validate reloptions for the toast
1040 * table
1041 */
1042 toast_options = transformRelOptions((Datum) 0,
1043 cstmt->options,
1044 "toast",
1045 validnsps,
1046 true,
1047 false);
1048 (void) heap_reloptions(RELKIND_TOASTVALUE,
1049 toast_options,
1050 true);
1051
1052 NewRelationCreateToastTable(address.objectId,
1053 toast_options);
1054 }
1055 else if (IsA(stmt, CreateForeignTableStmt))
1056 {
1057 CreateForeignTableStmt *cstmt = (CreateForeignTableStmt *) stmt;
1058
1059 /* Remember transformed RangeVar for LIKE */
1060 table_rv = cstmt->base.relation;
1061
1062 /* Create the table itself */
1063 address = DefineRelation(&cstmt->base,
1064 RELKIND_FOREIGN_TABLE,
1065 InvalidOid, NULL,
1066 queryString);
1067 CreateForeignTable(cstmt,
1068 address.objectId);
1069 EventTriggerCollectSimpleCommand(address,
1070 secondaryObject,
1071 stmt);
1072 }
1073 else if (IsA(stmt, TableLikeClause))
1074 {
1075 /*
1076 * Do delayed processing of LIKE options. This
1077 * will result in additional sub-statements for us
1078 * to process. Those should get done before any
1079 * remaining actions, so prepend them to "stmts".
1080 */
1081 TableLikeClause *like = (TableLikeClause *) stmt;
1082 List *morestmts;
1083
1084 Assert(table_rv != NULL);
1085
1086 morestmts = expandTableLikeClause(table_rv, like);
1087 stmts = list_concat(morestmts, stmts);
1088 }
1089 else
1090 {
1091 /*
1092 * Recurse for anything else. Note the recursive
1093 * call will stash the objects so created into our
1094 * event trigger context.
1095 */
1096 PlannedStmt *wrapper;
1097
1098 wrapper = makeNode(PlannedStmt);
1099 wrapper->commandType = CMD_UTILITY;
1100 wrapper->canSetTag = false;
1101 wrapper->utilityStmt = stmt;
1102 wrapper->stmt_location = pstmt->stmt_location;
1103 wrapper->stmt_len = pstmt->stmt_len;
1104
1105 ProcessUtility(wrapper,
1106 queryString,
1107 PROCESS_UTILITY_SUBCOMMAND,
1108 params,
1109 NULL,
1110 None_Receiver,
1111 NULL);
1112 }
1113
1114 /* Need CCI between commands */
1115 if (stmts != NIL)
1116 CommandCounterIncrement();
1117 }
1118
1119 /*
1120 * The multiple commands generated here are stashed
1121 * individually, so disable collection below.
1122 */
1123 commandCollected = true;
1124 }
1125 break;
1126
1127 case T_AlterTableStmt:
1128 {
1129 AlterTableStmt *atstmt = (AlterTableStmt *) parsetree;
1130 Oid relid;
1131 List *stmts;
1132 ListCell *l;
1133 LOCKMODE lockmode;
1134
1135 /*
1136 * Figure out lock mode, and acquire lock. This also does
1137 * basic permissions checks, so that we won't wait for a
1138 * lock on (for example) a relation on which we have no
1139 * permissions.
1140 */
1141 lockmode = AlterTableGetLockLevel(atstmt->cmds);
1142 relid = AlterTableLookupRelation(atstmt, lockmode);
1143
1144 if (OidIsValid(relid))
1145 {
1146 /* Run parse analysis ... */
1147 stmts = transformAlterTableStmt(relid, atstmt,
1148 queryString);
1149
1150 /* ... ensure we have an event trigger context ... */
1151 EventTriggerAlterTableStart(parsetree);
1152 EventTriggerAlterTableRelid(relid);
1153
1154 /* ... and do it */
1155 foreach(l, stmts)
1156 {
1157 Node *stmt = (Node *) lfirst(l);
1158
1159 if (IsA(stmt, AlterTableStmt))
1160 {
1161 /* Do the table alteration proper */
1162 AlterTable(relid, lockmode,
1163 (AlterTableStmt *) stmt);
1164 }
1165 else
1166 {
1167 /*
1168 * Recurse for anything else. If we need to
1169 * do so, "close" the current complex-command
1170 * set, and start a new one at the bottom;
1171 * this is needed to ensure the ordering of
1172 * queued commands is consistent with the way
1173 * they are executed here.
1174 */
1175 PlannedStmt *wrapper;
1176
1177 EventTriggerAlterTableEnd();
1178 wrapper = makeNode(PlannedStmt);
1179 wrapper->commandType = CMD_UTILITY;
1180 wrapper->canSetTag = false;
1181 wrapper->utilityStmt = stmt;
1182 wrapper->stmt_location = pstmt->stmt_location;
1183 wrapper->stmt_len = pstmt->stmt_len;
1184 ProcessUtility(wrapper,
1185 queryString,
1186 PROCESS_UTILITY_SUBCOMMAND,
1187 params,
1188 NULL,
1189 None_Receiver,
1190 NULL);
1191 EventTriggerAlterTableStart(parsetree);
1192 EventTriggerAlterTableRelid(relid);
1193 }
1194
1195 /* Need CCI between commands */
1196 if (lnext(l) != NULL)
1197 CommandCounterIncrement();
1198 }
1199
1200 /* done */
1201 EventTriggerAlterTableEnd();
1202 }
1203 else
1204 ereport(NOTICE,
1205 (errmsg("relation \"%s\" does not exist, skipping",
1206 atstmt->relation->relname)));
1207 }
1208
1209 /* ALTER TABLE stashes commands internally */
1210 commandCollected = true;
1211 break;
1212
1213 case T_AlterDomainStmt:
1214 {
1215 AlterDomainStmt *stmt = (AlterDomainStmt *) parsetree;
1216
1217 /*
1218 * Some or all of these functions are recursive to cover
1219 * inherited things, so permission checks are done there.
1220 */
1221 switch (stmt->subtype)
1222 {
1223 case 'T': /* ALTER DOMAIN DEFAULT */
1224
1225 /*
1226 * Recursively alter column default for table and,
1227 * if requested, for descendants
1228 */
1229 address =
1230 AlterDomainDefault(stmt->typeName,
1231 stmt->def);
1232 break;
1233 case 'N': /* ALTER DOMAIN DROP NOT NULL */
1234 address =
1235 AlterDomainNotNull(stmt->typeName,
1236 false);
1237 break;
1238 case 'O': /* ALTER DOMAIN SET NOT NULL */
1239 address =
1240 AlterDomainNotNull(stmt->typeName,
1241 true);
1242 break;
1243 case 'C': /* ADD CONSTRAINT */
1244 address =
1245 AlterDomainAddConstraint(stmt->typeName,
1246 stmt->def,
1247 &secondaryObject);
1248 break;
1249 case 'X': /* DROP CONSTRAINT */
1250 address =
1251 AlterDomainDropConstraint(stmt->typeName,
1252 stmt->name,
1253 stmt->behavior,
1254 stmt->missing_ok);
1255 break;
1256 case 'V': /* VALIDATE CONSTRAINT */
1257 address =
1258 AlterDomainValidateConstraint(stmt->typeName,
1259 stmt->name);
1260 break;
1261 default: /* oops */
1262 elog(ERROR, "unrecognized alter domain type: %d",
1263 (int) stmt->subtype);
1264 break;
1265 }
1266 }
1267 break;
1268
1269 /*
1270 * ************* object creation / destruction **************
1271 */
1272 case T_DefineStmt:
1273 {
1274 DefineStmt *stmt = (DefineStmt *) parsetree;
1275
1276 switch (stmt->kind)
1277 {
1278 case OBJECT_AGGREGATE:
1279 address =
1280 DefineAggregate(pstate, stmt->defnames, stmt->args,
1281 stmt->oldstyle,
1282 stmt->definition,
1283 stmt->replace);
1284 break;
1285 case OBJECT_OPERATOR:
1286 Assert(stmt->args == NIL);
1287 address = DefineOperator(stmt->defnames,
1288 stmt->definition);
1289 break;
1290 case OBJECT_TYPE:
1291 Assert(stmt->args == NIL);
1292 address = DefineType(pstate,
1293 stmt->defnames,
1294 stmt->definition);
1295 break;
1296 case OBJECT_TSPARSER:
1297 Assert(stmt->args == NIL);
1298 address = DefineTSParser(stmt->defnames,
1299 stmt->definition);
1300 break;
1301 case OBJECT_TSDICTIONARY:
1302 Assert(stmt->args == NIL);
1303 address = DefineTSDictionary(stmt->defnames,
1304 stmt->definition);
1305 break;
1306 case OBJECT_TSTEMPLATE:
1307 Assert(stmt->args == NIL);
1308 address = DefineTSTemplate(stmt->defnames,
1309 stmt->definition);
1310 break;
1311 case OBJECT_TSCONFIGURATION:
1312 Assert(stmt->args == NIL);
1313 address = DefineTSConfiguration(stmt->defnames,
1314 stmt->definition,
1315 &secondaryObject);
1316 break;
1317 case OBJECT_COLLATION:
1318 Assert(stmt->args == NIL);
1319 address = DefineCollation(pstate,
1320 stmt->defnames,
1321 stmt->definition,
1322 stmt->if_not_exists);
1323 break;
1324 default:
1325 elog(ERROR, "unrecognized define stmt type: %d",
1326 (int) stmt->kind);
1327 break;
1328 }
1329 }
1330 break;
1331
1332 case T_IndexStmt: /* CREATE INDEX */
1333 {
1334 IndexStmt *stmt = (IndexStmt *) parsetree;
1335 Oid relid;
1336 LOCKMODE lockmode;
1337 bool is_alter_table;
1338
1339 if (stmt->concurrent)
1340 PreventInTransactionBlock(isTopLevel,
1341 "CREATE INDEX CONCURRENTLY");
1342
1343 /*
1344 * Look up the relation OID just once, right here at the
1345 * beginning, so that we don't end up repeating the name
1346 * lookup later and latching onto a different relation
1347 * partway through. To avoid lock upgrade hazards, it's
1348 * important that we take the strongest lock that will
1349 * eventually be needed here, so the lockmode calculation
1350 * needs to match what DefineIndex() does.
1351 */
1352 lockmode = stmt->concurrent ? ShareUpdateExclusiveLock
1353 : ShareLock;
1354 relid =
1355 RangeVarGetRelidExtended(stmt->relation, lockmode,
1356 0,
1357 RangeVarCallbackOwnsRelation,
1358 NULL);
1359
1360 /*
1361 * CREATE INDEX on partitioned tables (but not regular
1362 * inherited tables) recurses to partitions, so we must
1363 * acquire locks early to avoid deadlocks.
1364 *
1365 * We also take the opportunity to verify that all
1366 * partitions are something we can put an index on, to
1367 * avoid building some indexes only to fail later.
1368 */
1369 if (stmt->relation->inh &&
1370 get_rel_relkind(relid) == RELKIND_PARTITIONED_TABLE)
1371 {
1372 ListCell *lc;
1373 List *inheritors = NIL;
1374
1375 inheritors = find_all_inheritors(relid, lockmode, NULL);
1376 foreach(lc, inheritors)
1377 {
1378 char relkind = get_rel_relkind(lfirst_oid(lc));
1379
1380 if (relkind != RELKIND_RELATION &&
1381 relkind != RELKIND_MATVIEW &&
1382 relkind != RELKIND_PARTITIONED_TABLE &&
1383 relkind != RELKIND_FOREIGN_TABLE)
1384 elog(ERROR, "unexpected relkind \"%c\" on partition \"%s\"",
1385 relkind, stmt->relation->relname);
1386
1387 if (relkind == RELKIND_FOREIGN_TABLE &&
1388 (stmt->unique || stmt->primary))
1389 ereport(ERROR,
1390 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1391 errmsg("cannot create unique index on partitioned table \"%s\"",
1392 stmt->relation->relname),
1393 errdetail("Table \"%s\" contains partitions that are foreign tables.",
1394 stmt->relation->relname)));
1395 }
1396 list_free(inheritors);
1397 }
1398
1399 /*
1400 * If the IndexStmt is already transformed, it must have
1401 * come from generateClonedIndexStmt, which in current
1402 * usage means it came from expandTableLikeClause rather
1403 * than from original parse analysis. And that means we
1404 * must treat it like ALTER TABLE ADD INDEX, not CREATE.
1405 * (This is a bit grotty, but currently it doesn't seem
1406 * worth adding a separate bool field for the purpose.)
1407 */
1408 is_alter_table = stmt->transformed;
1409
1410 /* Run parse analysis ... */
1411 stmt = transformIndexStmt(relid, stmt, queryString);
1412
1413 /* ... and do it */
1414 EventTriggerAlterTableStart(parsetree);
1415 address =
1416 DefineIndex(relid, /* OID of heap relation */
1417 stmt,
1418 InvalidOid, /* no predefined OID */
1419 InvalidOid, /* no parent index */
1420 InvalidOid, /* no parent constraint */
1421 is_alter_table,
1422 true, /* check_rights */
1423 true, /* check_not_in_use */
1424 false, /* skip_build */
1425 false); /* quiet */
1426
1427 /*
1428 * Add the CREATE INDEX node itself to stash right away;
1429 * if there were any commands stashed in the ALTER TABLE
1430 * code, we need them to appear after this one.
1431 */
1432 EventTriggerCollectSimpleCommand(address, secondaryObject,
1433 parsetree);
1434 commandCollected = true;
1435 EventTriggerAlterTableEnd();
1436 }
1437 break;
1438
1439 case T_CreateExtensionStmt:
1440 address = CreateExtension(pstate, (CreateExtensionStmt *) parsetree);
1441 break;
1442
1443 case T_AlterExtensionStmt:
1444 address = ExecAlterExtensionStmt(pstate, (AlterExtensionStmt *) parsetree);
1445 break;
1446
1447 case T_AlterExtensionContentsStmt:
1448 address = ExecAlterExtensionContentsStmt((AlterExtensionContentsStmt *) parsetree,
1449 &secondaryObject);
1450 break;
1451
1452 case T_CreateFdwStmt:
1453 address = CreateForeignDataWrapper((CreateFdwStmt *) parsetree);
1454 break;
1455
1456 case T_AlterFdwStmt:
1457 address = AlterForeignDataWrapper((AlterFdwStmt *) parsetree);
1458 break;
1459
1460 case T_CreateForeignServerStmt:
1461 address = CreateForeignServer((CreateForeignServerStmt *) parsetree);
1462 break;
1463
1464 case T_AlterForeignServerStmt:
1465 address = AlterForeignServer((AlterForeignServerStmt *) parsetree);
1466 break;
1467
1468 case T_CreateUserMappingStmt:
1469 address = CreateUserMapping((CreateUserMappingStmt *) parsetree);
1470 break;
1471
1472 case T_AlterUserMappingStmt:
1473 address = AlterUserMapping((AlterUserMappingStmt *) parsetree);
1474 break;
1475
1476 case T_DropUserMappingStmt:
1477 RemoveUserMapping((DropUserMappingStmt *) parsetree);
1478 /* no commands stashed for DROP */
1479 commandCollected = true;
1480 break;
1481
1482 case T_ImportForeignSchemaStmt:
1483 ImportForeignSchema((ImportForeignSchemaStmt *) parsetree);
1484 /* commands are stashed inside ImportForeignSchema */
1485 commandCollected = true;
1486 break;
1487
1488 case T_CompositeTypeStmt: /* CREATE TYPE (composite) */
1489 {
1490 CompositeTypeStmt *stmt = (CompositeTypeStmt *) parsetree;
1491
1492 address = DefineCompositeType(stmt->typevar,
1493 stmt->coldeflist);
1494 }
1495 break;
1496
1497 case T_CreateEnumStmt: /* CREATE TYPE AS ENUM */
1498 address = DefineEnum((CreateEnumStmt *) parsetree);
1499 break;
1500
1501 case T_CreateRangeStmt: /* CREATE TYPE AS RANGE */
1502 address = DefineRange((CreateRangeStmt *) parsetree);
1503 break;
1504
1505 case T_AlterEnumStmt: /* ALTER TYPE (enum) */
1506 address = AlterEnum((AlterEnumStmt *) parsetree);
1507 break;
1508
1509 case T_ViewStmt: /* CREATE VIEW */
1510 EventTriggerAlterTableStart(parsetree);
1511 address = DefineView((ViewStmt *) parsetree, queryString,
1512 pstmt->stmt_location, pstmt->stmt_len);
1513 EventTriggerCollectSimpleCommand(address, secondaryObject,
1514 parsetree);
1515 /* stashed internally */
1516 commandCollected = true;
1517 EventTriggerAlterTableEnd();
1518 break;
1519
1520 case T_CreateFunctionStmt: /* CREATE FUNCTION */
1521 address = CreateFunction(pstate, (CreateFunctionStmt *) parsetree);
1522 break;
1523
1524 case T_AlterFunctionStmt: /* ALTER FUNCTION */
1525 address = AlterFunction(pstate, (AlterFunctionStmt *) parsetree);
1526 break;
1527
1528 case T_RuleStmt: /* CREATE RULE */
1529 address = DefineRule((RuleStmt *) parsetree, queryString);
1530 break;
1531
1532 case T_CreateSeqStmt:
1533 address = DefineSequence(pstate, (CreateSeqStmt *) parsetree);
1534 break;
1535
1536 case T_AlterSeqStmt:
1537 address = AlterSequence(pstate, (AlterSeqStmt *) parsetree);
1538 break;
1539
1540 case T_CreateTableAsStmt:
1541 address = ExecCreateTableAs((CreateTableAsStmt *) parsetree,
1542 queryString, params, queryEnv,
1543 completionTag);
1544 break;
1545
1546 case T_RefreshMatViewStmt:
1547
1548 /*
1549 * REFRESH CONCURRENTLY executes some DDL commands internally.
1550 * Inhibit DDL command collection here to avoid those commands
1551 * from showing up in the deparsed command queue. The refresh
1552 * command itself is queued, which is enough.
1553 */
1554 EventTriggerInhibitCommandCollection();
1555 PG_TRY();
1556 {
1557 address = ExecRefreshMatView((RefreshMatViewStmt *) parsetree,
1558 queryString, params, completionTag);
1559 }
1560 PG_CATCH();
1561 {
1562 EventTriggerUndoInhibitCommandCollection();
1563 PG_RE_THROW();
1564 }
1565 PG_END_TRY();
1566 EventTriggerUndoInhibitCommandCollection();
1567 break;
1568
1569 case T_CreateTrigStmt:
1570 address = CreateTrigger((CreateTrigStmt *) parsetree,
1571 queryString, InvalidOid, InvalidOid,
1572 InvalidOid, InvalidOid, InvalidOid,
1573 InvalidOid, NULL, false, false);
1574 break;
1575
1576 case T_CreatePLangStmt:
1577 address = CreateProceduralLanguage((CreatePLangStmt *) parsetree);
1578 break;
1579
1580 case T_CreateDomainStmt:
1581 address = DefineDomain((CreateDomainStmt *) parsetree);
1582 break;
1583
1584 case T_CreateConversionStmt:
1585 address = CreateConversionCommand((CreateConversionStmt *) parsetree);
1586 break;
1587
1588 case T_CreateCastStmt:
1589 address = CreateCast((CreateCastStmt *) parsetree);
1590 break;
1591
1592 case T_CreateOpClassStmt:
1593 DefineOpClass((CreateOpClassStmt *) parsetree);
1594 /* command is stashed in DefineOpClass */
1595 commandCollected = true;
1596 break;
1597
1598 case T_CreateOpFamilyStmt:
1599 address = DefineOpFamily((CreateOpFamilyStmt *) parsetree);
1600 break;
1601
1602 case T_CreateTransformStmt:
1603 address = CreateTransform((CreateTransformStmt *) parsetree);
1604 break;
1605
1606 case T_AlterOpFamilyStmt:
1607 AlterOpFamily((AlterOpFamilyStmt *) parsetree);
1608 /* commands are stashed in AlterOpFamily */
1609 commandCollected = true;
1610 break;
1611
1612 case T_AlterTSDictionaryStmt:
1613 address = AlterTSDictionary((AlterTSDictionaryStmt *) parsetree);
1614 break;
1615
1616 case T_AlterTSConfigurationStmt:
1617 AlterTSConfiguration((AlterTSConfigurationStmt *) parsetree);
1618
1619 /*
1620 * Commands are stashed in MakeConfigurationMapping and
1621 * DropConfigurationMapping, which are called from
1622 * AlterTSConfiguration
1623 */
1624 commandCollected = true;
1625 break;
1626
1627 case T_AlterTableMoveAllStmt:
1628 AlterTableMoveAll((AlterTableMoveAllStmt *) parsetree);
1629 /* commands are stashed in AlterTableMoveAll */
1630 commandCollected = true;
1631 break;
1632
1633 case T_DropStmt:
1634 ExecDropStmt((DropStmt *) parsetree, isTopLevel);
1635 /* no commands stashed for DROP */
1636 commandCollected = true;
1637 break;
1638
1639 case T_RenameStmt:
1640 address = ExecRenameStmt((RenameStmt *) parsetree);
1641 break;
1642
1643 case T_AlterObjectDependsStmt:
1644 address =
1645 ExecAlterObjectDependsStmt((AlterObjectDependsStmt *) parsetree,
1646 &secondaryObject);
1647 break;
1648
1649 case T_AlterObjectSchemaStmt:
1650 address =
1651 ExecAlterObjectSchemaStmt((AlterObjectSchemaStmt *) parsetree,
1652 &secondaryObject);
1653 break;
1654
1655 case T_AlterOwnerStmt:
1656 address = ExecAlterOwnerStmt((AlterOwnerStmt *) parsetree);
1657 break;
1658
1659 case T_AlterOperatorStmt:
1660 address = AlterOperator((AlterOperatorStmt *) parsetree);
1661 break;
1662
1663 case T_CommentStmt:
1664 address = CommentObject((CommentStmt *) parsetree);
1665 break;
1666
1667 case T_GrantStmt:
1668 ExecuteGrantStmt((GrantStmt *) parsetree);
1669 /* commands are stashed in ExecGrantStmt_oids */
1670 commandCollected = true;
1671 break;
1672
1673 case T_DropOwnedStmt:
1674 DropOwnedObjects((DropOwnedStmt *) parsetree);
1675 /* no commands stashed for DROP */
1676 commandCollected = true;
1677 break;
1678
1679 case T_AlterDefaultPrivilegesStmt:
1680 ExecAlterDefaultPrivilegesStmt(pstate, (AlterDefaultPrivilegesStmt *) parsetree);
1681 EventTriggerCollectAlterDefPrivs((AlterDefaultPrivilegesStmt *) parsetree);
1682 commandCollected = true;
1683 break;
1684
1685 case T_CreatePolicyStmt: /* CREATE POLICY */
1686 address = CreatePolicy((CreatePolicyStmt *) parsetree);
1687 break;
1688
1689 case T_AlterPolicyStmt: /* ALTER POLICY */
1690 address = AlterPolicy((AlterPolicyStmt *) parsetree);
1691 break;
1692
1693 case T_SecLabelStmt:
1694 address = ExecSecLabelStmt((SecLabelStmt *) parsetree);
1695 break;
1696
1697 case T_CreateAmStmt:
1698 address = CreateAccessMethod((CreateAmStmt *) parsetree);
1699 break;
1700
1701 case T_CreatePublicationStmt:
1702 address = CreatePublication((CreatePublicationStmt *) parsetree);
1703 break;
1704
1705 case T_AlterPublicationStmt:
1706 AlterPublication((AlterPublicationStmt *) parsetree);
1707
1708 /*
1709 * AlterPublication calls EventTriggerCollectSimpleCommand
1710 * directly
1711 */
1712 commandCollected = true;
1713 break;
1714
1715 case T_CreateSubscriptionStmt:
1716 address = CreateSubscription((CreateSubscriptionStmt *) parsetree,
1717 isTopLevel);
1718 break;
1719
1720 case T_AlterSubscriptionStmt:
1721 address = AlterSubscription((AlterSubscriptionStmt *) parsetree);
1722 break;
1723
1724 case T_DropSubscriptionStmt:
1725 DropSubscription((DropSubscriptionStmt *) parsetree, isTopLevel);
1726 /* no commands stashed for DROP */
1727 commandCollected = true;
1728 break;
1729
1730 case T_CreateStatsStmt:
1731 address = CreateStatistics((CreateStatsStmt *) parsetree);
1732 break;
1733
1734 case T_AlterCollationStmt:
1735 address = AlterCollation((AlterCollationStmt *) parsetree);
1736 break;
1737
1738 default:
1739 elog(ERROR, "unrecognized node type: %d",
1740 (int) nodeTag(parsetree));
1741 break;
1742 }
1743
1744 /*
1745 * Remember the object so that ddl_command_end event triggers have
1746 * access to it.
1747 */
1748 if (!commandCollected)
1749 EventTriggerCollectSimpleCommand(address, secondaryObject,
1750 parsetree);
1751
1752 if (isCompleteQuery)
1753 {
1754 EventTriggerSQLDrop(parsetree);
1755 EventTriggerDDLCommandEnd(parsetree);
1756 }
1757 }
1758 PG_CATCH();
1759 {
1760 if (needCleanup)
1761 EventTriggerEndCompleteQuery();
1762 PG_RE_THROW();
1763 }
1764 PG_END_TRY();
1765
1766 if (needCleanup)
1767 EventTriggerEndCompleteQuery();
1768 }
1769
1770 /*
1771 * Dispatch function for DropStmt
1772 */
1773 static void
ExecDropStmt(DropStmt * stmt,bool isTopLevel)1774 ExecDropStmt(DropStmt *stmt, bool isTopLevel)
1775 {
1776 switch (stmt->removeType)
1777 {
1778 case OBJECT_INDEX:
1779 if (stmt->concurrent)
1780 PreventInTransactionBlock(isTopLevel,
1781 "DROP INDEX CONCURRENTLY");
1782 /* fall through */
1783
1784 case OBJECT_TABLE:
1785 case OBJECT_SEQUENCE:
1786 case OBJECT_VIEW:
1787 case OBJECT_MATVIEW:
1788 case OBJECT_FOREIGN_TABLE:
1789 RemoveRelations(stmt);
1790 break;
1791 default:
1792 RemoveObjects(stmt);
1793 break;
1794 }
1795 }
1796
1797
1798 /*
1799 * UtilityReturnsTuples
1800 * Return "true" if this utility statement will send output to the
1801 * destination.
1802 *
1803 * Generally, there should be a case here for each case in ProcessUtility
1804 * where "dest" is passed on.
1805 */
1806 bool
UtilityReturnsTuples(Node * parsetree)1807 UtilityReturnsTuples(Node *parsetree)
1808 {
1809 switch (nodeTag(parsetree))
1810 {
1811 case T_CallStmt:
1812 {
1813 CallStmt *stmt = (CallStmt *) parsetree;
1814
1815 return (stmt->funcexpr->funcresulttype == RECORDOID);
1816 }
1817 case T_FetchStmt:
1818 {
1819 FetchStmt *stmt = (FetchStmt *) parsetree;
1820 Portal portal;
1821
1822 if (stmt->ismove)
1823 return false;
1824 portal = GetPortalByName(stmt->portalname);
1825 if (!PortalIsValid(portal))
1826 return false; /* not our business to raise error */
1827 return portal->tupDesc ? true : false;
1828 }
1829
1830 case T_ExecuteStmt:
1831 {
1832 ExecuteStmt *stmt = (ExecuteStmt *) parsetree;
1833 PreparedStatement *entry;
1834
1835 entry = FetchPreparedStatement(stmt->name, false);
1836 if (!entry)
1837 return false; /* not our business to raise error */
1838 if (entry->plansource->resultDesc)
1839 return true;
1840 return false;
1841 }
1842
1843 case T_ExplainStmt:
1844 return true;
1845
1846 case T_VariableShowStmt:
1847 return true;
1848
1849 default:
1850 return false;
1851 }
1852 }
1853
1854 /*
1855 * UtilityTupleDescriptor
1856 * Fetch the actual output tuple descriptor for a utility statement
1857 * for which UtilityReturnsTuples() previously returned "true".
1858 *
1859 * The returned descriptor is created in (or copied into) the current memory
1860 * context.
1861 */
1862 TupleDesc
UtilityTupleDescriptor(Node * parsetree)1863 UtilityTupleDescriptor(Node *parsetree)
1864 {
1865 switch (nodeTag(parsetree))
1866 {
1867 case T_CallStmt:
1868 return CallStmtResultDesc((CallStmt *) parsetree);
1869
1870 case T_FetchStmt:
1871 {
1872 FetchStmt *stmt = (FetchStmt *) parsetree;
1873 Portal portal;
1874
1875 if (stmt->ismove)
1876 return NULL;
1877 portal = GetPortalByName(stmt->portalname);
1878 if (!PortalIsValid(portal))
1879 return NULL; /* not our business to raise error */
1880 return CreateTupleDescCopy(portal->tupDesc);
1881 }
1882
1883 case T_ExecuteStmt:
1884 {
1885 ExecuteStmt *stmt = (ExecuteStmt *) parsetree;
1886 PreparedStatement *entry;
1887
1888 entry = FetchPreparedStatement(stmt->name, false);
1889 if (!entry)
1890 return NULL; /* not our business to raise error */
1891 return FetchPreparedStatementResultDesc(entry);
1892 }
1893
1894 case T_ExplainStmt:
1895 return ExplainResultDesc((ExplainStmt *) parsetree);
1896
1897 case T_VariableShowStmt:
1898 {
1899 VariableShowStmt *n = (VariableShowStmt *) parsetree;
1900
1901 return GetPGVariableResultDesc(n->name);
1902 }
1903
1904 default:
1905 return NULL;
1906 }
1907 }
1908
1909
1910 /*
1911 * QueryReturnsTuples
1912 * Return "true" if this Query will send output to the destination.
1913 */
1914 #ifdef NOT_USED
1915 bool
QueryReturnsTuples(Query * parsetree)1916 QueryReturnsTuples(Query *parsetree)
1917 {
1918 switch (parsetree->commandType)
1919 {
1920 case CMD_SELECT:
1921 /* returns tuples */
1922 return true;
1923 case CMD_INSERT:
1924 case CMD_UPDATE:
1925 case CMD_DELETE:
1926 /* the forms with RETURNING return tuples */
1927 if (parsetree->returningList)
1928 return true;
1929 break;
1930 case CMD_UTILITY:
1931 return UtilityReturnsTuples(parsetree->utilityStmt);
1932 case CMD_UNKNOWN:
1933 case CMD_NOTHING:
1934 /* probably shouldn't get here */
1935 break;
1936 }
1937 return false; /* default */
1938 }
1939 #endif
1940
1941
1942 /*
1943 * UtilityContainsQuery
1944 * Return the contained Query, or NULL if there is none
1945 *
1946 * Certain utility statements, such as EXPLAIN, contain a plannable Query.
1947 * This function encapsulates knowledge of exactly which ones do.
1948 * We assume it is invoked only on already-parse-analyzed statements
1949 * (else the contained parsetree isn't a Query yet).
1950 *
1951 * In some cases (currently, only EXPLAIN of CREATE TABLE AS/SELECT INTO and
1952 * CREATE MATERIALIZED VIEW), potentially Query-containing utility statements
1953 * can be nested. This function will drill down to a non-utility Query, or
1954 * return NULL if none.
1955 */
1956 Query *
UtilityContainsQuery(Node * parsetree)1957 UtilityContainsQuery(Node *parsetree)
1958 {
1959 Query *qry;
1960
1961 switch (nodeTag(parsetree))
1962 {
1963 case T_DeclareCursorStmt:
1964 qry = castNode(Query, ((DeclareCursorStmt *) parsetree)->query);
1965 if (qry->commandType == CMD_UTILITY)
1966 return UtilityContainsQuery(qry->utilityStmt);
1967 return qry;
1968
1969 case T_ExplainStmt:
1970 qry = castNode(Query, ((ExplainStmt *) parsetree)->query);
1971 if (qry->commandType == CMD_UTILITY)
1972 return UtilityContainsQuery(qry->utilityStmt);
1973 return qry;
1974
1975 case T_CreateTableAsStmt:
1976 qry = castNode(Query, ((CreateTableAsStmt *) parsetree)->query);
1977 if (qry->commandType == CMD_UTILITY)
1978 return UtilityContainsQuery(qry->utilityStmt);
1979 return qry;
1980
1981 default:
1982 return NULL;
1983 }
1984 }
1985
1986
1987 /*
1988 * AlterObjectTypeCommandTag
1989 * helper function for CreateCommandTag
1990 *
1991 * This covers most cases where ALTER is used with an ObjectType enum.
1992 */
1993 static const char *
AlterObjectTypeCommandTag(ObjectType objtype)1994 AlterObjectTypeCommandTag(ObjectType objtype)
1995 {
1996 const char *tag;
1997
1998 switch (objtype)
1999 {
2000 case OBJECT_AGGREGATE:
2001 tag = "ALTER AGGREGATE";
2002 break;
2003 case OBJECT_ATTRIBUTE:
2004 tag = "ALTER TYPE";
2005 break;
2006 case OBJECT_CAST:
2007 tag = "ALTER CAST";
2008 break;
2009 case OBJECT_COLLATION:
2010 tag = "ALTER COLLATION";
2011 break;
2012 case OBJECT_COLUMN:
2013 tag = "ALTER TABLE";
2014 break;
2015 case OBJECT_CONVERSION:
2016 tag = "ALTER CONVERSION";
2017 break;
2018 case OBJECT_DATABASE:
2019 tag = "ALTER DATABASE";
2020 break;
2021 case OBJECT_DOMAIN:
2022 case OBJECT_DOMCONSTRAINT:
2023 tag = "ALTER DOMAIN";
2024 break;
2025 case OBJECT_EXTENSION:
2026 tag = "ALTER EXTENSION";
2027 break;
2028 case OBJECT_FDW:
2029 tag = "ALTER FOREIGN DATA WRAPPER";
2030 break;
2031 case OBJECT_FOREIGN_SERVER:
2032 tag = "ALTER SERVER";
2033 break;
2034 case OBJECT_FOREIGN_TABLE:
2035 tag = "ALTER FOREIGN TABLE";
2036 break;
2037 case OBJECT_FUNCTION:
2038 tag = "ALTER FUNCTION";
2039 break;
2040 case OBJECT_INDEX:
2041 tag = "ALTER INDEX";
2042 break;
2043 case OBJECT_LANGUAGE:
2044 tag = "ALTER LANGUAGE";
2045 break;
2046 case OBJECT_LARGEOBJECT:
2047 tag = "ALTER LARGE OBJECT";
2048 break;
2049 case OBJECT_OPCLASS:
2050 tag = "ALTER OPERATOR CLASS";
2051 break;
2052 case OBJECT_OPERATOR:
2053 tag = "ALTER OPERATOR";
2054 break;
2055 case OBJECT_OPFAMILY:
2056 tag = "ALTER OPERATOR FAMILY";
2057 break;
2058 case OBJECT_POLICY:
2059 tag = "ALTER POLICY";
2060 break;
2061 case OBJECT_PROCEDURE:
2062 tag = "ALTER PROCEDURE";
2063 break;
2064 case OBJECT_ROLE:
2065 tag = "ALTER ROLE";
2066 break;
2067 case OBJECT_ROUTINE:
2068 tag = "ALTER ROUTINE";
2069 break;
2070 case OBJECT_RULE:
2071 tag = "ALTER RULE";
2072 break;
2073 case OBJECT_SCHEMA:
2074 tag = "ALTER SCHEMA";
2075 break;
2076 case OBJECT_SEQUENCE:
2077 tag = "ALTER SEQUENCE";
2078 break;
2079 case OBJECT_TABLE:
2080 case OBJECT_TABCONSTRAINT:
2081 tag = "ALTER TABLE";
2082 break;
2083 case OBJECT_TABLESPACE:
2084 tag = "ALTER TABLESPACE";
2085 break;
2086 case OBJECT_TRIGGER:
2087 tag = "ALTER TRIGGER";
2088 break;
2089 case OBJECT_EVENT_TRIGGER:
2090 tag = "ALTER EVENT TRIGGER";
2091 break;
2092 case OBJECT_TSCONFIGURATION:
2093 tag = "ALTER TEXT SEARCH CONFIGURATION";
2094 break;
2095 case OBJECT_TSDICTIONARY:
2096 tag = "ALTER TEXT SEARCH DICTIONARY";
2097 break;
2098 case OBJECT_TSPARSER:
2099 tag = "ALTER TEXT SEARCH PARSER";
2100 break;
2101 case OBJECT_TSTEMPLATE:
2102 tag = "ALTER TEXT SEARCH TEMPLATE";
2103 break;
2104 case OBJECT_TYPE:
2105 tag = "ALTER TYPE";
2106 break;
2107 case OBJECT_VIEW:
2108 tag = "ALTER VIEW";
2109 break;
2110 case OBJECT_MATVIEW:
2111 tag = "ALTER MATERIALIZED VIEW";
2112 break;
2113 case OBJECT_PUBLICATION:
2114 tag = "ALTER PUBLICATION";
2115 break;
2116 case OBJECT_SUBSCRIPTION:
2117 tag = "ALTER SUBSCRIPTION";
2118 break;
2119 case OBJECT_STATISTIC_EXT:
2120 tag = "ALTER STATISTICS";
2121 break;
2122 default:
2123 tag = "???";
2124 break;
2125 }
2126
2127 return tag;
2128 }
2129
2130 /*
2131 * CreateCommandTag
2132 * utility to get a string representation of the command operation,
2133 * given either a raw (un-analyzed) parsetree, an analyzed Query,
2134 * or a PlannedStmt.
2135 *
2136 * This must handle all command types, but since the vast majority
2137 * of 'em are utility commands, it seems sensible to keep it here.
2138 *
2139 * NB: all result strings must be shorter than COMPLETION_TAG_BUFSIZE.
2140 * Also, the result must point at a true constant (permanent storage).
2141 */
2142 const char *
CreateCommandTag(Node * parsetree)2143 CreateCommandTag(Node *parsetree)
2144 {
2145 const char *tag;
2146
2147 switch (nodeTag(parsetree))
2148 {
2149 /* recurse if we're given a RawStmt */
2150 case T_RawStmt:
2151 tag = CreateCommandTag(((RawStmt *) parsetree)->stmt);
2152 break;
2153
2154 /* raw plannable queries */
2155 case T_InsertStmt:
2156 tag = "INSERT";
2157 break;
2158
2159 case T_DeleteStmt:
2160 tag = "DELETE";
2161 break;
2162
2163 case T_UpdateStmt:
2164 tag = "UPDATE";
2165 break;
2166
2167 case T_SelectStmt:
2168 tag = "SELECT";
2169 break;
2170
2171 /* utility statements --- same whether raw or cooked */
2172 case T_TransactionStmt:
2173 {
2174 TransactionStmt *stmt = (TransactionStmt *) parsetree;
2175
2176 switch (stmt->kind)
2177 {
2178 case TRANS_STMT_BEGIN:
2179 tag = "BEGIN";
2180 break;
2181
2182 case TRANS_STMT_START:
2183 tag = "START TRANSACTION";
2184 break;
2185
2186 case TRANS_STMT_COMMIT:
2187 tag = "COMMIT";
2188 break;
2189
2190 case TRANS_STMT_ROLLBACK:
2191 case TRANS_STMT_ROLLBACK_TO:
2192 tag = "ROLLBACK";
2193 break;
2194
2195 case TRANS_STMT_SAVEPOINT:
2196 tag = "SAVEPOINT";
2197 break;
2198
2199 case TRANS_STMT_RELEASE:
2200 tag = "RELEASE";
2201 break;
2202
2203 case TRANS_STMT_PREPARE:
2204 tag = "PREPARE TRANSACTION";
2205 break;
2206
2207 case TRANS_STMT_COMMIT_PREPARED:
2208 tag = "COMMIT PREPARED";
2209 break;
2210
2211 case TRANS_STMT_ROLLBACK_PREPARED:
2212 tag = "ROLLBACK PREPARED";
2213 break;
2214
2215 default:
2216 tag = "???";
2217 break;
2218 }
2219 }
2220 break;
2221
2222 case T_DeclareCursorStmt:
2223 tag = "DECLARE CURSOR";
2224 break;
2225
2226 case T_ClosePortalStmt:
2227 {
2228 ClosePortalStmt *stmt = (ClosePortalStmt *) parsetree;
2229
2230 if (stmt->portalname == NULL)
2231 tag = "CLOSE CURSOR ALL";
2232 else
2233 tag = "CLOSE CURSOR";
2234 }
2235 break;
2236
2237 case T_FetchStmt:
2238 {
2239 FetchStmt *stmt = (FetchStmt *) parsetree;
2240
2241 tag = (stmt->ismove) ? "MOVE" : "FETCH";
2242 }
2243 break;
2244
2245 case T_CreateDomainStmt:
2246 tag = "CREATE DOMAIN";
2247 break;
2248
2249 case T_CreateSchemaStmt:
2250 tag = "CREATE SCHEMA";
2251 break;
2252
2253 case T_CreateStmt:
2254 tag = "CREATE TABLE";
2255 break;
2256
2257 case T_CreateTableSpaceStmt:
2258 tag = "CREATE TABLESPACE";
2259 break;
2260
2261 case T_DropTableSpaceStmt:
2262 tag = "DROP TABLESPACE";
2263 break;
2264
2265 case T_AlterTableSpaceOptionsStmt:
2266 tag = "ALTER TABLESPACE";
2267 break;
2268
2269 case T_CreateExtensionStmt:
2270 tag = "CREATE EXTENSION";
2271 break;
2272
2273 case T_AlterExtensionStmt:
2274 tag = "ALTER EXTENSION";
2275 break;
2276
2277 case T_AlterExtensionContentsStmt:
2278 tag = "ALTER EXTENSION";
2279 break;
2280
2281 case T_CreateFdwStmt:
2282 tag = "CREATE FOREIGN DATA WRAPPER";
2283 break;
2284
2285 case T_AlterFdwStmt:
2286 tag = "ALTER FOREIGN DATA WRAPPER";
2287 break;
2288
2289 case T_CreateForeignServerStmt:
2290 tag = "CREATE SERVER";
2291 break;
2292
2293 case T_AlterForeignServerStmt:
2294 tag = "ALTER SERVER";
2295 break;
2296
2297 case T_CreateUserMappingStmt:
2298 tag = "CREATE USER MAPPING";
2299 break;
2300
2301 case T_AlterUserMappingStmt:
2302 tag = "ALTER USER MAPPING";
2303 break;
2304
2305 case T_DropUserMappingStmt:
2306 tag = "DROP USER MAPPING";
2307 break;
2308
2309 case T_CreateForeignTableStmt:
2310 tag = "CREATE FOREIGN TABLE";
2311 break;
2312
2313 case T_ImportForeignSchemaStmt:
2314 tag = "IMPORT FOREIGN SCHEMA";
2315 break;
2316
2317 case T_DropStmt:
2318 switch (((DropStmt *) parsetree)->removeType)
2319 {
2320 case OBJECT_TABLE:
2321 tag = "DROP TABLE";
2322 break;
2323 case OBJECT_SEQUENCE:
2324 tag = "DROP SEQUENCE";
2325 break;
2326 case OBJECT_VIEW:
2327 tag = "DROP VIEW";
2328 break;
2329 case OBJECT_MATVIEW:
2330 tag = "DROP MATERIALIZED VIEW";
2331 break;
2332 case OBJECT_INDEX:
2333 tag = "DROP INDEX";
2334 break;
2335 case OBJECT_TYPE:
2336 tag = "DROP TYPE";
2337 break;
2338 case OBJECT_DOMAIN:
2339 tag = "DROP DOMAIN";
2340 break;
2341 case OBJECT_COLLATION:
2342 tag = "DROP COLLATION";
2343 break;
2344 case OBJECT_CONVERSION:
2345 tag = "DROP CONVERSION";
2346 break;
2347 case OBJECT_SCHEMA:
2348 tag = "DROP SCHEMA";
2349 break;
2350 case OBJECT_TSPARSER:
2351 tag = "DROP TEXT SEARCH PARSER";
2352 break;
2353 case OBJECT_TSDICTIONARY:
2354 tag = "DROP TEXT SEARCH DICTIONARY";
2355 break;
2356 case OBJECT_TSTEMPLATE:
2357 tag = "DROP TEXT SEARCH TEMPLATE";
2358 break;
2359 case OBJECT_TSCONFIGURATION:
2360 tag = "DROP TEXT SEARCH CONFIGURATION";
2361 break;
2362 case OBJECT_FOREIGN_TABLE:
2363 tag = "DROP FOREIGN TABLE";
2364 break;
2365 case OBJECT_EXTENSION:
2366 tag = "DROP EXTENSION";
2367 break;
2368 case OBJECT_FUNCTION:
2369 tag = "DROP FUNCTION";
2370 break;
2371 case OBJECT_PROCEDURE:
2372 tag = "DROP PROCEDURE";
2373 break;
2374 case OBJECT_ROUTINE:
2375 tag = "DROP ROUTINE";
2376 break;
2377 case OBJECT_AGGREGATE:
2378 tag = "DROP AGGREGATE";
2379 break;
2380 case OBJECT_OPERATOR:
2381 tag = "DROP OPERATOR";
2382 break;
2383 case OBJECT_LANGUAGE:
2384 tag = "DROP LANGUAGE";
2385 break;
2386 case OBJECT_CAST:
2387 tag = "DROP CAST";
2388 break;
2389 case OBJECT_TRIGGER:
2390 tag = "DROP TRIGGER";
2391 break;
2392 case OBJECT_EVENT_TRIGGER:
2393 tag = "DROP EVENT TRIGGER";
2394 break;
2395 case OBJECT_RULE:
2396 tag = "DROP RULE";
2397 break;
2398 case OBJECT_FDW:
2399 tag = "DROP FOREIGN DATA WRAPPER";
2400 break;
2401 case OBJECT_FOREIGN_SERVER:
2402 tag = "DROP SERVER";
2403 break;
2404 case OBJECT_OPCLASS:
2405 tag = "DROP OPERATOR CLASS";
2406 break;
2407 case OBJECT_OPFAMILY:
2408 tag = "DROP OPERATOR FAMILY";
2409 break;
2410 case OBJECT_POLICY:
2411 tag = "DROP POLICY";
2412 break;
2413 case OBJECT_TRANSFORM:
2414 tag = "DROP TRANSFORM";
2415 break;
2416 case OBJECT_ACCESS_METHOD:
2417 tag = "DROP ACCESS METHOD";
2418 break;
2419 case OBJECT_PUBLICATION:
2420 tag = "DROP PUBLICATION";
2421 break;
2422 case OBJECT_STATISTIC_EXT:
2423 tag = "DROP STATISTICS";
2424 break;
2425 default:
2426 tag = "???";
2427 }
2428 break;
2429
2430 case T_TruncateStmt:
2431 tag = "TRUNCATE TABLE";
2432 break;
2433
2434 case T_CommentStmt:
2435 tag = "COMMENT";
2436 break;
2437
2438 case T_SecLabelStmt:
2439 tag = "SECURITY LABEL";
2440 break;
2441
2442 case T_CopyStmt:
2443 tag = "COPY";
2444 break;
2445
2446 case T_RenameStmt:
2447 tag = AlterObjectTypeCommandTag(((RenameStmt *) parsetree)->renameType);
2448 break;
2449
2450 case T_AlterObjectDependsStmt:
2451 tag = AlterObjectTypeCommandTag(((AlterObjectDependsStmt *) parsetree)->objectType);
2452 break;
2453
2454 case T_AlterObjectSchemaStmt:
2455 tag = AlterObjectTypeCommandTag(((AlterObjectSchemaStmt *) parsetree)->objectType);
2456 break;
2457
2458 case T_AlterOwnerStmt:
2459 tag = AlterObjectTypeCommandTag(((AlterOwnerStmt *) parsetree)->objectType);
2460 break;
2461
2462 case T_AlterTableMoveAllStmt:
2463 tag = AlterObjectTypeCommandTag(((AlterTableMoveAllStmt *) parsetree)->objtype);
2464 break;
2465
2466 case T_AlterTableStmt:
2467 tag = AlterObjectTypeCommandTag(((AlterTableStmt *) parsetree)->relkind);
2468 break;
2469
2470 case T_AlterDomainStmt:
2471 tag = "ALTER DOMAIN";
2472 break;
2473
2474 case T_AlterFunctionStmt:
2475 switch (((AlterFunctionStmt *) parsetree)->objtype)
2476 {
2477 case OBJECT_FUNCTION:
2478 tag = "ALTER FUNCTION";
2479 break;
2480 case OBJECT_PROCEDURE:
2481 tag = "ALTER PROCEDURE";
2482 break;
2483 case OBJECT_ROUTINE:
2484 tag = "ALTER ROUTINE";
2485 break;
2486 default:
2487 tag = "???";
2488 }
2489 break;
2490
2491 case T_GrantStmt:
2492 {
2493 GrantStmt *stmt = (GrantStmt *) parsetree;
2494
2495 tag = (stmt->is_grant) ? "GRANT" : "REVOKE";
2496 }
2497 break;
2498
2499 case T_GrantRoleStmt:
2500 {
2501 GrantRoleStmt *stmt = (GrantRoleStmt *) parsetree;
2502
2503 tag = (stmt->is_grant) ? "GRANT ROLE" : "REVOKE ROLE";
2504 }
2505 break;
2506
2507 case T_AlterDefaultPrivilegesStmt:
2508 tag = "ALTER DEFAULT PRIVILEGES";
2509 break;
2510
2511 case T_DefineStmt:
2512 switch (((DefineStmt *) parsetree)->kind)
2513 {
2514 case OBJECT_AGGREGATE:
2515 tag = "CREATE AGGREGATE";
2516 break;
2517 case OBJECT_OPERATOR:
2518 tag = "CREATE OPERATOR";
2519 break;
2520 case OBJECT_TYPE:
2521 tag = "CREATE TYPE";
2522 break;
2523 case OBJECT_TSPARSER:
2524 tag = "CREATE TEXT SEARCH PARSER";
2525 break;
2526 case OBJECT_TSDICTIONARY:
2527 tag = "CREATE TEXT SEARCH DICTIONARY";
2528 break;
2529 case OBJECT_TSTEMPLATE:
2530 tag = "CREATE TEXT SEARCH TEMPLATE";
2531 break;
2532 case OBJECT_TSCONFIGURATION:
2533 tag = "CREATE TEXT SEARCH CONFIGURATION";
2534 break;
2535 case OBJECT_COLLATION:
2536 tag = "CREATE COLLATION";
2537 break;
2538 case OBJECT_ACCESS_METHOD:
2539 tag = "CREATE ACCESS METHOD";
2540 break;
2541 default:
2542 tag = "???";
2543 }
2544 break;
2545
2546 case T_CompositeTypeStmt:
2547 tag = "CREATE TYPE";
2548 break;
2549
2550 case T_CreateEnumStmt:
2551 tag = "CREATE TYPE";
2552 break;
2553
2554 case T_CreateRangeStmt:
2555 tag = "CREATE TYPE";
2556 break;
2557
2558 case T_AlterEnumStmt:
2559 tag = "ALTER TYPE";
2560 break;
2561
2562 case T_ViewStmt:
2563 tag = "CREATE VIEW";
2564 break;
2565
2566 case T_CreateFunctionStmt:
2567 if (((CreateFunctionStmt *) parsetree)->is_procedure)
2568 tag = "CREATE PROCEDURE";
2569 else
2570 tag = "CREATE FUNCTION";
2571 break;
2572
2573 case T_IndexStmt:
2574 tag = "CREATE INDEX";
2575 break;
2576
2577 case T_RuleStmt:
2578 tag = "CREATE RULE";
2579 break;
2580
2581 case T_CreateSeqStmt:
2582 tag = "CREATE SEQUENCE";
2583 break;
2584
2585 case T_AlterSeqStmt:
2586 tag = "ALTER SEQUENCE";
2587 break;
2588
2589 case T_DoStmt:
2590 tag = "DO";
2591 break;
2592
2593 case T_CreatedbStmt:
2594 tag = "CREATE DATABASE";
2595 break;
2596
2597 case T_AlterDatabaseStmt:
2598 tag = "ALTER DATABASE";
2599 break;
2600
2601 case T_AlterDatabaseSetStmt:
2602 tag = "ALTER DATABASE";
2603 break;
2604
2605 case T_DropdbStmt:
2606 tag = "DROP DATABASE";
2607 break;
2608
2609 case T_NotifyStmt:
2610 tag = "NOTIFY";
2611 break;
2612
2613 case T_ListenStmt:
2614 tag = "LISTEN";
2615 break;
2616
2617 case T_UnlistenStmt:
2618 tag = "UNLISTEN";
2619 break;
2620
2621 case T_LoadStmt:
2622 tag = "LOAD";
2623 break;
2624
2625 case T_CallStmt:
2626 tag = "CALL";
2627 break;
2628
2629 case T_ClusterStmt:
2630 tag = "CLUSTER";
2631 break;
2632
2633 case T_VacuumStmt:
2634 if (((VacuumStmt *) parsetree)->is_vacuumcmd)
2635 tag = "VACUUM";
2636 else
2637 tag = "ANALYZE";
2638 break;
2639
2640 case T_ExplainStmt:
2641 tag = "EXPLAIN";
2642 break;
2643
2644 case T_CreateTableAsStmt:
2645 switch (((CreateTableAsStmt *) parsetree)->relkind)
2646 {
2647 case OBJECT_TABLE:
2648 if (((CreateTableAsStmt *) parsetree)->is_select_into)
2649 tag = "SELECT INTO";
2650 else
2651 tag = "CREATE TABLE AS";
2652 break;
2653 case OBJECT_MATVIEW:
2654 tag = "CREATE MATERIALIZED VIEW";
2655 break;
2656 default:
2657 tag = "???";
2658 }
2659 break;
2660
2661 case T_RefreshMatViewStmt:
2662 tag = "REFRESH MATERIALIZED VIEW";
2663 break;
2664
2665 case T_AlterSystemStmt:
2666 tag = "ALTER SYSTEM";
2667 break;
2668
2669 case T_VariableSetStmt:
2670 switch (((VariableSetStmt *) parsetree)->kind)
2671 {
2672 case VAR_SET_VALUE:
2673 case VAR_SET_CURRENT:
2674 case VAR_SET_DEFAULT:
2675 case VAR_SET_MULTI:
2676 tag = "SET";
2677 break;
2678 case VAR_RESET:
2679 case VAR_RESET_ALL:
2680 tag = "RESET";
2681 break;
2682 default:
2683 tag = "???";
2684 }
2685 break;
2686
2687 case T_VariableShowStmt:
2688 tag = "SHOW";
2689 break;
2690
2691 case T_DiscardStmt:
2692 switch (((DiscardStmt *) parsetree)->target)
2693 {
2694 case DISCARD_ALL:
2695 tag = "DISCARD ALL";
2696 break;
2697 case DISCARD_PLANS:
2698 tag = "DISCARD PLANS";
2699 break;
2700 case DISCARD_TEMP:
2701 tag = "DISCARD TEMP";
2702 break;
2703 case DISCARD_SEQUENCES:
2704 tag = "DISCARD SEQUENCES";
2705 break;
2706 default:
2707 tag = "???";
2708 }
2709 break;
2710
2711 case T_CreateTransformStmt:
2712 tag = "CREATE TRANSFORM";
2713 break;
2714
2715 case T_CreateTrigStmt:
2716 tag = "CREATE TRIGGER";
2717 break;
2718
2719 case T_CreateEventTrigStmt:
2720 tag = "CREATE EVENT TRIGGER";
2721 break;
2722
2723 case T_AlterEventTrigStmt:
2724 tag = "ALTER EVENT TRIGGER";
2725 break;
2726
2727 case T_CreatePLangStmt:
2728 tag = "CREATE LANGUAGE";
2729 break;
2730
2731 case T_CreateRoleStmt:
2732 tag = "CREATE ROLE";
2733 break;
2734
2735 case T_AlterRoleStmt:
2736 tag = "ALTER ROLE";
2737 break;
2738
2739 case T_AlterRoleSetStmt:
2740 tag = "ALTER ROLE";
2741 break;
2742
2743 case T_DropRoleStmt:
2744 tag = "DROP ROLE";
2745 break;
2746
2747 case T_DropOwnedStmt:
2748 tag = "DROP OWNED";
2749 break;
2750
2751 case T_ReassignOwnedStmt:
2752 tag = "REASSIGN OWNED";
2753 break;
2754
2755 case T_LockStmt:
2756 tag = "LOCK TABLE";
2757 break;
2758
2759 case T_ConstraintsSetStmt:
2760 tag = "SET CONSTRAINTS";
2761 break;
2762
2763 case T_CheckPointStmt:
2764 tag = "CHECKPOINT";
2765 break;
2766
2767 case T_ReindexStmt:
2768 tag = "REINDEX";
2769 break;
2770
2771 case T_CreateConversionStmt:
2772 tag = "CREATE CONVERSION";
2773 break;
2774
2775 case T_CreateCastStmt:
2776 tag = "CREATE CAST";
2777 break;
2778
2779 case T_CreateOpClassStmt:
2780 tag = "CREATE OPERATOR CLASS";
2781 break;
2782
2783 case T_CreateOpFamilyStmt:
2784 tag = "CREATE OPERATOR FAMILY";
2785 break;
2786
2787 case T_AlterOpFamilyStmt:
2788 tag = "ALTER OPERATOR FAMILY";
2789 break;
2790
2791 case T_AlterOperatorStmt:
2792 tag = "ALTER OPERATOR";
2793 break;
2794
2795 case T_AlterTSDictionaryStmt:
2796 tag = "ALTER TEXT SEARCH DICTIONARY";
2797 break;
2798
2799 case T_AlterTSConfigurationStmt:
2800 tag = "ALTER TEXT SEARCH CONFIGURATION";
2801 break;
2802
2803 case T_CreatePolicyStmt:
2804 tag = "CREATE POLICY";
2805 break;
2806
2807 case T_AlterPolicyStmt:
2808 tag = "ALTER POLICY";
2809 break;
2810
2811 case T_CreateAmStmt:
2812 tag = "CREATE ACCESS METHOD";
2813 break;
2814
2815 case T_CreatePublicationStmt:
2816 tag = "CREATE PUBLICATION";
2817 break;
2818
2819 case T_AlterPublicationStmt:
2820 tag = "ALTER PUBLICATION";
2821 break;
2822
2823 case T_CreateSubscriptionStmt:
2824 tag = "CREATE SUBSCRIPTION";
2825 break;
2826
2827 case T_AlterSubscriptionStmt:
2828 tag = "ALTER SUBSCRIPTION";
2829 break;
2830
2831 case T_DropSubscriptionStmt:
2832 tag = "DROP SUBSCRIPTION";
2833 break;
2834
2835 case T_AlterCollationStmt:
2836 tag = "ALTER COLLATION";
2837 break;
2838
2839 case T_PrepareStmt:
2840 tag = "PREPARE";
2841 break;
2842
2843 case T_ExecuteStmt:
2844 tag = "EXECUTE";
2845 break;
2846
2847 case T_CreateStatsStmt:
2848 tag = "CREATE STATISTICS";
2849 break;
2850
2851 case T_DeallocateStmt:
2852 {
2853 DeallocateStmt *stmt = (DeallocateStmt *) parsetree;
2854
2855 if (stmt->name == NULL)
2856 tag = "DEALLOCATE ALL";
2857 else
2858 tag = "DEALLOCATE";
2859 }
2860 break;
2861
2862 /* already-planned queries */
2863 case T_PlannedStmt:
2864 {
2865 PlannedStmt *stmt = (PlannedStmt *) parsetree;
2866
2867 switch (stmt->commandType)
2868 {
2869 case CMD_SELECT:
2870
2871 /*
2872 * We take a little extra care here so that the result
2873 * will be useful for complaints about read-only
2874 * statements
2875 */
2876 if (stmt->rowMarks != NIL)
2877 {
2878 /* not 100% but probably close enough */
2879 switch (((PlanRowMark *) linitial(stmt->rowMarks))->strength)
2880 {
2881 case LCS_FORKEYSHARE:
2882 tag = "SELECT FOR KEY SHARE";
2883 break;
2884 case LCS_FORSHARE:
2885 tag = "SELECT FOR SHARE";
2886 break;
2887 case LCS_FORNOKEYUPDATE:
2888 tag = "SELECT FOR NO KEY UPDATE";
2889 break;
2890 case LCS_FORUPDATE:
2891 tag = "SELECT FOR UPDATE";
2892 break;
2893 default:
2894 tag = "SELECT";
2895 break;
2896 }
2897 }
2898 else
2899 tag = "SELECT";
2900 break;
2901 case CMD_UPDATE:
2902 tag = "UPDATE";
2903 break;
2904 case CMD_INSERT:
2905 tag = "INSERT";
2906 break;
2907 case CMD_DELETE:
2908 tag = "DELETE";
2909 break;
2910 case CMD_UTILITY:
2911 tag = CreateCommandTag(stmt->utilityStmt);
2912 break;
2913 default:
2914 elog(WARNING, "unrecognized commandType: %d",
2915 (int) stmt->commandType);
2916 tag = "???";
2917 break;
2918 }
2919 }
2920 break;
2921
2922 /* parsed-and-rewritten-but-not-planned queries */
2923 case T_Query:
2924 {
2925 Query *stmt = (Query *) parsetree;
2926
2927 switch (stmt->commandType)
2928 {
2929 case CMD_SELECT:
2930
2931 /*
2932 * We take a little extra care here so that the result
2933 * will be useful for complaints about read-only
2934 * statements
2935 */
2936 if (stmt->rowMarks != NIL)
2937 {
2938 /* not 100% but probably close enough */
2939 switch (((RowMarkClause *) linitial(stmt->rowMarks))->strength)
2940 {
2941 case LCS_FORKEYSHARE:
2942 tag = "SELECT FOR KEY SHARE";
2943 break;
2944 case LCS_FORSHARE:
2945 tag = "SELECT FOR SHARE";
2946 break;
2947 case LCS_FORNOKEYUPDATE:
2948 tag = "SELECT FOR NO KEY UPDATE";
2949 break;
2950 case LCS_FORUPDATE:
2951 tag = "SELECT FOR UPDATE";
2952 break;
2953 default:
2954 tag = "???";
2955 break;
2956 }
2957 }
2958 else
2959 tag = "SELECT";
2960 break;
2961 case CMD_UPDATE:
2962 tag = "UPDATE";
2963 break;
2964 case CMD_INSERT:
2965 tag = "INSERT";
2966 break;
2967 case CMD_DELETE:
2968 tag = "DELETE";
2969 break;
2970 case CMD_UTILITY:
2971 tag = CreateCommandTag(stmt->utilityStmt);
2972 break;
2973 default:
2974 elog(WARNING, "unrecognized commandType: %d",
2975 (int) stmt->commandType);
2976 tag = "???";
2977 break;
2978 }
2979 }
2980 break;
2981
2982 default:
2983 elog(WARNING, "unrecognized node type: %d",
2984 (int) nodeTag(parsetree));
2985 tag = "???";
2986 break;
2987 }
2988
2989 return tag;
2990 }
2991
2992
2993 /*
2994 * GetCommandLogLevel
2995 * utility to get the minimum log_statement level for a command,
2996 * given either a raw (un-analyzed) parsetree, an analyzed Query,
2997 * or a PlannedStmt.
2998 *
2999 * This must handle all command types, but since the vast majority
3000 * of 'em are utility commands, it seems sensible to keep it here.
3001 */
3002 LogStmtLevel
GetCommandLogLevel(Node * parsetree)3003 GetCommandLogLevel(Node *parsetree)
3004 {
3005 LogStmtLevel lev;
3006
3007 switch (nodeTag(parsetree))
3008 {
3009 /* recurse if we're given a RawStmt */
3010 case T_RawStmt:
3011 lev = GetCommandLogLevel(((RawStmt *) parsetree)->stmt);
3012 break;
3013
3014 /* raw plannable queries */
3015 case T_InsertStmt:
3016 case T_DeleteStmt:
3017 case T_UpdateStmt:
3018 lev = LOGSTMT_MOD;
3019 break;
3020
3021 case T_SelectStmt:
3022 if (((SelectStmt *) parsetree)->intoClause)
3023 lev = LOGSTMT_DDL; /* SELECT INTO */
3024 else
3025 lev = LOGSTMT_ALL;
3026 break;
3027
3028 /* utility statements --- same whether raw or cooked */
3029 case T_TransactionStmt:
3030 lev = LOGSTMT_ALL;
3031 break;
3032
3033 case T_DeclareCursorStmt:
3034 lev = LOGSTMT_ALL;
3035 break;
3036
3037 case T_ClosePortalStmt:
3038 lev = LOGSTMT_ALL;
3039 break;
3040
3041 case T_FetchStmt:
3042 lev = LOGSTMT_ALL;
3043 break;
3044
3045 case T_CreateSchemaStmt:
3046 lev = LOGSTMT_DDL;
3047 break;
3048
3049 case T_CreateStmt:
3050 case T_CreateForeignTableStmt:
3051 lev = LOGSTMT_DDL;
3052 break;
3053
3054 case T_CreateTableSpaceStmt:
3055 case T_DropTableSpaceStmt:
3056 case T_AlterTableSpaceOptionsStmt:
3057 lev = LOGSTMT_DDL;
3058 break;
3059
3060 case T_CreateExtensionStmt:
3061 case T_AlterExtensionStmt:
3062 case T_AlterExtensionContentsStmt:
3063 lev = LOGSTMT_DDL;
3064 break;
3065
3066 case T_CreateFdwStmt:
3067 case T_AlterFdwStmt:
3068 case T_CreateForeignServerStmt:
3069 case T_AlterForeignServerStmt:
3070 case T_CreateUserMappingStmt:
3071 case T_AlterUserMappingStmt:
3072 case T_DropUserMappingStmt:
3073 case T_ImportForeignSchemaStmt:
3074 lev = LOGSTMT_DDL;
3075 break;
3076
3077 case T_DropStmt:
3078 lev = LOGSTMT_DDL;
3079 break;
3080
3081 case T_TruncateStmt:
3082 lev = LOGSTMT_MOD;
3083 break;
3084
3085 case T_CommentStmt:
3086 lev = LOGSTMT_DDL;
3087 break;
3088
3089 case T_SecLabelStmt:
3090 lev = LOGSTMT_DDL;
3091 break;
3092
3093 case T_CopyStmt:
3094 if (((CopyStmt *) parsetree)->is_from)
3095 lev = LOGSTMT_MOD;
3096 else
3097 lev = LOGSTMT_ALL;
3098 break;
3099
3100 case T_PrepareStmt:
3101 {
3102 PrepareStmt *stmt = (PrepareStmt *) parsetree;
3103
3104 /* Look through a PREPARE to the contained stmt */
3105 lev = GetCommandLogLevel(stmt->query);
3106 }
3107 break;
3108
3109 case T_ExecuteStmt:
3110 {
3111 ExecuteStmt *stmt = (ExecuteStmt *) parsetree;
3112 PreparedStatement *ps;
3113
3114 /* Look through an EXECUTE to the referenced stmt */
3115 ps = FetchPreparedStatement(stmt->name, false);
3116 if (ps && ps->plansource->raw_parse_tree)
3117 lev = GetCommandLogLevel(ps->plansource->raw_parse_tree->stmt);
3118 else
3119 lev = LOGSTMT_ALL;
3120 }
3121 break;
3122
3123 case T_DeallocateStmt:
3124 lev = LOGSTMT_ALL;
3125 break;
3126
3127 case T_RenameStmt:
3128 lev = LOGSTMT_DDL;
3129 break;
3130
3131 case T_AlterObjectDependsStmt:
3132 lev = LOGSTMT_DDL;
3133 break;
3134
3135 case T_AlterObjectSchemaStmt:
3136 lev = LOGSTMT_DDL;
3137 break;
3138
3139 case T_AlterOwnerStmt:
3140 lev = LOGSTMT_DDL;
3141 break;
3142
3143 case T_AlterOperatorStmt:
3144 lev = LOGSTMT_DDL;
3145 break;
3146
3147 case T_AlterTableMoveAllStmt:
3148 case T_AlterTableStmt:
3149 lev = LOGSTMT_DDL;
3150 break;
3151
3152 case T_AlterDomainStmt:
3153 lev = LOGSTMT_DDL;
3154 break;
3155
3156 case T_GrantStmt:
3157 lev = LOGSTMT_DDL;
3158 break;
3159
3160 case T_GrantRoleStmt:
3161 lev = LOGSTMT_DDL;
3162 break;
3163
3164 case T_AlterDefaultPrivilegesStmt:
3165 lev = LOGSTMT_DDL;
3166 break;
3167
3168 case T_DefineStmt:
3169 lev = LOGSTMT_DDL;
3170 break;
3171
3172 case T_CompositeTypeStmt:
3173 lev = LOGSTMT_DDL;
3174 break;
3175
3176 case T_CreateEnumStmt:
3177 lev = LOGSTMT_DDL;
3178 break;
3179
3180 case T_CreateRangeStmt:
3181 lev = LOGSTMT_DDL;
3182 break;
3183
3184 case T_AlterEnumStmt:
3185 lev = LOGSTMT_DDL;
3186 break;
3187
3188 case T_ViewStmt:
3189 lev = LOGSTMT_DDL;
3190 break;
3191
3192 case T_CreateFunctionStmt:
3193 lev = LOGSTMT_DDL;
3194 break;
3195
3196 case T_AlterFunctionStmt:
3197 lev = LOGSTMT_DDL;
3198 break;
3199
3200 case T_IndexStmt:
3201 lev = LOGSTMT_DDL;
3202 break;
3203
3204 case T_RuleStmt:
3205 lev = LOGSTMT_DDL;
3206 break;
3207
3208 case T_CreateSeqStmt:
3209 lev = LOGSTMT_DDL;
3210 break;
3211
3212 case T_AlterSeqStmt:
3213 lev = LOGSTMT_DDL;
3214 break;
3215
3216 case T_DoStmt:
3217 lev = LOGSTMT_ALL;
3218 break;
3219
3220 case T_CreatedbStmt:
3221 lev = LOGSTMT_DDL;
3222 break;
3223
3224 case T_AlterDatabaseStmt:
3225 lev = LOGSTMT_DDL;
3226 break;
3227
3228 case T_AlterDatabaseSetStmt:
3229 lev = LOGSTMT_DDL;
3230 break;
3231
3232 case T_DropdbStmt:
3233 lev = LOGSTMT_DDL;
3234 break;
3235
3236 case T_NotifyStmt:
3237 lev = LOGSTMT_ALL;
3238 break;
3239
3240 case T_ListenStmt:
3241 lev = LOGSTMT_ALL;
3242 break;
3243
3244 case T_UnlistenStmt:
3245 lev = LOGSTMT_ALL;
3246 break;
3247
3248 case T_LoadStmt:
3249 lev = LOGSTMT_ALL;
3250 break;
3251
3252 case T_CallStmt:
3253 lev = LOGSTMT_ALL;
3254 break;
3255
3256 case T_ClusterStmt:
3257 lev = LOGSTMT_DDL;
3258 break;
3259
3260 case T_VacuumStmt:
3261 lev = LOGSTMT_ALL;
3262 break;
3263
3264 case T_ExplainStmt:
3265 {
3266 ExplainStmt *stmt = (ExplainStmt *) parsetree;
3267 bool analyze = false;
3268 ListCell *lc;
3269
3270 /* Look through an EXPLAIN ANALYZE to the contained stmt */
3271 foreach(lc, stmt->options)
3272 {
3273 DefElem *opt = (DefElem *) lfirst(lc);
3274
3275 if (strcmp(opt->defname, "analyze") == 0)
3276 analyze = defGetBoolean(opt);
3277 /* don't "break", as explain.c will use the last value */
3278 }
3279 if (analyze)
3280 return GetCommandLogLevel(stmt->query);
3281
3282 /* Plain EXPLAIN isn't so interesting */
3283 lev = LOGSTMT_ALL;
3284 }
3285 break;
3286
3287 case T_CreateTableAsStmt:
3288 lev = LOGSTMT_DDL;
3289 break;
3290
3291 case T_RefreshMatViewStmt:
3292 lev = LOGSTMT_DDL;
3293 break;
3294
3295 case T_AlterSystemStmt:
3296 lev = LOGSTMT_DDL;
3297 break;
3298
3299 case T_VariableSetStmt:
3300 lev = LOGSTMT_ALL;
3301 break;
3302
3303 case T_VariableShowStmt:
3304 lev = LOGSTMT_ALL;
3305 break;
3306
3307 case T_DiscardStmt:
3308 lev = LOGSTMT_ALL;
3309 break;
3310
3311 case T_CreateTrigStmt:
3312 lev = LOGSTMT_DDL;
3313 break;
3314
3315 case T_CreateEventTrigStmt:
3316 lev = LOGSTMT_DDL;
3317 break;
3318
3319 case T_AlterEventTrigStmt:
3320 lev = LOGSTMT_DDL;
3321 break;
3322
3323 case T_CreatePLangStmt:
3324 lev = LOGSTMT_DDL;
3325 break;
3326
3327 case T_CreateDomainStmt:
3328 lev = LOGSTMT_DDL;
3329 break;
3330
3331 case T_CreateRoleStmt:
3332 lev = LOGSTMT_DDL;
3333 break;
3334
3335 case T_AlterRoleStmt:
3336 lev = LOGSTMT_DDL;
3337 break;
3338
3339 case T_AlterRoleSetStmt:
3340 lev = LOGSTMT_DDL;
3341 break;
3342
3343 case T_DropRoleStmt:
3344 lev = LOGSTMT_DDL;
3345 break;
3346
3347 case T_DropOwnedStmt:
3348 lev = LOGSTMT_DDL;
3349 break;
3350
3351 case T_ReassignOwnedStmt:
3352 lev = LOGSTMT_DDL;
3353 break;
3354
3355 case T_LockStmt:
3356 lev = LOGSTMT_ALL;
3357 break;
3358
3359 case T_ConstraintsSetStmt:
3360 lev = LOGSTMT_ALL;
3361 break;
3362
3363 case T_CheckPointStmt:
3364 lev = LOGSTMT_ALL;
3365 break;
3366
3367 case T_ReindexStmt:
3368 lev = LOGSTMT_ALL; /* should this be DDL? */
3369 break;
3370
3371 case T_CreateConversionStmt:
3372 lev = LOGSTMT_DDL;
3373 break;
3374
3375 case T_CreateCastStmt:
3376 lev = LOGSTMT_DDL;
3377 break;
3378
3379 case T_CreateOpClassStmt:
3380 lev = LOGSTMT_DDL;
3381 break;
3382
3383 case T_CreateOpFamilyStmt:
3384 lev = LOGSTMT_DDL;
3385 break;
3386
3387 case T_CreateTransformStmt:
3388 lev = LOGSTMT_DDL;
3389 break;
3390
3391 case T_AlterOpFamilyStmt:
3392 lev = LOGSTMT_DDL;
3393 break;
3394
3395 case T_CreatePolicyStmt:
3396 lev = LOGSTMT_DDL;
3397 break;
3398
3399 case T_AlterPolicyStmt:
3400 lev = LOGSTMT_DDL;
3401 break;
3402
3403 case T_AlterTSDictionaryStmt:
3404 lev = LOGSTMT_DDL;
3405 break;
3406
3407 case T_AlterTSConfigurationStmt:
3408 lev = LOGSTMT_DDL;
3409 break;
3410
3411 case T_CreateAmStmt:
3412 lev = LOGSTMT_DDL;
3413 break;
3414
3415 case T_CreatePublicationStmt:
3416 lev = LOGSTMT_DDL;
3417 break;
3418
3419 case T_AlterPublicationStmt:
3420 lev = LOGSTMT_DDL;
3421 break;
3422
3423 case T_CreateSubscriptionStmt:
3424 lev = LOGSTMT_DDL;
3425 break;
3426
3427 case T_AlterSubscriptionStmt:
3428 lev = LOGSTMT_DDL;
3429 break;
3430
3431 case T_DropSubscriptionStmt:
3432 lev = LOGSTMT_DDL;
3433 break;
3434
3435 case T_CreateStatsStmt:
3436 lev = LOGSTMT_DDL;
3437 break;
3438
3439 case T_AlterCollationStmt:
3440 lev = LOGSTMT_DDL;
3441 break;
3442
3443 /* already-planned queries */
3444 case T_PlannedStmt:
3445 {
3446 PlannedStmt *stmt = (PlannedStmt *) parsetree;
3447
3448 switch (stmt->commandType)
3449 {
3450 case CMD_SELECT:
3451 lev = LOGSTMT_ALL;
3452 break;
3453
3454 case CMD_UPDATE:
3455 case CMD_INSERT:
3456 case CMD_DELETE:
3457 lev = LOGSTMT_MOD;
3458 break;
3459
3460 case CMD_UTILITY:
3461 lev = GetCommandLogLevel(stmt->utilityStmt);
3462 break;
3463
3464 default:
3465 elog(WARNING, "unrecognized commandType: %d",
3466 (int) stmt->commandType);
3467 lev = LOGSTMT_ALL;
3468 break;
3469 }
3470 }
3471 break;
3472
3473 /* parsed-and-rewritten-but-not-planned queries */
3474 case T_Query:
3475 {
3476 Query *stmt = (Query *) parsetree;
3477
3478 switch (stmt->commandType)
3479 {
3480 case CMD_SELECT:
3481 lev = LOGSTMT_ALL;
3482 break;
3483
3484 case CMD_UPDATE:
3485 case CMD_INSERT:
3486 case CMD_DELETE:
3487 lev = LOGSTMT_MOD;
3488 break;
3489
3490 case CMD_UTILITY:
3491 lev = GetCommandLogLevel(stmt->utilityStmt);
3492 break;
3493
3494 default:
3495 elog(WARNING, "unrecognized commandType: %d",
3496 (int) stmt->commandType);
3497 lev = LOGSTMT_ALL;
3498 break;
3499 }
3500
3501 }
3502 break;
3503
3504 default:
3505 elog(WARNING, "unrecognized node type: %d",
3506 (int) nodeTag(parsetree));
3507 lev = LOGSTMT_ALL;
3508 break;
3509 }
3510
3511 return lev;
3512 }
3513