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-2000, PostgreSQL, Inc
9 * Portions Copyright (c) 1994, Regents of the University of California
13 * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.85 2000/04/04 21:44:40 tgl Exp $
15 *-------------------------------------------------------------------------
19 #include "access/heapam.h"
20 #include "catalog/catalog.h"
21 #include "catalog/pg_type.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 "rewrite/rewriteDefine.h"
42 #include "rewrite/rewriteRemove.h"
43 #include "tcop/utility.h"
44 #include "utils/acl.h"
45 #include "utils/ps_status.h"
46 #include "utils/syscache.h"
50 * CHECK_IF_ABORTED() is used to avoid doing unnecessary
51 * processing within an aborted transaction block.
54 /* we have to use IF because of the 'break' */
55 #define CHECK_IF_ABORTED() \
58 if (IsAbortedTransactionBlockState()) \
60 elog(NOTICE, "current transaction is aborted, " \
61 "queries ignored until end of transaction block"); \
62 commandTag = "*ABORT STATE*"; \
68 * general utility function invoker
72 ProcessUtility(Node *parsetree,
75 char *commandTag = NULL;
80 userName = GetPgUserName();
82 switch (nodeTag(parsetree))
86 * ******************************** transactions ********************************
89 case T_TransactionStmt:
91 TransactionStmt *stmt = (TransactionStmt *) parsetree;
93 switch (stmt->command)
96 PS_SET_STATUS(commandTag = "BEGIN");
98 BeginTransactionBlock();
102 PS_SET_STATUS(commandTag = "COMMIT");
103 EndTransactionBlock();
107 PS_SET_STATUS(commandTag = "ROLLBACK");
108 UserAbortTransactionBlock();
115 * ******************************** portal manipulation ********************************
118 case T_ClosePortalStmt:
120 ClosePortalStmt *stmt = (ClosePortalStmt *) parsetree;
122 PS_SET_STATUS(commandTag = "CLOSE");
125 PerformPortalClose(stmt->portalname, dest);
131 FetchStmt *stmt = (FetchStmt *) parsetree;
132 char *portalName = stmt->portalname;
136 PS_SET_STATUS(commandTag = (stmt->ismove) ? "MOVE" : "FETCH");
141 forward = (bool) (stmt->direction == FORWARD);
144 * parser ensures that count is >= 0 and 'fetch ALL' -> 0
147 count = stmt->howMany;
148 PerformPortalFetch(portalName, forward, count, commandTag,
149 (stmt->ismove) ? None : dest); /* /dev/null for MOVE */
154 * ******************************** relation and attribute
155 * manipulation ********************************
159 PS_SET_STATUS(commandTag = "CREATE");
162 DefineRelation((CreateStmt *) parsetree, RELKIND_RELATION);
167 DropStmt *stmt = (DropStmt *) parsetree;
168 List *args = stmt->relNames;
171 PS_SET_STATUS(commandTag = "DROP");
174 /* check as much as we can before we start dropping ... */
179 relname = strVal(lfirst(arg));
180 if (!allowSystemTableMods && IsSystemRelationName(relname))
181 elog(ERROR, "class \"%s\" is a system catalog",
183 rel = heap_openr(relname, AccessExclusiveLock);
184 if (stmt->sequence &&
185 rel->rd_rel->relkind != RELKIND_SEQUENCE)
186 elog(ERROR, "Use DROP TABLE to drop table '%s'",
188 if (!(stmt->sequence) &&
189 rel->rd_rel->relkind == RELKIND_SEQUENCE)
190 elog(ERROR, "Use DROP SEQUENCE to drop sequence '%s'",
192 /* close rel, but keep lock until end of xact */
193 heap_close(rel, NoLock);
195 if (!pg_ownercheck(userName, relname, RELNAME))
196 elog(ERROR, "you do not own class \"%s\"",
200 /* OK, terminate 'em all */
203 relname = strVal(lfirst(arg));
204 RemoveRelation(relname);
213 PS_SET_STATUS(commandTag = "TRUNCATE");
216 relname = ((TruncateStmt *) parsetree)->relName;
217 if (!allowSystemTableMods && IsSystemRelationName(relname))
218 elog(ERROR, "TRUNCATE cannot be used on system tables. '%s' is a system table",
221 /* Grab exclusive lock in preparation for truncate... */
222 rel = heap_openr(relname, AccessExclusiveLock);
223 if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
224 elog(ERROR, "TRUNCATE cannot be used on sequences. '%s' is a sequence",
226 heap_close(rel, NoLock);
229 if (!pg_ownercheck(userName, relname, RELNAME))
230 elog(ERROR, "you do not own class \"%s\"", relname);
232 TruncateRelation(relname);
239 CommentStmt *statement;
241 statement = ((CommentStmt *) parsetree);
243 PS_SET_STATUS(commandTag = "COMMENT");
245 CommentObject(statement->objtype, statement->objname,
246 statement->objproperty, statement->objlist,
255 CopyStmt *stmt = (CopyStmt *) parsetree;
257 PS_SET_STATUS(commandTag = "COPY");
260 if (stmt->direction != FROM)
263 DoCopy(stmt->relname,
266 (bool) (stmt->direction == FROM),
267 (bool) (stmt->filename == NULL),
270 * null filename means copy to/from stdout/stdin, rather
271 * than to/from a file.
284 RenameStmt *stmt = (RenameStmt *) parsetree;
286 PS_SET_STATUS(commandTag = "ALTER");
289 relname = stmt->relname;
290 if (!allowSystemTableMods && IsSystemRelationName(relname))
291 elog(ERROR, "ALTER TABLE: relation \"%s\" is a system catalog",
294 if (!pg_ownercheck(userName, relname, RELNAME))
295 elog(ERROR, "permission denied");
299 * XXX using len == 3 to tell the difference
300 * between "rename rel to newrel" and
301 * "rename att in rel to newatt" will not
302 * work soon because "rename type/operator/rule"
303 * stuff is being added. - cim 10/24/90
305 * [another piece of amuzing but useless anecdote -- ay]
307 if (stmt->column == NULL)
312 * Note: we also rename the "type" tuple
313 * corresponding to the relation.
316 renamerel(relname, /* old name */
317 stmt->newname); /* new name */
318 TypeRename(relname, /* old name */
319 stmt->newname); /* new name */
327 renameatt(relname, /* relname */
328 stmt->column, /* old att name */
329 stmt->newname, /* new att name */
331 stmt->inh); /* recursive? */
336 /* various Alter Table forms */
338 case T_AlterTableStmt:
340 AlterTableStmt *stmt = (AlterTableStmt *) parsetree;
342 PS_SET_STATUS(commandTag = "ALTER");
346 * Some or all of these functions are recursive to cover inherited things,
347 * so permission checks are done there.
349 switch(stmt->subtype)
351 case 'A': /* ADD COLUMN */
352 AlterTableAddColumn(stmt->relname, stmt->inh, (ColumnDef *) stmt->def);
354 case 'T': /* ALTER COLUMN */
355 AlterTableAlterColumn(stmt->relname, stmt->inh, stmt->name, stmt->def);
357 case 'D': /* ALTER DROP */
358 AlterTableDropColumn(stmt->relname, stmt->inh, stmt->name, stmt->behavior);
360 case 'C': /* ADD CONSTRAINT */
361 AlterTableAddConstraint(stmt->relname, stmt->inh, stmt->def);
363 case 'X': /* DROP CONSTRAINT */
364 AlterTableDropConstraint(stmt->relname, stmt->inh, stmt->name, stmt->behavior);
367 elog(ERROR, "T_AlterTableStmt: unknown subtype");
374 case T_ChangeACLStmt:
376 ChangeACLStmt *stmt = (ChangeACLStmt *) parsetree;
381 PS_SET_STATUS(commandTag = "CHANGE");
386 modechg = stmt->modechg;
387 foreach(i, stmt->relNames)
391 relname = strVal(lfirst(i));
392 rel = heap_openr(relname, AccessExclusiveLock);
393 if (rel && rel->rd_rel->relkind == RELKIND_INDEX)
394 elog(ERROR, "\"%s\" is an index relation",
396 /* close rel, but keep lock until end of xact */
397 heap_close(rel, NoLock);
399 if (!pg_ownercheck(userName, relname, RELNAME))
400 elog(ERROR, "you do not own class \"%s\"",
403 ChangeAcl(relname, aip, modechg);
409 * ******************************** object creation /
410 * destruction ********************************
415 DefineStmt *stmt = (DefineStmt *) parsetree;
417 PS_SET_STATUS(commandTag = "CREATE");
420 switch (stmt->defType)
423 DefineOperator(stmt->defname, /* operator name */
424 stmt->definition); /* rest */
427 DefineType(stmt->defname, stmt->definition);
430 DefineAggregate(stmt->defname, /* aggregate name */
431 stmt->definition); /* rest */
437 case T_ViewStmt: /* CREATE VIEW */
439 ViewStmt *stmt = (ViewStmt *) parsetree;
441 PS_SET_STATUS(commandTag = "CREATE");
443 DefineView(stmt->viewname, stmt->query); /* retrieve parsetree */
447 case T_ProcedureStmt: /* CREATE FUNCTION */
448 PS_SET_STATUS(commandTag = "CREATE");
450 CreateFunction((ProcedureStmt *) parsetree, dest); /* everything */
453 case T_IndexStmt: /* CREATE INDEX */
455 IndexStmt *stmt = (IndexStmt *) parsetree;
457 PS_SET_STATUS(commandTag = "CREATE");
459 DefineIndex(stmt->relname, /* relation name */
460 stmt->idxname, /* index name */
461 stmt->accessMethod, /* am name */
462 stmt->indexParams, /* parameters */
466 (Expr *) stmt->whereClause,
471 case T_RuleStmt: /* CREATE RULE */
473 RuleStmt *stmt = (RuleStmt *) parsetree;
477 relname = stmt->object->relname;
478 aclcheck_result = pg_aclcheck(relname, userName, ACL_RU);
479 if (aclcheck_result != ACLCHECK_OK)
480 elog(ERROR, "%s: %s", relname, aclcheck_error_strings[aclcheck_result]);
482 PS_SET_STATUS(commandTag = "CREATE");
484 DefineQueryRewrite(stmt);
488 case T_CreateSeqStmt:
489 PS_SET_STATUS(commandTag = "CREATE");
492 DefineSequence((CreateSeqStmt *) parsetree);
497 ExtendStmt *stmt = (ExtendStmt *) parsetree;
499 PS_SET_STATUS(commandTag = "EXTEND");
502 ExtendIndex(stmt->idxname, /* index name */
503 (Expr *) stmt->whereClause, /* where */
510 RemoveStmt *stmt = (RemoveStmt *) parsetree;
512 PS_SET_STATUS(commandTag = "DROP");
515 switch (stmt->removeType)
518 relname = stmt->name;
519 if (!allowSystemTableMods && IsSystemRelationName(relname))
520 elog(ERROR, "class \"%s\" is a system catalog index",
523 if (!pg_ownercheck(userName, relname, RELNAME))
524 elog(ERROR, "%s: %s", relname, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
526 RemoveIndex(relname);
530 char *rulename = stmt->name;
535 relationName = RewriteGetRuleEventRel(rulename);
536 aclcheck_result = pg_aclcheck(relationName, userName, ACL_RU);
537 if (aclcheck_result != ACLCHECK_OK)
538 elog(ERROR, "%s: %s", relationName, aclcheck_error_strings[aclcheck_result]);
540 RemoveRewriteRule(rulename);
545 /* XXX moved to remove.c */
547 RemoveType(stmt->name);
551 char *viewName = stmt->name;
556 ruleName = MakeRetrieveViewRuleName(viewName);
557 relationName = RewriteGetRuleEventRel(ruleName);
558 if (!pg_ownercheck(userName, relationName, RELNAME))
559 elog(ERROR, "%s: %s", relationName, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
562 RemoveView(viewName);
570 case T_RemoveAggrStmt:
572 RemoveAggrStmt *stmt = (RemoveAggrStmt *) parsetree;
574 PS_SET_STATUS(commandTag = "DROP");
576 RemoveAggregate(stmt->aggname, stmt->aggtype);
580 case T_RemoveFuncStmt:
582 RemoveFuncStmt *stmt = (RemoveFuncStmt *) parsetree;
584 PS_SET_STATUS(commandTag = "DROP");
586 RemoveFunction(stmt->funcname,
592 case T_RemoveOperStmt:
594 RemoveOperStmt *stmt = (RemoveOperStmt *) parsetree;
595 char *type1 = (char *) NULL;
596 char *type2 = (char *) NULL;
598 PS_SET_STATUS(commandTag = "DROP");
601 if (lfirst(stmt->args) != NULL)
602 type1 = strVal(lfirst(stmt->args));
603 if (lsecond(stmt->args) != NULL)
604 type2 = strVal(lsecond(stmt->args));
605 RemoveOperator(stmt->opname, type1, type2);
610 elog(ERROR, "CREATE VERSION is not currently implemented");
615 CreatedbStmt *stmt = (CreatedbStmt *) parsetree;
617 PS_SET_STATUS(commandTag = "CREATE DATABASE");
619 createdb(stmt->dbname, stmt->dbpath, stmt->encoding);
625 DropdbStmt *stmt = (DropdbStmt *) parsetree;
627 PS_SET_STATUS(commandTag = "DROP DATABASE");
629 dropdb(stmt->dbname);
633 /* Query-level asynchronous notification */
636 NotifyStmt *stmt = (NotifyStmt *) parsetree;
638 PS_SET_STATUS(commandTag = "NOTIFY");
641 Async_Notify(stmt->relname);
647 ListenStmt *stmt = (ListenStmt *) parsetree;
649 PS_SET_STATUS(commandTag = "LISTEN");
652 Async_Listen(stmt->relname, MyProcPid);
658 UnlistenStmt *stmt = (UnlistenStmt *) parsetree;
660 PS_SET_STATUS(commandTag = "UNLISTEN");
663 Async_Unlisten(stmt->relname, MyProcPid);
668 * ******************************** dynamic loader ********************************
673 LoadStmt *stmt = (LoadStmt *) parsetree;
675 PS_SET_STATUS(commandTag = "LOAD");
678 closeAllVfds(); /* probably not necessary... */
679 load_file(stmt->filename);
685 ClusterStmt *stmt = (ClusterStmt *) parsetree;
687 PS_SET_STATUS(commandTag = "CLUSTER");
690 cluster(stmt->relname, stmt->indexname);
695 PS_SET_STATUS(commandTag = "VACUUM");
697 vacuum(((VacuumStmt *) parsetree)->vacrel,
698 ((VacuumStmt *) parsetree)->verbose,
699 ((VacuumStmt *) parsetree)->analyze,
700 ((VacuumStmt *) parsetree)->va_spec);
705 ExplainStmt *stmt = (ExplainStmt *) parsetree;
707 PS_SET_STATUS(commandTag = "EXPLAIN");
710 ExplainQuery(stmt->query, stmt->verbose, dest);
717 * ******************************** Tioga-related statements *******************************
721 RecipeStmt *stmt = (RecipeStmt *) parsetree;
723 PS_SET_STATUS(commandTag = "EXECUTE RECIPE");
731 * ******************************** set variable statements *******************************
733 case T_VariableSetStmt:
735 VariableSetStmt *n = (VariableSetStmt *) parsetree;
737 SetPGVariable(n->name, n->value);
738 PS_SET_STATUS(commandTag = "SET VARIABLE");
742 case T_VariableShowStmt:
744 VariableShowStmt *n = (VariableShowStmt *) parsetree;
746 GetPGVariable(n->name);
747 PS_SET_STATUS(commandTag = "SHOW VARIABLE");
751 case T_VariableResetStmt:
753 VariableResetStmt *n = (VariableResetStmt *) parsetree;
755 ResetPGVariable(n->name);
756 PS_SET_STATUS(commandTag = "RESET VARIABLE");
761 * ******************************** TRIGGER statements *******************************
763 case T_CreateTrigStmt:
764 PS_SET_STATUS(commandTag = "CREATE");
767 CreateTrigger((CreateTrigStmt *) parsetree);
771 PS_SET_STATUS(commandTag = "DROP");
774 DropTrigger((DropTrigStmt *) parsetree);
778 * ************* PROCEDURAL LANGUAGE statements *****************
780 case T_CreatePLangStmt:
781 PS_SET_STATUS(commandTag = "CREATE");
784 CreateProceduralLanguage((CreatePLangStmt *) parsetree);
787 case T_DropPLangStmt:
788 PS_SET_STATUS(commandTag = "DROP");
791 DropProceduralLanguage((DropPLangStmt *) parsetree);
795 * ******************************** USER statements ****
798 case T_CreateUserStmt:
799 PS_SET_STATUS(commandTag = "CREATE USER");
802 CreateUser((CreateUserStmt *) parsetree);
805 case T_AlterUserStmt:
806 PS_SET_STATUS(commandTag = "ALTER USER");
809 AlterUser((AlterUserStmt *) parsetree);
813 PS_SET_STATUS(commandTag = "DROP USER");
816 DropUser((DropUserStmt *) parsetree);
820 PS_SET_STATUS(commandTag = "LOCK TABLE");
823 LockTableCommand((LockStmt *) parsetree);
826 case T_ConstraintsSetStmt:
827 PS_SET_STATUS(commandTag = "SET CONSTRAINTS");
830 DeferredTriggerSetState((ConstraintsSetStmt *) parsetree);
833 case T_CreateGroupStmt:
834 PS_SET_STATUS(commandTag = "CREATE GROUP");
837 CreateGroup((CreateGroupStmt *) parsetree);
840 case T_AlterGroupStmt:
841 PS_SET_STATUS(commandTag = "ALTER GROUP");
844 AlterGroup((AlterGroupStmt *) parsetree, "ALTER GROUP");
847 case T_DropGroupStmt:
848 PS_SET_STATUS(commandTag = "DROP GROUP");
851 DropGroup((DropGroupStmt *) parsetree);
856 ReindexStmt *stmt = (ReindexStmt *) parsetree;
858 PS_SET_STATUS(commandTag = "REINDEX");
861 switch (stmt->reindexType)
864 relname = (char*) stmt->name;
865 if (IsSystemRelationName(relname))
867 if (!allowSystemTableMods && IsSystemRelationName(relname))
868 elog(ERROR, "class \"%s\" is a system catalog index",
870 if (!IsIgnoringSystemIndexes())
871 elog(ERROR, "class \"%s\" is a system catalog index",
875 if (!pg_ownercheck(userName, relname, RELNAME))
876 elog(ERROR, "%s: %s", relname, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
878 ReindexIndex(relname, stmt->force);
881 relname = (char*) stmt->name;
882 if (IsSystemRelationName(relname))
884 if (!allowSystemTableMods && IsSystemRelationName(relname))
885 elog(ERROR, "class \"%s\" is a system catalog index",
887 if (!IsIgnoringSystemIndexes())
888 elog(ERROR, "class \"%s\" is a system catalog index",
892 if (!pg_ownercheck(userName, relname, RELNAME))
893 elog(ERROR, "%s: %s", relname, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
895 ReindexTable(relname, stmt->force);
898 relname = (char*) stmt->name;
899 if (!allowSystemTableMods)
900 elog(ERROR, "-O option is needed");
901 if (!IsIgnoringSystemIndexes())
902 elog(ERROR, "-P option is needed");
903 ReindexDatabase(relname, stmt->force, false);
910 * ******************************** default ********************************
914 elog(ERROR, "ProcessUtility: command #%d unsupported",
920 * tell fe/be or whatever that we're done.
923 EndCommand(commandTag, dest);