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