1 /*-------------------------------------------------------------------------
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
8 * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
9 * Portions Copyright (c) 1994, Regents of the University of California
13 * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.127 2002/02/26 22:47:09 tgl Exp $
15 *-------------------------------------------------------------------------
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"
52 * Error-checking support for DROP commands
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", "???", "???"}
73 DropErrorMsg(char *relname, char wrongkind, char rightkind)
75 struct kindstrings *rentry;
76 struct kindstrings *wentry;
78 for (rentry = kindstringarray; rentry->kind != '\0'; rentry++)
79 if (rentry->kind == rightkind)
81 Assert(rentry->kind != '\0');
83 for (wentry = kindstringarray; wentry->kind != '\0'; wentry++)
84 if (wentry->kind == wrongkind)
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);
92 elog(ERROR, "\"%s\" is not %s %s",
93 relname, rentry->indef_article, rentry->name);
97 CheckDropPermissions(char *name, char rightkind)
99 struct kindstrings *rentry;
101 Form_pg_class classform;
103 for (rentry = kindstringarray; rentry->kind != '\0'; rentry++)
104 if (rentry->kind == rightkind)
106 Assert(rentry->kind != '\0');
108 tuple = SearchSysCache(RELNAME,
109 PointerGetDatum(name),
111 if (!HeapTupleIsValid(tuple))
112 elog(ERROR, "%s \"%s\" does not exist", rentry->name, name);
114 classform = (Form_pg_class) GETSTRUCT(tuple);
116 if (classform->relkind != rightkind)
117 DropErrorMsg(name, classform->relkind, rightkind);
119 if (!pg_ownercheck(GetUserId(), name, RELNAME))
120 elog(ERROR, "you do not own %s \"%s\"",
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);
128 ReleaseSysCache(tuple);
134 * general utility function invoker
136 * parsetree: the parse tree for the utility statement
137 * dest: where to send results
138 * completionTag: points to a buffer of size COMPLETION_TAG_BUFSIZE
139 * in which to store a command completion status string.
141 * completionTag is only set nonempty if we want to return a nondefault
142 * status (currently, only used for MOVE/FETCH).
144 * completionTag may be NULL if caller doesn't want a status string.
147 ProcessUtility(Node *parsetree,
155 completionTag[0] = '\0';
157 switch (nodeTag(parsetree))
160 * ******************************** transactions ********************************
163 case T_TransactionStmt:
165 TransactionStmt *stmt = (TransactionStmt *) parsetree;
167 switch (stmt->command)
170 BeginTransactionBlock();
174 EndTransactionBlock();
178 UserAbortTransactionBlock();
185 * ******************************** portal manipulation ********************************
188 case T_ClosePortalStmt:
190 ClosePortalStmt *stmt = (ClosePortalStmt *) parsetree;
192 PerformPortalClose(stmt->portalname, dest);
198 FetchStmt *stmt = (FetchStmt *) parsetree;
199 char *portalName = stmt->portalname;
205 forward = (bool) (stmt->direction == FORWARD);
208 * parser ensures that count is >= 0 and 'fetch ALL' -> 0
211 count = stmt->howMany;
212 PerformPortalFetch(portalName, forward, count,
213 (stmt->ismove) ? None : dest,
219 * ******************************** relation and attribute
220 * manipulation ********************************
224 DefineRelation((CreateStmt *) parsetree, RELKIND_RELATION);
227 * Let AlterTableCreateToastTable decide if this one needs a
228 * secondary relation too.
230 CommandCounterIncrement();
231 AlterTableCreateToastTable(((CreateStmt *) parsetree)->relname,
237 DropStmt *stmt = (DropStmt *) parsetree;
238 List *args = stmt->names;
243 relname = strVal(lfirst(arg));
245 switch (stmt->removeType)
248 CheckDropPermissions(relname, RELKIND_RELATION);
249 RemoveRelation(relname);
253 CheckDropPermissions(relname, RELKIND_SEQUENCE);
254 RemoveRelation(relname);
258 CheckDropPermissions(relname, RELKIND_VIEW);
263 CheckDropPermissions(relname, RELKIND_INDEX);
264 RemoveIndex(relname);
269 char *rulename = relname;
272 relationName = RewriteGetRuleEventRel(rulename);
273 aclcheck_result = pg_aclcheck(relationName, GetUserId(), ACL_RULE);
274 if (aclcheck_result != ACLCHECK_OK)
275 elog(ERROR, "%s: %s", relationName,
276 aclcheck_error_strings[aclcheck_result]);
277 RemoveRewriteRule(rulename);
282 /* RemoveType does its own permissions checks */
288 * Make sure subsequent loop iterations will see
289 * results of this one; needed if removing multiple
290 * rules for same table, for example.
292 CommandCounterIncrement();
301 relname = ((TruncateStmt *) parsetree)->relName;
302 if (!allowSystemTableMods && IsSystemRelationName(relname))
303 elog(ERROR, "TRUNCATE cannot be used on system tables. '%s' is a system table",
306 /* Grab exclusive lock in preparation for truncate... */
307 rel = heap_openr(relname, AccessExclusiveLock);
308 if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
309 elog(ERROR, "TRUNCATE cannot be used on sequences. '%s' is a sequence",
311 if (rel->rd_rel->relkind == RELKIND_VIEW)
312 elog(ERROR, "TRUNCATE cannot be used on views. '%s' is a view",
314 heap_close(rel, NoLock);
316 if (!pg_ownercheck(GetUserId(), relname, RELNAME))
317 elog(ERROR, "you do not own class \"%s\"", relname);
318 TruncateRelation(relname);
324 CommentStmt *statement;
326 statement = ((CommentStmt *) parsetree);
328 CommentObject(statement->objtype, statement->objname,
329 statement->objproperty, statement->objlist,
336 CopyStmt *stmt = (CopyStmt *) parsetree;
338 if (stmt->direction != FROM)
341 DoCopy(stmt->relname,
344 (bool) (stmt->direction == FROM),
345 (bool) (stmt->filename == NULL),
348 * null filename means copy to/from stdout/stdin, rather
349 * than to/from a file.
362 RenameStmt *stmt = (RenameStmt *) parsetree;
364 relname = stmt->relname;
365 if (!allowSystemTableMods && IsSystemRelationName(relname))
366 elog(ERROR, "ALTER TABLE: relation \"%s\" is a system catalog",
368 if (!pg_ownercheck(GetUserId(), relname, RELNAME))
369 elog(ERROR, "permission denied");
372 * XXX using len == 3 to tell the difference
373 * between "rename rel to newrel" and
374 * "rename att in rel to newatt" will not
375 * work soon because "rename type/operator/rule"
376 * stuff is being added. - cim 10/24/90
378 * [another piece of amuzing but useless anecdote -- ay]
380 if (stmt->column == NULL)
385 * Note: we also rename the "type" tuple corresponding to
388 renamerel(relname, /* old name */
389 stmt->newname); /* new name */
396 renameatt(relname, /* relname */
397 stmt->column, /* old att name */
398 stmt->newname, /* new att name */
399 interpretInhOption(stmt->inhOpt)); /* recursive? */
404 /* various Alter Table forms */
406 case T_AlterTableStmt:
408 AlterTableStmt *stmt = (AlterTableStmt *) parsetree;
411 * Some or all of these functions are recursive to cover
412 * inherited things, so permission checks are done there.
414 switch (stmt->subtype)
416 case 'A': /* ADD COLUMN */
417 AlterTableAddColumn(stmt->relname,
418 interpretInhOption(stmt->inhOpt),
419 (ColumnDef *) stmt->def);
421 case 'T': /* ALTER COLUMN DEFAULT */
422 AlterTableAlterColumnDefault(stmt->relname,
423 interpretInhOption(stmt->inhOpt),
427 case 'S': /* ALTER COLUMN STATISTICS */
428 AlterTableAlterColumnStatistics(stmt->relname,
429 interpretInhOption(stmt->inhOpt),
433 case 'D': /* DROP COLUMN */
434 AlterTableDropColumn(stmt->relname,
435 interpretInhOption(stmt->inhOpt),
439 case 'C': /* ADD CONSTRAINT */
440 AlterTableAddConstraint(stmt->relname,
441 interpretInhOption(stmt->inhOpt),
444 case 'X': /* DROP CONSTRAINT */
445 AlterTableDropConstraint(stmt->relname,
446 interpretInhOption(stmt->inhOpt),
450 case 'E': /* CREATE TOAST TABLE */
451 AlterTableCreateToastTable(stmt->relname,
454 case 'U': /* ALTER OWNER */
455 AlterTableOwner(stmt->relname,
459 elog(ERROR, "T_AlterTableStmt: unknown subtype");
468 GrantStmt *stmt = (GrantStmt *) parsetree;
470 ExecuteGrantStmt(stmt);
475 * ******************************** object creation /
476 * destruction ********************************
481 DefineStmt *stmt = (DefineStmt *) parsetree;
483 switch (stmt->defType)
486 DefineOperator(stmt->defname, /* operator name */
487 stmt->definition); /* rest */
490 DefineType(stmt->defname, stmt->definition);
493 DefineAggregate(stmt->defname, /* aggregate name */
494 stmt->definition); /* rest */
500 case T_ViewStmt: /* CREATE VIEW */
502 ViewStmt *stmt = (ViewStmt *) parsetree;
504 DefineView(stmt->viewname, stmt->query); /* retrieve parsetree */
508 case T_ProcedureStmt: /* CREATE FUNCTION */
509 CreateFunction((ProcedureStmt *) parsetree);
512 case T_IndexStmt: /* CREATE INDEX */
514 IndexStmt *stmt = (IndexStmt *) parsetree;
516 relname = stmt->relname;
517 if (!allowSystemTableMods && IsSystemRelationName(relname))
518 elog(ERROR, "CREATE INDEX: relation \"%s\" is a system catalog",
520 if (!pg_ownercheck(GetUserId(), relname, RELNAME))
521 elog(ERROR, "permission denied");
523 DefineIndex(stmt->relname, /* relation name */
524 stmt->idxname, /* index name */
525 stmt->accessMethod, /* am name */
526 stmt->indexParams, /* parameters */
529 (Expr *) stmt->whereClause,
534 case T_RuleStmt: /* CREATE RULE */
536 RuleStmt *stmt = (RuleStmt *) parsetree;
539 relname = stmt->object->relname;
540 aclcheck_result = pg_aclcheck(relname, GetUserId(), ACL_RULE);
541 if (aclcheck_result != ACLCHECK_OK)
542 elog(ERROR, "%s: %s", relname, aclcheck_error_strings[aclcheck_result]);
544 DefineQueryRewrite(stmt);
548 case T_CreateSeqStmt:
549 DefineSequence((CreateSeqStmt *) parsetree);
552 case T_RemoveAggrStmt:
554 RemoveAggrStmt *stmt = (RemoveAggrStmt *) parsetree;
555 char *typename = (char *) NULL;
557 if (stmt->aggtype != NULL)
558 typename = TypeNameToInternalName((TypeName *) stmt->aggtype);
560 RemoveAggregate(stmt->aggname, typename);
564 case T_RemoveFuncStmt:
566 RemoveFuncStmt *stmt = (RemoveFuncStmt *) parsetree;
568 RemoveFunction(stmt->funcname, stmt->args);
572 case T_RemoveOperStmt:
574 RemoveOperStmt *stmt = (RemoveOperStmt *) parsetree;
575 TypeName *typenode1 = (TypeName *) lfirst(stmt->args);
576 TypeName *typenode2 = (TypeName *) lsecond(stmt->args);
577 char *typename1 = (char *) NULL;
578 char *typename2 = (char *) NULL;
580 if (typenode1 != NULL)
581 typename1 = TypeNameToInternalName(typenode1);
582 if (typenode2 != NULL)
583 typename2 = TypeNameToInternalName(typenode2);
585 RemoveOperator(stmt->opname, typename1, typename2);
590 elog(ERROR, "CREATE VERSION is not currently implemented");
595 CreatedbStmt *stmt = (CreatedbStmt *) parsetree;
597 createdb(stmt->dbname, stmt->dbowner,
598 stmt->dbpath, stmt->dbtemplate,
605 DropdbStmt *stmt = (DropdbStmt *) parsetree;
607 dropdb(stmt->dbname);
611 /* Query-level asynchronous notification */
614 NotifyStmt *stmt = (NotifyStmt *) parsetree;
616 Async_Notify(stmt->relname);
622 ListenStmt *stmt = (ListenStmt *) parsetree;
624 Async_Listen(stmt->relname, MyProcPid);
630 UnlistenStmt *stmt = (UnlistenStmt *) parsetree;
632 Async_Unlisten(stmt->relname, MyProcPid);
637 * ******************************** dynamic loader ********************************
642 LoadStmt *stmt = (LoadStmt *) parsetree;
644 closeAllVfds(); /* probably not necessary... */
645 load_file(stmt->filename);
651 ClusterStmt *stmt = (ClusterStmt *) parsetree;
653 relname = stmt->relname;
654 if (IsSystemRelationName(relname))
655 elog(ERROR, "CLUSTER: relation \"%s\" is a system catalog",
657 if (!pg_ownercheck(GetUserId(), relname, RELNAME))
658 elog(ERROR, "permission denied");
660 cluster(relname, stmt->indexname);
665 vacuum((VacuumStmt *) parsetree);
670 ExplainStmt *stmt = (ExplainStmt *) parsetree;
672 ExplainQuery(stmt->query, stmt->verbose, stmt->analyze, dest);
679 * ******************************** Tioga-related statements *******************************
683 RecipeStmt *stmt = (RecipeStmt *) parsetree;
691 * ******************************** set variable statements *******************************
693 case T_VariableSetStmt:
695 VariableSetStmt *n = (VariableSetStmt *) parsetree;
697 SetPGVariable(n->name, n->args);
701 case T_VariableShowStmt:
703 VariableShowStmt *n = (VariableShowStmt *) parsetree;
705 GetPGVariable(n->name);
709 case T_VariableResetStmt:
711 VariableResetStmt *n = (VariableResetStmt *) parsetree;
713 ResetPGVariable(n->name);
718 * ******************************** TRIGGER statements *******************************
720 case T_CreateTrigStmt:
721 CreateTrigger((CreateTrigStmt *) parsetree);
725 DropTrigger((DropTrigStmt *) parsetree);
729 * ************* PROCEDURAL LANGUAGE statements *****************
731 case T_CreatePLangStmt:
732 CreateProceduralLanguage((CreatePLangStmt *) parsetree);
735 case T_DropPLangStmt:
736 DropProceduralLanguage((DropPLangStmt *) parsetree);
740 * ******************************** USER statements ****
743 case T_CreateUserStmt:
744 CreateUser((CreateUserStmt *) parsetree);
747 case T_AlterUserStmt:
748 AlterUser((AlterUserStmt *) parsetree);
752 DropUser((DropUserStmt *) parsetree);
756 LockTableCommand((LockStmt *) parsetree);
759 case T_ConstraintsSetStmt:
760 DeferredTriggerSetState((ConstraintsSetStmt *) parsetree);
763 case T_CreateGroupStmt:
764 CreateGroup((CreateGroupStmt *) parsetree);
767 case T_AlterGroupStmt:
768 AlterGroup((AlterGroupStmt *) parsetree, "ALTER GROUP");
771 case T_DropGroupStmt:
772 DropGroup((DropGroupStmt *) parsetree);
775 case T_CheckPointStmt:
778 elog(ERROR, "permission denied");
779 CreateCheckPoint(false);
785 ReindexStmt *stmt = (ReindexStmt *) parsetree;
787 switch (stmt->reindexType)
790 relname = (char *) stmt->name;
791 if (IsSystemRelationName(relname))
793 if (!allowSystemTableMods)
794 elog(ERROR, "\"%s\" is a system index. call REINDEX under standalone postgres with -O -P options",
796 if (!IsIgnoringSystemIndexes())
797 elog(ERROR, "\"%s\" is a system index. call REINDEX under standalone postgres with -P -O options",
800 if (!pg_ownercheck(GetUserId(), relname, RELNAME))
801 elog(ERROR, "%s: %s", relname, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
802 ReindexIndex(relname, stmt->force);
805 relname = (char *) stmt->name;
806 if (!pg_ownercheck(GetUserId(), relname, RELNAME))
807 elog(ERROR, "%s: %s", relname, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
808 ReindexTable(relname, stmt->force);
811 relname = (char *) stmt->name;
812 if (!allowSystemTableMods)
813 elog(ERROR, "must be called under standalone postgres with -O -P options");
814 if (!IsIgnoringSystemIndexes())
815 elog(ERROR, "must be called under standalone postgres with -P -O options");
816 ReindexDatabase(relname, stmt->force, false);
824 * ******************************** default ********************************
828 elog(ERROR, "ProcessUtility: command #%d unsupported",