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.107 2001/01/27 10:19:52 petere 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/ps_status.h"
48 #include "utils/syscache.h"
49 #include "access/xlog.h"
52 * Error-checking support for DROP commands
62 static struct kindstrings kindstringarray[] = {
63 { RELKIND_RELATION, "a", "table", "TABLE" },
64 { RELKIND_SEQUENCE, "a", "sequence", "SEQUENCE" },
65 { RELKIND_VIEW, "a", "view", "VIEW" },
66 { RELKIND_INDEX, "an", "index", "INDEX" },
67 { '\0', "a", "???", "???" }
72 DropErrorMsg(char* relname, char wrongkind, char rightkind)
74 struct kindstrings *rentry;
75 struct kindstrings *wentry;
77 for (rentry = kindstringarray; rentry->kind != '\0'; rentry++)
78 if (rentry->kind == rightkind)
80 Assert(rentry->kind != '\0');
82 for (wentry = kindstringarray; wentry->kind != '\0'; wentry++)
83 if (wentry->kind == wrongkind)
85 /* wrongkind could be something we don't have in our table... */
86 if (wentry->kind != '\0')
87 elog(ERROR, "\"%s\" is not %s %s. Use DROP %s to remove %s %s",
88 relname, rentry->indef_article, rentry->name,
89 wentry->command, wentry->indef_article, wentry->name);
91 elog(ERROR, "\"%s\" is not %s %s",
92 relname, rentry->indef_article, rentry->name);
96 CheckDropPermissions(char *name, char rightkind)
98 struct kindstrings *rentry;
100 Form_pg_class classform;
102 for (rentry = kindstringarray; rentry->kind != '\0'; rentry++)
103 if (rentry->kind == rightkind)
105 Assert(rentry->kind != '\0');
107 tuple = SearchSysCache(RELNAME,
108 PointerGetDatum(name),
110 if (!HeapTupleIsValid(tuple))
111 elog(ERROR, "%s \"%s\" does not exist", rentry->name, name);
113 classform = (Form_pg_class) GETSTRUCT(tuple);
115 if (classform->relkind != rightkind)
116 DropErrorMsg(name, classform->relkind, rightkind);
118 if (!pg_ownercheck(GetUserId(), name, RELNAME))
119 elog(ERROR, "you do not own %s \"%s\"",
122 if (!allowSystemTableMods && IsSystemRelationName(name))
123 elog(ERROR, "%s \"%s\" is a system %s",
124 rentry->name, name, rentry->name);
126 ReleaseSysCache(tuple);
131 * general utility function invoker
135 ProcessUtility(Node *parsetree,
138 char *commandTag = NULL;
142 switch (nodeTag(parsetree))
146 * ******************************** transactions ********************************
149 case T_TransactionStmt:
151 TransactionStmt *stmt = (TransactionStmt *) parsetree;
153 switch (stmt->command)
156 set_ps_display(commandTag = "BEGIN");
157 BeginTransactionBlock();
161 set_ps_display(commandTag = "COMMIT");
162 EndTransactionBlock();
166 set_ps_display(commandTag = "ROLLBACK");
167 UserAbortTransactionBlock();
174 * ******************************** portal manipulation ********************************
177 case T_ClosePortalStmt:
179 ClosePortalStmt *stmt = (ClosePortalStmt *) parsetree;
181 set_ps_display(commandTag = "CLOSE");
183 PerformPortalClose(stmt->portalname, dest);
189 FetchStmt *stmt = (FetchStmt *) parsetree;
190 char *portalName = stmt->portalname;
194 set_ps_display(commandTag = (stmt->ismove) ? "MOVE" : "FETCH");
198 forward = (bool) (stmt->direction == FORWARD);
201 * parser ensures that count is >= 0 and 'fetch ALL' -> 0
204 count = stmt->howMany;
205 PerformPortalFetch(portalName, forward, count, commandTag,
206 (stmt->ismove) ? None : dest); /* /dev/null for MOVE */
211 * ******************************** relation and attribute
212 * manipulation ********************************
216 set_ps_display(commandTag = "CREATE");
218 DefineRelation((CreateStmt *) parsetree, RELKIND_RELATION);
221 * Let AlterTableCreateToastTable decide if this
222 * one needs a secondary relation too.
224 CommandCounterIncrement();
225 AlterTableCreateToastTable(((CreateStmt *)parsetree)->relname,
231 DropStmt *stmt = (DropStmt *) parsetree;
232 List *args = stmt->names;
235 set_ps_display(commandTag = "DROP");
239 relname = strVal(lfirst(arg));
241 switch(stmt->removeType)
244 CheckDropPermissions(relname, RELKIND_RELATION);
245 RemoveRelation(relname);
249 CheckDropPermissions(relname, RELKIND_SEQUENCE);
250 RemoveRelation(relname);
254 CheckDropPermissions(relname, RELKIND_VIEW);
259 CheckDropPermissions(relname, RELKIND_INDEX);
260 RemoveIndex(relname);
265 char *rulename = relname;
268 relationName = RewriteGetRuleEventRel(rulename);
269 aclcheck_result = pg_aclcheck(relationName, GetUserId(), ACL_RU);
270 if (aclcheck_result != ACLCHECK_OK)
271 elog(ERROR, "%s: %s", relationName,
272 aclcheck_error_strings[aclcheck_result]);
273 RemoveRewriteRule(rulename);
278 /* RemoveType does its own permissions checks */
284 * Make sure subsequent loop iterations will see results
285 * of this one; needed if removing multiple rules for
286 * same table, for example.
288 CommandCounterIncrement();
297 set_ps_display(commandTag = "TRUNCATE");
299 relname = ((TruncateStmt *) parsetree)->relName;
300 if (!allowSystemTableMods && IsSystemRelationName(relname))
301 elog(ERROR, "TRUNCATE cannot be used on system tables. '%s' is a system table",
304 /* Grab exclusive lock in preparation for truncate... */
305 rel = heap_openr(relname, AccessExclusiveLock);
306 if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
307 elog(ERROR, "TRUNCATE cannot be used on sequences. '%s' is a sequence",
309 if (rel->rd_rel->relkind == RELKIND_VIEW)
310 elog(ERROR, "TRUNCATE cannot be used on views. '%s' is a sequence",
312 heap_close(rel, NoLock);
314 if (!pg_ownercheck(GetUserId(), relname, RELNAME))
315 elog(ERROR, "you do not own class \"%s\"", relname);
316 TruncateRelation(relname);
322 CommentStmt *statement;
324 statement = ((CommentStmt *) parsetree);
326 set_ps_display(commandTag = "COMMENT");
328 CommentObject(statement->objtype, statement->objname,
329 statement->objproperty, statement->objlist,
336 CopyStmt *stmt = (CopyStmt *) parsetree;
338 set_ps_display(commandTag = "COPY");
340 if (stmt->direction != FROM)
343 DoCopy(stmt->relname,
346 (bool) (stmt->direction == FROM),
347 (bool) (stmt->filename == NULL),
350 * null filename means copy to/from stdout/stdin, rather
351 * than to/from a file.
364 RenameStmt *stmt = (RenameStmt *) parsetree;
366 set_ps_display(commandTag = "ALTER");
368 relname = stmt->relname;
369 if (!allowSystemTableMods && IsSystemRelationName(relname))
370 elog(ERROR, "ALTER TABLE: relation \"%s\" is a system catalog",
372 if (!pg_ownercheck(GetUserId(), relname, RELNAME))
373 elog(ERROR, "permission denied");
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
382 * [another piece of amuzing but useless anecdote -- ay]
384 if (stmt->column == NULL)
389 * Note: we also rename the "type" tuple
390 * corresponding to the relation.
393 renamerel(relname, /* old name */
394 stmt->newname); /* new name */
402 renameatt(relname, /* relname */
403 stmt->column, /* old att name */
404 stmt->newname, /* new att name */
405 interpretInhOption(stmt->inhOpt)); /* recursive? */
410 /* various Alter Table forms */
412 case T_AlterTableStmt:
414 AlterTableStmt *stmt = (AlterTableStmt *) parsetree;
416 set_ps_display(commandTag = "ALTER");
419 * Some or all of these functions are recursive to cover
420 * inherited things, so permission checks are done there.
422 switch (stmt->subtype)
424 case 'A': /* ADD COLUMN */
425 AlterTableAddColumn(stmt->relname,
426 interpretInhOption(stmt->inhOpt),
427 (ColumnDef *) stmt->def);
429 case 'T': /* ALTER COLUMN */
430 AlterTableAlterColumn(stmt->relname,
431 interpretInhOption(stmt->inhOpt),
435 case 'D': /* ALTER DROP */
436 AlterTableDropColumn(stmt->relname,
437 interpretInhOption(stmt->inhOpt),
441 case 'C': /* ADD CONSTRAINT */
442 AlterTableAddConstraint(stmt->relname,
443 interpretInhOption(stmt->inhOpt),
446 case 'X': /* DROP CONSTRAINT */
447 AlterTableDropConstraint(stmt->relname,
448 interpretInhOption(stmt->inhOpt),
452 case 'E': /* CREATE TOAST TABLE */
453 AlterTableCreateToastTable(stmt->relname,
456 case 'U': /* ALTER OWNER */
457 AlterTableOwner(stmt->relname,
461 elog(ERROR, "T_AlterTableStmt: unknown subtype");
468 case T_ChangeACLStmt:
470 ChangeACLStmt *stmt = (ChangeACLStmt *) parsetree;
472 set_ps_display(commandTag = "CHANGE");
474 ExecuteChangeACLStmt(stmt);
479 * ******************************** object creation /
480 * destruction ********************************
485 DefineStmt *stmt = (DefineStmt *) parsetree;
487 set_ps_display(commandTag = "CREATE");
489 switch (stmt->defType)
492 DefineOperator(stmt->defname, /* operator name */
493 stmt->definition); /* rest */
496 DefineType(stmt->defname, stmt->definition);
499 DefineAggregate(stmt->defname, /* aggregate name */
500 stmt->definition); /* rest */
506 case T_ViewStmt: /* CREATE VIEW */
508 ViewStmt *stmt = (ViewStmt *) parsetree;
510 set_ps_display(commandTag = "CREATE");
512 DefineView(stmt->viewname, stmt->query); /* retrieve parsetree */
516 case T_ProcedureStmt: /* CREATE FUNCTION */
517 set_ps_display(commandTag = "CREATE");
519 CreateFunction((ProcedureStmt *) parsetree, dest); /* everything */
522 case T_IndexStmt: /* CREATE INDEX */
524 IndexStmt *stmt = (IndexStmt *) parsetree;
526 set_ps_display(commandTag = "CREATE");
528 DefineIndex(stmt->relname, /* relation name */
529 stmt->idxname, /* index name */
530 stmt->accessMethod, /* am name */
531 stmt->indexParams, /* parameters */
535 (Expr *) stmt->whereClause,
540 case T_RuleStmt: /* CREATE RULE */
542 RuleStmt *stmt = (RuleStmt *) parsetree;
545 relname = stmt->object->relname;
546 aclcheck_result = pg_aclcheck(relname, GetUserId(), ACL_RU);
547 if (aclcheck_result != ACLCHECK_OK)
548 elog(ERROR, "%s: %s", relname, aclcheck_error_strings[aclcheck_result]);
549 set_ps_display(commandTag = "CREATE");
551 DefineQueryRewrite(stmt);
555 case T_CreateSeqStmt:
556 set_ps_display(commandTag = "CREATE");
558 DefineSequence((CreateSeqStmt *) parsetree);
563 ExtendStmt *stmt = (ExtendStmt *) parsetree;
565 set_ps_display(commandTag = "EXTEND");
567 ExtendIndex(stmt->idxname, /* index name */
568 (Expr *) stmt->whereClause, /* where */
573 case T_RemoveAggrStmt:
575 RemoveAggrStmt *stmt = (RemoveAggrStmt *) parsetree;
576 char *typename = (char *) NULL;
578 set_ps_display(commandTag = "DROP");
580 if (stmt->aggtype != NULL)
581 typename = TypeNameToInternalName((TypeName *) stmt->aggtype);
583 RemoveAggregate(stmt->aggname, typename);
587 case T_RemoveFuncStmt:
589 RemoveFuncStmt *stmt = (RemoveFuncStmt *) parsetree;
591 set_ps_display(commandTag = "DROP");
593 RemoveFunction(stmt->funcname, stmt->args);
597 case T_RemoveOperStmt:
599 RemoveOperStmt *stmt = (RemoveOperStmt *) parsetree;
600 TypeName *typenode1 = (TypeName *) lfirst(stmt->args);
601 TypeName *typenode2 = (TypeName *) lsecond(stmt->args);
602 char *typename1 = (char *) NULL;
603 char *typename2 = (char *) NULL;
605 set_ps_display(commandTag = "DROP");
607 if (typenode1 != NULL)
608 typename1 = TypeNameToInternalName(typenode1);
609 if (typenode2 != NULL)
610 typename2 = TypeNameToInternalName(typenode2);
612 RemoveOperator(stmt->opname, typename1, typename2);
617 elog(ERROR, "CREATE VERSION is not currently implemented");
622 CreatedbStmt *stmt = (CreatedbStmt *) parsetree;
624 set_ps_display(commandTag = "CREATE DATABASE");
626 createdb(stmt->dbname, stmt->dbpath,
627 stmt->dbtemplate, stmt->encoding);
633 DropdbStmt *stmt = (DropdbStmt *) parsetree;
635 set_ps_display(commandTag = "DROP DATABASE");
637 dropdb(stmt->dbname);
641 /* Query-level asynchronous notification */
644 NotifyStmt *stmt = (NotifyStmt *) parsetree;
646 set_ps_display(commandTag = "NOTIFY");
648 Async_Notify(stmt->relname);
654 ListenStmt *stmt = (ListenStmt *) parsetree;
656 set_ps_display(commandTag = "LISTEN");
658 Async_Listen(stmt->relname, MyProcPid);
664 UnlistenStmt *stmt = (UnlistenStmt *) parsetree;
666 set_ps_display(commandTag = "UNLISTEN");
668 Async_Unlisten(stmt->relname, MyProcPid);
673 * ******************************** dynamic loader ********************************
678 LoadStmt *stmt = (LoadStmt *) parsetree;
680 set_ps_display(commandTag = "LOAD");
682 closeAllVfds(); /* probably not necessary... */
683 load_file(stmt->filename);
689 ClusterStmt *stmt = (ClusterStmt *) parsetree;
691 set_ps_display(commandTag = "CLUSTER");
693 relname = stmt->relname;
694 if (IsSystemRelationName(relname))
695 elog(ERROR, "CLUSTER: relation \"%s\" is a system catalog",
697 if (!pg_ownercheck(GetUserId(), relname, RELNAME))
698 elog(ERROR, "permission denied");
700 cluster(relname, stmt->indexname);
705 set_ps_display(commandTag = "VACUUM");
707 vacuum(((VacuumStmt *) parsetree)->vacrel,
708 ((VacuumStmt *) parsetree)->verbose,
709 ((VacuumStmt *) parsetree)->analyze,
710 ((VacuumStmt *) parsetree)->va_spec);
715 ExplainStmt *stmt = (ExplainStmt *) parsetree;
717 set_ps_display(commandTag = "EXPLAIN");
719 ExplainQuery(stmt->query, stmt->verbose, dest);
726 * ******************************** Tioga-related statements *******************************
730 RecipeStmt *stmt = (RecipeStmt *) parsetree;
732 set_ps_display(commandTag = "EXECUTE RECIPE");
740 * ******************************** set variable statements *******************************
742 case T_VariableSetStmt:
744 VariableSetStmt *n = (VariableSetStmt *) parsetree;
746 SetPGVariable(n->name, n->value);
747 set_ps_display(commandTag = "SET VARIABLE");
751 case T_VariableShowStmt:
753 VariableShowStmt *n = (VariableShowStmt *) parsetree;
755 GetPGVariable(n->name);
756 set_ps_display(commandTag = "SHOW VARIABLE");
760 case T_VariableResetStmt:
762 VariableResetStmt *n = (VariableResetStmt *) parsetree;
764 ResetPGVariable(n->name);
765 set_ps_display(commandTag = "RESET VARIABLE");
770 * ******************************** TRIGGER statements *******************************
772 case T_CreateTrigStmt:
773 set_ps_display(commandTag = "CREATE");
775 CreateTrigger((CreateTrigStmt *) parsetree);
779 set_ps_display(commandTag = "DROP");
781 DropTrigger((DropTrigStmt *) parsetree);
785 * ************* PROCEDURAL LANGUAGE statements *****************
787 case T_CreatePLangStmt:
788 set_ps_display(commandTag = "CREATE");
790 CreateProceduralLanguage((CreatePLangStmt *) parsetree);
793 case T_DropPLangStmt:
794 set_ps_display(commandTag = "DROP");
796 DropProceduralLanguage((DropPLangStmt *) parsetree);
800 * ******************************** USER statements ****
803 case T_CreateUserStmt:
804 set_ps_display(commandTag = "CREATE USER");
806 CreateUser((CreateUserStmt *) parsetree);
809 case T_AlterUserStmt:
810 set_ps_display(commandTag = "ALTER USER");
812 AlterUser((AlterUserStmt *) parsetree);
816 set_ps_display(commandTag = "DROP USER");
818 DropUser((DropUserStmt *) parsetree);
822 set_ps_display(commandTag = "LOCK TABLE");
824 LockTableCommand((LockStmt *) parsetree);
827 case T_ConstraintsSetStmt:
828 set_ps_display(commandTag = "SET CONSTRAINTS");
830 DeferredTriggerSetState((ConstraintsSetStmt *) parsetree);
833 case T_CreateGroupStmt:
834 set_ps_display(commandTag = "CREATE GROUP");
836 CreateGroup((CreateGroupStmt *) parsetree);
839 case T_AlterGroupStmt:
840 set_ps_display(commandTag = "ALTER GROUP");
842 AlterGroup((AlterGroupStmt *) parsetree, "ALTER GROUP");
845 case T_DropGroupStmt:
846 set_ps_display(commandTag = "DROP GROUP");
848 DropGroup((DropGroupStmt *) parsetree);
851 case T_CheckPointStmt:
853 set_ps_display(commandTag = "CHECKPOINT");
856 elog(ERROR, "permission denied");
857 CreateCheckPoint(false);
863 ReindexStmt *stmt = (ReindexStmt *) parsetree;
865 set_ps_display(commandTag = "REINDEX");
867 switch (stmt->reindexType)
870 relname = (char *) stmt->name;
871 if (IsSystemRelationName(relname))
873 if (!allowSystemTableMods && IsSystemRelationName(relname))
874 elog(ERROR, "\"%s\" is a system index. call REINDEX under standalone postgres with -O -P options",
876 if (!IsIgnoringSystemIndexes())
877 elog(ERROR, "\"%s\" is a system index. call REINDEX under standalone postgres with -P -O options",
880 if (!pg_ownercheck(GetUserId(), relname, RELNAME))
881 elog(ERROR, "%s: %s", relname, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
882 ReindexIndex(relname, stmt->force);
885 relname = (char *) stmt->name;
886 if (IsSystemRelationName(relname))
888 #ifdef OLD_FILE_NAMING
889 if (!allowSystemTableMods && IsSystemRelationName(relname))
890 elog(ERROR, "\"%s\" is a system table. call REINDEX under standalone postgres with -O -P options",
892 if (!IsIgnoringSystemIndexes())
893 elog(ERROR, "\"%s\" is a system table. call REINDEX under standalone postgres with -P -O options",
896 #endif /* OLD_FILE_NAMING */
898 if (!pg_ownercheck(GetUserId(), relname, RELNAME))
899 elog(ERROR, "%s: %s", relname, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
900 ReindexTable(relname, stmt->force);
903 relname = (char *) stmt->name;
904 if (!allowSystemTableMods)
905 elog(ERROR, "must be called under standalone postgres with -O -P options");
906 if (!IsIgnoringSystemIndexes())
907 elog(ERROR, "must be called under standalone postgres with -P -O options");
908 ReindexDatabase(relname, stmt->force, false);
916 * ******************************** default ********************************
920 elog(ERROR, "ProcessUtility: command #%d unsupported",
926 * tell fe/be or whatever that we're done.
929 EndCommand(commandTag, dest);