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