]> granicus.if.org Git - postgresql/blob - src/backend/tcop/utility.c
85b81fd14b53f3fbda01b19508c72b00247d3b18
[postgresql] / src / backend / tcop / utility.c
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-2005, PostgreSQL Global Development Group
9  * Portions Copyright (c) 1994, Regents of the University of California
10  *
11  *
12  * IDENTIFICATION
13  *        $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.250 2005/11/29 01:25:49 tgl Exp $
14  *
15  *-------------------------------------------------------------------------
16  */
17 #include "postgres.h"
18
19 #include "access/heapam.h"
20 #include "access/twophase.h"
21 #include "catalog/catalog.h"
22 #include "catalog/namespace.h"
23 #include "commands/alter.h"
24 #include "commands/async.h"
25 #include "commands/cluster.h"
26 #include "commands/comment.h"
27 #include "commands/copy.h"
28 #include "commands/conversioncmds.h"
29 #include "commands/dbcommands.h"
30 #include "commands/defrem.h"
31 #include "commands/explain.h"
32 #include "commands/lockcmds.h"
33 #include "commands/portalcmds.h"
34 #include "commands/prepare.h"
35 #include "commands/proclang.h"
36 #include "commands/schemacmds.h"
37 #include "commands/sequence.h"
38 #include "commands/tablecmds.h"
39 #include "commands/tablespace.h"
40 #include "commands/trigger.h"
41 #include "commands/typecmds.h"
42 #include "commands/user.h"
43 #include "commands/vacuum.h"
44 #include "commands/view.h"
45 #include "miscadmin.h"
46 #include "nodes/makefuncs.h"
47 #include "parser/parse_expr.h"
48 #include "parser/parse_type.h"
49 #include "postmaster/bgwriter.h"
50 #include "rewrite/rewriteDefine.h"
51 #include "rewrite/rewriteRemove.h"
52 #include "storage/fd.h"
53 #include "tcop/pquery.h"
54 #include "tcop/utility.h"
55 #include "utils/acl.h"
56 #include "utils/guc.h"
57 #include "utils/lsyscache.h"
58 #include "utils/syscache.h"
59
60
61 /*
62  * Error-checking support for DROP commands
63  */
64
65 struct msgstrings
66 {
67         char            kind;
68         int                     nonexistent_code;
69         const char *nonexistent_msg;
70         const char *skipping_msg;
71         const char *nota_msg;
72         const char *drophint_msg;
73 };
74
75 static const struct msgstrings msgstringarray[] = {
76         {RELKIND_RELATION,
77                 ERRCODE_UNDEFINED_TABLE,
78                 gettext_noop("table \"%s\" does not exist"),
79                 gettext_noop("table \"%s\" does not exist, skipping"),
80                 gettext_noop("\"%s\" is not a table"),
81         gettext_noop("Use DROP TABLE to remove a table.")},
82         {RELKIND_SEQUENCE,
83                 ERRCODE_UNDEFINED_TABLE,
84                 gettext_noop("sequence \"%s\" does not exist"),
85                 gettext_noop("sequence \"%s\" does not exist, skipping"),
86                 gettext_noop("\"%s\" is not a sequence"),
87         gettext_noop("Use DROP SEQUENCE to remove a sequence.")},
88         {RELKIND_VIEW,
89                 ERRCODE_UNDEFINED_TABLE,
90                 gettext_noop("view \"%s\" does not exist"),
91                 gettext_noop("view \"%s\" does not exist, skipping"),
92                 gettext_noop("\"%s\" is not a view"),
93         gettext_noop("Use DROP VIEW to remove a view.")},
94         {RELKIND_INDEX,
95                 ERRCODE_UNDEFINED_OBJECT,
96                 gettext_noop("index \"%s\" does not exist"),
97                 gettext_noop("index \"%s\" does not exist, skipping"),
98                 gettext_noop("\"%s\" is not an index"),
99         gettext_noop("Use DROP INDEX to remove an index.")},
100         {RELKIND_COMPOSITE_TYPE,
101                 ERRCODE_UNDEFINED_OBJECT,
102                 gettext_noop("type \"%s\" does not exist"),
103                 gettext_noop("type \"%s\" does not exist, skipping"),
104                 gettext_noop("\"%s\" is not a type"),
105         gettext_noop("Use DROP TYPE to remove a type.")},
106         {'\0', 0, NULL, NULL, NULL}
107 };
108
109
110 /*
111  * Emit the right error message for a "DROP" command issued on a
112  * relation of the wrong type
113  */
114 static void
115 DropErrorMsgWrongType(char *relname, char wrongkind, char rightkind)
116 {
117         const struct msgstrings *rentry;
118         const struct msgstrings *wentry;
119
120         for (rentry = msgstringarray; rentry->kind != '\0'; rentry++)
121                 if (rentry->kind == rightkind)
122                         break;
123         Assert(rentry->kind != '\0');
124
125         for (wentry = msgstringarray; wentry->kind != '\0'; wentry++)
126                 if (wentry->kind == wrongkind)
127                         break;
128         /* wrongkind could be something we don't have in our table... */
129
130         ereport(ERROR,
131                         (errcode(ERRCODE_WRONG_OBJECT_TYPE),
132                          errmsg(rentry->nota_msg, relname),
133                          (wentry->kind != '\0') ? errhint(wentry->drophint_msg) : 0));
134 }
135
136 /*
137  * Emit the right error message for a "DROP" command issued on a
138  * non-existent relation
139  */
140 static void
141 DropErrorMsgNonExistent(RangeVar *rel, char rightkind, bool missing_ok)
142 {
143         const struct msgstrings *rentry;
144
145         for (rentry = msgstringarray; rentry->kind != '\0'; rentry++)
146         {
147                 if (rentry->kind == rightkind)
148                 {
149                         if (!missing_ok)
150                         {
151                                 ereport(ERROR,
152                                                 (errcode(rentry->nonexistent_code),
153                                                  errmsg(rentry->nonexistent_msg, rel->relname)));
154                         }
155                         else
156                         {
157                                 ereport(NOTICE, (errmsg(rentry->skipping_msg, rel->relname)));
158                                 break;
159                         }
160                 }
161         }
162
163         Assert(rentry->kind != '\0');           /* Should be impossible */
164 }
165
166 /*
167  * returns false if missing_ok is true and the object does not exist,
168  * true if object exists and permissions are OK,
169  * errors otherwise
170  *
171  */
172
173 static bool
174 CheckDropPermissions(RangeVar *rel, char rightkind, bool missing_ok)
175 {
176         Oid                     relOid;
177         HeapTuple       tuple;
178         Form_pg_class classform;
179
180         relOid = RangeVarGetRelid(rel, true);
181         if (!OidIsValid(relOid))
182         {
183                 DropErrorMsgNonExistent(rel, rightkind, missing_ok);
184                 return false;
185         }
186
187         tuple = SearchSysCache(RELOID,
188                                                    ObjectIdGetDatum(relOid),
189                                                    0, 0, 0);
190         if (!HeapTupleIsValid(tuple))
191                 elog(ERROR, "cache lookup failed for relation %u", relOid);
192
193         classform = (Form_pg_class) GETSTRUCT(tuple);
194
195         if (classform->relkind != rightkind)
196                 DropErrorMsgWrongType(rel->relname, classform->relkind,
197                                                           rightkind);
198
199         /* Allow DROP to either table owner or schema owner */
200         if (!pg_class_ownercheck(relOid, GetUserId()) &&
201                 !pg_namespace_ownercheck(classform->relnamespace, GetUserId()))
202                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
203                                            rel->relname);
204
205         if (!allowSystemTableMods && IsSystemClass(classform))
206                 ereport(ERROR,
207                                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
208                                  errmsg("permission denied: \"%s\" is a system catalog",
209                                                 rel->relname)));
210
211         ReleaseSysCache(tuple);
212
213         return true;
214 }
215
216 /*
217  * Verify user has ownership of specified relation, else ereport.
218  *
219  * If noCatalogs is true then we also deny access to system catalogs,
220  * except when allowSystemTableMods is true.
221  */
222 void
223 CheckRelationOwnership(RangeVar *rel, bool noCatalogs)
224 {
225         Oid                     relOid;
226         HeapTuple       tuple;
227
228         relOid = RangeVarGetRelid(rel, false);
229         tuple = SearchSysCache(RELOID,
230                                                    ObjectIdGetDatum(relOid),
231                                                    0, 0, 0);
232         if (!HeapTupleIsValid(tuple))           /* should not happen */
233                 elog(ERROR, "cache lookup failed for relation %u", relOid);
234
235         if (!pg_class_ownercheck(relOid, GetUserId()))
236                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
237                                            rel->relname);
238
239         if (noCatalogs)
240         {
241                 if (!allowSystemTableMods &&
242                         IsSystemClass((Form_pg_class) GETSTRUCT(tuple)))
243                         ereport(ERROR,
244                                         (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
245                                          errmsg("permission denied: \"%s\" is a system catalog",
246                                                         rel->relname)));
247         }
248
249         ReleaseSysCache(tuple);
250 }
251
252
253 /*
254  * QueryIsReadOnly: is an analyzed/rewritten query read-only?
255  *
256  * This is a much stricter test than we apply for XactReadOnly mode;
257  * the query must be *in truth* read-only, because the caller wishes
258  * not to do CommandCounterIncrement for it.
259  */
260 bool
261 QueryIsReadOnly(Query *parsetree)
262 {
263         switch (parsetree->commandType)
264         {
265                 case CMD_SELECT:
266                         if (parsetree->into != NULL)
267                                 return false;   /* SELECT INTO */
268                         else if (parsetree->rowMarks != NIL)
269                                 return false;   /* SELECT FOR UPDATE/SHARE */
270                         else
271                                 return true;
272                 case CMD_UPDATE:
273                 case CMD_INSERT:
274                 case CMD_DELETE:
275                         return false;
276                 case CMD_UTILITY:
277                         /* For now, treat all utility commands as read/write */
278                         return false;
279                 default:
280                         elog(WARNING, "unrecognized commandType: %d",
281                                  (int) parsetree->commandType);
282                         break;
283         }
284         return false;
285 }
286
287 /*
288  * check_xact_readonly: is a utility command read-only?
289  *
290  * Here we use the loose rules of XactReadOnly mode: no permanent effects
291  * on the database are allowed.
292  */
293 static void
294 check_xact_readonly(Node *parsetree)
295 {
296         if (!XactReadOnly)
297                 return;
298
299         /*
300          * Note: Commands that need to do more complicated checking are handled
301          * elsewhere.
302          */
303
304         switch (nodeTag(parsetree))
305         {
306                 case T_AlterDatabaseStmt:
307                 case T_AlterDatabaseSetStmt:
308                 case T_AlterDomainStmt:
309                 case T_AlterFunctionStmt:
310                 case T_AlterRoleStmt:
311                 case T_AlterRoleSetStmt:
312                 case T_AlterObjectSchemaStmt:
313                 case T_AlterOwnerStmt:
314                 case T_AlterSeqStmt:
315                 case T_AlterTableStmt:
316                 case T_RenameStmt:
317                 case T_CommentStmt:
318                 case T_DefineStmt:
319                 case T_CreateCastStmt:
320                 case T_CreateConversionStmt:
321                 case T_CreatedbStmt:
322                 case T_CreateDomainStmt:
323                 case T_CreateFunctionStmt:
324                 case T_CreateRoleStmt:
325                 case T_IndexStmt:
326                 case T_CreatePLangStmt:
327                 case T_CreateOpClassStmt:
328                 case T_RuleStmt:
329                 case T_CreateSchemaStmt:
330                 case T_CreateSeqStmt:
331                 case T_CreateStmt:
332                 case T_CreateTableSpaceStmt:
333                 case T_CreateTrigStmt:
334                 case T_CompositeTypeStmt:
335                 case T_ViewStmt:
336                 case T_RemoveAggrStmt:
337                 case T_DropCastStmt:
338                 case T_DropStmt:
339                 case T_DropdbStmt:
340                 case T_DropTableSpaceStmt:
341                 case T_RemoveFuncStmt:
342                 case T_DropRoleStmt:
343                 case T_DropPLangStmt:
344                 case T_RemoveOperStmt:
345                 case T_RemoveOpClassStmt:
346                 case T_DropPropertyStmt:
347                 case T_GrantStmt:
348                 case T_GrantRoleStmt:
349                 case T_TruncateStmt:
350                 case T_DropOwnedStmt:
351                 case T_ReassignOwnedStmt:
352                         ereport(ERROR,
353                                         (errcode(ERRCODE_READ_ONLY_SQL_TRANSACTION),
354                                          errmsg("transaction is read-only")));
355                         break;
356                 default:
357                         /* do nothing */
358                         break;
359         }
360 }
361
362
363 /*
364  * ProcessUtility
365  *              general utility function invoker
366  *
367  *      parsetree: the parse tree for the utility statement
368  *      params: parameters to use during execution
369  *      dest: where to send results
370  *      completionTag: points to a buffer of size COMPLETION_TAG_BUFSIZE
371  *              in which to store a command completion status string.
372  *
373  * completionTag is only set nonempty if we want to return a nondefault status.
374  *
375  * completionTag may be NULL if caller doesn't want a status string.
376  */
377 void
378 ProcessUtility(Node *parsetree,
379                            ParamListInfo params,
380                            DestReceiver *dest,
381                            char *completionTag)
382 {
383         check_xact_readonly(parsetree);
384
385         if (completionTag)
386                 completionTag[0] = '\0';
387
388         switch (nodeTag(parsetree))
389         {
390                         /*
391                          * ******************** transactions ********************
392                          */
393                 case T_TransactionStmt:
394                         {
395                                 TransactionStmt *stmt = (TransactionStmt *) parsetree;
396
397                                 switch (stmt->kind)
398                                 {
399                                                 /*
400                                                  * START TRANSACTION, as defined by SQL99: Identical
401                                                  * to BEGIN.  Same code for both.
402                                                  */
403                                         case TRANS_STMT_BEGIN:
404                                         case TRANS_STMT_START:
405                                                 {
406                                                         ListCell   *lc;
407
408                                                         BeginTransactionBlock();
409                                                         foreach(lc, stmt->options)
410                                                         {
411                                                                 DefElem    *item = (DefElem *) lfirst(lc);
412
413                                                                 if (strcmp(item->defname, "transaction_isolation") == 0)
414                                                                         SetPGVariable("transaction_isolation",
415                                                                                                   list_make1(item->arg),
416                                                                                                   true);
417                                                                 else if (strcmp(item->defname, "transaction_read_only") == 0)
418                                                                         SetPGVariable("transaction_read_only",
419                                                                                                   list_make1(item->arg),
420                                                                                                   true);
421                                                         }
422                                                 }
423                                                 break;
424
425                                         case TRANS_STMT_COMMIT:
426                                                 if (!EndTransactionBlock())
427                                                 {
428                                                         /* report unsuccessful commit in completionTag */
429                                                         if (completionTag)
430                                                                 strcpy(completionTag, "ROLLBACK");
431                                                 }
432                                                 break;
433
434                                         case TRANS_STMT_PREPARE:
435                                                 if (!PrepareTransactionBlock(stmt->gid))
436                                                 {
437                                                         /* report unsuccessful commit in completionTag */
438                                                         if (completionTag)
439                                                                 strcpy(completionTag, "ROLLBACK");
440                                                 }
441                                                 break;
442
443                                         case TRANS_STMT_COMMIT_PREPARED:
444                                                 PreventTransactionChain(stmt, "COMMIT PREPARED");
445                                                 FinishPreparedTransaction(stmt->gid, true);
446                                                 break;
447
448                                         case TRANS_STMT_ROLLBACK_PREPARED:
449                                                 PreventTransactionChain(stmt, "ROLLBACK PREPARED");
450                                                 FinishPreparedTransaction(stmt->gid, false);
451                                                 break;
452
453                                         case TRANS_STMT_ROLLBACK:
454                                                 UserAbortTransactionBlock();
455                                                 break;
456
457                                         case TRANS_STMT_SAVEPOINT:
458                                                 {
459                                                         ListCell   *cell;
460                                                         char       *name = NULL;
461
462                                                         RequireTransactionChain((void *) stmt, "SAVEPOINT");
463
464                                                         foreach(cell, stmt->options)
465                                                         {
466                                                                 DefElem    *elem = lfirst(cell);
467
468                                                                 if (strcmp(elem->defname, "savepoint_name") == 0)
469                                                                         name = strVal(elem->arg);
470                                                         }
471
472                                                         Assert(PointerIsValid(name));
473
474                                                         DefineSavepoint(name);
475                                                 }
476                                                 break;
477
478                                         case TRANS_STMT_RELEASE:
479                                                 RequireTransactionChain((void *) stmt, "RELEASE SAVEPOINT");
480                                                 ReleaseSavepoint(stmt->options);
481                                                 break;
482
483                                         case TRANS_STMT_ROLLBACK_TO:
484                                                 RequireTransactionChain((void *) stmt, "ROLLBACK TO SAVEPOINT");
485                                                 RollbackToSavepoint(stmt->options);
486
487                                                 /*
488                                                  * CommitTransactionCommand is in charge of
489                                                  * re-defining the savepoint again
490                                                  */
491                                                 break;
492                                 }
493                         }
494                         break;
495
496                         /*
497                          * Portal (cursor) manipulation
498                          */
499                 case T_DeclareCursorStmt:
500                         PerformCursorOpen((DeclareCursorStmt *) parsetree, params);
501                         break;
502
503                 case T_ClosePortalStmt:
504                         {
505                                 ClosePortalStmt *stmt = (ClosePortalStmt *) parsetree;
506
507                                 PerformPortalClose(stmt->portalname);
508                         }
509                         break;
510
511                 case T_FetchStmt:
512                         PerformPortalFetch((FetchStmt *) parsetree, dest,
513                                                            completionTag);
514                         break;
515
516                         /*
517                          * relation and attribute manipulation
518                          */
519                 case T_CreateSchemaStmt:
520                         CreateSchemaCommand((CreateSchemaStmt *) parsetree);
521                         break;
522
523                 case T_CreateStmt:
524                         {
525                                 Oid                     relOid;
526
527                                 relOid = DefineRelation((CreateStmt *) parsetree,
528                                                                                 RELKIND_RELATION);
529
530                                 /*
531                                  * Let AlterTableCreateToastTable decide if this one needs a
532                                  * secondary relation too.
533                                  */
534                                 CommandCounterIncrement();
535                                 AlterTableCreateToastTable(relOid, true);
536                         }
537                         break;
538
539                 case T_CreateTableSpaceStmt:
540                         CreateTableSpace((CreateTableSpaceStmt *) parsetree);
541                         break;
542
543                 case T_DropTableSpaceStmt:
544                         DropTableSpace((DropTableSpaceStmt *) parsetree);
545                         break;
546
547                 case T_DropStmt:
548                         {
549                                 DropStmt   *stmt = (DropStmt *) parsetree;
550                                 ListCell   *arg;
551
552                                 foreach(arg, stmt->objects)
553                                 {
554                                         List       *names = (List *) lfirst(arg);
555                                         RangeVar   *rel;
556
557                                         switch (stmt->removeType)
558                                         {
559                                                 case OBJECT_TABLE:
560                                                         rel = makeRangeVarFromNameList(names);
561                                                         if (CheckDropPermissions(rel, RELKIND_RELATION,
562                                                                                                          stmt->missing_ok))
563                                                                 RemoveRelation(rel, stmt->behavior);
564                                                         break;
565
566                                                 case OBJECT_SEQUENCE:
567                                                         rel = makeRangeVarFromNameList(names);
568                                                         if (CheckDropPermissions(rel, RELKIND_SEQUENCE,
569                                                                                                          stmt->missing_ok))
570                                                                 RemoveRelation(rel, stmt->behavior);
571                                                         break;
572
573                                                 case OBJECT_VIEW:
574                                                         rel = makeRangeVarFromNameList(names);
575                                                         if (CheckDropPermissions(rel, RELKIND_VIEW,
576                                                                                                          stmt->missing_ok))
577                                                                 RemoveView(rel, stmt->behavior);
578                                                         break;
579
580                                                 case OBJECT_INDEX:
581                                                         rel = makeRangeVarFromNameList(names);
582                                                         if (CheckDropPermissions(rel, RELKIND_INDEX,
583                                                                                                          stmt->missing_ok))
584                                                                 RemoveIndex(rel, stmt->behavior);
585                                                         break;
586
587                                                 case OBJECT_TYPE:
588                                                         /* RemoveType does its own permissions checks */
589                                                         RemoveType(names, stmt->behavior,
590                                                                            stmt->missing_ok);
591                                                         break;
592
593                                                 case OBJECT_DOMAIN:
594
595                                                         /*
596                                                          * RemoveDomain does its own permissions checks
597                                                          */
598                                                         RemoveDomain(names, stmt->behavior,
599                                                                                  stmt->missing_ok);
600                                                         break;
601
602                                                 case OBJECT_CONVERSION:
603                                                         DropConversionCommand(names, stmt->behavior,
604                                                                                                   stmt->missing_ok);
605                                                         break;
606
607                                                 case OBJECT_SCHEMA:
608
609                                                         /*
610                                                          * RemoveSchema does its own permissions checks
611                                                          */
612                                                         RemoveSchema(names, stmt->behavior,
613                                                                                  stmt->missing_ok);
614                                                         break;
615
616                                                 default:
617                                                         elog(ERROR, "unrecognized drop object type: %d",
618                                                                  (int) stmt->removeType);
619                                                         break;
620                                         }
621
622                                         /*
623                                          * We used to need to do CommandCounterIncrement() here,
624                                          * but now it's done inside performDeletion().
625                                          */
626                                 }
627                         }
628                         break;
629
630                 case T_TruncateStmt:
631                         {
632                                 TruncateStmt *stmt = (TruncateStmt *) parsetree;
633
634                                 ExecuteTruncate(stmt->relations);
635                         }
636                         break;
637
638                 case T_CommentStmt:
639                         CommentObject((CommentStmt *) parsetree);
640                         break;
641
642                 case T_CopyStmt:
643                         DoCopy((CopyStmt *) parsetree);
644                         break;
645
646                 case T_PrepareStmt:
647                         PrepareQuery((PrepareStmt *) parsetree);
648                         break;
649
650                 case T_ExecuteStmt:
651                         ExecuteQuery((ExecuteStmt *) parsetree, params,
652                                                  dest, completionTag);
653                         break;
654
655                 case T_DeallocateStmt:
656                         DeallocateQuery((DeallocateStmt *) parsetree);
657                         break;
658
659                         /*
660                          * schema
661                          */
662                 case T_RenameStmt:
663                         ExecRenameStmt((RenameStmt *) parsetree);
664                         break;
665
666                 case T_AlterObjectSchemaStmt:
667                         ExecAlterObjectSchemaStmt((AlterObjectSchemaStmt *) parsetree);
668                         break;
669
670                 case T_AlterOwnerStmt:
671                         ExecAlterOwnerStmt((AlterOwnerStmt *) parsetree);
672                         break;
673
674                 case T_AlterTableStmt:
675                         AlterTable((AlterTableStmt *) parsetree);
676                         break;
677
678                 case T_AlterDomainStmt:
679                         {
680                                 AlterDomainStmt *stmt = (AlterDomainStmt *) parsetree;
681
682                                 /*
683                                  * Some or all of these functions are recursive to cover
684                                  * inherited things, so permission checks are done there.
685                                  */
686                                 switch (stmt->subtype)
687                                 {
688                                         case 'T':       /* ALTER DOMAIN DEFAULT */
689
690                                                 /*
691                                                  * Recursively alter column default for table and, if
692                                                  * requested, for descendants
693                                                  */
694                                                 AlterDomainDefault(stmt->typename,
695                                                                                    stmt->def);
696                                                 break;
697                                         case 'N':       /* ALTER DOMAIN DROP NOT NULL */
698                                                 AlterDomainNotNull(stmt->typename,
699                                                                                    false);
700                                                 break;
701                                         case 'O':       /* ALTER DOMAIN SET NOT NULL */
702                                                 AlterDomainNotNull(stmt->typename,
703                                                                                    true);
704                                                 break;
705                                         case 'C':       /* ADD CONSTRAINT */
706                                                 AlterDomainAddConstraint(stmt->typename,
707                                                                                                  stmt->def);
708                                                 break;
709                                         case 'X':       /* DROP CONSTRAINT */
710                                                 AlterDomainDropConstraint(stmt->typename,
711                                                                                                   stmt->name,
712                                                                                                   stmt->behavior);
713                                                 break;
714                                         default:        /* oops */
715                                                 elog(ERROR, "unrecognized alter domain type: %d",
716                                                          (int) stmt->subtype);
717                                                 break;
718                                 }
719                         }
720                         break;
721
722                 case T_GrantStmt:
723                         ExecuteGrantStmt((GrantStmt *) parsetree);
724                         break;
725
726                 case T_GrantRoleStmt:
727                         GrantRole((GrantRoleStmt *) parsetree);
728                         break;
729
730                         /*
731                          * **************** object creation / destruction ******************
732                          */
733                 case T_DefineStmt:
734                         {
735                                 DefineStmt *stmt = (DefineStmt *) parsetree;
736
737                                 switch (stmt->kind)
738                                 {
739                                         case OBJECT_AGGREGATE:
740                                                 DefineAggregate(stmt->defnames, stmt->definition);
741                                                 break;
742                                         case OBJECT_OPERATOR:
743                                                 DefineOperator(stmt->defnames, stmt->definition);
744                                                 break;
745                                         case OBJECT_TYPE:
746                                                 DefineType(stmt->defnames, stmt->definition);
747                                                 break;
748                                         default:
749                                                 elog(ERROR, "unrecognized define stmt type: %d",
750                                                          (int) stmt->kind);
751                                                 break;
752                                 }
753                         }
754                         break;
755
756                 case T_CompositeTypeStmt:               /* CREATE TYPE (composite) */
757                         {
758                                 CompositeTypeStmt *stmt = (CompositeTypeStmt *) parsetree;
759
760                                 DefineCompositeType(stmt->typevar, stmt->coldeflist);
761                         }
762                         break;
763
764                 case T_ViewStmt:                /* CREATE VIEW */
765                         {
766                                 ViewStmt   *stmt = (ViewStmt *) parsetree;
767
768                                 DefineView(stmt->view, stmt->query, stmt->replace);
769                         }
770                         break;
771
772                 case T_CreateFunctionStmt:              /* CREATE FUNCTION */
773                         CreateFunction((CreateFunctionStmt *) parsetree);
774                         break;
775
776                 case T_AlterFunctionStmt:               /* ALTER FUNCTION */
777                         AlterFunction((AlterFunctionStmt *) parsetree);
778                         break;
779
780                 case T_IndexStmt:               /* CREATE INDEX */
781                         {
782                                 IndexStmt  *stmt = (IndexStmt *) parsetree;
783
784                                 CheckRelationOwnership(stmt->relation, true);
785
786                                 DefineIndex(stmt->relation,             /* relation */
787                                                         stmt->idxname,          /* index name */
788                                                         InvalidOid, /* no predefined OID */
789                                                         stmt->accessMethod, /* am name */
790                                                         stmt->tableSpace,
791                                                         stmt->indexParams,      /* parameters */
792                                                         (Expr *) stmt->whereClause,
793                                                         stmt->rangetable,
794                                                         stmt->unique,
795                                                         stmt->primary,
796                                                         stmt->isconstraint,
797                                                         false,          /* is_alter_table */
798                                                         true,           /* check_rights */
799                                                         false,          /* skip_build */
800                                                         false);         /* quiet */
801                         }
802                         break;
803
804                 case T_RuleStmt:                /* CREATE RULE */
805                         DefineQueryRewrite((RuleStmt *) parsetree);
806                         break;
807
808                 case T_CreateSeqStmt:
809                         DefineSequence((CreateSeqStmt *) parsetree);
810                         break;
811
812                 case T_AlterSeqStmt:
813                         AlterSequence((AlterSeqStmt *) parsetree);
814                         break;
815
816                 case T_RemoveAggrStmt:
817                         RemoveAggregate((RemoveAggrStmt *) parsetree);
818                         break;
819
820                 case T_RemoveFuncStmt:
821                         RemoveFunction((RemoveFuncStmt *) parsetree);
822                         break;
823
824                 case T_RemoveOperStmt:
825                         RemoveOperator((RemoveOperStmt *) parsetree);
826                         break;
827
828                 case T_CreatedbStmt:
829                         createdb((CreatedbStmt *) parsetree);
830                         break;
831
832                 case T_AlterDatabaseStmt:
833                         AlterDatabase((AlterDatabaseStmt *) parsetree);
834                         break;
835
836                 case T_AlterDatabaseSetStmt:
837                         AlterDatabaseSet((AlterDatabaseSetStmt *) parsetree);
838                         break;
839
840                 case T_DropdbStmt:
841                         {
842                                 DropdbStmt *stmt = (DropdbStmt *) parsetree;
843
844                                 dropdb(stmt->dbname, stmt->missing_ok);
845                         }
846                         break;
847
848                         /* Query-level asynchronous notification */
849                 case T_NotifyStmt:
850                         {
851                                 NotifyStmt *stmt = (NotifyStmt *) parsetree;
852
853                                 Async_Notify(stmt->relation->relname);
854                         }
855                         break;
856
857                 case T_ListenStmt:
858                         {
859                                 ListenStmt *stmt = (ListenStmt *) parsetree;
860
861                                 Async_Listen(stmt->relation->relname);
862                         }
863                         break;
864
865                 case T_UnlistenStmt:
866                         {
867                                 UnlistenStmt *stmt = (UnlistenStmt *) parsetree;
868
869                                 Async_Unlisten(stmt->relation->relname);
870                         }
871                         break;
872
873                 case T_LoadStmt:
874                         {
875                                 LoadStmt   *stmt = (LoadStmt *) parsetree;
876
877                                 if (!superuser())
878                                         ereport(ERROR,
879                                                         (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
880                                                          errmsg("must be superuser to do LOAD")));
881                                 closeAllVfds(); /* probably not necessary... */
882                                 load_file(stmt->filename);
883                         }
884                         break;
885
886                 case T_ClusterStmt:
887                         cluster((ClusterStmt *) parsetree);
888                         break;
889
890                 case T_VacuumStmt:
891                         vacuum((VacuumStmt *) parsetree, NIL);
892                         break;
893
894                 case T_ExplainStmt:
895                         ExplainQuery((ExplainStmt *) parsetree, params, dest);
896                         break;
897
898                 case T_VariableSetStmt:
899                         {
900                                 VariableSetStmt *n = (VariableSetStmt *) parsetree;
901
902                                 /*
903                                  * Special cases for special SQL syntax that effectively sets
904                                  * more than one variable per statement.
905                                  */
906                                 if (strcmp(n->name, "TRANSACTION") == 0)
907                                 {
908                                         ListCell   *head;
909
910                                         foreach(head, n->args)
911                                         {
912                                                 DefElem    *item = (DefElem *) lfirst(head);
913
914                                                 if (strcmp(item->defname, "transaction_isolation") == 0)
915                                                         SetPGVariable("transaction_isolation",
916                                                                                   list_make1(item->arg), n->is_local);
917                                                 else if (strcmp(item->defname, "transaction_read_only") == 0)
918                                                         SetPGVariable("transaction_read_only",
919                                                                                   list_make1(item->arg), n->is_local);
920                                         }
921                                 }
922                                 else if (strcmp(n->name, "SESSION CHARACTERISTICS") == 0)
923                                 {
924                                         ListCell   *head;
925
926                                         foreach(head, n->args)
927                                         {
928                                                 DefElem    *item = (DefElem *) lfirst(head);
929
930                                                 if (strcmp(item->defname, "transaction_isolation") == 0)
931                                                         SetPGVariable("default_transaction_isolation",
932                                                                                   list_make1(item->arg), n->is_local);
933                                                 else if (strcmp(item->defname, "transaction_read_only") == 0)
934                                                         SetPGVariable("default_transaction_read_only",
935                                                                                   list_make1(item->arg), n->is_local);
936                                         }
937                                 }
938                                 else
939                                         SetPGVariable(n->name, n->args, n->is_local);
940                         }
941                         break;
942
943                 case T_VariableShowStmt:
944                         {
945                                 VariableShowStmt *n = (VariableShowStmt *) parsetree;
946
947                                 GetPGVariable(n->name, dest);
948                         }
949                         break;
950
951                 case T_VariableResetStmt:
952                         {
953                                 VariableResetStmt *n = (VariableResetStmt *) parsetree;
954
955                                 ResetPGVariable(n->name);
956                         }
957                         break;
958
959                 case T_CreateTrigStmt:
960                         CreateTrigger((CreateTrigStmt *) parsetree, false);
961                         break;
962
963                 case T_DropPropertyStmt:
964                         {
965                                 DropPropertyStmt *stmt = (DropPropertyStmt *) parsetree;
966                                 Oid                     relId;
967
968                                 relId = RangeVarGetRelid(stmt->relation, false);
969
970                                 switch (stmt->removeType)
971                                 {
972                                         case OBJECT_RULE:
973                                                 /* RemoveRewriteRule checks permissions */
974                                                 RemoveRewriteRule(relId, stmt->property,
975                                                                                   stmt->behavior);
976                                                 break;
977                                         case OBJECT_TRIGGER:
978                                                 /* DropTrigger checks permissions */
979                                                 DropTrigger(relId, stmt->property,
980                                                                         stmt->behavior);
981                                                 break;
982                                         default:
983                                                 elog(ERROR, "unrecognized object type: %d",
984                                                          (int) stmt->removeType);
985                                                 break;
986                                 }
987                         }
988                         break;
989
990                 case T_CreatePLangStmt:
991                         CreateProceduralLanguage((CreatePLangStmt *) parsetree);
992                         break;
993
994                 case T_DropPLangStmt:
995                         DropProceduralLanguage((DropPLangStmt *) parsetree);
996                         break;
997
998                         /*
999                          * ******************************** DOMAIN statements ****
1000                          */
1001                 case T_CreateDomainStmt:
1002                         DefineDomain((CreateDomainStmt *) parsetree);
1003                         break;
1004
1005                         /*
1006                          * ******************************** ROLE statements ****
1007                          */
1008                 case T_CreateRoleStmt:
1009                         CreateRole((CreateRoleStmt *) parsetree);
1010                         break;
1011
1012                 case T_AlterRoleStmt:
1013                         AlterRole((AlterRoleStmt *) parsetree);
1014                         break;
1015
1016                 case T_AlterRoleSetStmt:
1017                         AlterRoleSet((AlterRoleSetStmt *) parsetree);
1018                         break;
1019
1020                 case T_DropRoleStmt:
1021                         DropRole((DropRoleStmt *) parsetree);
1022                         break;
1023
1024                 case T_DropOwnedStmt:
1025                         DropOwnedObjects((DropOwnedStmt *) parsetree);
1026                         break;
1027
1028                 case T_ReassignOwnedStmt:
1029                         ReassignOwnedObjects((ReassignOwnedStmt *) parsetree);
1030                         break;
1031
1032                 case T_LockStmt:
1033                         LockTableCommand((LockStmt *) parsetree);
1034                         break;
1035
1036                 case T_ConstraintsSetStmt:
1037                         AfterTriggerSetState((ConstraintsSetStmt *) parsetree);
1038                         break;
1039
1040                 case T_CheckPointStmt:
1041                         if (!superuser())
1042                                 ereport(ERROR,
1043                                                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1044                                                  errmsg("must be superuser to do CHECKPOINT")));
1045                         RequestCheckpoint(true, false);
1046                         break;
1047
1048                 case T_ReindexStmt:
1049                         {
1050                                 ReindexStmt *stmt = (ReindexStmt *) parsetree;
1051
1052                                 switch (stmt->kind)
1053                                 {
1054                                         case OBJECT_INDEX:
1055                                                 ReindexIndex(stmt->relation);
1056                                                 break;
1057                                         case OBJECT_TABLE:
1058                                                 ReindexTable(stmt->relation);
1059                                                 break;
1060                                         case OBJECT_DATABASE:
1061                                                 ReindexDatabase(stmt->name,
1062                                                                                 stmt->do_system, stmt->do_user);
1063                                                 break;
1064                                         default:
1065                                                 elog(ERROR, "unrecognized object type: %d",
1066                                                          (int) stmt->kind);
1067                                                 break;
1068                                 }
1069                                 break;
1070                         }
1071                         break;
1072
1073                 case T_CreateConversionStmt:
1074                         CreateConversionCommand((CreateConversionStmt *) parsetree);
1075                         break;
1076
1077                 case T_CreateCastStmt:
1078                         CreateCast((CreateCastStmt *) parsetree);
1079                         break;
1080
1081                 case T_DropCastStmt:
1082                         DropCast((DropCastStmt *) parsetree);
1083                         break;
1084
1085                 case T_CreateOpClassStmt:
1086                         DefineOpClass((CreateOpClassStmt *) parsetree);
1087                         break;
1088
1089                 case T_RemoveOpClassStmt:
1090                         RemoveOpClass((RemoveOpClassStmt *) parsetree);
1091                         break;
1092
1093                 default:
1094                         elog(ERROR, "unrecognized node type: %d",
1095                                  (int) nodeTag(parsetree));
1096                         break;
1097         }
1098 }
1099
1100 /*
1101  * UtilityReturnsTuples
1102  *              Return "true" if this utility statement will send output to the
1103  *              destination.
1104  *
1105  * Generally, there should be a case here for each case in ProcessUtility
1106  * where "dest" is passed on.
1107  */
1108 bool
1109 UtilityReturnsTuples(Node *parsetree)
1110 {
1111         switch (nodeTag(parsetree))
1112         {
1113                 case T_FetchStmt:
1114                         {
1115                                 FetchStmt  *stmt = (FetchStmt *) parsetree;
1116                                 Portal          portal;
1117
1118                                 if (stmt->ismove)
1119                                         return false;
1120                                 portal = GetPortalByName(stmt->portalname);
1121                                 if (!PortalIsValid(portal))
1122                                         return false;           /* not our business to raise error */
1123                                 return portal->tupDesc ? true : false;
1124                         }
1125
1126                 case T_ExecuteStmt:
1127                         {
1128                                 ExecuteStmt *stmt = (ExecuteStmt *) parsetree;
1129                                 PreparedStatement *entry;
1130
1131                                 if (stmt->into)
1132                                         return false;
1133                                 entry = FetchPreparedStatement(stmt->name, false);
1134                                 if (!entry)
1135                                         return false;           /* not our business to raise error */
1136                                 switch (ChoosePortalStrategy(entry->query_list))
1137                                 {
1138                                         case PORTAL_ONE_SELECT:
1139                                                 return true;
1140                                         case PORTAL_UTIL_SELECT:
1141                                                 return true;
1142                                         case PORTAL_MULTI_QUERY:
1143                                                 /* will not return tuples */
1144                                                 break;
1145                                 }
1146                                 return false;
1147                         }
1148
1149                 case T_ExplainStmt:
1150                         return true;
1151
1152                 case T_VariableShowStmt:
1153                         return true;
1154
1155                 default:
1156                         return false;
1157         }
1158 }
1159
1160 /*
1161  * UtilityTupleDescriptor
1162  *              Fetch the actual output tuple descriptor for a utility statement
1163  *              for which UtilityReturnsTuples() previously returned "true".
1164  *
1165  * The returned descriptor is created in (or copied into) the current memory
1166  * context.
1167  */
1168 TupleDesc
1169 UtilityTupleDescriptor(Node *parsetree)
1170 {
1171         switch (nodeTag(parsetree))
1172         {
1173                 case T_FetchStmt:
1174                         {
1175                                 FetchStmt  *stmt = (FetchStmt *) parsetree;
1176                                 Portal          portal;
1177
1178                                 if (stmt->ismove)
1179                                         return NULL;
1180                                 portal = GetPortalByName(stmt->portalname);
1181                                 if (!PortalIsValid(portal))
1182                                         return NULL;    /* not our business to raise error */
1183                                 return CreateTupleDescCopy(portal->tupDesc);
1184                         }
1185
1186                 case T_ExecuteStmt:
1187                         {
1188                                 ExecuteStmt *stmt = (ExecuteStmt *) parsetree;
1189                                 PreparedStatement *entry;
1190
1191                                 if (stmt->into)
1192                                         return NULL;
1193                                 entry = FetchPreparedStatement(stmt->name, false);
1194                                 if (!entry)
1195                                         return NULL;    /* not our business to raise error */
1196                                 return FetchPreparedStatementResultDesc(entry);
1197                         }
1198
1199                 case T_ExplainStmt:
1200                         return ExplainResultDesc((ExplainStmt *) parsetree);
1201
1202                 case T_VariableShowStmt:
1203                         {
1204                                 VariableShowStmt *n = (VariableShowStmt *) parsetree;
1205
1206                                 return GetPGVariableResultDesc(n->name);
1207                         }
1208
1209                 default:
1210                         return NULL;
1211         }
1212 }
1213
1214
1215 /*
1216  * CreateCommandTag
1217  *              utility to get a string representation of the
1218  *              command operation, given a raw (un-analyzed) parsetree.
1219  *
1220  * This must handle all raw command types, but since the vast majority
1221  * of 'em are utility commands, it seems sensible to keep it here.
1222  *
1223  * NB: all result strings must be shorter than COMPLETION_TAG_BUFSIZE.
1224  * Also, the result must point at a true constant (permanent storage).
1225  */
1226 const char *
1227 CreateCommandTag(Node *parsetree)
1228 {
1229         const char *tag;
1230
1231         switch (nodeTag(parsetree))
1232         {
1233                 case T_InsertStmt:
1234                         tag = "INSERT";
1235                         break;
1236
1237                 case T_DeleteStmt:
1238                         tag = "DELETE";
1239                         break;
1240
1241                 case T_UpdateStmt:
1242                         tag = "UPDATE";
1243                         break;
1244
1245                 case T_SelectStmt:
1246                         tag = "SELECT";
1247                         break;
1248
1249                 case T_TransactionStmt:
1250                         {
1251                                 TransactionStmt *stmt = (TransactionStmt *) parsetree;
1252
1253                                 switch (stmt->kind)
1254                                 {
1255                                         case TRANS_STMT_BEGIN:
1256                                                 tag = "BEGIN";
1257                                                 break;
1258
1259                                         case TRANS_STMT_START:
1260                                                 tag = "START TRANSACTION";
1261                                                 break;
1262
1263                                         case TRANS_STMT_COMMIT:
1264                                                 tag = "COMMIT";
1265                                                 break;
1266
1267                                         case TRANS_STMT_ROLLBACK:
1268                                         case TRANS_STMT_ROLLBACK_TO:
1269                                                 tag = "ROLLBACK";
1270                                                 break;
1271
1272                                         case TRANS_STMT_SAVEPOINT:
1273                                                 tag = "SAVEPOINT";
1274                                                 break;
1275
1276                                         case TRANS_STMT_RELEASE:
1277                                                 tag = "RELEASE";
1278                                                 break;
1279
1280                                         case TRANS_STMT_PREPARE:
1281                                                 tag = "PREPARE TRANSACTION";
1282                                                 break;
1283
1284                                         case TRANS_STMT_COMMIT_PREPARED:
1285                                                 tag = "COMMIT PREPARED";
1286                                                 break;
1287
1288                                         case TRANS_STMT_ROLLBACK_PREPARED:
1289                                                 tag = "ROLLBACK PREPARED";
1290                                                 break;
1291
1292                                         default:
1293                                                 tag = "???";
1294                                                 break;
1295                                 }
1296                         }
1297                         break;
1298
1299                 case T_DeclareCursorStmt:
1300                         tag = "DECLARE CURSOR";
1301                         break;
1302
1303                 case T_ClosePortalStmt:
1304                         tag = "CLOSE CURSOR";
1305                         break;
1306
1307                 case T_FetchStmt:
1308                         {
1309                                 FetchStmt  *stmt = (FetchStmt *) parsetree;
1310
1311                                 tag = (stmt->ismove) ? "MOVE" : "FETCH";
1312                         }
1313                         break;
1314
1315                 case T_CreateDomainStmt:
1316                         tag = "CREATE DOMAIN";
1317                         break;
1318
1319                 case T_CreateSchemaStmt:
1320                         tag = "CREATE SCHEMA";
1321                         break;
1322
1323                 case T_CreateStmt:
1324                         tag = "CREATE TABLE";
1325                         break;
1326
1327                 case T_CreateTableSpaceStmt:
1328                         tag = "CREATE TABLESPACE";
1329                         break;
1330
1331                 case T_DropTableSpaceStmt:
1332                         tag = "DROP TABLESPACE";
1333                         break;
1334
1335                 case T_DropStmt:
1336                         switch (((DropStmt *) parsetree)->removeType)
1337                         {
1338                                 case OBJECT_TABLE:
1339                                         tag = "DROP TABLE";
1340                                         break;
1341                                 case OBJECT_SEQUENCE:
1342                                         tag = "DROP SEQUENCE";
1343                                         break;
1344                                 case OBJECT_VIEW:
1345                                         tag = "DROP VIEW";
1346                                         break;
1347                                 case OBJECT_INDEX:
1348                                         tag = "DROP INDEX";
1349                                         break;
1350                                 case OBJECT_TYPE:
1351                                         tag = "DROP TYPE";
1352                                         break;
1353                                 case OBJECT_DOMAIN:
1354                                         tag = "DROP DOMAIN";
1355                                         break;
1356                                 case OBJECT_CONVERSION:
1357                                         tag = "DROP CONVERSION";
1358                                         break;
1359                                 case OBJECT_SCHEMA:
1360                                         tag = "DROP SCHEMA";
1361                                         break;
1362                                 default:
1363                                         tag = "???";
1364                         }
1365                         break;
1366
1367                 case T_TruncateStmt:
1368                         tag = "TRUNCATE TABLE";
1369                         break;
1370
1371                 case T_CommentStmt:
1372                         tag = "COMMENT";
1373                         break;
1374
1375                 case T_CopyStmt:
1376                         tag = "COPY";
1377                         break;
1378
1379                 case T_RenameStmt:
1380                         switch (((RenameStmt *) parsetree)->renameType)
1381                         {
1382                                 case OBJECT_AGGREGATE:
1383                                         tag = "ALTER AGGREGATE";
1384                                         break;
1385                                 case OBJECT_CONVERSION:
1386                                         tag = "ALTER CONVERSION";
1387                                         break;
1388                                 case OBJECT_DATABASE:
1389                                         tag = "ALTER DATABASE";
1390                                         break;
1391                                 case OBJECT_FUNCTION:
1392                                         tag = "ALTER FUNCTION";
1393                                         break;
1394                                 case OBJECT_INDEX:
1395                                         tag = "ALTER INDEX";
1396                                         break;
1397                                 case OBJECT_LANGUAGE:
1398                                         tag = "ALTER LANGUAGE";
1399                                         break;
1400                                 case OBJECT_OPCLASS:
1401                                         tag = "ALTER OPERATOR CLASS";
1402                                         break;
1403                                 case OBJECT_ROLE:
1404                                         tag = "ALTER ROLE";
1405                                         break;
1406                                 case OBJECT_SCHEMA:
1407                                         tag = "ALTER SCHEMA";
1408                                         break;
1409                                 case OBJECT_COLUMN:
1410                                 case OBJECT_TABLE:
1411                                         tag = "ALTER TABLE";
1412                                         break;
1413                                 case OBJECT_TABLESPACE:
1414                                         tag = "ALTER TABLESPACE";
1415                                         break;
1416                                 case OBJECT_TRIGGER:
1417                                         tag = "ALTER TRIGGER";
1418                                         break;
1419                                 default:
1420                                         tag = "???";
1421                                         break;
1422                         }
1423                         break;
1424
1425                 case T_AlterObjectSchemaStmt:
1426                         switch (((AlterObjectSchemaStmt *) parsetree)->objectType)
1427                         {
1428                                 case OBJECT_AGGREGATE:
1429                                         tag = "ALTER AGGREGATE";
1430                                         break;
1431                                 case OBJECT_DOMAIN:
1432                                         tag = "ALTER DOMAIN";
1433                                         break;
1434                                 case OBJECT_FUNCTION:
1435                                         tag = "ALTER FUNCTION";
1436                                         break;
1437                                 case OBJECT_SEQUENCE:
1438                                         tag = "ALTER SEQUENCE";
1439                                         break;
1440                                 case OBJECT_TABLE:
1441                                         tag = "ALTER TABLE";
1442                                         break;
1443                                 case OBJECT_TYPE:
1444                                         tag = "ALTER TYPE";
1445                                         break;
1446                                 default:
1447                                         tag = "???";
1448                                         break;
1449                         }
1450                         break;
1451
1452                 case T_AlterOwnerStmt:
1453                         switch (((AlterOwnerStmt *) parsetree)->objectType)
1454                         {
1455                                 case OBJECT_AGGREGATE:
1456                                         tag = "ALTER AGGREGATE";
1457                                         break;
1458                                 case OBJECT_CONVERSION:
1459                                         tag = "ALTER CONVERSION";
1460                                         break;
1461                                 case OBJECT_DATABASE:
1462                                         tag = "ALTER DATABASE";
1463                                         break;
1464                                 case OBJECT_DOMAIN:
1465                                         tag = "ALTER DOMAIN";
1466                                         break;
1467                                 case OBJECT_FUNCTION:
1468                                         tag = "ALTER FUNCTION";
1469                                         break;
1470                                 case OBJECT_OPERATOR:
1471                                         tag = "ALTER OPERATOR";
1472                                         break;
1473                                 case OBJECT_OPCLASS:
1474                                         tag = "ALTER OPERATOR CLASS";
1475                                         break;
1476                                 case OBJECT_SCHEMA:
1477                                         tag = "ALTER SCHEMA";
1478                                         break;
1479                                 case OBJECT_TABLESPACE:
1480                                         tag = "ALTER TABLESPACE";
1481                                         break;
1482                                 case OBJECT_TYPE:
1483                                         tag = "ALTER TYPE";
1484                                         break;
1485                                 default:
1486                                         tag = "???";
1487                                         break;
1488                         }
1489                         break;
1490
1491                 case T_AlterTableStmt:
1492                         {
1493                                 AlterTableStmt *stmt = (AlterTableStmt *) parsetree;
1494
1495                                 /*
1496                                  * We might be supporting ALTER INDEX here, so set the
1497                                  * completion table appropriately. Catch all other
1498                                  * possibilities with ALTER TABLE
1499                                  */
1500
1501                                 if (stmt->relkind == OBJECT_INDEX)
1502                                         tag = "ALTER INDEX";
1503                                 else
1504                                         tag = "ALTER TABLE";
1505                         }
1506                         break;
1507
1508                 case T_AlterDomainStmt:
1509                         tag = "ALTER DOMAIN";
1510                         break;
1511
1512                 case T_AlterFunctionStmt:
1513                         tag = "ALTER FUNCTION";
1514                         break;
1515
1516                 case T_GrantStmt:
1517                         {
1518                                 GrantStmt  *stmt = (GrantStmt *) parsetree;
1519
1520                                 tag = (stmt->is_grant) ? "GRANT" : "REVOKE";
1521                         }
1522                         break;
1523
1524                 case T_GrantRoleStmt:
1525                         {
1526                                 GrantRoleStmt *stmt = (GrantRoleStmt *) parsetree;
1527
1528                                 tag = (stmt->is_grant) ? "GRANT ROLE" : "REVOKE ROLE";
1529                         }
1530                         break;
1531
1532                 case T_DefineStmt:
1533                         switch (((DefineStmt *) parsetree)->kind)
1534                         {
1535                                 case OBJECT_AGGREGATE:
1536                                         tag = "CREATE AGGREGATE";
1537                                         break;
1538                                 case OBJECT_OPERATOR:
1539                                         tag = "CREATE OPERATOR";
1540                                         break;
1541                                 case OBJECT_TYPE:
1542                                         tag = "CREATE TYPE";
1543                                         break;
1544                                 default:
1545                                         tag = "???";
1546                         }
1547                         break;
1548
1549                 case T_CompositeTypeStmt:
1550                         tag = "CREATE TYPE";
1551                         break;
1552
1553                 case T_ViewStmt:
1554                         tag = "CREATE VIEW";
1555                         break;
1556
1557                 case T_CreateFunctionStmt:
1558                         tag = "CREATE FUNCTION";
1559                         break;
1560
1561                 case T_IndexStmt:
1562                         tag = "CREATE INDEX";
1563                         break;
1564
1565                 case T_RuleStmt:
1566                         tag = "CREATE RULE";
1567                         break;
1568
1569                 case T_CreateSeqStmt:
1570                         tag = "CREATE SEQUENCE";
1571                         break;
1572
1573                 case T_AlterSeqStmt:
1574                         tag = "ALTER SEQUENCE";
1575                         break;
1576
1577                 case T_RemoveAggrStmt:
1578                         tag = "DROP AGGREGATE";
1579                         break;
1580
1581                 case T_RemoveFuncStmt:
1582                         tag = "DROP FUNCTION";
1583                         break;
1584
1585                 case T_RemoveOperStmt:
1586                         tag = "DROP OPERATOR";
1587                         break;
1588
1589                 case T_CreatedbStmt:
1590                         tag = "CREATE DATABASE";
1591                         break;
1592
1593                 case T_AlterDatabaseStmt:
1594                         tag = "ALTER DATABASE";
1595                         break;
1596
1597                 case T_AlterDatabaseSetStmt:
1598                         tag = "ALTER DATABASE";
1599                         break;
1600
1601                 case T_DropdbStmt:
1602                         tag = "DROP DATABASE";
1603                         break;
1604
1605                 case T_NotifyStmt:
1606                         tag = "NOTIFY";
1607                         break;
1608
1609                 case T_ListenStmt:
1610                         tag = "LISTEN";
1611                         break;
1612
1613                 case T_UnlistenStmt:
1614                         tag = "UNLISTEN";
1615                         break;
1616
1617                 case T_LoadStmt:
1618                         tag = "LOAD";
1619                         break;
1620
1621                 case T_ClusterStmt:
1622                         tag = "CLUSTER";
1623                         break;
1624
1625                 case T_VacuumStmt:
1626                         if (((VacuumStmt *) parsetree)->vacuum)
1627                                 tag = "VACUUM";
1628                         else
1629                                 tag = "ANALYZE";
1630                         break;
1631
1632                 case T_ExplainStmt:
1633                         tag = "EXPLAIN";
1634                         break;
1635
1636                 case T_VariableSetStmt:
1637                         tag = "SET";
1638                         break;
1639
1640                 case T_VariableShowStmt:
1641                         tag = "SHOW";
1642                         break;
1643
1644                 case T_VariableResetStmt:
1645                         tag = "RESET";
1646                         break;
1647
1648                 case T_CreateTrigStmt:
1649                         tag = "CREATE TRIGGER";
1650                         break;
1651
1652                 case T_DropPropertyStmt:
1653                         switch (((DropPropertyStmt *) parsetree)->removeType)
1654                         {
1655                                 case OBJECT_TRIGGER:
1656                                         tag = "DROP TRIGGER";
1657                                         break;
1658                                 case OBJECT_RULE:
1659                                         tag = "DROP RULE";
1660                                         break;
1661                                 default:
1662                                         tag = "???";
1663                         }
1664                         break;
1665
1666                 case T_CreatePLangStmt:
1667                         tag = "CREATE LANGUAGE";
1668                         break;
1669
1670                 case T_DropPLangStmt:
1671                         tag = "DROP LANGUAGE";
1672                         break;
1673
1674                 case T_CreateRoleStmt:
1675                         tag = "CREATE ROLE";
1676                         break;
1677
1678                 case T_AlterRoleStmt:
1679                         tag = "ALTER ROLE";
1680                         break;
1681
1682                 case T_AlterRoleSetStmt:
1683                         tag = "ALTER ROLE";
1684                         break;
1685
1686                 case T_DropRoleStmt:
1687                         tag = "DROP ROLE";
1688                         break;
1689
1690                 case T_DropOwnedStmt:
1691                         tag = "DROP OWNED";
1692                         break;
1693
1694                 case T_ReassignOwnedStmt:
1695                         tag = "REASSIGN OWNED";
1696                         break;
1697
1698                 case T_LockStmt:
1699                         tag = "LOCK TABLE";
1700                         break;
1701
1702                 case T_ConstraintsSetStmt:
1703                         tag = "SET CONSTRAINTS";
1704                         break;
1705
1706                 case T_CheckPointStmt:
1707                         tag = "CHECKPOINT";
1708                         break;
1709
1710                 case T_ReindexStmt:
1711                         tag = "REINDEX";
1712                         break;
1713
1714                 case T_CreateConversionStmt:
1715                         tag = "CREATE CONVERSION";
1716                         break;
1717
1718                 case T_CreateCastStmt:
1719                         tag = "CREATE CAST";
1720                         break;
1721
1722                 case T_DropCastStmt:
1723                         tag = "DROP CAST";
1724                         break;
1725
1726                 case T_CreateOpClassStmt:
1727                         tag = "CREATE OPERATOR CLASS";
1728                         break;
1729
1730                 case T_RemoveOpClassStmt:
1731                         tag = "DROP OPERATOR CLASS";
1732                         break;
1733
1734                 case T_PrepareStmt:
1735                         tag = "PREPARE";
1736                         break;
1737
1738                 case T_ExecuteStmt:
1739                         tag = "EXECUTE";
1740                         break;
1741
1742                 case T_DeallocateStmt:
1743                         tag = "DEALLOCATE";
1744                         break;
1745
1746                 default:
1747                         elog(WARNING, "unrecognized node type: %d",
1748                                  (int) nodeTag(parsetree));
1749                         tag = "???";
1750                         break;
1751         }
1752
1753         return tag;
1754 }
1755
1756 /*
1757  * CreateQueryTag
1758  *              utility to get a string representation of a Query operation.
1759  *
1760  * This is exactly like CreateCommandTag, except it works on a Query
1761  * that has already been through parse analysis (and possibly further).
1762  */
1763 const char *
1764 CreateQueryTag(Query *parsetree)
1765 {
1766         const char *tag;
1767
1768         switch (parsetree->commandType)
1769         {
1770                 case CMD_SELECT:
1771
1772                         /*
1773                          * We take a little extra care here so that the result will be
1774                          * useful for complaints about read-only statements
1775                          */
1776                         if (parsetree->into != NULL)
1777                                 tag = "SELECT INTO";
1778                         else if (parsetree->rowMarks != NIL)
1779                         {
1780                                 if (parsetree->forUpdate)
1781                                         tag = "SELECT FOR UPDATE";
1782                                 else
1783                                         tag = "SELECT FOR SHARE";
1784                         }
1785                         else
1786                                 tag = "SELECT";
1787                         break;
1788                 case CMD_UPDATE:
1789                         tag = "UPDATE";
1790                         break;
1791                 case CMD_INSERT:
1792                         tag = "INSERT";
1793                         break;
1794                 case CMD_DELETE:
1795                         tag = "DELETE";
1796                         break;
1797                 case CMD_UTILITY:
1798                         tag = CreateCommandTag(parsetree->utilityStmt);
1799                         break;
1800                 default:
1801                         elog(WARNING, "unrecognized commandType: %d",
1802                                  (int) parsetree->commandType);
1803                         tag = "???";
1804                         break;
1805         }
1806
1807         return tag;
1808 }