OSDN Git Service

Change the aclchk.c routines to uniformly use OIDs to identify the
[pg-rex/syncrep.git] / 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-2001, PostgreSQL Global Development Group
9  * Portions Copyright (c) 1994, Regents of the University of California
10  *
11  *
12  * IDENTIFICATION
13  *        $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.137 2002/03/21 23:27:23 tgl Exp $
14  *
15  *-------------------------------------------------------------------------
16  */
17 #include "postgres.h"
18
19 #include "access/heapam.h"
20 #include "catalog/catalog.h"
21 #include "catalog/pg_shadow.h"
22 #include "commands/async.h"
23 #include "commands/cluster.h"
24 #include "commands/command.h"
25 #include "commands/comment.h"
26 #include "commands/copy.h"
27 #include "commands/creatinh.h"
28 #include "commands/dbcommands.h"
29 #include "commands/defrem.h"
30 #include "commands/explain.h"
31 #include "commands/proclang.h"
32 #include "commands/rename.h"
33 #include "commands/sequence.h"
34 #include "commands/trigger.h"
35 #include "commands/user.h"
36 #include "commands/vacuum.h"
37 #include "commands/variable.h"
38 #include "commands/view.h"
39 #include "miscadmin.h"
40 #include "parser/parse.h"
41 #include "parser/parse_clause.h"
42 #include "parser/parse_expr.h"
43 #include "rewrite/rewriteDefine.h"
44 #include "rewrite/rewriteRemove.h"
45 #include "tcop/utility.h"
46 #include "utils/acl.h"
47 #include "utils/syscache.h"
48 #include "utils/temprel.h"
49 #include "access/xlog.h"
50
51 /*
52  * Error-checking support for DROP commands
53  */
54
55 struct kindstrings
56 {
57         char            kind;
58         char       *indef_article;
59         char       *name;
60         char       *command;
61 };
62
63 static struct kindstrings kindstringarray[] = {
64         {RELKIND_RELATION, "a", "table", "TABLE"},
65         {RELKIND_SEQUENCE, "a", "sequence", "SEQUENCE"},
66         {RELKIND_VIEW, "a", "view", "VIEW"},
67         {RELKIND_INDEX, "an", "index", "INDEX"},
68         {'\0', "a", "???", "???"}
69 };
70
71
72 static void
73 DropErrorMsg(char *relname, char wrongkind, char rightkind)
74 {
75         struct kindstrings *rentry;
76         struct kindstrings *wentry;
77
78         for (rentry = kindstringarray; rentry->kind != '\0'; rentry++)
79                 if (rentry->kind == rightkind)
80                         break;
81         Assert(rentry->kind != '\0');
82
83         for (wentry = kindstringarray; wentry->kind != '\0'; wentry++)
84                 if (wentry->kind == wrongkind)
85                         break;
86         /* wrongkind could be something we don't have in our table... */
87         if (wentry->kind != '\0')
88                 elog(ERROR, "\"%s\" is not %s %s. Use DROP %s to remove %s %s",
89                          relname, rentry->indef_article, rentry->name,
90                          wentry->command, wentry->indef_article, wentry->name);
91         else
92                 elog(ERROR, "\"%s\" is not %s %s",
93                          relname, rentry->indef_article, rentry->name);
94 }
95
96 static void
97 CheckDropPermissions(char *name, char rightkind)
98 {
99         struct kindstrings *rentry;
100         HeapTuple       tuple;
101         Form_pg_class classform;
102
103         for (rentry = kindstringarray; rentry->kind != '\0'; rentry++)
104                 if (rentry->kind == rightkind)
105                         break;
106         Assert(rentry->kind != '\0');
107
108         tuple = SearchSysCache(RELNAME,
109                                                    PointerGetDatum(name),
110                                                    0, 0, 0);
111         if (!HeapTupleIsValid(tuple))
112                 elog(ERROR, "%s \"%s\" does not exist", rentry->name, name);
113
114         classform = (Form_pg_class) GETSTRUCT(tuple);
115
116         if (classform->relkind != rightkind)
117                 DropErrorMsg(name, classform->relkind, rightkind);
118
119         if (!pg_class_ownercheck(tuple->t_data->t_oid, GetUserId()))
120                 elog(ERROR, "you do not own %s \"%s\"",
121                          rentry->name, name);
122
123         if (!allowSystemTableMods && IsSystemRelationName(name) &&
124                 !is_temp_relname(name))
125                 elog(ERROR, "%s \"%s\" is a system %s",
126                          rentry->name, name, rentry->name);
127
128         ReleaseSysCache(tuple);
129 }
130
131 static void
132 CheckOwnership(char *relname, bool noCatalogs)
133 {
134         HeapTuple       tuple;
135
136         tuple = SearchSysCache(RELNAME,
137                                                    PointerGetDatum(relname),
138                                                    0, 0, 0);
139         if (!HeapTupleIsValid(tuple))
140                 elog(ERROR, "Relation \"%s\" does not exist", relname);
141
142         if (!pg_class_ownercheck(tuple->t_data->t_oid, GetUserId()))
143                 elog(ERROR, "%s: %s", relname,
144                          aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
145
146         if (noCatalogs)
147         {
148                 if (!allowSystemTableMods && IsSystemRelationName(relname))
149                         elog(ERROR, "relation \"%s\" is a system catalog",
150                                  relname);
151         }
152
153         ReleaseSysCache(tuple);
154 }
155
156
157 /*
158  * ProcessUtility
159  *              general utility function invoker
160  *
161  *      parsetree: the parse tree for the utility statement
162  *      dest: where to send results
163  *      completionTag: points to a buffer of size COMPLETION_TAG_BUFSIZE
164  *              in which to store a command completion status string.
165  *
166  * completionTag is only set nonempty if we want to return a nondefault
167  * status (currently, only used for MOVE/FETCH).
168  *
169  * completionTag may be NULL if caller doesn't want a status string.
170  */
171 void
172 ProcessUtility(Node *parsetree,
173                            CommandDest dest,
174                            char *completionTag)
175 {
176         char       *relname;
177
178         if (completionTag)
179                 completionTag[0] = '\0';
180
181         switch (nodeTag(parsetree))
182         {
183                         /*
184                          * ******************************** transactions ********************************
185                          *
186                          */
187                 case T_TransactionStmt:
188                         {
189                                 TransactionStmt *stmt = (TransactionStmt *) parsetree;
190
191                                 switch (stmt->command)
192                                 {
193                                         case BEGIN_TRANS:
194                                                 BeginTransactionBlock();
195                                                 break;
196
197                                         case COMMIT:
198                                                 EndTransactionBlock();
199                                                 break;
200
201                                         case ROLLBACK:
202                                                 UserAbortTransactionBlock();
203                                                 break;
204                                 }
205                         }
206                         break;
207
208                         /*
209                          * ******************************** portal manipulation ********************************
210                          *
211                          */
212                 case T_ClosePortalStmt:
213                         {
214                                 ClosePortalStmt *stmt = (ClosePortalStmt *) parsetree;
215
216                                 PerformPortalClose(stmt->portalname, dest);
217                         }
218                         break;
219
220                 case T_FetchStmt:
221                         {
222                                 FetchStmt  *stmt = (FetchStmt *) parsetree;
223                                 char       *portalName = stmt->portalname;
224                                 bool            forward;
225                                 int                     count;
226
227                                 SetQuerySnapshot();
228
229                                 forward = (bool) (stmt->direction == FORWARD);
230
231                                 /*
232                                  * parser ensures that count is >= 0 and 'fetch ALL' -> 0
233                                  */
234
235                                 count = stmt->howMany;
236                                 PerformPortalFetch(portalName, forward, count,
237                                                                    (stmt->ismove) ? None : dest,
238                                                                    completionTag);
239                         }
240                         break;
241
242                         /*
243                          * relation and attribute manipulation
244                          */
245                 case T_CreateSchemaStmt:
246                         {
247                                 CreateSchemaStmt  *stmt = (CreateSchemaStmt *) parsetree;
248
249                                 CreateSchemaCommand(stmt);
250                         }
251                         break;
252
253                 case T_CreateStmt:
254                         DefineRelation((CreateStmt *) parsetree, RELKIND_RELATION);
255
256                         /*
257                          * Let AlterTableCreateToastTable decide if this one needs a
258                          * secondary relation too.
259                          */
260                         CommandCounterIncrement();
261                         AlterTableCreateToastTable(((CreateStmt *) parsetree)->relation->relname,
262                                                                            true);
263                         break;
264
265                 case T_DropStmt:
266                         {
267                                 DropStmt   *stmt = (DropStmt *) parsetree;
268                                 List       *args = stmt->objects;
269                                 List       *arg;
270
271                                 foreach(arg, args)
272                                 {
273                                         relname = ((RangeVar *) lfirst(arg))->relname;
274
275                                         switch (stmt->removeType)
276                                         {
277                                                 case DROP_TABLE:
278                                                         CheckDropPermissions(relname, RELKIND_RELATION);
279                                                         RemoveRelation(relname);
280                                                         break;
281
282                                                 case DROP_SEQUENCE:
283                                                         CheckDropPermissions(relname, RELKIND_SEQUENCE);
284                                                         RemoveRelation(relname);
285                                                         break;
286
287                                                 case DROP_VIEW:
288                                                         CheckDropPermissions(relname, RELKIND_VIEW);
289                                                         RemoveView(relname);
290                                                         break;
291
292                                                 case DROP_INDEX:
293                                                         CheckDropPermissions(relname, RELKIND_INDEX);
294                                                         RemoveIndex(relname);
295                                                         break;
296
297                                                 case DROP_RULE:
298                                                         /* RemoveRewriteRule checks permissions */
299                                                         RemoveRewriteRule(relname);
300                                                         break;
301
302                                                 case DROP_TYPE:
303                                                         /* RemoveType does its own permissions checks */
304                                                         RemoveType(relname);
305                                                         break;
306
307                                                 case DROP_DOMAIN:
308                                                         /* RemoveDomain does its own permissions checks */
309                                                         RemoveDomain(relname, stmt->behavior);
310                                                         break;
311                                         }
312
313                                         /*
314                                          * Make sure subsequent loop iterations will see
315                                          * results of this one; needed if removing multiple
316                                          * rules for same table, for example.
317                                          */
318                                         CommandCounterIncrement();
319                                 }
320                         }
321                         break;
322
323                 case T_TruncateStmt:
324                         {
325                                 relname = ((TruncateStmt *) parsetree)->relation->relname;
326                                 TruncateRelation(relname);
327                         }
328                         break;
329
330                 case T_CommentStmt:
331                         {
332                                 CommentStmt *statement;
333
334                                 statement = ((CommentStmt *) parsetree);
335
336                                 CommentObject(statement->objtype, statement->objname,
337                                                           statement->objproperty, statement->objlist,
338                                                           statement->comment);
339                         }
340                         break;
341
342                 case T_CopyStmt:
343                         {
344                                 CopyStmt   *stmt = (CopyStmt *) parsetree;
345
346                                 if (stmt->direction != FROM)
347                                         SetQuerySnapshot();
348
349                                 DoCopy(stmt->relation->relname,
350                                            stmt->binary,
351                                            stmt->oids,
352                                            (bool) (stmt->direction == FROM),
353                                            (bool) (stmt->filename == NULL),
354
355                                 /*
356                                  * null filename means copy to/from stdout/stdin, rather
357                                  * than to/from a file.
358                                  */
359                                            stmt->filename,
360                                            stmt->delimiter,
361                                            stmt->null_print);
362                         }
363                         break;
364
365                         /*
366                          * schema
367                          */
368                 case T_RenameStmt:
369                         {
370                                 RenameStmt *stmt = (RenameStmt *) parsetree;
371
372                                 relname = stmt->relation->relname;
373                                 CheckOwnership(relname, true);
374
375                                 /* ----------------
376                                  *      XXX using len == 3 to tell the difference
377                                  *              between "rename rel to newrel" and
378                                  *              "rename att in rel to newatt" will not
379                                  *              work soon because "rename type/operator/rule"
380                                  *              stuff is being added. - cim 10/24/90
381                                  * ----------------
382                                  * [another piece of amuzing but useless anecdote -- ay]
383                                  */
384                                 if (stmt->column == NULL)
385                                 {
386                                         /*
387                                          * rename relation
388                                          *
389                                          * Note: we also rename the "type" tuple corresponding to
390                                          * the relation.
391                                          */
392                                         renamerel(relname,      /* old name */
393                                                           stmt->newname);       /* new name */
394                                 }
395                                 else
396                                 {
397                                         /*
398                                          * rename attribute
399                                          */
400                                         renameatt(relname,      /* relname */
401                                                           stmt->column,         /* old att name */
402                                                           stmt->newname,        /* new att name */
403                                                           interpretInhOption(stmt->relation->inhOpt));          /* recursive? */
404                                 }
405                         }
406                         break;
407
408                         /* various Alter Table forms */
409
410                 case T_AlterTableStmt:
411                         {
412                                 AlterTableStmt *stmt = (AlterTableStmt *) parsetree;
413
414                                 /*
415                                  * Some or all of these functions are recursive to cover
416                                  * inherited things, so permission checks are done there.
417                                  */
418                                 switch (stmt->subtype)
419                                 {
420                                         case 'A':       /* ADD COLUMN */
421                                                 AlterTableAddColumn(stmt->relation->relname,
422                                                                                 interpretInhOption((stmt->relation)->inhOpt),
423                                                                                         (ColumnDef *) stmt->def);
424                                                 break;
425                                         case 'T':       /* ALTER COLUMN DEFAULT */
426                                                 AlterTableAlterColumnDefault(stmt->relation->relname,
427                                                                                 interpretInhOption((stmt->relation)->inhOpt),
428                                                                                                          stmt->name,
429                                                                                                          stmt->def);
430                                                 break;
431                                         case 'S':       /* ALTER COLUMN STATISTICS */
432                                         case 'M':   /* ALTER COLUMN STORAGE */
433                                                 AlterTableAlterColumnFlags(stmt->relation->relname,
434                                                                                 interpretInhOption(stmt->relation->inhOpt),
435                                                                                                                 stmt->name,
436                                                                                                                 stmt->def,
437                                                                                                         &(stmt->subtype));
438                                                 break;
439                                         case 'D':       /* DROP COLUMN */
440                                                 AlterTableDropColumn(stmt->relation->relname,
441                                                                                 interpretInhOption(stmt->relation->inhOpt),
442                                                                                          stmt->name,
443                                                                                          stmt->behavior);
444                                                 break;
445                                         case 'C':       /* ADD CONSTRAINT */
446                                                 AlterTableAddConstraint(stmt->relation->relname,
447                                                                                 interpretInhOption(stmt->relation->inhOpt),
448                                                                                                 (List *) stmt->def);
449                                                 break;
450                                         case 'X':       /* DROP CONSTRAINT */
451                                                 AlterTableDropConstraint(stmt->relation->relname,
452                                                                                 interpretInhOption(stmt->relation->inhOpt),
453                                                                                                  stmt->name,
454                                                                                                  stmt->behavior);
455                                                 break;
456                                         case 'E':       /* CREATE TOAST TABLE */
457                                                 AlterTableCreateToastTable(stmt->relation->relname,
458                                                                                                    false);
459                                                 break;
460                                         case 'U':       /* ALTER OWNER */
461                                                 AlterTableOwner(stmt->relation->relname,
462                                                                                 stmt->name);
463                                                 break;
464                                         default:        /* oops */
465                                                 elog(ERROR, "T_AlterTableStmt: unknown subtype");
466                                                 break;
467                                 }
468                         }
469                         break;
470
471
472                 case T_GrantStmt:
473                         {
474                                 GrantStmt  *stmt = (GrantStmt *) parsetree;
475
476                                 ExecuteGrantStmt(stmt);
477                         }
478                         break;
479
480                         /*
481                          * ******************************** object creation /
482                          * destruction ********************************
483                          *
484                          */
485                 case T_DefineStmt:
486                         {
487                                 DefineStmt *stmt = (DefineStmt *) parsetree;
488
489                                 switch (stmt->defType)
490                                 {
491                                         case OPERATOR:
492                                                 DefineOperator(stmt->defname,   /* operator name */
493                                                                            stmt->definition);           /* rest */
494                                                 break;
495                                         case TYPE_P:
496                                                 DefineType(stmt->defname, stmt->definition);
497                                                 break;
498                                         case AGGREGATE:
499                                                 DefineAggregate(stmt->defname,  /* aggregate name */
500                                                                                 stmt->definition);              /* rest */
501                                                 break;
502                                 }
503                         }
504                         break;
505
506                 case T_ViewStmt:                /* CREATE VIEW */
507                         {
508                                 ViewStmt   *stmt = (ViewStmt *) parsetree;
509
510                                 DefineView(stmt->view->relname, stmt->query);   /* retrieve parsetree */
511                         }
512                         break;
513
514                 case T_ProcedureStmt:   /* CREATE FUNCTION */
515                         CreateFunction((ProcedureStmt *) parsetree);
516                         break;
517
518                 case T_IndexStmt:               /* CREATE INDEX */
519                         {
520                                 IndexStmt  *stmt = (IndexStmt *) parsetree;
521
522                                 relname = stmt->relation->relname;
523                                 CheckOwnership(relname, true);
524
525                                 DefineIndex(stmt->relation->relname,    /* relation */
526                                                         stmt->idxname,                          /* index name */
527                                                         stmt->accessMethod,             /* am name */
528                                                         stmt->indexParams,                      /* parameters */
529                                                         stmt->unique,
530                                                         stmt->primary,
531                                                         (Expr *) stmt->whereClause,
532                                                         stmt->rangetable);
533                         }
534                         break;
535
536                 case T_RuleStmt:                /* CREATE RULE */
537                         DefineQueryRewrite((RuleStmt *) parsetree);
538                         break;
539
540                 case T_CreateSeqStmt:
541                         DefineSequence((CreateSeqStmt *) parsetree);
542                         break;
543
544                 case T_RemoveAggrStmt:
545                         {
546                                 RemoveAggrStmt *stmt = (RemoveAggrStmt *) parsetree;
547                                 char       *typename = (char *) NULL;
548
549                                 if (stmt->aggtype != NULL)
550                                         typename = TypeNameToInternalName((TypeName *) stmt->aggtype);
551
552                                 RemoveAggregate(stmt->aggname, typename);
553                         }
554                         break;
555
556                 case T_RemoveFuncStmt:
557                         {
558                                 RemoveFuncStmt *stmt = (RemoveFuncStmt *) parsetree;
559
560                                 RemoveFunction(stmt->funcname, stmt->args);
561                         }
562                         break;
563
564                 case T_RemoveOperStmt:
565                         {
566                                 RemoveOperStmt *stmt = (RemoveOperStmt *) parsetree;
567                                 TypeName   *typenode1 = (TypeName *) lfirst(stmt->args);
568                                 TypeName   *typenode2 = (TypeName *) lsecond(stmt->args);
569                                 char       *typename1 = (char *) NULL;
570                                 char       *typename2 = (char *) NULL;
571
572                                 if (typenode1 != NULL)
573                                         typename1 = TypeNameToInternalName(typenode1);
574                                 if (typenode2 != NULL)
575                                         typename2 = TypeNameToInternalName(typenode2);
576
577                                 RemoveOperator(stmt->opname, typename1, typename2);
578                         }
579                         break;
580
581                 case T_VersionStmt:
582                         elog(ERROR, "CREATE VERSION is not currently implemented");
583                         break;
584
585                 case T_CreatedbStmt:
586                         {
587                                 CreatedbStmt *stmt = (CreatedbStmt *) parsetree;
588
589                                 createdb(stmt->dbname, stmt->dbowner,
590                                                  stmt->dbpath, stmt->dbtemplate,
591                                                  stmt->encoding);
592                         }
593                         break;
594
595                 case T_AlterDatabaseSetStmt:
596                         AlterDatabaseSet((AlterDatabaseSetStmt *)parsetree);
597                         break;
598
599                 case T_DropdbStmt:
600                         {
601                                 DropdbStmt *stmt = (DropdbStmt *) parsetree;
602
603                                 dropdb(stmt->dbname);
604                         }
605                         break;
606
607                         /* Query-level asynchronous notification */
608                 case T_NotifyStmt:
609                         {
610                                 NotifyStmt *stmt = (NotifyStmt *) parsetree;
611
612                                 Async_Notify(stmt->relation->relname);
613                         }
614                         break;
615
616                 case T_ListenStmt:
617                         {
618                                 ListenStmt *stmt = (ListenStmt *) parsetree;
619
620                                 Async_Listen(stmt->relation->relname, MyProcPid);
621                         }
622                         break;
623
624                 case T_UnlistenStmt:
625                         {
626                                 UnlistenStmt *stmt = (UnlistenStmt *) parsetree;
627
628                                 Async_Unlisten(stmt->relation->relname, MyProcPid);
629                         }
630                         break;
631
632                 case T_LoadStmt:
633                         {
634                                 LoadStmt   *stmt = (LoadStmt *) parsetree;
635
636                                 closeAllVfds(); /* probably not necessary... */
637                                 load_file(stmt->filename);
638                         }
639                         break;
640
641                 case T_ClusterStmt:
642                         {
643                                 ClusterStmt *stmt = (ClusterStmt *) parsetree;
644
645                                 relname = stmt->relation->relname;
646                                 CheckOwnership(relname, true);
647
648                                 cluster(relname, stmt->indexname);
649                         }
650                         break;
651
652                 case T_VacuumStmt:
653                         vacuum((VacuumStmt *) parsetree);
654                         break;
655
656                 case T_ExplainStmt:
657                         {
658                                 ExplainStmt *stmt = (ExplainStmt *) parsetree;
659
660                                 ExplainQuery(stmt->query, stmt->verbose, stmt->analyze, dest);
661                         }
662                         break;
663
664 #ifdef NOT_USED
665
666                 case T_RecipeStmt:
667                         {
668                                 RecipeStmt *stmt = (RecipeStmt *) parsetree;
669
670                                 beginRecipe(stmt);
671                         }
672                         break;
673 #endif
674
675                 case T_VariableSetStmt:
676                         {
677                                 VariableSetStmt *n = (VariableSetStmt *) parsetree;
678
679                                 SetPGVariable(n->name, n->args);
680                         }
681                         break;
682
683                 case T_VariableShowStmt:
684                         {
685                                 VariableShowStmt *n = (VariableShowStmt *) parsetree;
686
687                                 GetPGVariable(n->name);
688                         }
689                         break;
690
691                 case T_VariableResetStmt:
692                         {
693                                 VariableResetStmt *n = (VariableResetStmt *) parsetree;
694
695                                 ResetPGVariable(n->name);
696                         }
697                         break;
698
699                 case T_CreateTrigStmt:
700                         CreateTrigger((CreateTrigStmt *) parsetree);
701                         break;
702
703                 case T_DropTrigStmt:
704                         DropTrigger((DropTrigStmt *) parsetree);
705                         break;
706
707                 case T_CreatePLangStmt:
708                         CreateProceduralLanguage((CreatePLangStmt *) parsetree);
709                         break;
710
711                 case T_DropPLangStmt:
712                         DropProceduralLanguage((DropPLangStmt *) parsetree);
713                         break;
714
715                         /*
716                          * ******************************** DOMAIN statements ****
717                          */
718                 case T_CreateDomainStmt:
719                         DefineDomain((CreateDomainStmt *) parsetree);
720                         break;
721
722                         /*
723                          * ******************************** USER statements ****
724                          */
725                 case T_CreateUserStmt:
726                         CreateUser((CreateUserStmt *) parsetree);
727                         break;
728
729                 case T_AlterUserStmt:
730                         AlterUser((AlterUserStmt *) parsetree);
731                         break;
732
733                 case T_AlterUserSetStmt:
734                         AlterUserSet((AlterUserSetStmt *) parsetree);
735                         break;
736
737                 case T_DropUserStmt:
738                         DropUser((DropUserStmt *) parsetree);
739                         break;
740
741                 case T_LockStmt:
742                         LockTableCommand((LockStmt *) parsetree);
743                         break;
744
745                 case T_ConstraintsSetStmt:
746                         DeferredTriggerSetState((ConstraintsSetStmt *) parsetree);
747                         break;
748
749                 case T_CreateGroupStmt:
750                         CreateGroup((CreateGroupStmt *) parsetree);
751                         break;
752
753                 case T_AlterGroupStmt:
754                         AlterGroup((AlterGroupStmt *) parsetree, "ALTER GROUP");
755                         break;
756
757                 case T_DropGroupStmt:
758                         DropGroup((DropGroupStmt *) parsetree);
759                         break;
760
761                 case T_CheckPointStmt:
762                         {
763                                 if (!superuser())
764                                         elog(ERROR, "permission denied");
765                                 CreateCheckPoint(false);
766                         }
767                         break;
768
769                 case T_ReindexStmt:
770                         {
771                                 ReindexStmt *stmt = (ReindexStmt *) parsetree;
772
773                                 switch (stmt->reindexType)
774                                 {
775                                         case INDEX:
776                                                 relname = (char *) stmt->relation->relname;
777                                                 if (IsSystemRelationName(relname))
778                                                 {
779                                                         if (!allowSystemTableMods)
780                                                                 elog(ERROR, "\"%s\" is a system index. call REINDEX under standalone postgres with -O -P options",
781                                                                          relname);
782                                                         if (!IsIgnoringSystemIndexes())
783                                                                 elog(ERROR, "\"%s\" is a system index. call REINDEX under standalone postgres with -P -O options",
784                                                                          relname);
785                                                 }
786                                                 CheckOwnership(relname, false);
787                                                 ReindexIndex(relname, stmt->force);
788                                                 break;
789                                         case TABLE:
790                                                 relname = (char *) stmt->relation->relname;
791                                                 CheckOwnership(relname, false);
792                                                 ReindexTable(relname, stmt->force);
793                                                 break;
794                                         case DATABASE:
795                                                 relname = (char *) stmt->name;
796                                                 if (!allowSystemTableMods)
797                                                         elog(ERROR, "must be called under standalone postgres with -O -P options");
798                                                 if (!IsIgnoringSystemIndexes())
799                                                         elog(ERROR, "must be called under standalone postgres with -P -O options");
800                                                 ReindexDatabase(relname, stmt->force, false);
801                                                 break;
802                                 }
803                                 break;
804                         }
805                         break;
806
807                 default:
808                         elog(ERROR, "ProcessUtility: command #%d unsupported",
809                                  nodeTag(parsetree));
810                         break;
811         }
812 }